[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 <jco@odoo.com>
This commit is contained in:
Davan CHIEM DAO
2022-03-24 13:57:15 +01:00
parent eb23c0c9d5
commit dc9ebd3472
+43 -78
View File
@@ -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"