diff --git a/addons/account_edi_ubl_cii/models/account_edi_common.py b/addons/account_edi_ubl_cii/models/account_edi_common.py index 1b528f7ee6d..01bc3bb4cf9 100644 --- a/addons/account_edi_ubl_cii/models/account_edi_common.py +++ b/addons/account_edi_ubl_cii/models/account_edi_common.py @@ -266,6 +266,12 @@ class AccountEdiCommon(models.AbstractModel): default_journal_id=journal.id, )._get_edi_creation() as invoice: logs = self._import_fill_invoice_form(journal, tree, invoice, qty_factor) + + # For UBL, we should override the computed tax amount if it is less than 0.05 different of the one in the xml. + # In order to support use case where the tax total is adapted for rounding purpose. + # This has to be done after the first import in order to let Odoo compute the taxes before overriding if needed. + with invoice.with_context(account_predictive_bills_disable_prediction=True)._get_edi_creation() as invoice: + self._correct_invoice_tax_amount(tree, invoice) if invoice: if logs: body = _( @@ -595,6 +601,9 @@ class AccountEdiCommon(models.AbstractModel): invoice_line_form.tax_ids = inv_line_vals['taxes'] return logs + def _correct_invoice_tax_amount(self, tree, invoice): + pass # To be implemented by the format if needed + # ------------------------------------------------------------------------- # Check xml using the free API from Ph. Helger, don't abuse it ! # ------------------------------------------------------------------------- diff --git a/addons/account_edi_ubl_cii/models/account_edi_xml_ubl_20.py b/addons/account_edi_ubl_cii/models/account_edi_xml_ubl_20.py index c9b9cd3f679..979c2b6a8d8 100644 --- a/addons/account_edi_ubl_cii/models/account_edi_xml_ubl_20.py +++ b/addons/account_edi_ubl_cii/models/account_edi_xml_ubl_20.py @@ -487,11 +487,28 @@ class AccountEdiXmlUBL20(models.AbstractModel): logs.append(_("Could not retrieve currency: %s. Did you enable the multicurrency option " "and activate the currency ?", currency_code_node.text)) + # ==== invoice_date ==== + + invoice_date_node = tree.find('./{*}IssueDate') + if invoice_date_node is not None and invoice_date_node.text: + invoice.invoice_date = invoice_date_node.text + + # ==== invoice_date_due ==== + + for xpath in ('./{*}DueDate', './/{*}PaymentDueDate'): + invoice_date_due_node = tree.find(xpath) + if invoice_date_due_node is not None and invoice_date_due_node.text: + invoice.invoice_date_due = invoice_date_due_node.text + break + # ==== Reference ==== ref_node = tree.find('./{*}ID') if ref_node is not None: - invoice.ref = ref_node.text + if invoice.is_sale_document(include_receipts=True) and invoice.quick_edit_mode: + invoice.name = ref_node.text + else: + invoice.ref = ref_node.text # === Note/narration ==== @@ -512,20 +529,6 @@ class AccountEdiXmlUBL20(models.AbstractModel): if payment_reference_node is not None: invoice.payment_reference = payment_reference_node.text - # ==== invoice_date ==== - - invoice_date_node = tree.find('./{*}IssueDate') - if invoice_date_node is not None and invoice_date_node.text: - invoice.invoice_date = invoice_date_node.text - - # ==== invoice_date_due ==== - - for xpath in ('./{*}DueDate', './/{*}PaymentDueDate'): - invoice_date_due_node = tree.find(xpath) - if invoice_date_due_node is not None and invoice_date_due_node.text: - invoice.invoice_date_due = invoice_date_due_node.text - break - # ==== invoice_incoterm_id ==== incoterm_code_node = tree.find('./{*}TransportExecutionTerms/{*}DeliveryTerms/{*}ID') @@ -596,6 +599,28 @@ class AccountEdiXmlUBL20(models.AbstractModel): tax_nodes += elem.findall('.//{*}TaxSubtotal/{*}Percent') return self._import_fill_invoice_line_taxes(journal, tax_nodes, invoice_line, inv_line_vals, logs) + def _correct_invoice_tax_amount(self, tree, invoice): + """ The tax total may have been modified for rounding purpose, if so we should use the imported tax and not + the computed one """ + # For each tax in our tax total, get the amount as well as the total in the xml. + for elem in tree.findall('.//{*}TaxTotal/{*}TaxSubtotal'): + percentage = elem.find('.//{*}TaxCategory/{*}Percent') + amount = elem.find('.//{*}TaxAmount') + if (percentage is not None and percentage.text is not None) and (amount is not None and amount.text is not None): + tax_percent = float(percentage.text) + # Compare the result with our tax total on the invoice, and apply correction if needed. + # First look for taxes matching the percentage in the xml. + taxes = invoice.line_ids.tax_line_id.filtered(lambda tax: tax.amount == tax_percent) + # If we found taxes with the correct amount, look for a tax line using it, and correct it as needed. + if taxes: + tax_total = float(amount.text) + tax_line = invoice.line_ids.filtered(lambda line: line.tax_line_id in taxes)[:1] + if tax_line: + sign = -1 if invoice.is_inbound(include_receipts=True) else 1 + tax_line_amount = abs(tax_line.amount_currency) + if abs(tax_total - tax_line_amount) <= 0.05: + tax_line.amount_currency = tax_total * sign + # ------------------------------------------------------------------------- # IMPORT : helpers # -------------------------------------------------------------------------