[FIX] base_vat: patch orm limitation

https://github.com/odoo/odoo/pull/68253 fixed a bug in check_vat that caused it not to run any check when called on a partner with no country.

However, doing this caused another issue because of an ORM limitation: when writing vat and country_id with a single write() on the res.company, two distinct write are triggered on the related res.partner, one for each field. Both those write trigger the check_vat constraint.

Depending on the order in which the keys of the dictionnary passed to res.company's write were ordered, country_id could or could not be written before vat. If vat was written first and did not start with a country code, the write() on res.partner failed the constraint, because country_id wasn't set yet. This was wrong, but used to pass as there was no country_id on the partner, before https://github.com/odoo/odoo/pull/68253 fixed that.

To circumvent the issue, we now allow entering any vat number without performing any check if it does not start with a country code and no country_id is set on the partner.

closes odoo/odoo#69243

X-original-commit: 7036b671228fdb5986b4f62a610a2e4d4132b8b1
Signed-off-by: Laurent Smet <smetl@users.noreply.github.com>
Signed-off-by: oco-odoo <oco-odoo@users.noreply.github.com>
This commit is contained in:
oco-odoo
2021-04-14 10:29:00 +00:00
parent ee7287430f
commit eaf5d86fe7
2 changed files with 23 additions and 10 deletions
+20 -7
View File
@@ -142,7 +142,7 @@ class ResPartner(models.Model):
def check_vat(self):
for partner in self:
country = partner.commercial_partner_id.country_id
if partner.vat and not self._run_vat_test(partner.vat, country):
if partner.vat and self._run_vat_test(partner.vat, country) is False:
partner_label = _("partner [%s]", partner.name)
msg = partner._build_vat_error_message(country and country.code.lower() or None, partner.vat, partner_label)
raise ValidationError(msg)
@@ -158,7 +158,9 @@ class ResPartner(models.Model):
:param default_country: a res.country object
:return: The country code (in lower case) of the country the VAT number
was validated for, if it was validated. Else, False.
was validated for, if it was validated. False if it could not be validated
against the provided or guessed country. None if no country was available
for the check, and no conclusion could be made with certainty.
"""
# Get company
if self.env.context.get('company_id'):
@@ -173,16 +175,27 @@ class ResPartner(models.Model):
else:
check_func = self.simple_vat_check
check_result = None
# First check with country code as prefix of the TIN
vat_country_code, vat_number_split = self._split_vat(vat_number)
if check_func(vat_country_code, vat_number_split):
return vat_country_code
vat_guessed_country = self.env['res.country'].search([('code', '=', vat_country_code.upper())])
if vat_guessed_country:
check_result = check_func(vat_country_code, vat_number_split)
if check_result:
return vat_country_code
# If it fails, check with default_country (if it exists)
if default_country and check_func(default_country.code.lower(), vat_number):
return default_country.code.lower()
if default_country:
check_result = check_func(default_country.code.lower(), vat_number)
if check_result:
return default_country.code.lower()
return False
# We allow any number if it doesn't start with a country code and the partner has no country.
# This is necessary to support an ORM limitation: setting vat and country_id together on a company
# triggers two distinct write on res.partner, one for each field, both triggering this constraint.
# If vat is set before country_id, the constraint must not break.
return check_result
@api.model
def _build_vat_error_message(self, country_code, wrong_vat, record_label):
+3 -3
View File
@@ -81,9 +81,9 @@ class TestStructure(TransactionCase):
with self.assertRaises(ValidationError):
test_partner.write({'vat': '42', 'country_id': self.env.ref('base.be').id})
# If no country can be guessed: VAT number cannot be validated
with self.assertRaises(ValidationError):
test_partner.write({'vat': '0477472701', 'country_id': None})
# If no country can be guessed: VAT number should always be considered valid
# (for technical reasons due to ORM and res.company making related fields towards res.partner for country_id and vat)
test_partner.write({'vat': '0477472701', 'country_id': None})
@tagged('-standard', 'external')