Skip to content

Commit 33b0722

Browse files
[REF] l10n_br_nfe: DFe implementation
1 parent b2acf40 commit 33b0722

21 files changed

+638
-858
lines changed

l10n_br_nfe/__manifest__.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,16 @@
2929
"views/res_company_view.xml",
3030
"views/nfe_document_view.xml",
3131
"views/res_config_settings_view.xml",
32-
"views/mde/mde_views.xml",
33-
"views/dfe/dfe_views.xml",
32+
"views/nfe_recipient_manifestation_event/nfe_recipient_manifestation_event_view.xml",
33+
"views/dfe/dfe_access_key_views.xml",
3434
"views/supplier_info_view.xml",
3535
# Report
3636
"report/reports.xml",
3737
"report/danfe_nfce.xml",
3838
"report/danfe_report.xml",
3939
# Wizards
4040
"wizards/import_document.xml",
41+
"wizards/nfe_recipient_manifestation_event_wizard.xml",
4142
# Actions,
4243
"views/nfe_action.xml",
4344
# Menus

l10n_br_nfe/constants/mde.py

+1-25
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,10 @@
11
# Copyright (C) 2023 KMEE Informática LTDA
22
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
33

4-
SIT_MANIF_PENDENTE = ("pendente", "Pendente")
5-
SIT_MANIF_CIENTE = ("ciente", "Ciente da Operação")
4+
SIT_MANIF_PENDENTE = ("rascunho", "Rascunho")
65
SIT_MANIF_CONFIRMADO = ("confirmado", "Confirmada operação")
7-
SIT_MANIF_DESCONHECIDO = ("desconhecido", "Desconhecimento")
8-
SIT_MANIF_NAO_REALIZADO = ("nao_realizado", "Não realizado")
9-
10-
SCHEMA_RESNFE = ("resNFe", "NFe Resumida")
11-
SCHEMA_RESEVENTO = ("resEvento", "Evento de NFe Resumido")
12-
SCHEMA_PROCNFE = ("procNFe", "NFe Completa")
13-
SCHEMA_PROCEVENTONFE = ("procEventoNFe", "Evento de NFe Completo")
14-
15-
SCHEMAS = [SCHEMA_RESNFE, SCHEMA_RESEVENTO, SCHEMA_PROCNFE, SCHEMA_PROCEVENTONFE]
166

177
SITUACAO_MANIFESTACAO = [
188
SIT_MANIF_PENDENTE,
19-
SIT_MANIF_CIENTE,
209
SIT_MANIF_CONFIRMADO,
21-
SIT_MANIF_DESCONHECIDO,
22-
SIT_MANIF_NAO_REALIZADO,
2310
]
24-
25-
SIT_NFE_AUTORIZADA = ("1", "Autorizada")
26-
SIT_NFE_CANCELADA = ("2", "Cancelada")
27-
SIT_NFE_DENEGADA = ("3", "Denegada")
28-
29-
SITUACAO_NFE = [SIT_NFE_AUTORIZADA, SIT_NFE_CANCELADA, SIT_NFE_DENEGADA]
30-
31-
OP_TYPE_ENTRADA = ("0", "Entrada")
32-
OP_TYPE_SAIDA = ("1", "Saída")
33-
34-
OPERATION_TYPE = [OP_TYPE_ENTRADA, OP_TYPE_SAIDA]

l10n_br_nfe/models/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@
1818
from . import res_config_settings
1919
from . import cfop
2020
from . import invalidate_number
21+
from . import nfe_recipient_manifestation_event
2122
from . import dfe
22-
from . import mde
2323

2424
spec_schema = "nfe"
2525
spec_version = "40"

l10n_br_nfe/models/dfe.py

+16-123
Original file line numberDiff line numberDiff line change
@@ -1,131 +1,24 @@
1-
# Copyright (C) 2023 KMEE Informatica LTDA
2-
# License AGPL-3 or later (http://www.gnu.org/licenses/agpl)
3-
4-
from datetime import datetime
5-
6-
from lxml import objectify
7-
from nfelib.nfe.bindings.v4_0.leiaute_nfe_v4_00 import TnfeProc
8-
9-
from odoo import api, fields, models
10-
11-
from odoo.addons.l10n_br_fiscal_dfe.tools import utils
1+
# Copyright (C) 2025-Today - Engenere (<https://engenere.one>).
2+
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
3+
from odoo import _, models
124

135

146
class DFe(models.Model):
157
_inherit = "l10n_br_fiscal.dfe"
168

17-
mde_ids = fields.One2many(
18-
comodel_name="l10n_br_nfe.mde",
19-
inverse_name="dfe_id",
20-
string="Manifestações do Destinatário Importadas",
21-
)
22-
23-
def _process_distribution(self, result):
24-
for doc in result.resposta.loteDistDFeInt.docZip:
25-
xml = utils.parse_gzip_xml(doc.valueOf_).read()
26-
root = objectify.fromstring(xml)
27-
28-
mde_id = self.env["l10n_br_nfe.mde"].search(
29-
[
30-
("nsu", "=", utils.format_nsu(doc.NSU)),
31-
("company_id", "=", self.company_id.id),
32-
],
33-
limit=1,
9+
def import_document(self):
10+
self.ensure_one()
11+
try:
12+
document = self.dfe_monitor_id._download_document(self.key)
13+
document_id = self.dfe_monitor_id._parse_xml_document(document)
14+
except Exception as e:
15+
self.message_post(
16+
body=_("Error importing document: \n\n %(error)s", error=e)
3417
)
35-
if not mde_id:
36-
mde_id = self._create_mde_from_schema(doc.schema, root)
37-
if mde_id:
38-
mde_id.nsu = doc.NSU
39-
mde_id.create_xml_attachment(xml)
40-
41-
@api.model
42-
def _create_mde_from_schema(self, schema, root):
43-
schema_type = schema.split("_")[0]
44-
method = "_create_mde_from_%s" % schema_type
45-
if not hasattr(self, method):
4618
return
19+
if document_id:
20+
self.document_id = document_id
4721

48-
return getattr(self, method)(root)
49-
50-
@api.model
51-
def _create_mde_from_procNFe(self, root):
52-
nfe_key = root.protNFe.infProt.chNFe
53-
mde_id = self.find_mde_by_key(nfe_key)
54-
if mde_id:
55-
return mde_id
56-
57-
supplier_cnpj = utils.mask_cnpj("%014d" % root.NFe.infNFe.emit.CNPJ)
58-
partner = self.env["res.partner"].search([("cnpj_cpf", "=", supplier_cnpj)])
59-
60-
return self.env["l10n_br_nfe.mde"].create(
61-
{
62-
"number": root.NFe.infNFe.ide.nNF,
63-
"key": nfe_key,
64-
"operation_type": str(root.NFe.infNFe.ide.tpNF),
65-
"document_value": root.NFe.infNFe.total.ICMSTot.vNF,
66-
"state": "pendente",
67-
"inclusion_datetime": datetime.now(),
68-
"cnpj_cpf": supplier_cnpj,
69-
"ie": root.NFe.infNFe.emit.IE,
70-
"partner_id": partner.id,
71-
"emission_datetime": datetime.strptime(
72-
str(root.NFe.infNFe.ide.dhEmi)[:19],
73-
"%Y-%m-%dT%H:%M:%S",
74-
),
75-
"company_id": self.company_id.id,
76-
"dfe_id": self.id,
77-
"inclusion_mode": "Verificação agendada",
78-
"schema": "procNFe",
79-
}
80-
)
81-
82-
@api.model
83-
def _create_mde_from_resNFe(self, root):
84-
nfe_key = root.chNFe
85-
mde_id = self.find_mde_by_key(nfe_key)
86-
if mde_id:
87-
return mde_id
88-
89-
supplier_cnpj = utils.mask_cnpj("%014d" % root.CNPJ)
90-
partner_id = self.env["res.partner"].search([("cnpj_cpf", "=", supplier_cnpj)])
91-
92-
return self.env["l10n_br_nfe.mde"].create(
93-
{
94-
"key": nfe_key,
95-
"emitter": root.xNome,
96-
"operation_type": str(root.tpNF),
97-
"document_value": root.vNF,
98-
"document_state": str(root.cSitNFe),
99-
"state": "pendente",
100-
"inclusion_datetime": datetime.now(),
101-
"cnpj_cpf": supplier_cnpj,
102-
"ie": root.IE,
103-
"partner_id": partner_id.id,
104-
"emission_datetime": datetime.strptime(
105-
str(root.dhEmi)[:19], "%Y-%m-%dT%H:%M:%S"
106-
),
107-
"company_id": self.company_id.id,
108-
"dfe_id": self.id,
109-
"inclusion_mode": "Verificação agendada - manifestada por outro app",
110-
"schema": "resNFe",
111-
}
112-
)
113-
114-
@api.model
115-
def find_mde_by_key(self, key):
116-
mde_id = self.env["l10n_br_nfe.mde"].search([("key", "=", key)])
117-
if not mde_id:
118-
return False
119-
120-
if mde_id not in self.mde_ids:
121-
mde_id.dfe_id = self.id
122-
return mde_id
123-
124-
def import_documents(self):
125-
for record in self:
126-
record.mde_ids.import_document_multi()
127-
128-
@api.model
129-
def parse_procNFe(self, xml):
130-
binding = TnfeProc.from_xml(xml.read().decode())
131-
return self.env["l10n_br_fiscal.document"].import_binding_nfe(binding)
22+
def import_document_multi(self):
23+
for rec in self:
24+
rec.import_document()

l10n_br_nfe/models/dfe_access_key.py

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Copyright (C) 2025-Today - Engenere (<https://engenere.one>).
2+
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
3+
from odoo import fields, models
4+
5+
6+
class DFeAccessKey(models.Model):
7+
_inherit = "l10n_br_fiscal.dfe_access_key"
8+
9+
nfe_recipient_manifestation_event_ids = fields.One2many(
10+
comodel_name="l10n_br_nfe.recipient_manifestation_event",
11+
inverse_name="dfe_access_key_id",
12+
string="Manifestações do Destinatário Importadas",
13+
)

0 commit comments

Comments
 (0)