[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:
@@ -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',
|
||||
}])
|
||||
|
||||
@@ -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])
|
||||
|
||||
@@ -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']
|
||||
|
||||
@@ -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']
|
||||
|
||||
@@ -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']
|
||||
|
||||
@@ -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']
|
||||
|
||||
Reference in New Issue
Block a user