From dc9ebd3472363fef8ca2d5ca2340f34478d4500e Mon Sep 17 00:00:00 2001 From: Davan CHIEM DAO Date: Wed, 16 Mar 2022 14:44:58 +0000 Subject: [PATCH] [FIX] l10n_it_edi: Discount computation from invoice import This fixes the how general discounts and product discounts are represented in the Italian EDI. Previously, discounts were erroneously calculated and represented on several invoice lines not linked to the product. Now, cascading discounts are summaries as 1 percentage discount for products and 1 amount for the general discount. closes odoo/odoo#85863 Task: 2764978 X-original-commit: 5769f13e48c5b68bf19fc82377b9ea716ea4a85e Signed-off-by: Josse Colpaert --- .../l10n_it_edi/models/account_edi_format.py | 121 +++++++----------- 1 file changed, 43 insertions(+), 78 deletions(-) diff --git a/addons/l10n_it_edi/models/account_edi_format.py b/addons/l10n_it_edi/models/account_edi_format.py index b58cc27e07b..7202d37cd08 100644 --- a/addons/l10n_it_edi/models/account_edi_format.py +++ b/addons/l10n_it_edi/models/account_edi_format.py @@ -11,6 +11,7 @@ from lxml import etree from datetime import datetime import re import logging +import json _logger = logging.getLogger(__name__) @@ -343,36 +344,6 @@ class AccountEdiFormat(models.Model): if elements: invoice_form.l10n_it_stamp_duty = float(elements[0].text) - # List of all amount discount (will be add after all article to avoid to have a negative sum) - discount_list = [] - percentage_global_discount = 1.0 - - # Global discount. <2.1.1.8> - discount_elements = body_tree.xpath('.//DatiGeneraliDocumento/ScontoMaggiorazione') - total_discount_amount = 0.0 - if discount_elements: - for discount_element in discount_elements: - discount_line = discount_element.xpath('.//Tipo') - discount_sign = -1 - if discount_line and discount_line[0].text == 'SC': - discount_sign = 1 - discount_percentage = discount_element.xpath('.//Percentuale') - if discount_percentage and discount_percentage[0].text: - percentage_global_discount *= 1 - float(discount_percentage[0].text)/100 * discount_sign - - discount_amount_text = discount_element.xpath('.//Importo') - if discount_amount_text and discount_amount_text[0].text: - discount_amount = float(discount_amount_text[0].text) * discount_sign * -1 - discount = {} - discount["seq"] = 0 - - if discount_amount < 0: - discount["name"] = _('GLOBAL DISCOUNT') - else: - discount["name"] = _('GLOBAL EXTRA CHARGE') - discount["amount"] = discount_amount - discount["tax"] = [] - discount_list.append(discount) # Comment. <2.1.1.11> elements = body_tree.xpath('.//DatiGeneraliDocumento//Causale') @@ -457,7 +428,7 @@ class AccountEdiFormat(models.Model): # Sequence. line_elements = element.xpath('.//NumeroLinea') if line_elements: - invoice_line_form.sequence = int(line_elements[0].text) * 2 + invoice_line_form.sequence = int(line_elements[0].text) # Product. line_elements = element.xpath('.//Descrizione') @@ -536,57 +507,51 @@ class AccountEdiFormat(models.Model): percentage, invoice_line_form.name)) - # Discount in cascade mode. - # if 3 discounts : -10% -50€ -20% - # the result must be : (((price -10%)-50€) -20%) - # Generic form : (((price -P1%)-A1€) -P2%) - # It will be split in two parts: fix amount and pourcent amount - # example: (((((price - A1€) -P2%) -A3€) -A4€) -P5€) - # pourcent: 1-(1-P2)*(1-P5) - # fix amount: A1*(1-P2)*(1-P5)+A3*(1-P5)+A4*(1-P5) (we must take account of all - # percentage present after the fix amount) - line_elements = element.xpath('.//ScontoMaggiorazione') - total_discount_amount = 0.0 - total_discount_percentage = percentage_global_discount - if line_elements: - for line_element in line_elements: - discount_line = line_element.xpath('.//Tipo') - discount_sign = -1 - if discount_line and discount_line[0].text == 'SC': - discount_sign = 1 - discount_percentage = line_element.xpath('.//Percentuale') - if discount_percentage and discount_percentage[0].text: - pourcentage_actual = 1 - float(discount_percentage[0].text)/100 * discount_sign - total_discount_percentage *= pourcentage_actual - total_discount_amount *= pourcentage_actual + # Discounts + discount_elements = element.xpath('.//ScontoMaggiorazione') + if discount_elements: + discount_element = discount_elements[0] + discount_percentage = discount_element.xpath('.//Percentuale') + # Special case of only 1 percentage discount + if discount_percentage and len(discount_elements) == 1: + discount_type = discount_element.xpath('.//Tipo') + discount_sign = 1 + if discount_type and discount_type[0].text == 'MG': + discount_sign = -1 + invoice_line_form.discount = discount_sign * float(discount_percentage[0].text) + # Discounts in cascade summarized in 1 percentage + else: + total = float(element.xpath('.//PrezzoTotale')[0].text) + discount = 100 - (100 * total) / (invoice_line_form.quantity * invoice_line_form.price_unit) + invoice_line_form.discount = discount - discount_amount = line_element.xpath('.//Importo') - if discount_amount and discount_amount[0].text: - total_discount_amount += float(discount_amount[0].text) * discount_sign * -1 - # Save amount discount. - if total_discount_amount != 0: - discount = {} - discount["seq"] = invoice_line_form.sequence + 1 + # Global discount summarized in 1 amount + discount_elements = body_tree.xpath('.//DatiGeneraliDocumento/ScontoMaggiorazione') + if discount_elements: + taxable_amount = float(json.loads(invoice_form.tax_totals_json)['amount_untaxed']) + discounted_amount = taxable_amount + for discount_element in discount_elements: + discount_type = discount_element.xpath('.//Tipo') + discount_sign = 1 + if discount_type and discount_type[0].text == 'MG': + discount_sign = -1 + discount_amount = discount_element.xpath('.//Importo') + if discount_amount: + discounted_amount -= discount_sign * float(discount_amount[0].text) + continue + discount_percentage = discount_element.xpath('.//Percentuale') + if discount_percentage: + discounted_amount *= 1 - discount_sign * float(discount_percentage[0].text) / 100 - if total_discount_amount < 0: - discount["name"] = _('DISCOUNT: %s', invoice_line_form.name) - else: - discount["name"] = _('EXTRA CHARGE: %s', invoice_line_form.name) - discount["amount"] = total_discount_amount - discount["tax"] = [] - for tax in invoice_line_form.tax_ids: - discount["tax"].append(tax) - discount_list.append(discount) - invoice_line_form.discount = (1 - total_discount_percentage) * 100 + general_discount = discounted_amount - taxable_amount + sequence = len(elements) + 1 - # Apply amount discount. - for discount in discount_list: - with invoice_form.invoice_line_ids.new() as invoice_line_form_discount: - invoice_line_form_discount.tax_ids.clear() - invoice_line_form_discount.sequence = discount["seq"] - invoice_line_form_discount.name = discount["name"] - invoice_line_form_discount.price_unit = discount["amount"] + with invoice_form.invoice_line_ids.new() as invoice_line_global_discount: + invoice_line_global_discount.tax_ids.clear() + invoice_line_global_discount.sequence = sequence + invoice_line_global_discount.name = 'SCONTO' if general_discount < 0 else 'MAGGIORAZIONE' + invoice_line_global_discount.price_unit = general_discount new_invoice = invoice_form.save() new_invoice.l10n_it_send_state = "other"