From d4e8c88da67655bd0f9200ba6bd9ccfff6b4fe9d Mon Sep 17 00:00:00 2001 From: Joren Van Onder Date: Thu, 17 Aug 2023 16:31:12 -0700 Subject: [PATCH] [IMP] base_vat,l10n_br: depend on l10n_latam_base to categorize id types This adds the two main identification types we use in Brazil. CNPJ is used the standard VAT type. The custom check_vat logic was removed because stdnum supports this out of the box. Another non-VAT CPF type was added that is checked for validity using stdnum as well. task-3475609 closes odoo/odoo#132773 Related: odoo/enterprise#46127 Related: odoo/upgrade#5062 Signed-off-by: Josse Colpaert --- addons/base_vat/models/res_partner.py | 1 + addons/l10n_br/__manifest__.py | 2 + .../data/l10n_latam.identification.type.csv | 3 ++ addons/l10n_br/i18n/l10n_br.pot | 9 +---- addons/l10n_br/i18n/pt.po | 11 +----- addons/l10n_br/models/res_partner.py | 37 +++---------------- addons/l10n_br/views/res_partner_views.xml | 1 - 7 files changed, 15 insertions(+), 49 deletions(-) create mode 100644 addons/l10n_br/data/l10n_latam.identification.type.csv diff --git a/addons/base_vat/models/res_partner.py b/addons/base_vat/models/res_partner.py index 4594bad3b99..0d3f13b4afc 100644 --- a/addons/base_vat/models/res_partner.py +++ b/addons/base_vat/models/res_partner.py @@ -32,6 +32,7 @@ _ref_vat = { 'au': '83 914 571 673', 'be': 'BE0477472701', 'bg': 'BG1234567892', + 'br': '48.906.308/0001-27', 'ch': 'CHE-123.456.788 TVA or CHE-123.456.788 MWST or CHE-123.456.788 IVA', # Swiss by Yannick Vaucher @ Camptocamp 'cl': 'CL76086428-5', 'co': 'CO213123432-1 or CO213.123.432-1', diff --git a/addons/l10n_br/__manifest__.py b/addons/l10n_br/__manifest__.py index 72d26642e9d..79250fc61d5 100644 --- a/addons/l10n_br/__manifest__.py +++ b/addons/l10n_br/__manifest__.py @@ -46,9 +46,11 @@ come with any additional paid permission for online use of 'private modules'. 'depends': [ 'account', 'base_vat', + 'l10n_latam_base', ], 'data': [ 'data/account_tax_report_data.xml', + 'data/l10n_latam.identification.type.csv', 'views/account_view.xml', 'views/account_fiscal_position_views.xml', 'views/res_company_views.xml', diff --git a/addons/l10n_br/data/l10n_latam.identification.type.csv b/addons/l10n_br/data/l10n_latam.identification.type.csv new file mode 100644 index 00000000000..cbaccd170e8 --- /dev/null +++ b/addons/l10n_br/data/l10n_latam.identification.type.csv @@ -0,0 +1,3 @@ +id,name,country_id:id,is_vat +cnpj,CNPJ,base.br,True +cpf,CPF,base.br,False diff --git a/addons/l10n_br/i18n/l10n_br.pot b/addons/l10n_br/i18n/l10n_br.pot index 29313d84c96..caed4ee0adc 100644 --- a/addons/l10n_br/i18n/l10n_br.pot +++ b/addons/l10n_br/i18n/l10n_br.pot @@ -243,14 +243,7 @@ msgstr "" #. odoo-python #: code:addons/l10n_br/models/res_partner.py:0 #, python-format -msgid "Invalid CNPJ. Make sure that all the typs are entered correctly." -msgstr "" - -#. module: l10n_br -#. odoo-python -#: code:addons/l10n_br/models/res_partner.py:0 -#, python-format -msgid "Invalid CNPJ. Make sure that the CNPJ is a 14 digits number." +msgid "CPF number %s for %s is not valid." msgstr "" #. module: l10n_br diff --git a/addons/l10n_br/i18n/pt.po b/addons/l10n_br/i18n/pt.po index 085b2b28b78..e813b1d2dd0 100644 --- a/addons/l10n_br/i18n/pt.po +++ b/addons/l10n_br/i18n/pt.po @@ -230,15 +230,8 @@ msgstr "Interstate Fiscal Position Type" #. odoo-python #: code:addons/l10n_br/models/res_partner.py:0 #, python-format -msgid "Invalid CNPJ. Make sure that all the typs are entered correctly." -msgstr "Invalid CNPJ. Make sure that all the digits are entered correctly." - -#. module: l10n_br -#. odoo-python -#: code:addons/l10n_br/models/res_partner.py:0 -#, python-format -msgid "Invalid CNPJ. Make sure that the CNPJ is a 14 digits number." -msgstr "Invalid CNPJ. Make sure that the CNPJ is a 14 digits number." +msgid "CPF number %s for %s is not valid." +msgstr "O número de CPF %s para %s não é válido." #. module: l10n_br #: model:ir.model.fields,field_description:l10n_br.field_account_tax__amount_mva diff --git a/addons/l10n_br/models/res_partner.py b/addons/l10n_br/models/res_partner.py index 0a1cb5de94b..8b674741b50 100644 --- a/addons/l10n_br/models/res_partner.py +++ b/addons/l10n_br/models/res_partner.py @@ -1,45 +1,20 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. +import stdnum.br.cpf from odoo import _, api, fields, models from odoo.exceptions import ValidationError -import re class ResPartner(models.Model): _inherit = 'res.partner' - l10n_br_cpf_code = fields.Char(string="CPF", help="Natural Persons Register.") l10n_br_ie_code = fields.Char(string="IE", help="State Tax Identification Number. Should contain 9-14 digits.") l10n_br_im_code = fields.Char(string="IM", help="Municipal Tax Identification Number") l10n_br_isuf_code = fields.Char(string="SUFRAMA code", help="SUFRAMA registration number.") - @api.constrains("vat") - def check_vat(self): - ''' - Example of a Brazilian CNPJ number: 76.634.583/0001-74. - The 13th digit is the check digit of the previous 12 digits. - The check digit is calculated by multiplying the first 12 digits by weights and calculate modulo 11 of the result. - The 14th digit is the check digit of the previous 13 digits. Calculated the same way. - Both remainders are appended to the first 12 digits. - ''' - def _l10n_br_calculate_mod_11(check, weights): - result = (sum([i*j for (i, j) in zip(check, weights)])) % 11 - if result <= 1: - return 0 - return 11 - result - - for partner in self: - if not partner.vat: - return - if not partner.country_code == 'BR': - return super().check_vat() - weights = [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2] - vat_clean = list(map(int, re.sub("[^0-9]", "", partner.vat))) - if len(vat_clean) != 14: - raise ValidationError(_("Invalid CNPJ. Make sure that the CNPJ is a 14 digits number.")) - vat_check = vat_clean[:12] - vat_check.append(_l10n_br_calculate_mod_11(vat_check, weights[1:])) - vat_check.append(_l10n_br_calculate_mod_11(vat_check, weights)) - if vat_check != vat_clean: - raise ValidationError(_("Invalid CNPJ. Make sure that all the digits are entered correctly.")) + @api.constrains('vat', 'l10n_latam_identification_type_id') + def check_cpf(self): + for partner in self.filtered(lambda partner: partner.l10n_latam_identification_type_id == self.env.ref('l10n_br.cpf')): + if partner.vat and not stdnum.br.cpf.is_valid(partner.vat): + raise ValidationError(_('CPF number %s for %s is not valid.') % (partner.vat, partner.display_name)) diff --git a/addons/l10n_br/views/res_partner_views.xml b/addons/l10n_br/views/res_partner_views.xml index 40442a837c0..ad803236c02 100644 --- a/addons/l10n_br/views/res_partner_views.xml +++ b/addons/l10n_br/views/res_partner_views.xml @@ -7,7 +7,6 @@ -