[FIX] account_peppol: peppol_eas compute dependencies

1. set a country like belgium
2. set a VAT number like BE123456789 => peppol_endpoint is not computed

This is because some dependencies are missing on the field (current is: "country_code").
Step 1: Add the missing dependencies to the field (and improve the tests to make sure it works).
Step 2: Try to make the code smarter! If the country_code is BE but the VAT number starts with FR,
consider it's FR, not BE. If the codice_fiscale is set, it's IT whatever the country_code.
If the VAT number has no ISO country code, use the country_code in that case.

task-3690913

closes odoo/odoo#154375

X-original-commit: 46d2bf0dd08b1a925ad51c91aa37024cd5a6ee16
Signed-off-by: Laurent Smet (las) <las@odoo.com>
Signed-off-by: Aliya Tastemirova (alta) <alta@odoo.com>
This commit is contained in:
aliya
2024-02-19 12:27:48 +00:00
parent dcb871208e
commit 2bbd8ad3c1
9 changed files with 117 additions and 20 deletions
+14
View File
@@ -890,3 +890,17 @@ class ResPartner(models.Model):
if self.env['account.move.line'].sudo().search([('move_id.inalterable_hash', '!=', False), ('partner_id', 'in', source.ids)], limit=1):
raise UserError(_('Partners that are used in hashed entries cannot be merged.'))
return super()._merge_method(destination, source)
def _deduce_country_code(self):
""" deduce the country code based on the information available.
we have three cases:
- country_code is BE but the VAT number starts with FR, the country code is FR, not BE
- if a country-specific field is set (e.g. the codice_fiscale), that country is used for the country code
- if the VAT number has no ISO country code, use the country_code in that case.
"""
self.ensure_one()
country_code = self.country_code
if self.vat and self.vat[:2].isalpha():
country_code = self.vat[:2].upper()
return country_code
@@ -135,38 +135,49 @@ class ResPartner(models.Model):
if error:
raise ValidationError(error)
@api.depends('country_code')
@api.model
def _get_ubl_cii_formats(self):
return {
'DE': 'xrechnung',
'AU': 'ubl_a_nz',
'NZ': 'ubl_a_nz',
'NL': 'nlcius',
'FR': 'facturx',
'SG': 'ubl_sg',
}
def _peppol_eas_endpoint_depends(self):
# field dependencies of methods _compute_peppol_endpoint() and _compute_peppol_eas()
# because we need to extend depends in l10n modules
return ['country_code', 'vat', 'company_registry']
@api.depends(lambda self: self._peppol_eas_endpoint_depends())
def _compute_ubl_cii_format(self):
format_mapping = self._get_ubl_cii_formats()
for partner in self:
if partner.country_code == 'DE':
partner.ubl_cii_format = 'xrechnung'
elif partner.country_code in ('AU', 'NZ'):
partner.ubl_cii_format = 'ubl_a_nz'
elif partner.country_code == 'NL':
partner.ubl_cii_format = 'nlcius'
elif partner.country_code == 'FR':
partner.ubl_cii_format = 'facturx'
elif partner.country_code == 'SG':
partner.ubl_cii_format = 'ubl_sg'
elif partner.country_code in EAS_MAPPING:
country_code = partner._deduce_country_code()
if country_code in format_mapping:
partner.ubl_cii_format = format_mapping[country_code]
elif country_code in EAS_MAPPING:
partner.ubl_cii_format = 'ubl_bis3'
else:
partner.ubl_cii_format = partner.ubl_cii_format
@api.depends('peppol_eas')
@api.depends(lambda self: self._peppol_eas_endpoint_depends() + ['peppol_eas'])
def _compute_peppol_endpoint(self):
""" If the EAS changes and a valid endpoint is available, set it. Otherwise, keep the existing value."""
for partner in self:
partner.peppol_endpoint = partner.peppol_endpoint
if partner.country_code in EAS_MAPPING:
field = EAS_MAPPING[partner.country_code].get(partner.peppol_eas)
country_code = partner._deduce_country_code()
if country_code in EAS_MAPPING:
field = EAS_MAPPING[country_code].get(partner.peppol_eas)
if field \
and field in partner._fields \
and partner[field] \
and not partner._build_error_peppol_endpoint(partner.peppol_eas, partner[field]):
partner.peppol_endpoint = partner[field]
@api.depends('country_code')
@api.depends(lambda self: self._peppol_eas_endpoint_depends())
def _compute_peppol_eas(self):
"""
If the country_code changes, recompute the EAS only if there is a country_code, it exists in the
@@ -174,10 +185,11 @@ class ResPartner(models.Model):
"""
for partner in self:
partner.peppol_eas = partner.peppol_eas
if partner.country_code and partner.country_code in EAS_MAPPING:
eas_to_field = EAS_MAPPING[partner.country_code]
country_code = partner._deduce_country_code()
if country_code in EAS_MAPPING:
eas_to_field = EAS_MAPPING[country_code]
if partner.peppol_eas not in eas_to_field.keys():
new_eas = list(EAS_MAPPING[partner.country_code].keys())[0]
new_eas = next(iter(EAS_MAPPING[country_code].keys()))
# Iterate on the possible EAS until a valid one is found
for eas, field in eas_to_field.items():
if field and field in partner._fields and partner[field]:
@@ -149,3 +149,36 @@ class TestAccountEdiUblCii(AccountTestInvoicingCommon):
.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)
def test_peppol_eas_endpoint_compute(self):
partner = self.partner_a
partner.vat = 'DE123456788'
self.assertRecordValues(partner, [{
'peppol_eas': '9930',
'peppol_endpoint': 'DE123456788',
}])
partner.vat = 'FR23334175221'
self.assertRecordValues(partner, [{
'peppol_eas': '9957',
'peppol_endpoint': 'FR23334175221',
}])
partner.vat = '23334175221'
self.assertRecordValues(partner, [{
'peppol_eas': '9957',
'peppol_endpoint': 'FR23334175221',
}])
partner.write({
'vat': 'BE0477472701',
'company_registry': '0477472701',
})
self.assertRecordValues(partner, [{
'peppol_eas': '0208',
'peppol_endpoint': '0477472701',
}])
+1 -1
View File
@@ -14,7 +14,7 @@ class ResPartner(models.Model):
# OVERRIDE
# If a belgian company has a VAT number then its company registry is its VAT Number (without country code).
super()._compute_company_registry()
for partner in self.filtered(lambda p: p.country_id.code == 'BE' and p.vat):
for partner in self.filtered(lambda p: p._deduce_country_code() == 'BE' and p.vat):
vat_country, vat_number = self._split_vat(partner.vat)
if vat_country.isnumeric():
vat_country = 'be'
@@ -173,6 +173,7 @@ class TestUBLDK(TestUBLCommon, TestAccountMoveSendCommon):
@freeze_time('2017-01-01')
def test_export_partner_fr_without_siret_should_raise_an_error(self):
self.partner_c.company_registry = False
self.partner_c.ubl_cii_format = 'oioubl_201' # default format for French partners is facturx
with self.assertRaisesRegex(UserError, "The company registry is required for french partner:"):
self.create_post_and_send_invoice(partner=self.partner_c)
@@ -183,6 +184,7 @@ class TestUBLDK(TestUBLCommon, TestAccountMoveSendCommon):
telling to the user that this field is missing.
"""
self.partner_b.vat = None
self.partner_b.ubl_cii_format = 'oioubl_201' # default format recomputes when vat is changed
with self.assertRaises(UserError) as exception:
self.create_post_and_send_invoice(partner=self.partner_b)
self.assertIn(f"The field '{self.partner_b._fields['vat'].string}' is required", exception.exception.args[0])
+9
View File
@@ -7,3 +7,12 @@ class ResPartner(models.Model):
_inherit = 'res.partner'
siret = fields.Char(string='SIRET', size=14)
def _deduce_country_code(self):
if self.siret:
return 'FR'
return super()._deduce_country_code()
def _peppol_eas_endpoint_depends(self):
# extends account_edi_ubl_cii
return super()._peppol_eas_endpoint_depends() + ['siret']
+9
View File
@@ -183,3 +183,12 @@ class ResPartner(models.Model):
'action': invalid_records._get_records_action(name=_("Check Partner(s)"), views=views),
}
return errors
def _deduce_country_code(self):
if self.l10n_it_codice_fiscale:
return 'IT'
return super()._deduce_country_code()
def _peppol_eas_endpoint_depends(self):
# extends account_edi_ubl_cii
return super()._peppol_eas_endpoint_depends() + ['l10n_it_codice_fiscale']
+9
View File
@@ -6,3 +6,12 @@ class ResPartner(models.Model):
_inherit = 'res.partner'
l10n_no_bronnoysund_number = fields.Char(string='Register of Legal Entities (Brønnøysund Register Center)', size=9)
def _deduce_country_code(self):
if self.l10n_no_bronnoysund_number:
return 'NO'
return super()._deduce_country_code()
def _peppol_eas_endpoint_depends(self):
# extends account_edi_ubl_cii
return super()._peppol_eas_endpoint_depends() + ['l10n_no_bronnoysund_number']
+9
View File
@@ -7,3 +7,12 @@ class ResPartner(models.Model):
_inherit = 'res.partner'
l10n_sg_unique_entity_number = fields.Char(string='UEN')
def _deduce_country_code(self):
if self.l10n_sg_unique_entity_number:
return 'SG'
return super()._deduce_country_code()
def _peppol_eas_endpoint_depends(self):
# extends account_edi_ubl_cii
return super()._peppol_eas_endpoint_depends() + ['l10n_sg_unique_entity_number']