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 d8138151b2d..e8d21ce64f1 100644 --- a/addons/account_edi_ubl_cii/models/account_edi_common.py +++ b/addons/account_edi_ubl_cii/models/account_edi_common.py @@ -661,15 +661,24 @@ class AccountEdiCommon(models.AbstractModel): ('type_tax_use', '=', invoice_line.move_id.journal_id.type), ('amount', '=', amount), ] - tax_excl = self.env['account.tax'].search(domain + [('price_include', '=', False)], limit=1) - tax_incl = self.env['account.tax'].search(domain + [('price_include', '=', True)], limit=1) - if tax_excl: - inv_line_vals['taxes'].append(tax_excl.id) - elif tax_incl: - inv_line_vals['taxes'].append(tax_incl.id) - inv_line_vals['price_unit'] *= (1 + tax_incl.amount / 100) - else: + + tax = False + if hasattr(invoice_line, '_predict_specific_tax'): + # company check is already done in the prediction query + predicted_tax_id = invoice_line\ + ._predict_specific_tax('percent', amount, invoice_line.move_id.journal_id.type) + tax = self.env['account.tax'].browse(predicted_tax_id) + if not tax: + tax = self.env['account.tax'].search(domain + [('price_include', '=', False)], limit=1) + if not tax: + tax = self.env['account.tax'].search(domain + [('price_include', '=', True)], limit=1) + + if not tax: logs.append(_("Could not retrieve the tax: %s %% for line '%s'.", amount, invoice_line.name)) + else: + inv_line_vals['taxes'].append(tax.id) + if tax.price_include: + inv_line_vals['price_unit'] *= (1 + tax.amount / 100) # Handle Fixed Taxes for fixed_tax_vals in inv_line_vals['fixed_taxes_list']: diff --git a/addons/account_edi_ubl_cii/tests/test_files/bis3_bill_example.xml b/addons/account_edi_ubl_cii/tests/test_files/bis3_bill_example.xml new file mode 100644 index 00000000000..6c6f0a10569 --- /dev/null +++ b/addons/account_edi_ubl_cii/tests/test_files/bis3_bill_example.xml @@ -0,0 +1,136 @@ + + + urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0 + urn:fdc:peppol.eu:2017:poacc:billing:01:1.0 + FAC/2023/00052 + 2023-08-04 + 2023-09-04 + 380 + EUR + + FAC/2023/00052 + S00012 + + + FAC_2023_00052.pdf + + + + + + LU25587702 + + ALD Automotive LU + + + 270 rte d'Arlon + Strassen + 8010 + + LU + + + + LU12977109 + + VAT + + + + ALD Automotive LU + LU12977109 + + + ALD Automotive LU + adl@test.com + + + + + + LU25587702 + + Odoo Lu + + + Rue de l'industrie 13 + Windhof + + LU + + + + LU25587702 + + VAT + + + + Odoo Lu + LU25587702 + + + Odoo Lu + odoo@test.com + + + + + + + Rue de l'industrie 13 + Windhof + + LU + + + + + + 30 + FAC/2023/00052 + + LU071241358706500000 + + + + 105.12 + + 657.00 + 105.12 + + S + 16.0 + + VAT + + + + + + 657.00 + 657.00 + 762.12 + 0.00 + 762.12 + + + 1 + 1.0 + 657.00 + + Locations et leasing opérationnel - Véhicule HG6542 + Locations et leasing opérationnel + + S + 16.0 + + VAT + + + + + 657.00 + + + diff --git a/addons/account_edi_ubl_cii/tests/test_ubl_cii.py b/addons/account_edi_ubl_cii/tests/test_ubl_cii.py index c5f8875da8e..4671e59483d 100644 --- a/addons/account_edi_ubl_cii/tests/test_ubl_cii.py +++ b/addons/account_edi_ubl_cii/tests/test_ubl_cii.py @@ -5,6 +5,7 @@ from lxml import etree from odoo import Command from odoo.addons.account.tests.common import AccountTestInvoicingCommon from odoo.tests import tagged +from odoo.tools import file_open @tagged('post_install', '-at_install') @@ -94,3 +95,56 @@ class TestAccountEdiUblCii(AccountTestInvoicingCommon): new_invoice = invoice.journal_id._create_document_from_attachment(facturx_attachment.ids) self.assertRecordValues(new_invoice.invoice_line_ids, line_vals) + + def test_import_tax_prediction(self): + """ We are going to create 2 tax and import the e-invoice twice. + + On the first attempt, as there isn't any data to leverage, the classic 'search' will be called and we expect + the first tax created to be the selected one as the retrieval order is `sequence, id`. + + We will set the second tax on the bill and post it which make it the most probable one. + + On the second attempt, we expect that second tax to be retrieved. + """ + if not hasattr(self.env["account.move.line"], '_predict_specific_tax'): + self.skipTest("The predictive bill module isn't install and thus prediction with edi can't be tested.") + # create 2 new taxes for the test seperatly to ensure the first gets the smaller id + new_tax_1 = self.env["account.tax"].create({ + 'name': 'tax with lower id could be retrieved first', + 'amount_type': 'percent', + 'type_tax_use': 'purchase', + 'amount': 16.0, + }) + new_tax_2 = self.env["account.tax"].create({ + 'name': 'tax with higher id could be retrieved second', + 'amount_type': 'percent', + 'type_tax_use': 'purchase', + 'amount': 16.0, + }) + + file_path = "bis3_bill_example.xml" + file_path = f"{self.test_module}/tests/test_files/{file_path}" + with file_open(file_path, 'rb') as file: + xml_attachment = self.env['ir.attachment'].create({ + 'mimetype': 'application/xml', + 'name': 'test_invoice.xml', + 'raw': file.read(), + }) + + # Import the document for the first time + bill = self.env['account.journal']\ + .with_context(default_journal_id=self.company_data["default_journal_purchase"].id)\ + ._create_document_from_attachment(xml_attachment.id) + + # Ensure the first tax is retrieved as there isn't any prediction that could be leverage + self.assertEqual(bill.invoice_line_ids.tax_ids, new_tax_1) + + # Set the second tax on the line to make it the most probable one + bill.invoice_line_ids.tax_ids = new_tax_2 + bill.action_post() + + # Import the bill again and ensure the prediction did his work + bill = self.env['account.journal']\ + .with_context(default_journal_id=self.company_data["default_journal_purchase"].id)\ + ._create_document_from_attachment(xml_attachment.id) + self.assertEqual(bill.invoice_line_ids.tax_ids, new_tax_2)