From dcd84cc71e2e0051d7a301b3b8c3e2ebf733ba8e Mon Sep 17 00:00:00 2001 From: Paul Morelle <pmo@odoo.com> Date: Mon, 30 Aug 2021 11:20:47 +0000 Subject: [PATCH] [FIX] account_edi*: retrieve records within allowed companies _retrieve_{partner,product,tax} methods were not taking into account a scope of a company, and methods like _import_ubl or _import_facturx could end up on creating an invoice with a company mismatch between the company of the journal and the company of the partner, product or tax. With this commit, these methods will consider the allowed_company_ids context value, and calling code should set it to an acceptable value. OPW-2560795 closes odoo/odoo#75738 Signed-off-by: Laurent Smet <smetl@users.noreply.github.com> --- .../account_edi/models/account_edi_format.py | 21 ++++++++++++------- .../models/account_edi_format.py | 10 +++++---- .../test_file/test_facturx.xml | 3 +++ .../account_edi_facturx/tests/test_facturx.py | 18 ++++++++++++++++ .../models/account_edi_format.py | 7 ++++--- 5 files changed, 44 insertions(+), 15 deletions(-) diff --git a/addons/account_edi/models/account_edi_format.py b/addons/account_edi/models/account_edi_format.py index 1dce2c580df0..68ae2c9532c7 100644 --- a/addons/account_edi/models/account_edi_format.py +++ b/addons/account_edi/models/account_edi_format.py @@ -497,7 +497,10 @@ class AccountEdiFormat(models.Model): if value is not None: domains.append(domain) - domain = expression.OR(domains) + domain = expression.AND([ + expression.OR(domains), + [('company_id', 'in', [False, self.env.company.id])], + ]) return self.env['res.partner'].search(domain, limit=1) def _retrieve_product(self, name=None, default_code=None, barcode=None): @@ -517,7 +520,10 @@ class AccountEdiFormat(models.Model): if value is not None: domains.append([domain]) - domain = expression.OR(domains) + domain = expression.AND([ + expression.OR(domains), + [('company_id', 'in', [False, self.env.company.id])], + ]) return self.env['product.product'].search(domain, limit=1) def _retrieve_tax(self, amount, type_tax_use): @@ -527,12 +533,11 @@ class AccountEdiFormat(models.Model): :param type_tax_use: The type of the tax. :returns: A tax or an empty recordset if not found. ''' - domains = [ - [('amount', '=', float(amount))], - [('type_tax_use', '=', type_tax_use)] - ] - - return self.env['account.tax'].search(expression.AND(domains), order='sequence ASC', limit=1) + return self.env['account.tax'].search([ + ('amount', '=', float(amount)), + ('type_tax_use', '=', type_tax_use), + ('company_id', '=', self.env.company.id), + ], limit=1) def _retrieve_currency(self, code): '''Search all currencies and find one that matches the code. diff --git a/addons/account_edi_facturx/models/account_edi_format.py b/addons/account_edi_facturx/models/account_edi_format.py index 60f74b82e1db..8b3a1f684f7f 100644 --- a/addons/account_edi_facturx/models/account_edi_format.py +++ b/addons/account_edi_facturx/models/account_edi_format.py @@ -193,9 +193,11 @@ class AccountEdiFormat(models.Model): # self could be a single record (editing) or be empty (new). with Form(invoice.with_context(default_move_type=default_move_type, account_predictive_bills_disable_prediction=True)) as invoice_form: + self_ctx = self.with_company(invoice.company_id) + # Partner (first step to avoid warning 'Warning! You must first select a partner.'). partner_type = invoice_form.journal_id.type == 'purchase' and 'SellerTradeParty' or 'BuyerTradeParty' - invoice_form.partner_id = self._retrieve_partner( + invoice_form.partner_id = self_ctx._retrieve_partner( name=self._find_value('//ram:' + partner_type + '/ram:Name', tree, namespaces=tree.nsmap), mail=self._find_value('//ram:' + partner_type + '//ram:URIID[@schemeID=\'SMTP\']', tree, namespaces=tree.nsmap), vat=self._find_value('//ram:' + partner_type + '/ram:SpecifiedTaxRegistration/ram:ID', tree, namespaces=tree.nsmap), @@ -203,7 +205,7 @@ class AccountEdiFormat(models.Model): # Delivery partner if 'partner_shipping_id' in invoice._fields: - invoice_form.partner_shipping_id = self._retrieve_partner( + invoice_form.partner_shipping_id = self_ctx._retrieve_partner( name=self._find_value('//ram:ShipToTradeParty/ram:Name', tree, namespaces=tree.nsmap), mail=self._find_value('//ram:ShipToTradeParty//ram:URIID[@schemeID=\'SMTP\']', tree, namespaces=tree.nsmap), vat=self._find_value('//ram:ShipToTradeParty/ram:SpecifiedTaxRegistration/ram:ID', tree, namespaces=tree.nsmap), @@ -267,7 +269,7 @@ class AccountEdiFormat(models.Model): name = _find_value('.//ram:SpecifiedTradeProduct/ram:Name', element) if name: invoice_line_form.name = name - invoice_line_form.product_id = self._retrieve_product( + invoice_line_form.product_id = self_ctx._retrieve_product( default_code=_find_value('.//ram:SpecifiedTradeProduct/ram:SellerAssignedID', element), name=_find_value('.//ram:SpecifiedTradeProduct/ram:Name', element), barcode=_find_value('.//ram:SpecifiedTradeProduct/ram:GlobalID', element) @@ -303,7 +305,7 @@ class AccountEdiFormat(models.Model): tax_element = element.xpath('.//ram:SpecifiedLineTradeSettlement/ram:ApplicableTradeTax/ram:RateApplicablePercent', namespaces=tree.nsmap) invoice_line_form.tax_ids.clear() for eline in tax_element: - tax = self._retrieve_tax( + tax = self_ctx._retrieve_tax( amount=eline.text, type_tax_use=invoice_form.journal_id.type ) diff --git a/addons/account_edi_facturx/test_file/test_facturx.xml b/addons/account_edi_facturx/test_file/test_facturx.xml index ad5d797ad342..0216f86af1c0 100644 --- a/addons/account_edi_facturx/test_file/test_facturx.xml +++ b/addons/account_edi_facturx/test_file/test_facturx.xml @@ -42,6 +42,9 @@ Conference room table</ram:Name> <ram:SpecifiedTradeSettlementLineMonetarySummation> <ram:LineTotalAmount currencyID="USD">3210.00</ram:LineTotalAmount> </ram:SpecifiedTradeSettlementLineMonetarySummation> + <ram:ApplicableTradeTax> + <ram:RateApplicablePercent>0.0</ram:RateApplicablePercent> + </ram:ApplicableTradeTax> </ram:SpecifiedLineTradeSettlement> </ram:IncludedSupplyChainTradeLineItem> diff --git a/addons/account_edi_facturx/tests/test_facturx.py b/addons/account_edi_facturx/tests/test_facturx.py index 46729101fbe1..bc0a4c01989b 100644 --- a/addons/account_edi_facturx/tests/test_facturx.py +++ b/addons/account_edi_facturx/tests/test_facturx.py @@ -244,3 +244,21 @@ class TestAccountEdiFacturx(AccountEdiTestCommon): self.assertEqual(invoice.amount_total, 4610) self.assertEqual(len(self.env['account.move'].search([])), invoice_count + 1) + + def test_invoice_edi_multicompany(self): + # Create taxes that will match the first line of the facturx invoice + my_company_id = TestAccountEdiFacturx.company_data['company'].id + other_company_id = TestAccountEdiFacturx.company_data_2['company'].id + + common_tax_fields = dict(amount_type='percent', type_tax_use='purchase', amount=0.0) + self.env['account.tax'].create([ + dict(name="OtherCompany Tax", company_id=other_company_id, sequence=10, **common_tax_fields), + dict(name="MyCompany Tax", company_id=my_company_id, sequence=20, **common_tax_fields), + ]) + + invoice = self._create_empty_vendor_bill() + self.update_invoice_from_file('account_edi_facturx', 'test_file', 'test_facturx.xml', invoice) + + tax_ids = invoice.line_ids.tax_ids + self.assertEqual(len(tax_ids), 1) + self.assertEqual(tax_ids[0].name, "MyCompany Tax") diff --git a/addons/account_edi_ubl/models/account_edi_format.py b/addons/account_edi_ubl/models/account_edi_format.py index 29b93b67a4ab..fcd5f84a78ce 100644 --- a/addons/account_edi_ubl/models/account_edi_format.py +++ b/addons/account_edi_ubl/models/account_edi_format.py @@ -58,6 +58,7 @@ class AccountEdiFormat(models.Model): return self._find_value(xpath, element, namespaces) with Form(invoice.with_context(account_predictive_bills_disable_prediction=True)) as invoice_form: + self_ctx = self.with_company(invoice.company_id.id) # Reference elements = tree.xpath('//cbc:ID', namespaces=namespaces) @@ -91,7 +92,7 @@ class AccountEdiFormat(models.Model): invoice_form.invoice_incoterm_id = self.env['account.incoterms'].search([('code', '=', elements[0].text)], limit=1) # Partner - invoice_form.partner_id = self._retrieve_partner( + invoice_form.partner_id = self_ctx._retrieve_partner( name=_find_value('//cac:AccountingSupplierParty/cac:Party//cbc:Name'), phone=_find_value('//cac:AccountingSupplierParty/cac:Party//cbc:Telephone'), mail=_find_value('//cac:AccountingSupplierParty/cac:Party//cbc:ElectronicMail'), @@ -103,7 +104,7 @@ class AccountEdiFormat(models.Model): for eline in lines_elements: with invoice_form.invoice_line_ids.new() as invoice_line_form: # Product - invoice_line_form.product_id = self._retrieve_product( + invoice_line_form.product_id = self_ctx._retrieve_product( default_code=_find_value('cac:Item/cac:SellersItemIdentification/cbc:ID', eline), name=_find_value('cac:Item/cbc:Name', eline), barcode=_find_value('cac:Item/cac:StandardItemIdentification/cbc:ID[@schemeID=\'0160\']', eline) @@ -135,7 +136,7 @@ class AccountEdiFormat(models.Model): tax_element = eline.xpath('cac:TaxTotal/cac:TaxSubtotal', namespaces=namespaces) invoice_line_form.tax_ids.clear() for eline in tax_element: - tax = self._retrieve_tax( + tax = self_ctx._retrieve_tax( amount=_find_value('cbc:Percent', eline), type_tax_use=invoice_form.journal_id.type ) -- GitLab