From 8c8d492a48d3b2c6f5d6f5661c33ed59c98832b4 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sun, 19 Jan 2020 15:19:07 +0100 Subject: [PATCH] FIX Protection to avoid blocking situation with negative lines --- htdocs/compta/facture/card.php | 48 ++++++++++++++++++++++++++++++++-- htdocs/langs/en_US/errors.lang | 3 ++- 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/htdocs/compta/facture/card.php b/htdocs/compta/facture/card.php index bc51fabfefc..3308d0e816e 100644 --- a/htdocs/compta/facture/card.php +++ b/htdocs/compta/facture/card.php @@ -137,6 +137,7 @@ $isdraft = (($object->statut == Facture::STATUS_DRAFT) ? 1 : 0); $result = restrictedArea($user, 'facture', $id, '', '', 'fk_soc', $fieldid, $isdraft); + /* * Actions */ @@ -289,6 +290,39 @@ if (empty($reshook)) setEventMessages($langs->trans("ErrorInvoiceOfThisTypeMustBePositive"), null, 'errors'); $action = ''; } + + // Also negative lines should not be allowed on 'non Credit notes' invoices. A test is done when adding or updating lines but we must + // do it again in validation to avoid cases where invoice is created from another object that allow negative lines. + // Note that we can accept the negative line if sum with other lines with same vat is positivie: Because all the lines will be merged together + // when converted into 'available credit' and we will get a positive available credit line. + // Note: Other solution if you want to add a negative line on invoice, is to create a discount for customer and consumme it (but this is possible on standard invoice only). + $array_of_pu_ht_per_vat_rate = array(); + $array_of_pu_ht_devise_per_vat_rate = array(); + foreach($object->lines as $line) { + if (empty($array_of_pu_ht_per_vat_rate[$line->tva_tx.'_'.$line->vat_src_code])) $array_of_pu_ht_per_vat_rate[$line->tva_tx.'_'.$line->vat_src_code] = 0; + if (empty($array_of_pu_ht_devise_per_vat_rate[$line->tva_tx.'_'.$line->vat_src_code])) $array_of_pu_ht_devise_per_vat_rate[$line->tva_tx.'_'.$line->vat_src_code] = 0; + $array_of_pu_ht_per_vat_rate[$line->tva_tx.'_'.$line->vat_src_code] += $line->subprice; + $array_of_pu_ht_devise_per_vat_rate[$line->tva_tx.'_'.$line->vat_src_code] += $line->multicurrency_subprice; + } + //var_dump($array_of_pu_ht_per_vat_rate);exit; + foreach($array_of_pu_ht_per_vat_rate as $vatrate => $tmpvalue) + { + $pu_ht = $array_of_pu_ht_per_vat_rate[$vatrate]; + $pu_ht_devise = $array_of_pu_ht_devise_per_vat_rate[$vatrate]; + + if (($pu_ht < 0 || $pu_ht_devise < 0) && empty($conf->global->FACTURE_ENABLE_NEGATIVE_LINES)) + { + $langs->load("errors"); + if ($object->type == $object::TYPE_DEPOSIT) { + // Using negative lines on deposit lead to headach and blocking problems when you want to consume them. + setEventMessages($langs->trans("ErrorLinesCantBeNegativeOnDeposits"), null, 'errors'); + } else { + setEventMessages($langs->trans("ErrorFieldCantBeNegativeOnInvoice", $langs->transnoentitiesnoconv("UnitPriceHT"), $langs->transnoentitiesnoconv("CustomerAbsoluteDiscountShort")), null, 'errors'); + } + $error++; + $action = ''; + } + } } } @@ -1822,7 +1856,12 @@ if (empty($reshook)) if ($price_ht < 0 && empty($conf->global->FACTURE_ENABLE_NEGATIVE_LINES)) { $langs->load("errors"); - setEventMessages($langs->trans("ErrorFieldCantBeNegativeOnInvoice", $langs->transnoentitiesnoconv("UnitPriceHT")), null, 'errors'); + if ($object->type == $object::TYPE_DEPOSIT) { + // Using negative lines on deposit lead to headach and blocking problems when you want to consume them. + setEventMessages($langs->trans("ErrorLinesCantBeNegativeOnDeposits"), null, 'errors'); + } else { + setEventMessages($langs->trans("ErrorFieldCantBeNegativeOnInvoice", $langs->transnoentitiesnoconv("UnitPriceHT"), $langs->transnoentitiesnoconv("CustomerAbsoluteDiscountShort")), null, 'errors'); + } $error++; } else @@ -2203,7 +2242,12 @@ if (empty($reshook)) if ($pu_ht < 0 && empty($conf->global->FACTURE_ENABLE_NEGATIVE_LINES)) { $langs->load("errors"); - setEventMessages($langs->trans("ErrorFieldCantBeNegativeOnInvoice", $langs->transnoentitiesnoconv("UnitPriceHT")), null, 'errors'); + if ($object->type == $object::TYPE_DEPOSIT) { + // Using negative lines on deposit lead to headach and blocking problems when you want to consume them. + setEventMessages($langs->trans("ErrorLinesCantBeNegativeOnDeposits"), null, 'errors'); + } else { + setEventMessages($langs->trans("ErrorFieldCantBeNegativeOnInvoice", $langs->transnoentitiesnoconv("UnitPriceHT"), $langs->transnoentitiesnoconv("CustomerAbsoluteDiscountShort")), null, 'errors'); + } $error++; } else diff --git a/htdocs/langs/en_US/errors.lang b/htdocs/langs/en_US/errors.lang index 7aafdfbbd65..4edca737c66 100644 --- a/htdocs/langs/en_US/errors.lang +++ b/htdocs/langs/en_US/errors.lang @@ -117,7 +117,8 @@ ErrorLoginDoesNotExists=User with login %s could not be found. ErrorLoginHasNoEmail=This user has no email address. Process aborted. ErrorBadValueForCode=Bad value for security code. Try again with new value... ErrorBothFieldCantBeNegative=Fields %s and %s can't be both negative -ErrorFieldCantBeNegativeOnInvoice=Field %s cannot be negative on this type of invoice. If you want to add a discount line, just create the discount first with link %s on screen and apply it to the invoice. You can also ask your admin to set option FACTURE_ENABLE_NEGATIVE_LINES to 1 to allow the old behaviour. +ErrorFieldCantBeNegativeOnInvoice=Field %s cannot be negative on this type of invoice. If you need to add a discount line, just create the discount first (from field '%s' in thirdparty card) and apply it to the invoice. You can also ask your admin to set option FACTURE_ENABLE_NEGATIVE_LINES to 1 to allow the old behaviour. +ErrorLinesCantBeNegativeOnDeposits=Lines can't be negative in a deposit. You will face problems when you will need to consume the deposit in final invoice if you do so. ErrorQtyForCustomerInvoiceCantBeNegative=Quantity for line into customer invoices can't be negative ErrorWebServerUserHasNotPermission=User account %s used to execute web server has no permission for that ErrorNoActivatedBarcode=No barcode type activated