Skip to content

Commit 97f0c99

Browse files
trabalho em desenvolvimento
1 parent be49e28 commit 97f0c99

38 files changed

+1332
-770
lines changed

l10n_br_fiscal/views/cfop_view.xml

+1
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@
8787
name="tax_definition_ids"
8888
nolabel="1"
8989
context="{'tree_view_ref': 'l10n_br_fiscal.tax_definition_tree','form_view_ref': 'l10n_br_fiscal.tax_definition_form', 'default_cfop_id': id}"
90+
colspan="2"
9091
/>
9192
</group>
9293
</sheet>

l10n_br_fiscal_dfe/README.rst

+8-4
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,15 @@ Authors
5656
Contributors
5757
------------
5858

59-
- `KMEE <https://www.kmee.com.br>`__:
59+
- `KMEE <https://www.kmee.com.br>`__:
6060

61-
- Luis Felipe Miléo <mileo@kmee.com.br>
62-
- Gabriel Cardoso <gabriel.cardoso@kmee.com.br>
63-
- Felipe Zago <felipe.zago@kmee.com.br>
61+
- Luis Felipe Miléo <mileo@kmee.com.br>
62+
- Gabriel Cardoso <gabriel.cardoso@kmee.com.br>
63+
- Felipe Zago <felipe.zago@kmee.com.br>
64+
65+
- `Engenere <https://engenere.one>`__:
66+
67+
- Cristiano Mafra Junior
6468

6569
Maintainers
6670
-----------

l10n_br_fiscal_dfe/__manifest__.py

+6
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,15 @@
1010
"website": "https://github.com/OCA/l10n-brazil",
1111
"depends": ["l10n_br_fiscal", "l10n_br_fiscal_certificate"],
1212
"data": [
13+
# Data
1314
"data/ir_cron.xml",
15+
# Security
16+
"security/dfe_security.xml",
1417
"security/ir.model.access.csv",
18+
# Views
19+
"views/dfe/dfe_monitor_views.xml",
1520
"views/dfe/dfe_views.xml",
21+
"views/dfe/dfe_access_key.xml",
1622
"views/l10n_br_fiscal_menu.xml",
1723
"views/res_company_view.xml",
1824
],

l10n_br_fiscal_dfe/constants/dfe.py

+11
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,14 @@
88
DFE_ENVIRONMENTS = [("1", "Produção"), ("2", "Homologação")]
99

1010
DFE_ENVIRONMENT_DEFAULT = "2"
11+
12+
OP_TYPE_ENTRADA = ("0", "Entrada")
13+
OP_TYPE_SAIDA = ("1", "Saída")
14+
15+
OPERATION_TYPE = [OP_TYPE_ENTRADA, OP_TYPE_SAIDA]
16+
17+
18+
SIT_NFE_AUTORIZADA = ("1", "Autorizada")
19+
SIT_NFE_CANCELADA = ("2", "Cancelada")
20+
SIT_NFE_DENEGADA = ("3", "Denegada")
21+
SITUACAO_NFE = [SIT_NFE_AUTORIZADA, SIT_NFE_CANCELADA, SIT_NFE_DENEGADA]

l10n_br_fiscal_dfe/models/__init__.py

+2
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,5 @@
22
from . import document
33
from . import attachment
44
from . import res_company
5+
from . import dfe_monitor
6+
from . import dfe_access_key

l10n_br_fiscal_dfe/models/dfe.py

+74-131
Original file line numberDiff line numberDiff line change
@@ -1,157 +1,100 @@
1-
# Copyright (C) 2023 KMEE Informatica LTDA
2-
# License AGPL-3 or later (http://www.gnu.org/licenses/agpl)
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
34

4-
import logging
5-
import re
6-
7-
from erpbrasil.transmissao import TransmissaoSOAP
8-
from nfelib.nfe.ws.edoc_legacy import NFeAdapter as edoc_nfe
9-
from requests import Session
10-
11-
from odoo import _, api, fields, models
12-
13-
from ..tools import utils
14-
15-
_logger = logging.getLogger(__name__)
5+
from ..constants.dfe import (
6+
OPERATION_TYPE,
7+
SITUACAO_NFE,
8+
)
169

1710

1811
class DFe(models.Model):
1912
_name = "l10n_br_fiscal.dfe"
20-
_inherit = ["mail.thread", "mail.activity.mixin"]
21-
_description = "Consult DF-e"
22-
_order = "id desc"
23-
_rec_name = "display_name"
13+
_description = "DF-e"
2414

25-
display_name = fields.Char(compute="_compute_display_name")
15+
dfe_access_key_id = fields.Many2one(
16+
comodel_name="l10n_br_fiscal.dfe_access_key", string="Chave de Acesso"
17+
)
2618

27-
company_id = fields.Many2one(comodel_name="res.company", string="Company")
19+
key = fields.Char(string="Access Key", size=44, related="dfe_access_key_id.key")
2820

29-
version = fields.Selection(related="company_id.dfe_version")
21+
serie = fields.Char(size=3, index=True)
3022

31-
environment = fields.Selection(related="company_id.dfe_environment")
23+
number = fields.Float(string="Document Number", index=True, digits=(18, 0))
3224

33-
last_nsu = fields.Char(string="Last NSU", size=25, default="0")
25+
emitter = fields.Char(size=60)
3426

35-
last_query = fields.Datetime(string="Last query")
27+
cnpj_cpf = fields.Char(string="CNPJ/CPF", size=18)
3628

37-
imported_document_ids = fields.One2many(
38-
comodel_name="l10n_br_fiscal.document",
39-
inverse_name="dfe_id",
40-
string="Imported Documents",
41-
)
29+
nsu = fields.Char(string="NSU", size=25, index=True)
4230

43-
use_cron = fields.Boolean(
44-
default=False,
45-
string="Download new documents automatically",
46-
help="If activated, allows new manifestations to be automatically "
47-
"searched with a Cron",
31+
operation_type = fields.Selection(
32+
selection=OPERATION_TYPE,
4833
)
4934

50-
@api.depends("company_id.name", "last_nsu")
51-
def name_get(self):
52-
return self.mapped(lambda d: (d.id, f"{d.company_id.name} - NSU: {d.last_nsu}"))
53-
54-
@api.model
55-
def _get_processor(self):
56-
certificado = self.env.company._get_br_ecertificate()
57-
session = Session()
58-
session.verify = False
59-
return edoc_nfe(
60-
TransmissaoSOAP(certificado, session),
61-
self.company_id.state_id.ibge_code,
62-
versao=self.version,
63-
ambiente=self.environment,
64-
)
65-
66-
@api.model
67-
def validate_distribution_response(self, result):
68-
valid = False
69-
message = result.resposta.xMotivo
70-
if result.retorno.status_code != 200:
71-
code = result.retorno.status_code
72-
elif result.resposta.cStat != "138":
73-
code = result.resposta.cStat
74-
else:
75-
valid = True
76-
77-
if not valid:
78-
self.message_post(
79-
body=_(
80-
_(
81-
"Error validating document distribution:"
82-
"\n\n%(code)s - %(message)s",
83-
code=code,
84-
message=message,
85-
)
86-
)
87-
)
88-
89-
return valid
90-
91-
@api.model
92-
def _document_distribution(self):
93-
maxNSU = ""
94-
while maxNSU != self.last_nsu:
95-
try:
96-
result = self._get_processor().consultar_distribuicao(
97-
cnpj_cpf=re.sub("[^0-9]", "", self.company_id.cnpj_cpf),
98-
ultimo_nsu=utils.format_nsu(self.last_nsu),
99-
)
100-
except Exception as e:
101-
self.message_post(
102-
body=_("Error on searching documents.\n%(error)s", error=e)
103-
)
104-
break
105-
106-
self.write(
107-
{
108-
"last_nsu": result.resposta.ultNSU,
109-
"last_query": fields.Datetime.now(),
110-
}
111-
)
35+
document_value = fields.Float(
36+
string="Document Total Value",
37+
readonly=True,
38+
digits=(18, 2),
39+
)
11240

113-
if not self.validate_distribution_response(result):
114-
break
41+
ie = fields.Char(string="Inscrição estadual", size=18)
11542

116-
self._process_distribution(result)
43+
partner_id = fields.Many2one(
44+
comodel_name="res.partner",
45+
string="Supplier (partner)",
46+
)
11747

118-
maxNSU = result.resposta.maxNSU
48+
company_id = fields.Many2one(
49+
comodel_name="res.company",
50+
string="Company",
51+
default=lambda self: self.env.company,
52+
readonly=True,
53+
)
11954

120-
@api.model
121-
def _process_distribution(self, result):
122-
"""Method to process the distribution data."""
55+
emission_datetime = fields.Datetime(
56+
string="Emission Date",
57+
index=True,
58+
default=fields.Datetime.now,
59+
)
12360

124-
@api.model
125-
def _parse_xml_document(self, document):
126-
schema_type = document.schema.split("_")[0]
127-
method = "parse_%s" % schema_type
128-
if not hasattr(self, method):
129-
return
61+
inclusion_datetime = fields.Datetime(
62+
string="Inclusion Date",
63+
index=True,
64+
default=fields.Datetime.now,
65+
)
13066

131-
xml = utils.parse_gzip_xml(document.valueOf_)
132-
return getattr(self, method)(xml)
67+
inclusion_mode = fields.Char(size=255)
13368

134-
@api.model
135-
def _download_document(self, nfe_key):
136-
try:
137-
result = self._get_processor().consultar_distribuicao(
138-
chave=nfe_key, cnpj_cpf=re.sub("[^0-9]", "", self.company_id.cnpj_cpf)
139-
)
140-
except Exception as e:
141-
self.message_post(
142-
body=_("Error on searching documents.\n%(error)s", error=e)
143-
)
144-
return
69+
document_state = fields.Selection(
70+
selection=SITUACAO_NFE,
71+
index=True,
72+
)
14573

146-
if not self.validate_distribution_response(result):
147-
return
74+
cfop_ids = fields.Many2many(
75+
comodel_name="l10n_br_fiscal.cfop",
76+
string="CFOPs",
77+
)
14878

149-
return result.resposta.loteDistDFeInt.docZip[0]
79+
dfe_nfe_document_type = fields.Selection(
80+
selection=[
81+
("dfe_nfe_complete", "NF-e Completa"),
82+
("dfe_nfe_summary", "Resumo da NF-e"),
83+
("dfe_nfe_event", "Evento da NF-e"),
84+
],
85+
string="DFe Document Type",
86+
)
15087

151-
@api.model
152-
def _cron_search_documents(self):
153-
self.search([("use_cron", "=", True)]).search_documents()
88+
dfe_monitor_id = fields.Many2one(
89+
comodel_name="l10n_br_fiscal.dfe_monitor",
90+
string="DFe Monitor",
91+
)
15492

155-
def search_documents(self):
156-
for record in self:
157-
record._document_distribution()
93+
def name_get(self):
94+
return [
95+
(
96+
rec.id,
97+
f"{rec.emitter} - {rec.key}",
98+
)
99+
for rec in self
100+
]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
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 AccessKey(models.Model):
7+
_name = "l10n_br_fiscal.dfe_access_key"
8+
_description = ""
9+
10+
key = fields.Char(size=44, required=True)
11+
12+
dfe_ids = fields.One2many(
13+
comodel_name="l10n_br_fiscal.dfe",
14+
inverse_name="dfe_access_key_id",
15+
string="DFe",
16+
)
17+
18+
emitter = fields.Char(related="dfe_ids.emitter")
19+
20+
cnpj_cpf = fields.Char(related="dfe_ids.cnpj_cpf")
21+
22+
document_value = fields.Float(
23+
string="Document Total Value", digits=(18, 2), related="dfe_ids.document_value"
24+
)
25+
26+
dfe_monitor_id = fields.Many2one(
27+
comodel_name="l10n_br_fiscal.dfe_monitor",
28+
string="Monitor de DFe",
29+
)
30+
31+
_sql_constraints = [
32+
(
33+
"unique_key",
34+
"UNIQUE(key)",
35+
"The access key already exists",
36+
),
37+
]

0 commit comments

Comments
 (0)