diff --git a/addons/account_edi/models/account_edi_format.py b/addons/account_edi/models/account_edi_format.py index ca0eb9b5835..70c17b21a74 100644 --- a/addons/account_edi/models/account_edi_format.py +++ b/addons/account_edi/models/account_edi_format.py @@ -455,21 +455,95 @@ class AccountEdiFormat(models.Model): :param vat: The vat number of the partner. :returns: A partner or an empty recordset if not found. ''' - domains = [] - for value, dom in ( - (name, [('name', 'ilike', name)]), - (phone, expression.OR([[('phone', '=', phone)], [('mobile', '=', phone)]])), - (mail, [('email', '=', mail)]), - (vat, [('vat', 'like', vat)]), - ): - if value is not None: - domains.append(dom) + def search_with_vat(extra_domain): + if not vat: + return None - if domain: - domains.append(domain) + # Sometimes, the vat is specified with some whitespaces. + normalized_vat = vat.replace(' ', '') + country_prefix = None - domain = expression.OR(domains) - return self.env['res.partner'].search(domain, limit=1) + partner = self.env['res.partner'].search(extra_domain + [('vat', '=', normalized_vat)], limit=1) + + # Try to remove the country code prefix from the vat. + if not partner and len(normalized_vat) > 2 and normalized_vat[:2].isalpha(): + country_prefix = normalized_vat[:2] + normalized_vat = normalized_vat[2:] + partner = self.env['res.partner'].search(extra_domain + [ + ('vat', '=', normalized_vat), + ('country_id.code', '=', country_prefix.lower()), + ], limit=1) + + # The country could be not specified on the partner. + if not partner: + partner = self.env['res.partner'].search(extra_domain + [ + ('vat', '=', normalized_vat), + ('country_id', '=', False), + ], limit=1) + + # The vat could be a string of alphanumeric values without country code but with missing zeros at the + # beginning. + if not partner: + try: + vat_only_numeric = str(int(normalized_vat)) + except ValueError: + vat_only_numeric = None + + if vat_only_numeric: + query = self.env['res.partner']._where_calc(extra_domain + [('active', '=', True)]) + tables, where_clause, where_params = query.get_sql() + + if country_prefix: + vat_prefix_regex = f'({country_prefix})?' + else: + vat_prefix_regex = '([A-z]{2})?' + + self._cr.execute(f''' + SELECT res_partner.id + FROM {tables} + WHERE {where_clause} + AND res_partner.vat ~ %s + LIMIT 1 + ''', where_params + ['^%s0*%s$' % (vat_prefix_regex, vat_only_numeric)]) + partner_row = self._cr.fetchone() + if partner_row: + partner = self.env['res.partner'].browse(partner_row[0]) + + return partner + + def search_with_phone_mail(extra_domain): + domains = [] + if phone: + domains.append([('phone', '=', phone)]) + domains.append([('mobile', '=', phone)]) + if mail: + domains.append([('email', '=', mail)]) + + if not domains: + return None + + domain = expression.OR(domains) + if extra_domain: + domain = expression.AND([domain, extra_domain]) + return self.env['res.partner'].search(domain, limit=1) + + def search_with_name(extra_domain): + if not name: + return None + return self.env['res.partner'].search([('name', 'ilike', name)] + extra_domain, limit=1) + + def search_with_domain(extra_domain): + if not domain: + return None + return self.env['res.partner'].search(domain + extra_domain, limit=1) + + for search_method in (search_with_vat, search_with_domain, search_with_phone_mail, search_with_name): + for extra_domain in ([('company_id', '=', self.env.company.id)], []): + partner = search_method(extra_domain) + if partner: + return partner + + return self.env['res.partner'] def _retrieve_product(self, name=None, default_code=None, barcode=None): '''Search all products and find one that matches one of the parameters. diff --git a/addons/account_edi/tests/__init__.py b/addons/account_edi/tests/__init__.py index eea5d7edcd2..e6e930de306 100644 --- a/addons/account_edi/tests/__init__.py +++ b/addons/account_edi/tests/__init__.py @@ -3,3 +3,4 @@ from . import common from . import test_edi +from . import test_import_vendor_bill diff --git a/addons/account_edi/tests/test_import_vendor_bill.py b/addons/account_edi/tests/test_import_vendor_bill.py new file mode 100644 index 00000000000..1f004014c94 --- /dev/null +++ b/addons/account_edi/tests/test_import_vendor_bill.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +from odoo.addons.account.tests.common import AccountTestInvoicingCommon +from odoo.tests import tagged + + +@tagged('post_install', '-at_install') +class TestImportVendorBill(AccountTestInvoicingCommon): + + def test_retrieve_partner(self): + + def retrieve_partner(vat, import_vat): + self.partner_a.with_context(no_vat_validation=True).vat = vat + self.partner_a.flush() + return self.env['account.edi.format']._retrieve_partner(vat=import_vat) + + self.assertEqual(self.partner_a, retrieve_partner('BE0477472701', 'BE0477472701')) + self.assertEqual(self.partner_a, retrieve_partner('BE0477472701', '0477472701')) + self.assertEqual(self.partner_a, retrieve_partner('BE0477472701', '477472701')) + self.assertEqual(self.partner_a, retrieve_partner('0477472701', 'BE0477472701')) + self.assertEqual(self.partner_a, retrieve_partner('477472701', 'BE0477472701')) + self.assertEqual(self.env['res.partner'], retrieve_partner('DE0477472701', 'BE0477472701'))