diff --git a/l10n_br_fiscal_certificate/__manifest__.py b/l10n_br_fiscal_certificate/__manifest__.py index 45c2e2eeb135..ce8e92fbe53a 100644 --- a/l10n_br_fiscal_certificate/__manifest__.py +++ b/l10n_br_fiscal_certificate/__manifest__.py @@ -9,9 +9,10 @@ "maintainers": ["renatonlima"], "website": "https://github.com/OCA/l10n-brazil", "development_status": "Production/Stable", - "version": "18.0.1.3.1", + "version": "18.0.2.0.0", "depends": [ "l10n_br_fiscal", + "certificate", ], "data": [ "security/ir.model.access.csv", diff --git a/l10n_br_fiscal_certificate/hooks.py b/l10n_br_fiscal_certificate/hooks.py index 81f06f77139c..e353a0e8fca2 100644 --- a/l10n_br_fiscal_certificate/hooks.py +++ b/l10n_br_fiscal_certificate/hooks.py @@ -24,8 +24,9 @@ def prepare_fake_certificate_vals( return { "type": cert_type, "subtype": "a1", - "password": passwd, - "file": misc.create_fake_certificate_file( + "scope": "l10n_br", + "pkcs12_password": passwd, + "content": misc.create_fake_certificate_file( valid, passwd, issuer, country, subject ), } @@ -41,14 +42,16 @@ def prepare_fake_certificate_vals( env.ref("l10n_br_base.empresa_lucro_real", raise_if_not_found=False), ] try: + certificate_model = env["certificate.certificate"] for company in companies: - l10n_br_fiscal_certificate_id = env["l10n_br_fiscal.certificate"] - company.certificate_nfe_id = l10n_br_fiscal_certificate_id.create( - prepare_fake_certificate_vals() - ) - company.certificate_ecnpj_id = l10n_br_fiscal_certificate_id.create( - prepare_fake_certificate_vals(cert_type=CERTIFICATE_TYPE_ECNPJ) - ) + if not company: + continue + vals = prepare_fake_certificate_vals() + vals["company_id"] = company.id + company.certificate_nfe_id = certificate_model.create(vals) + vals = prepare_fake_certificate_vals(cert_type=CERTIFICATE_TYPE_ECNPJ) + vals["company_id"] = company.id + company.certificate_ecnpj_id = certificate_model.create(vals) except NameError: # (means from erpbrasil.assinatura import misc failed) _logger.error( _( diff --git a/l10n_br_fiscal_certificate/migrations/18.0.2.0.0/post-migration.py b/l10n_br_fiscal_certificate/migrations/18.0.2.0.0/post-migration.py new file mode 100644 index 000000000000..9873116f7488 --- /dev/null +++ b/l10n_br_fiscal_certificate/migrations/18.0.2.0.0/post-migration.py @@ -0,0 +1,81 @@ +# Copyright (C) 2026 Raphaël Valyi - Akretion +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html + +import logging + +from openupgradelib import openupgrade + +_logger = logging.getLogger(__name__) + +_LEGACY_TABLE = "l10n_br_fiscal_certificate" +_TMP_TABLE = "l10n_br_fiscal_certificate_migration" + + +def _company_by_legacy_cert_id(env): + env.cr.execute( + "SELECT id, certificate_nfe_id, certificate_ecnpj_id FROM res_company" + ) + mapping = {} + for company_id, nfe_id, ecnpj_id in env.cr.fetchall(): + if nfe_id: + mapping.setdefault(nfe_id, company_id) + if ecnpj_id: + mapping.setdefault(ecnpj_id, company_id) + return mapping + + +@openupgrade.migrate(use_env=True) +def migrate(env, version): + if not openupgrade.table_exists(env.cr, _TMP_TABLE): + return + + company_by_old = _company_by_legacy_cert_id(env) + main_company = env.ref("base.main_company", raise_if_not_found=False) + fallback_company_id = main_company.id if main_company else None + + certificate_model = env["certificate.certificate"] + old_new = {} + + env.cr.execute( + f"SELECT legacy_id, file, password, type, subtype, active " + f"FROM {_TMP_TABLE} ORDER BY legacy_id" + ) + for old_id, file, password, ctype, subtype, active in env.cr.fetchall(): + vals = { + "content": file, + "pkcs12_password": password, + "type": ctype, + "subtype": subtype, + "active": active, + "scope": "l10n_br", + "company_id": company_by_old.get(old_id, fallback_company_id), + } + try: + # Core re-parses ``content`` and derives pem_certificate, dates, + # subject_common_name, serial_number and the private key. Its + # ``_constrains_certificate_loaded`` rejects unparseable files, which + # the legacy module also rejected on create, so this is a no-op in + # practice. + old_new[old_id] = certificate_model.create(vals).id + except Exception: # noqa: BLE001 + _logger.exception( + "Skipping legacy certificate %s: could not be re-parsed", old_id + ) + + # Repoint the res.company foreign keys to the new certificate IDs. + for old_id, new_id in old_new.items(): + env.cr.execute( + "UPDATE res_company SET certificate_nfe_id = %s " + "WHERE certificate_nfe_id = %s", + (new_id, old_id), + ) + env.cr.execute( + "UPDATE res_company SET certificate_ecnpj_id = %s " + "WHERE certificate_ecnpj_id = %s", + (new_id, old_id), + ) + + # Cleanup. + env.cr.execute(f"DROP TABLE IF EXISTS {_TMP_TABLE}") + if openupgrade.table_exists(env.cr, _LEGACY_TABLE): + env.cr.execute(f"DROP TABLE IF EXISTS {_LEGACY_TABLE}") diff --git a/l10n_br_fiscal_certificate/migrations/18.0.2.0.0/pre-migration.py b/l10n_br_fiscal_certificate/migrations/18.0.2.0.0/pre-migration.py new file mode 100644 index 000000000000..781fcad83b43 --- /dev/null +++ b/l10n_br_fiscal_certificate/migrations/18.0.2.0.0/pre-migration.py @@ -0,0 +1,57 @@ +# Copyright (C) 2026 Raphaël Valyi - Akretion +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html + +from openupgradelib import openupgrade + +_TMP_TABLE = "l10n_br_fiscal_certificate_migration" + + +@openupgrade.migrate(use_env=True) +def migrate(env, version): + """Snapshot the legacy certificates before the model is replaced. + + The old ``l10n_br_fiscal.certificate`` model is merged into the Odoo core + ``certificate.certificate`` model. We read it here (while the ORM still knows + the old model) and stash the payload into a temporary table, because the + ``file`` binary lives in ``ir.attachment`` and can no longer be read through + the ORM once the model is gone. + """ + try: + legacy_model = env["l10n_br_fiscal.certificate"] + except KeyError: + return + + legacy_certs = legacy_model.sudo().search([]) + if not legacy_certs: + return + + openupgrade.logged_query( + env.cr, + f""" + CREATE TABLE IF NOT EXISTS {_TMP_TABLE} ( + legacy_id INTEGER PRIMARY KEY, + file TEXT, + password VARCHAR, + type VARCHAR, + subtype VARCHAR, + active BOOLEAN + ) + """, + ) + for cert in legacy_certs: + openupgrade.logged_query( + env.cr, + f""" + INSERT INTO {_TMP_TABLE} + (legacy_id, file, password, type, subtype, active) + VALUES (%s, %s, %s, %s, %s, %s) + """, + ( + cert.id, + cert.with_context(bin_size=False).file or None, + cert.password, + cert.type, + cert.subtype, + cert.active, + ), + ) diff --git a/l10n_br_fiscal_certificate/models/certificate.py b/l10n_br_fiscal_certificate/models/certificate.py index 41d7965946be..ad9c7ec7f271 100644 --- a/l10n_br_fiscal_certificate/models/certificate.py +++ b/l10n_br_fiscal_certificate/models/certificate.py @@ -1,146 +1,88 @@ # Copyright (C) 2019 Renato Lima - Akretion +# Copyright (C) 2024 Raphaël Valyi - Akretion # License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html +import base64 +from contextlib import suppress -from erpbrasil.assinatura import certificado +from cryptography import x509 -from odoo import _, api, fields, models -from odoo.exceptions import ValidationError -from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT +from odoo import api, fields, models from odoo.tools.misc import format_date -from ..constants import ( - CERTIFICATE_SUBTYPE, - CERTIFICATE_SUBTYPE_DEFAULT, - CERTIFICATE_TYPE, - CERTIFICATE_TYPE_DEFAULT, -) +from ..constants import CERTIFICATE_SUBTYPE, CERTIFICATE_TYPE class Certificate(models.Model): - _name = "l10n_br_fiscal.certificate" - _inherit = ["mail.thread", "mail.activity.mixin"] - _description = "Certificate" - _order = "date_expiration" + _inherit = "certificate.certificate" - name = fields.Char(compute="_compute_name", readonly=True) - - active = fields.Boolean(default=True) - - date_start = fields.Datetime(readonly=True, store=True) - - date_expiration = fields.Datetime(readonly=True, store=True) - - issuer_name = fields.Char(size=120, readonly=True, store=True) - - owner_name = fields.Char(string="Owner", size=120, readonly=True, store=True) - - owner_cnpj_cpf = fields.Char(string="CNPJ/CPF", size=18, readonly=True, store=True) + scope = fields.Selection( + selection_add=[("l10n_br", "Brazilian Fiscal")], + ) type = fields.Selection( selection=CERTIFICATE_TYPE, string="Certificate Type", - default=CERTIFICATE_TYPE_DEFAULT, - required=True, ) subtype = fields.Selection( selection=CERTIFICATE_SUBTYPE, string="Document SubType", - default=CERTIFICATE_SUBTYPE_DEFAULT, - required=True, ) - file = fields.Binary(string="file", prefetch=True, required=True) - - file_name = fields.Char(compute="_compute_name", size=255) - - password = fields.Char(required=True) - - is_valid = fields.Boolean(compute="_compute_is_valid", string="Is Valid?") + name = fields.Char( + compute="_compute_name", + store=True, + ) - @api.model - def _certificate_data(self, cert_file, cert_password): - values = {} - if cert_file and cert_password: - try: - cert = certificado.Certificado(cert_file, cert_password) - except Exception as e: - raise ValidationError( - _("Cannot load Certificate ! \n\n {}").format(e) - ) from e + owner_cnpj_cpf = fields.Char( + string="CNPJ/CPF", + compute="_compute_owner_cnpj_cpf", + store=True, + ) - if cert: - values["issuer_name"] = cert.emissor - values["owner_name"] = cert.proprietario - values["owner_cnpj_cpf"] = cert.cnpj_cpf - if cert.fim_validade: - values["date_expiration"] = cert.fim_validade.strftime( - DEFAULT_SERVER_DATETIME_FORMAT - ) + issuer_name = fields.Char( + string="Issuer", + compute="_compute_issuer_name", + store=True, + ) - if cert.inicio_validade: - values["date_start"] = cert.inicio_validade.strftime( - DEFAULT_SERVER_DATETIME_FORMAT + @api.depends("subject_common_name") + def _compute_owner_cnpj_cpf(self): + for certificate in self: + cnpj_cpf = "" + subject = certificate.subject_common_name or "" + if ":" in subject: + # Brazilian certificates carry the CNPJ/CPF in the subject CN + # after the last colon, e.g. "NOME DA EMPRESA:12345678000190". + cnpj_cpf = subject.rsplit(":", 1)[1] + certificate.owner_cnpj_cpf = cnpj_cpf + + @api.depends("pem_certificate") + def _compute_issuer_name(self): + for certificate in self: + issuer_name = "" + pem_certificate = certificate.with_context(bin_size=False).pem_certificate + if pem_certificate: + with suppress(ValueError, TypeError): + x509_cert = x509.load_pem_x509_certificate( + base64.b64decode(pem_certificate) ) + issuer_name = self._get_common_name(x509_cert, issuer=True) or "" + certificate.issuer_name = issuer_name - return values - - @api.constrains("file", "password") - def _check_certificate(self): - for c in self: - cert_values = c._certificate_data(c.file, c.password) - if not cert_values: - raise ValidationError(_("Cannot load Certificate !")) - - @api.depends("file", "password") + @api.depends("type", "subtype", "subject_common_name", "date_end") def _compute_name(self): - for cert in self: - name = False - file_name = False - if cert.file and cert.password: - name = "{} - {} - {} - Valid: {}".format( - cert.type and cert.type.upper() or "", - cert.subtype and cert.subtype.upper() or "", - cert.owner_name or "", - format_date(self.env, cert.date_expiration.date()) - if cert.date_expiration - else "", - ) - file_name = name + ".p12" - - cert.name = name - cert.file_name = file_name - - def update_certificate_data(self, values): - cert_file = values.get("file") - if isinstance(cert_file, str): - cert_file = cert_file.encode() - values.update(self._certificate_data(cert_file, values.get("password"))) - return values - - @api.depends("date_expiration") - def _compute_is_valid(self): - for c in self: - c.is_valid = False - if c.date_expiration: - c.is_valid = c.date_expiration >= fields.Datetime.now() - - @api.model_create_multi - def create(self, vals_list): - for vals in vals_list: - self.update_certificate_data(vals) - return super().create(vals_list) - - def write(self, values): - values = self.update_certificate_data(values) - return super().write(values) - - @api.onchange("file", "password") - def _onchange_file_password(self): - if self.file and self.password: - self.update( - self.update_certificate_data( - {"file": self.file, "password": self.password} + for certificate in self: + parts = [] + if certificate.type: + parts.append(certificate.type.upper()) + if certificate.subtype: + parts.append(certificate.subtype.upper()) + if certificate.subject_common_name: + parts.append(certificate.subject_common_name) + if certificate.date_end: + parts.append( + f"Valid: {format_date(self.env, certificate.date_end.date())}" ) - ) + certificate.name = " - ".join(parts) diff --git a/l10n_br_fiscal_certificate/models/res_company.py b/l10n_br_fiscal_certificate/models/res_company.py index 1f5ad276590c..7cf0fe99f241 100644 --- a/l10n_br_fiscal_certificate/models/res_company.py +++ b/l10n_br_fiscal_certificate/models/res_company.py @@ -13,19 +13,19 @@ class ResCompany(models.Model): _inherit = "res.company" certificate_ecnpj_id = fields.Many2one( - comodel_name="l10n_br_fiscal.certificate", + comodel_name="certificate.certificate", string="E-CNPJ", domain="[('type', '=', 'e-cnpj')]", ) certificate_nfe_id = fields.Many2one( - comodel_name="l10n_br_fiscal.certificate", + comodel_name="certificate.certificate", string="NFe", domain="[('type', '=', 'nf-e')]", ) certificate = fields.Many2one( - comodel_name="l10n_br_fiscal.certificate", + comodel_name="certificate.certificate", compute="_compute_certificate", ) @@ -58,6 +58,6 @@ def _get_br_ecertificate(self, only_ecnpj=False): _("Only e-CNPJ Certicate can be used for this case.") ) return cert.Certificado( - arquivo=certificate.file, - senha=certificate.password, + arquivo=certificate.with_context(bin_size=False).content, + senha=certificate.pkcs12_password, ) diff --git a/l10n_br_fiscal_certificate/security/ir.model.access.csv b/l10n_br_fiscal_certificate/security/ir.model.access.csv index 68ea2681d6dc..ae550b04b95e 100644 --- a/l10n_br_fiscal_certificate/security/ir.model.access.csv +++ b/l10n_br_fiscal_certificate/security/ir.model.access.csv @@ -1,3 +1,5 @@ "id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink" -"l10n_br_fiscal_certificate_user","Fiscal Certificate for User","model_l10n_br_fiscal_certificate","l10n_br_fiscal.group_user",1,0,0,0 -"l10n_br_fiscal_certificate_manager","Fiscal Certificate for Manager","model_l10n_br_fiscal_certificate","l10n_br_fiscal.group_manager",1,1,1,1 +"l10n_br_fiscal_certificate_user","Fiscal Certificate for User","certificate.model_certificate_certificate","l10n_br_fiscal.group_user",1,0,0,0 +"l10n_br_fiscal_certificate_manager","Fiscal Certificate for Manager","certificate.model_certificate_certificate","l10n_br_fiscal.group_manager",1,1,1,1 +"l10n_br_fiscal_certificate_key_user","Fiscal Certificate Key for User","certificate.model_certificate_key","l10n_br_fiscal.group_user",1,0,0,0 +"l10n_br_fiscal_certificate_key_manager","Fiscal Certificate Key for Manager","certificate.model_certificate_key","l10n_br_fiscal.group_manager",1,1,1,1 diff --git a/l10n_br_fiscal_certificate/tests/test_certificate.py b/l10n_br_fiscal_certificate/tests/test_certificate.py index b4c39490ce8b..58c087e3c64d 100644 --- a/l10n_br_fiscal_certificate/tests/test_certificate.py +++ b/l10n_br_fiscal_certificate/tests/test_certificate.py @@ -8,7 +8,6 @@ from odoo import Command, fields from odoo.exceptions import ValidationError from odoo.tests import TransactionCase -from odoo.tools.misc import format_date class TestCertificate(TransactionCase): @@ -16,7 +15,7 @@ class TestCertificate(TransactionCase): def setUpClass(cls): super().setUpClass() cls.company_model = cls.env["res.company"] - cls.certificate_model = cls.env["l10n_br_fiscal.certificate"] + cls.certificate_model = cls.env["certificate.certificate"] cls.company = cls._create_compay() cls._switch_user_company(cls.env.user, cls.company) @@ -27,12 +26,6 @@ def setUpClass(cls): cls.cert_date_exp = fields.Datetime.today() + timedelta(days=365) cls.cert_subject_invalid = "CERTIFICADO INVALIDO TESTE" cls.cert_passwd = "123456" - cls.cert_name = "{} - {} - {} - Valid: {}".format( - "NF-E", - "A1", - cls.cert_subject_valid, - format_date(cls.env, cls.cert_date_exp), - ) cls.certificate_valid = misc.create_fake_certificate_file( valid=True, @@ -72,51 +65,48 @@ def _switch_user_company(cls, user, company): } ) + def _certificate_vals(self, cert_file, cert_type="nf-e", passwd=None): + return { + "type": cert_type, + "subtype": "a1", + "scope": "l10n_br", + "pkcs12_password": passwd or self.cert_passwd, + "content": cert_file, + "company_id": self.company.id, + } + def test_valid_certificate(self): """Create and check a valid certificate""" cert = self.certificate_model.create( - { - "type": "nf-e", - "subtype": "a1", - "password": self.cert_passwd, - "file": self.certificate_valid, - } + self._certificate_vals(self.certificate_valid) ) self.assertEqual(cert.issuer_name, self.cert_issuer_a) - self.assertEqual(cert.owner_name, self.cert_subject_valid) - self.assertEqual(cert.date_expiration.year, self.cert_date_exp.year) - self.assertEqual(cert.date_expiration.month, self.cert_date_exp.month) - self.assertEqual(cert.date_expiration.day, self.cert_date_exp.day) - self.assertEqual(cert.name, self.cert_name) + self.assertEqual(cert.subject_common_name, self.cert_subject_valid) + self.assertEqual(cert.date_end.year, self.cert_date_exp.year) + self.assertEqual(cert.date_end.month, self.cert_date_exp.month) + self.assertEqual(cert.date_end.day, self.cert_date_exp.day) self.assertEqual(cert.is_valid, True) - # Testa metodo write + self.assertEqual(cert.owner_cnpj_cpf, "") + self.assertTrue( + cert.name.startswith("NF-E - A1 - CERTIFICADO VALIDO TESTE - Valid:") + ) + # Test method write cert.type = "e-cnpj" - cert._onchange_file_password() def test_certificate_wrong_password(self): """Write a valid certificate with wrong password""" with self.assertRaises(ValidationError): self.certificate_model.create( - { - "type": "nf-e", - "subtype": "a1", - "password": "INVALID", - "file": self.certificate_valid, - } + self._certificate_vals(self.certificate_valid, passwd="INVALID") ) def test_invalid_certificate(self): - """Create and check a invalid certificate""" - with self.assertRaises(ValidationError): - self.certificate_model.create( - { - "type": "nf-e", - "subtype": "a1", - "password": self.cert_passwd, - "file": self.certificate_invalid, - } - ) + """Create and check an expired certificate is flagged as invalid""" + cert = self.certificate_model.create( + self._certificate_vals(self.certificate_invalid) + ) + self.assertFalse(cert.is_valid) def test_compute_field_and_method_to_get_certificate(self): """Test compute field and Method to get Certificate or e-CNPJ or e-NFe""" @@ -124,28 +114,18 @@ def test_compute_field_and_method_to_get_certificate(self): with self.assertRaises(ValidationError): assert company.certificate cert = self.certificate_model.create( - { - "type": "nf-e", - "subtype": "a1", - "password": self.cert_passwd, - "file": self.certificate_valid, - } + self._certificate_vals(self.certificate_valid) ) company.certificate_nfe_id = cert assert company.certificate - # Caso onde apenas o e-CNPJ atende + # Case where only e-CNPJ applies with self.assertRaises(ValidationError): assert company._get_br_ecertificate(only_ecnpj=True) company.certificate_nfe_id = False cert_ecnpj = self.certificate_model.create( - { - "type": "e-cnpj", - "subtype": "a1", - "password": self.cert_passwd, - "file": self.certificate_valid, - } + self._certificate_vals(self.certificate_valid, cert_type="e-cnpj") ) company.certificate_ecnpj_id = cert_ecnpj assert company._get_br_ecertificate(only_ecnpj=True) diff --git a/l10n_br_fiscal_certificate/views/certificate_view.xml b/l10n_br_fiscal_certificate/views/certificate_view.xml index 4d924d182669..0de99c7f0b67 100644 --- a/l10n_br_fiscal_certificate/views/certificate_view.xml +++ b/l10n_br_fiscal_certificate/views/certificate_view.xml @@ -1,36 +1,56 @@ - l10n_br_fiscal.certificate.search - l10n_br_fiscal.certificate + certificate.certificate.search.br + certificate.certificate + + + + + + - l10n_br_fiscal.certificate.tree - l10n_br_fiscal.certificate + certificate.certificate.tree.br + certificate.certificate + + + + - l10n_br_fiscal.certificate.form - l10n_br_fiscal.certificate + certificate.certificate.form.br + certificate.certificate
-
-

- -

+
@@ -42,32 +62,37 @@ />
- - + + + + - - + - + - + - - + + + - - + + - @@ -75,16 +100,17 @@ Certificate ir.actions.act_window - l10n_br_fiscal.certificate + certificate.certificate list,form + [('scope', '=', 'l10n_br')] + {'default_scope': 'l10n_br'}

Add a new Certificate

- All Certificate by - Brazilian Fiscal modulo for Odoo. + Brazilian fiscal A1 certificates (NF-e, CT-e, MDF-e and NFS-e).

diff --git a/l10n_br_ie_search/tests/test_sefaz.py b/l10n_br_ie_search/tests/test_sefaz.py index efb725f779c8..c3dc6657c170 100644 --- a/l10n_br_ie_search/tests/test_sefaz.py +++ b/l10n_br_ie_search/tests/test_sefaz.py @@ -51,7 +51,7 @@ def setUpClass(cls): cls.set_param("ie_search", "sefaz") cls.model = cls.env["res.company"] cls.company_model = cls.env["res.company"] - cls.certificate_model = cls.env["l10n_br_fiscal.certificate"] + cls.certificate_model = cls.env["certificate.certificate"] cls.cert_passwd = "123456" cls.cert_country = "BR" cls.cert_issuer_a = "EMISSOR A TESTE" @@ -84,8 +84,9 @@ def setUpClass(cls): { "type": "nf-e", "subtype": "a1", - "password": cls.cert_passwd, - "file": cls.certificate_valid, + "pkcs12_password": cls.cert_passwd, + "content": cls.certificate_valid, + "company_id": cls.env.company.id, } ) diff --git a/l10n_br_nfe/models/document.py b/l10n_br_nfe/models/document.py index 743ce69f82f1..437921671a18 100644 --- a/l10n_br_nfe/models/document.py +++ b/l10n_br_nfe/models/document.py @@ -1240,8 +1240,8 @@ def _document_export(self, pretty_print=True): record.authorization_event_id = event_id signed_xml = edoc.sign_xml( xml_file, - self.company_id.certificate.file, - self.company_id.certificate.password, + self.company_id.certificate.content, + self.company_id.certificate.pkcs12_password, edoc.infNFe.Id, ) self._validate_xml(signed_xml) diff --git a/l10n_br_nfe/tests/test_nfce.py b/l10n_br_nfe/tests/test_nfce.py index b600fcaa5279..ebce0d01ad76 100644 --- a/l10n_br_nfe/tests/test_nfce.py +++ b/l10n_br_nfe/tests/test_nfce.py @@ -37,12 +37,13 @@ def setUpClass(cls): country="BR", subject="CERTIFICADO VALIDO TESTE", ) - certificate_id = cls.env["l10n_br_fiscal.certificate"].create( + certificate_id = cls.env["certificate.certificate"].create( { "type": "nf-e", "subtype": "a1", - "password": "123456", - "file": certificate_valid, + "pkcs12_password": "123456", + "content": certificate_valid, + "company_id": cls.document_id.company_id.id, } ) cls.document_id.company_id.certificate_nfe_id = certificate_id diff --git a/l10n_br_nfe/tests/test_nfe_workflow.py b/l10n_br_nfe/tests/test_nfe_workflow.py index 871e26b9bf73..a211d14ea52b 100644 --- a/l10n_br_nfe/tests/test_nfe_workflow.py +++ b/l10n_br_nfe/tests/test_nfe_workflow.py @@ -339,18 +339,19 @@ class TestNFCeWorkflowContingency(TestNFeExport): def setUpClass(cls): super().setUpClass(nfe_list=[]) cls.nfce = cls.env.ref(NFCE_DEMO) - certificate = cls.env["l10n_br_fiscal.certificate"].create( + certificate = cls.env["certificate.certificate"].create( { "type": "nf-e", "subtype": "a1", - "password": "123456", - "file": misc.create_fake_certificate_file( + "pkcs12_password": "123456", + "content": misc.create_fake_certificate_file( valid=True, passwd="123456", issuer="EMISSOR A TESTE", country="BR", subject="CERTIFICADO VALIDO TESTE", ), + "company_id": cls.nfce.company_id.id, } ) cls.nfce.company_id.certificate_nfe_id = certificate