Closed qaOYR closed 1 month ago
To clarify, Tax 3 is localtax_2 in code/DB.
Tested on 16.0.3, locatax2 gets copied to the new invoice with out needing to update a line.
Hi Daviid-P,
Thanks for responding. We are testing and using Dolibarr 16.05 and can reproduce the above-mentioned bug in more than one install. We have resolved the issue by adding the following type definitions before line 3744 in file facture.class.php
Path: /htdocs/compta/facture/class
File: facture.class.php
Insert the following code before line 3744:
$localtaxes_type[2] = 5;
$localtaxes_type[3] = $txlocaltax2;
Line: 3744
$tabprice = calcul_price_total($qty, $pu, $remise_percent, $txtva, $txlocaltax1, $txlocaltax2, 0, $price_base_type, $info_bits, $product_type, $mysoc, $localtaxes_type, $situation_percent, $this->multicurrency_tx, $pu_ht_devise);
Do you see any downsides or possible side-effects to what we are proposing?
Thanks,
qaOYR
How does your
function getLocalTaxesFromRate($vatrate, $local, $buyer, $seller, $firstparamisid = 0)
{
global $db, $mysoc;
dol_syslog("getLocalTaxesFromRate vatrate=".$vatrate." local=".$local);
// Search local taxes
$sql = "SELECT t.taux as rate, t.code, t.localtax1, t.localtax1_type, t.localtax2, t.localtax2_type, t.accountancy_code_sell, t.accountancy_code_buy";
$sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t";
if ($firstparamisid) {
$sql .= " WHERE t.rowid = ".(int) $vatrate;
} else {
$vatratecleaned = $vatrate;
$vatratecode = '';
$reg = array();
if (preg_match('/^(.*)\s*\((.*)\)$/', $vatrate, $reg)) { // If vat is "x.x (yy)"
$vatratecleaned = $reg[1];
$vatratecode = $reg[2];
}
$sql .= ", ".MAIN_DB_PREFIX."c_country as c";
if ($mysoc->country_code == 'ES') {
$sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($buyer->country_code)."'"; // local tax in spain use the buyer country ??
} else {
$sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape(empty($seller->country_code) ? $mysoc->country_code : $seller->country_code)."'";
}
$sql .= " AND t.taux = ".((float) $vatratecleaned)." AND t.active = 1";
if ($vatratecode) {
$sql .= " AND t.code = '".$db->escape($vatratecode)."'";
}
}
$resql = $db->query($sql);
if ($resql) {
$obj = $db->fetch_object($resql);
if ($obj) {
$vateratestring = $obj->rate.($obj->code ? ' ('.$obj->code.')' : '');
if ($local == 1) {
return array($obj->localtax1_type, get_localtax($vateratestring, $local, $buyer, $seller), $obj->accountancy_code_sell, $obj->accountancy_code_buy);
} elseif ($local == 2) {
return array($obj->localtax2_type, get_localtax($vateratestring, $local, $buyer, $seller), $obj->accountancy_code_sell, $obj->accountancy_code_buy);
} else {
return array($obj->localtax1_type, get_localtax($vateratestring, 1, $buyer, $seller), $obj->localtax2_type, get_localtax($vateratestring, 2, $buyer, $seller), $obj->accountancy_code_sell, $obj->accountancy_code_buy);
}
}
}
return array();
}
and
function get_localtax($vatrate, $local, $thirdparty_buyer = "", $thirdparty_seller = "", $vatnpr = 0)
{
global $db, $conf, $mysoc;
if (empty($thirdparty_seller) || !is_object($thirdparty_seller)) {
$thirdparty_seller = $mysoc;
}
dol_syslog("get_localtax tva=".$vatrate." local=".$local." thirdparty_buyer id=".(is_object($thirdparty_buyer) ? $thirdparty_buyer->id : '')."/country_code=".(is_object($thirdparty_buyer) ? $thirdparty_buyer->country_code : '')." thirdparty_seller id=".$thirdparty_seller->id."/country_code=".$thirdparty_seller->country_code." thirdparty_seller localtax1_assuj=".$thirdparty_seller->localtax1_assuj." thirdparty_seller localtax2_assuj=".$thirdparty_seller->localtax2_assuj);
$vatratecleaned = $vatrate;
$reg = array();
if (preg_match('/^(.*)\s*\((.*)\)$/', $vatrate, $reg)) { // If vat is "xx (yy)"
$vatratecleaned = trim($reg[1]);
$vatratecode = $reg[2];
}
/*if ($thirdparty_buyer->country_code != $thirdparty_seller->country_code)
{
return 0;
}*/
// Some test to guess with no need to make database access
if ($mysoc->country_code == 'ES') { // For spain localtaxes 1 and 2, tax is qualified if buyer use local tax
if ($local == 1) {
if (!$mysoc->localtax1_assuj || (string) $vatratecleaned == "0") {
return 0;
}
if ($thirdparty_seller->id == $mysoc->id) {
if (!$thirdparty_buyer->localtax1_assuj) {
return 0;
}
} else {
if (!$thirdparty_seller->localtax1_assuj) {
return 0;
}
}
}
if ($local == 2) {
//if (! $mysoc->localtax2_assuj || (string) $vatratecleaned == "0") return 0;
//if (!$mysoc->localtax2_assuj) {
// return 0; // If main vat is 0, IRPF may be different than 0.
//}
if ($thirdparty_seller->id == $mysoc->id) {
// if (!$thirdparty_buyer->localtax2_assuj) {
// return 0;
// }
// customCode
if (
$conf->global->FACTURE_LOCAL_TAX2_OPTION != "localtax2off" &&
isset($conf->global->MAIN_INFO_VALUE_LOCALTAX2)
) {
return $conf->global->MAIN_INFO_VALUE_LOCALTAX2;
} elseif ($thirdparty_seller->localtax2_assuj) {
return $thirdparty_seller->localtax2_value;
}
// customCode
} else {
if (!$thirdparty_seller->localtax2_assuj) {
return 0;
}
}
}
} else {
if ($local == 1 && !$thirdparty_seller->localtax1_assuj) {
return 0;
}
if ($local == 2 && !$thirdparty_seller->localtax2_assuj) {
return 0;
}
}
// For some country MAIN_GET_LOCALTAXES_VALUES_FROM_THIRDPARTY is forced to on.
if (in_array($mysoc->country_code, array('ES'))) {
$conf->global->MAIN_GET_LOCALTAXES_VALUES_FROM_THIRDPARTY = 1;
}
// Search local taxes
if (!empty($conf->global->MAIN_GET_LOCALTAXES_VALUES_FROM_THIRDPARTY)) {
if ($local == 1) {
if ($thirdparty_seller != $mysoc) {
if (!isOnlyOneLocalTax($local)) { // TODO We should provide $vatrate to search on correct line and not always on line with highest vat rate
return $thirdparty_seller->localtax1_value;
}
} else { // i am the seller
if (!isOnlyOneLocalTax($local)) { // TODO If seller is me, why not always returning this, even if there is only one locatax vat.
return $conf->global->MAIN_INFO_VALUE_LOCALTAX1;
}
}
}
if ($local == 2) {
if ($thirdparty_seller != $mysoc) {
if (!isOnlyOneLocalTax($local)) { // TODO We should provide $vatrate to search on correct line and not always on line with highest vat rate
// TODO We should also return value defined on thirdparty only if defined
return $thirdparty_seller->localtax2_value;
}
} else { // i am the seller
// customCode
if ($conf->global->FACTURE_LOCAL_TAX2_OPTION != "localtax2off" &&
isset($conf->global->MAIN_INFO_VALUE_LOCALTAX2)) {
return $conf->global->MAIN_INFO_VALUE_LOCALTAX2;
} elseif ($thirdparty_buyer->localtax2_value > 0) {
return $thirdparty_buyer->localtax2_value;
}
// customCode
//if (in_array($mysoc->country_code, array('ES'))) {
// return $thirdparty_buyer->localtax2_value;
//} else {
// return $conf->global->MAIN_INFO_VALUE_LOCALTAX2;
//}
}
}
}
// By default, search value of local tax on line of common tax
$sql = "SELECT t.localtax1, t.localtax2, t.localtax1_type, t.localtax2_type";
$sql .= " FROM ".MAIN_DB_PREFIX."c_tva as t, ".MAIN_DB_PREFIX."c_country as c";
$sql .= " WHERE t.fk_pays = c.rowid AND c.code = '".$db->escape($thirdparty_seller->country_code)."'";
$sql .= " AND t.taux = ".((float) $vatratecleaned)." AND t.active = 1";
if (!empty($vatratecode)) {
$sql .= " AND t.code ='".$db->escape($vatratecode)."'"; // If we have the code, we use it in priority
} else {
$sql .= " AND t.recuperableonly = '".$db->escape($vatnpr)."'";
}
$resql = $db->query($sql);
if ($resql) {
$obj = $db->fetch_object($resql);
if ($obj) {
if ($local == 1) {
return $obj->localtax1;
} elseif ($local == 2) {
return $obj->localtax2;
}
}
}
return 0;
}
look like?
I think I've modified mine becuase of some problems I had so maybe mine is working because of that.
Also how is your tva dictionary? /htdocs/admin/dict.php
in "Tasa de IVA"
@simnandez - Could you please review our proposed fix as I believe it is a bug that is easy to reproduce?
This issue affects many users of Dolibarr in Spain and we belive that our proposed fix addresses the issue. It has been in production for some time without any visible downsides.
Look forward to your response,
qaOYR.
@simnandez - Could you please review our proposed fix as I believe it is a bug that is easy to reproduce?
This issue affects many users of Dolibarr in Spain and we belive that our proposed fix addresses the issue. It has been in production for some time without any visible downsides.
Look forward to your response,
qaOYR.
I doubt the suggested fix will be imp,emented, you're hardcoding values here.
Assuming localtax2, getLocalTaxesFromRate
returns:
array(
0 $obj->localtax2_type,
1 get_localtax($vateratestring, $local, $buyer, $seller),
2 $obj->accountancy_code_sell,
3 $obj->accountancy_code_buy
)
Are you sure accountancy_code_sell
should be always 5
and accountancy_code_buy
always $txlocaltax2
And that's v16 and maybe v17
Now in v18 it returns:
array(
'rowid'=>$obj->rowid,
'code'=>$obj->code,
'rate'=>$obj->rate,
'localtax1'=>$obj->localtax1,
'localtax1_type'=>$obj->localtax1_type,
'localtax2'=>$obj->localtax2,
'localtax2_type'=>$obj->localtax2_type,
'npr'=>$obj->npr,
'accountancy_code_sell'=>$obj->accountancy_code_sell,
'accountancy_code_buy'=>$obj->accountancy_code_buy
);
So no integer index.
This issue is stale because it has been open 1 year with no activity. If this is a bug, please comment to confirm it is still present on latest stable version. if this is a feature request, please comment to notify the request is still relevant and not yet covered by latest stable version. This issue may be closed automatically by stale bot in 10 days (you should still be able to re-open it if required).
Bug
Scenario: An invoice contains both VAT and an addiontal tax (tax 3). We use this additional tax in Spain for income taxes applied to invoices (IRPF). The rate of Tax 3 has been setup in the dictionary setup for VAT tax.
Environment Version
16.05 and 17.01
Environment OS
Ubuntu Server 22.04
Environment Web server
Apache
Environment PHP
PHP 7.4.29 and PHP 8.1
Environment Database
MySQL 7.4.29
Environment URL(s)
No response
Expected and actual behavior
Behavior: When copying an invoice that contains a VAT Tax and an additional Tax 3 , Tax 3 is only applied to the generated PDF file when you update individually each line on an invoice. No actual changes need to be made to each invoiced service line, just click on edit without changing anything and save.
Once this is done, the tax is correctly applied to that line in your invoice.
My guess is that the right tax value exists in the database, but it is not applied to each item of an invoice until the invoiced is reloaded for editing
Expected Behavior: when an invoice is copied all attributes and taxes should be preserved.
Steps to reproduce the behavior
Copy any existing invoice that has both a VAT and Local Tax 3 (IRPF in Spain) and local tax 3 will not be applied until you edit each service line on the invoice.
Attached files
No response