odoo-addon-l10n-br-fiscal-edi 15.0.1.0.0.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- odoo/addons/l10n_br_fiscal_edi/README.rst +124 -0
- odoo/addons/l10n_br_fiscal_edi/__init__.py +2 -0
- odoo/addons/l10n_br_fiscal_edi/__manifest__.py +41 -0
- odoo/addons/l10n_br_fiscal_edi/i18n/l10n_br_fiscal_edi.pot +896 -0
- odoo/addons/l10n_br_fiscal_edi/models/__init__.py +4 -0
- odoo/addons/l10n_br_fiscal_edi/models/document.py +294 -0
- odoo/addons/l10n_br_fiscal_edi/models/document_event.py +392 -0
- odoo/addons/l10n_br_fiscal_edi/models/document_workflow.py +387 -0
- odoo/addons/l10n_br_fiscal_edi/models/invalidate_number.py +53 -0
- odoo/addons/l10n_br_fiscal_edi/readme/CONTRIBUTORS.md +5 -0
- odoo/addons/l10n_br_fiscal_edi/readme/DESCRIPTION.md +6 -0
- odoo/addons/l10n_br_fiscal_edi/readme/ROADMAP.md +6 -0
- odoo/addons/l10n_br_fiscal_edi/readme/USAGE.md +7 -0
- odoo/addons/l10n_br_fiscal_edi/security/ir.model.access.csv +7 -0
- odoo/addons/l10n_br_fiscal_edi/static/description/icon.png +0 -0
- odoo/addons/l10n_br_fiscal_edi/static/description/index.html +460 -0
- odoo/addons/l10n_br_fiscal_edi/tests/__init__.py +1 -0
- odoo/addons/l10n_br_fiscal_edi/tests/test_fiscal_document_generic.py +1191 -0
- odoo/addons/l10n_br_fiscal_edi/tests/test_tax_benefit.py +74 -0
- odoo/addons/l10n_br_fiscal_edi/tests/test_workflow.py +118 -0
- odoo/addons/l10n_br_fiscal_edi/views/document_event_report.xml +15 -0
- odoo/addons/l10n_br_fiscal_edi/views/document_event_template.xml +114 -0
- odoo/addons/l10n_br_fiscal_edi/views/document_event_view.xml +68 -0
- odoo/addons/l10n_br_fiscal_edi/views/document_view.xml +77 -0
- odoo/addons/l10n_br_fiscal_edi/views/invalidate_number_view.xml +19 -0
- odoo/addons/l10n_br_fiscal_edi/views/l10n_br_fiscal_action.xml +38 -0
- odoo/addons/l10n_br_fiscal_edi/views/l10n_br_fiscal_menu.xml +23 -0
- odoo/addons/l10n_br_fiscal_edi/wizards/__init__.py +7 -0
- odoo/addons/l10n_br_fiscal_edi/wizards/base_wizard_mixin.py +13 -0
- odoo/addons/l10n_br_fiscal_edi/wizards/document_cancel_wizard.py +20 -0
- odoo/addons/l10n_br_fiscal_edi/wizards/document_cancel_wizard.xml +30 -0
- odoo/addons/l10n_br_fiscal_edi/wizards/document_correction_wizard.py +17 -0
- odoo/addons/l10n_br_fiscal_edi/wizards/document_correction_wizard.xml +30 -0
- odoo/addons/l10n_br_fiscal_edi/wizards/document_import_wizard_mixin.py +132 -0
- odoo/addons/l10n_br_fiscal_edi/wizards/document_import_wizard_mixin.xml +44 -0
- odoo/addons/l10n_br_fiscal_edi/wizards/document_status_wizard.xml +58 -0
- odoo/addons/l10n_br_fiscal_edi/wizards/invalidate_number_wizard.py +33 -0
- odoo/addons/l10n_br_fiscal_edi/wizards/invalidate_number_wizard.xml +30 -0
- odoo_addon_l10n_br_fiscal_edi-15.0.1.0.0.2.dist-info/METADATA +141 -0
- odoo_addon_l10n_br_fiscal_edi-15.0.1.0.0.2.dist-info/RECORD +42 -0
- odoo_addon_l10n_br_fiscal_edi-15.0.1.0.0.2.dist-info/WHEEL +5 -0
- odoo_addon_l10n_br_fiscal_edi-15.0.1.0.0.2.dist-info/top_level.txt +1 -0
@@ -0,0 +1,294 @@
|
|
1
|
+
# Copyright (C) 2019 Renato Lima - Akretion
|
2
|
+
# Copyright (C) 2019 KMEE INFORMATICA LTDA
|
3
|
+
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
|
4
|
+
|
5
|
+
from odoo import _, api, fields, models
|
6
|
+
from odoo.exceptions import UserError, ValidationError
|
7
|
+
|
8
|
+
from odoo.addons.l10n_br_fiscal.constants.fiscal import (
|
9
|
+
DOCUMENT_ISSUER,
|
10
|
+
DOCUMENT_ISSUER_COMPANY,
|
11
|
+
PROCESSADOR_NENHUM,
|
12
|
+
SITUACAO_EDOC_AUTORIZADA,
|
13
|
+
)
|
14
|
+
|
15
|
+
|
16
|
+
def filter_processador(record):
|
17
|
+
if record.document_electronic and record.processador_edoc == PROCESSADOR_NENHUM:
|
18
|
+
return True
|
19
|
+
return False
|
20
|
+
|
21
|
+
|
22
|
+
class Document(models.Model):
|
23
|
+
"""
|
24
|
+
As of August 2024, this is the extraction of the legacy
|
25
|
+
l10n_br_fiscal.document.electronic mixin that was part of l10n_br_fiscal
|
26
|
+
from version 12 to 14. This code was made before the OCA/edi and OCA/edi-framework
|
27
|
+
and might easily be improved...
|
28
|
+
"""
|
29
|
+
|
30
|
+
_name = "l10n_br_fiscal.document"
|
31
|
+
|
32
|
+
_inherit = [
|
33
|
+
"l10n_br_fiscal.document",
|
34
|
+
"l10n_br_fiscal.document.workflow",
|
35
|
+
]
|
36
|
+
|
37
|
+
event_ids = fields.One2many(
|
38
|
+
comodel_name="l10n_br_fiscal.event",
|
39
|
+
inverse_name="document_id",
|
40
|
+
string="Events",
|
41
|
+
copy=False,
|
42
|
+
readonly=True,
|
43
|
+
)
|
44
|
+
|
45
|
+
correction_event_ids = fields.One2many(
|
46
|
+
comodel_name="l10n_br_fiscal.event",
|
47
|
+
inverse_name="document_id",
|
48
|
+
domain=[("type", "=", "14")],
|
49
|
+
string="Correction Events",
|
50
|
+
copy=False,
|
51
|
+
readonly=True,
|
52
|
+
)
|
53
|
+
|
54
|
+
issuer = fields.Selection(
|
55
|
+
selection=DOCUMENT_ISSUER,
|
56
|
+
default=DOCUMENT_ISSUER_COMPANY,
|
57
|
+
)
|
58
|
+
|
59
|
+
status_code = fields.Char(
|
60
|
+
copy=False,
|
61
|
+
)
|
62
|
+
|
63
|
+
status_name = fields.Char(
|
64
|
+
copy=False,
|
65
|
+
)
|
66
|
+
|
67
|
+
status_description = fields.Char(
|
68
|
+
compute="_compute_status_description",
|
69
|
+
copy=False,
|
70
|
+
)
|
71
|
+
|
72
|
+
# Authorization Event Related Fields
|
73
|
+
authorization_event_id = fields.Many2one(
|
74
|
+
comodel_name="l10n_br_fiscal.event",
|
75
|
+
string="Authorization Event",
|
76
|
+
readonly=True,
|
77
|
+
copy=False,
|
78
|
+
)
|
79
|
+
|
80
|
+
authorization_date = fields.Datetime(
|
81
|
+
related="authorization_event_id.protocol_date",
|
82
|
+
string="Authorization Protocol Date",
|
83
|
+
readonly=True,
|
84
|
+
)
|
85
|
+
|
86
|
+
authorization_protocol = fields.Char(
|
87
|
+
related="authorization_event_id.protocol_number",
|
88
|
+
string="Authorization Protocol Number",
|
89
|
+
readonly=True,
|
90
|
+
)
|
91
|
+
|
92
|
+
send_file_id = fields.Many2one(
|
93
|
+
comodel_name="ir.attachment",
|
94
|
+
related="authorization_event_id.file_request_id",
|
95
|
+
string="Send Document File XML",
|
96
|
+
ondelete="restrict",
|
97
|
+
readonly=True,
|
98
|
+
)
|
99
|
+
|
100
|
+
authorization_file_id = fields.Many2one(
|
101
|
+
comodel_name="ir.attachment",
|
102
|
+
related="authorization_event_id.file_response_id",
|
103
|
+
string="Authorization File XML",
|
104
|
+
ondelete="restrict",
|
105
|
+
readonly=True,
|
106
|
+
)
|
107
|
+
|
108
|
+
# Cancel Event Related Fields
|
109
|
+
cancel_event_id = fields.Many2one(
|
110
|
+
comodel_name="l10n_br_fiscal.event",
|
111
|
+
string="Cancel Event",
|
112
|
+
copy=False,
|
113
|
+
)
|
114
|
+
|
115
|
+
cancel_date = fields.Datetime(
|
116
|
+
related="cancel_event_id.protocol_date",
|
117
|
+
string="Cancel Protocol Date",
|
118
|
+
readonly=True,
|
119
|
+
)
|
120
|
+
|
121
|
+
cancel_protocol_number = fields.Char(
|
122
|
+
related="cancel_event_id.protocol_number",
|
123
|
+
string="Cancel Protocol Protocol",
|
124
|
+
readonly=True,
|
125
|
+
)
|
126
|
+
|
127
|
+
cancel_file_id = fields.Many2one(
|
128
|
+
comodel_name="ir.attachment",
|
129
|
+
related="cancel_event_id.file_response_id",
|
130
|
+
string="Cancel File XML",
|
131
|
+
ondelete="restrict",
|
132
|
+
readonly=True,
|
133
|
+
)
|
134
|
+
|
135
|
+
# Invalidate Event Related Fields
|
136
|
+
invalidate_event_id = fields.Many2one(
|
137
|
+
comodel_name="l10n_br_fiscal.event",
|
138
|
+
string="Invalidate Event",
|
139
|
+
copy=False,
|
140
|
+
)
|
141
|
+
|
142
|
+
invalidate_date = fields.Datetime(
|
143
|
+
related="invalidate_event_id.protocol_date",
|
144
|
+
string="Invalidate Protocol Date",
|
145
|
+
readonly=True,
|
146
|
+
)
|
147
|
+
|
148
|
+
invalidate_protocol_number = fields.Char(
|
149
|
+
related="invalidate_event_id.protocol_number",
|
150
|
+
string="Invalidate Protocol Number",
|
151
|
+
readonly=True,
|
152
|
+
)
|
153
|
+
|
154
|
+
invalidate_file_id = fields.Many2one(
|
155
|
+
comodel_name="ir.attachment",
|
156
|
+
related="invalidate_event_id.file_response_id",
|
157
|
+
string="Invalidate File XML",
|
158
|
+
ondelete="restrict",
|
159
|
+
readonly=True,
|
160
|
+
)
|
161
|
+
|
162
|
+
document_version = fields.Char(string="Version", default="4.00", readonly=True)
|
163
|
+
|
164
|
+
is_edoc_printed = fields.Boolean(string="Is Printed?", readonly=True)
|
165
|
+
|
166
|
+
file_report_id = fields.Many2one(
|
167
|
+
comodel_name="ir.attachment",
|
168
|
+
string="Document Report",
|
169
|
+
ondelete="restrict",
|
170
|
+
readonly=True,
|
171
|
+
copy=False,
|
172
|
+
)
|
173
|
+
|
174
|
+
# these workflow methods are plugged here so their interface defined in
|
175
|
+
# l10n_br_fiscal can easily be overriden in other modules.
|
176
|
+
def action_document_confirm(self):
|
177
|
+
super().action_document_confirm()
|
178
|
+
return self._document_confirm_to_send()
|
179
|
+
|
180
|
+
def action_document_send(self):
|
181
|
+
super().action_document_send()
|
182
|
+
return self._action_document_send()
|
183
|
+
|
184
|
+
def action_document_back2draft(self):
|
185
|
+
super().action_document_back2draft()
|
186
|
+
return self._action_document_back2draft()
|
187
|
+
|
188
|
+
def action_document_cancel(self):
|
189
|
+
super().action_document_confirm()
|
190
|
+
return self._action_document_cancel()
|
191
|
+
|
192
|
+
def action_document_invalidate(self):
|
193
|
+
super().action_document_invalidate()
|
194
|
+
return self._action_document_invalidate()
|
195
|
+
|
196
|
+
def action_document_correction(self):
|
197
|
+
super().action_document_correction()
|
198
|
+
return self._action_document_correction()
|
199
|
+
|
200
|
+
def exec_after_SITUACAO_EDOC_DENEGADA(self, old_state, new_state):
|
201
|
+
# see https://github.com/OCA/l10n-brazil/pull/3272
|
202
|
+
super().exec_after_SITUACAO_EDOC_DENEGADA(old_state, new_state)
|
203
|
+
return self._exec_after_SITUACAO_EDOC_DENEGADA(old_state, new_state)
|
204
|
+
|
205
|
+
@api.depends("status_code", "status_name")
|
206
|
+
def _compute_status_description(self):
|
207
|
+
for record in self:
|
208
|
+
if record.status_code:
|
209
|
+
record.status_description = "{} - {}".format(
|
210
|
+
record.status_code or "",
|
211
|
+
record.status_name or "",
|
212
|
+
)
|
213
|
+
else:
|
214
|
+
record.status_description = False
|
215
|
+
|
216
|
+
def _eletronic_document_send(self):
|
217
|
+
"""Implement this method in your transmission module,
|
218
|
+
to send the electronic document and use the method _change_state
|
219
|
+
to update the state of the transmited document,
|
220
|
+
|
221
|
+
def _eletronic_document_send(self):
|
222
|
+
super()._document_send()
|
223
|
+
for record in self.filtered(myfilter):
|
224
|
+
Do your transmission stuff
|
225
|
+
[...]
|
226
|
+
Change the state of the document
|
227
|
+
"""
|
228
|
+
for record in self.filtered(filter_processador):
|
229
|
+
record._change_state(SITUACAO_EDOC_AUTORIZADA)
|
230
|
+
|
231
|
+
def _document_send(self):
|
232
|
+
no_electronic = self.filtered(
|
233
|
+
lambda d: not d.document_electronic
|
234
|
+
or not d.issuer == DOCUMENT_ISSUER_COMPANY
|
235
|
+
)
|
236
|
+
no_electronic._no_eletronic_document_send()
|
237
|
+
electronic = self - no_electronic
|
238
|
+
electronic._eletronic_document_send()
|
239
|
+
|
240
|
+
def serialize(self):
|
241
|
+
edocs = []
|
242
|
+
self._serialize(edocs)
|
243
|
+
return edocs
|
244
|
+
|
245
|
+
def _serialize(self, edocs):
|
246
|
+
return edocs
|
247
|
+
|
248
|
+
def _target_new_tab(self, attachment_id):
|
249
|
+
if attachment_id:
|
250
|
+
return {
|
251
|
+
"type": "ir.actions.act_url",
|
252
|
+
"url": "/web/content/{id}/{nome}".format(
|
253
|
+
id=attachment_id.id, nome=attachment_id.name
|
254
|
+
),
|
255
|
+
"target": "new",
|
256
|
+
}
|
257
|
+
|
258
|
+
def view_xml(self):
|
259
|
+
self.ensure_one()
|
260
|
+
super().view_xml()
|
261
|
+
xml_file = self.authorization_file_id or self.send_file_id
|
262
|
+
if not xml_file:
|
263
|
+
self._document_export()
|
264
|
+
xml_file = self.authorization_file_id or self.send_file_id
|
265
|
+
if not xml_file:
|
266
|
+
raise UserError(_("No XML file generated!"))
|
267
|
+
return self._target_new_tab(xml_file)
|
268
|
+
|
269
|
+
def make_pdf(self):
|
270
|
+
pass
|
271
|
+
|
272
|
+
def view_pdf(self):
|
273
|
+
self.ensure_one()
|
274
|
+
super().view_pdf()
|
275
|
+
if not self.file_report_id or not self.authorization_file_id:
|
276
|
+
self.make_pdf()
|
277
|
+
if not self.file_report_id:
|
278
|
+
raise UserError(_("No PDF file generated!"))
|
279
|
+
return self._target_new_tab(self.file_report_id)
|
280
|
+
|
281
|
+
def _document_status(self):
|
282
|
+
"""Retorna o status do documento em texto e se necessário,
|
283
|
+
atualiza o status do documento"""
|
284
|
+
return
|
285
|
+
|
286
|
+
@api.constrains("issuer")
|
287
|
+
def _check_issuer(self):
|
288
|
+
for record in self.filtered(lambda d: d.document_electronic):
|
289
|
+
if not record.issuer:
|
290
|
+
raise ValidationError(
|
291
|
+
_(
|
292
|
+
"The field 'Issuer' is required for brazilian electronic documents!"
|
293
|
+
)
|
294
|
+
)
|
@@ -0,0 +1,392 @@
|
|
1
|
+
# Copyright (C) 2009 - TODAY Renato Lima - Akretion
|
2
|
+
# Copyright (C) 2014 KMEE - www.kmee.com.br
|
3
|
+
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
|
4
|
+
|
5
|
+
import base64
|
6
|
+
import logging
|
7
|
+
import os
|
8
|
+
|
9
|
+
from odoo import _, api, fields, models
|
10
|
+
from odoo.exceptions import UserError
|
11
|
+
|
12
|
+
from odoo.addons.l10n_br_fiscal.constants.fiscal import EVENT_ENVIRONMENT
|
13
|
+
from odoo.addons.l10n_br_fiscal.tools import build_edoc_path
|
14
|
+
|
15
|
+
_logger = logging.getLogger(__name__)
|
16
|
+
|
17
|
+
FILE_SUFIX_EVENT = {
|
18
|
+
"0": "env",
|
19
|
+
"1": "con-rec",
|
20
|
+
"2": "can",
|
21
|
+
"3": "inu",
|
22
|
+
"4": "con-edoc",
|
23
|
+
"5": "con-status",
|
24
|
+
"6": "con-cad",
|
25
|
+
"7": "dpec-rec",
|
26
|
+
"8": "dpec-con",
|
27
|
+
"9": "rec-eve",
|
28
|
+
"10": "dow",
|
29
|
+
"11": "con-dest",
|
30
|
+
"12": "dist-dfe",
|
31
|
+
"13": "man",
|
32
|
+
"14": "cce",
|
33
|
+
}
|
34
|
+
|
35
|
+
|
36
|
+
class Event(models.Model):
|
37
|
+
_name = "l10n_br_fiscal.event"
|
38
|
+
_description = "Fiscal Event"
|
39
|
+
|
40
|
+
@api.depends("document_id.name", "invalidate_number_id.name")
|
41
|
+
def _compute_display_name(self):
|
42
|
+
for record in self:
|
43
|
+
if record.document_id:
|
44
|
+
names = [
|
45
|
+
_("Fiscal Document"),
|
46
|
+
record.document_id.name,
|
47
|
+
]
|
48
|
+
record.display_name = " / ".join(filter(None, names))
|
49
|
+
elif record.invalidate_number_id:
|
50
|
+
names = [
|
51
|
+
_("Invalidate Number"),
|
52
|
+
record.invalidate_number_id.name,
|
53
|
+
]
|
54
|
+
record.display_name = " / ".join(filter(None, names))
|
55
|
+
else:
|
56
|
+
record.display_name = ""
|
57
|
+
|
58
|
+
create_date = fields.Datetime(
|
59
|
+
readonly=True,
|
60
|
+
index=True,
|
61
|
+
default=fields.Datetime.now,
|
62
|
+
)
|
63
|
+
|
64
|
+
write_date = fields.Datetime(
|
65
|
+
readonly=True,
|
66
|
+
index=True,
|
67
|
+
)
|
68
|
+
|
69
|
+
type = fields.Selection(
|
70
|
+
selection=[
|
71
|
+
("-1", "Exception"),
|
72
|
+
("0", "Autorização de Uso"),
|
73
|
+
("1", "Consulta Recibo"),
|
74
|
+
("2", "Cancelamento"),
|
75
|
+
("3", "Inutilização"),
|
76
|
+
("4", "Consulta NFE"),
|
77
|
+
("5", "Consulta Situação"),
|
78
|
+
("6", "Consulta Cadastro"),
|
79
|
+
("7", "DPEC Recepção"),
|
80
|
+
("8", "DPEC Consulta"),
|
81
|
+
("9", "Recepção Evento"),
|
82
|
+
("10", "Download"),
|
83
|
+
("11", "Consulta Destinadas"),
|
84
|
+
("12", "Distribuição DFe"),
|
85
|
+
("13", "Manifestação"),
|
86
|
+
("14", "Carta de Correção"),
|
87
|
+
],
|
88
|
+
string="Service",
|
89
|
+
)
|
90
|
+
|
91
|
+
origin = fields.Char(
|
92
|
+
string="Source Document",
|
93
|
+
readonly=True,
|
94
|
+
help="Document reference that generated this event.",
|
95
|
+
)
|
96
|
+
|
97
|
+
document_id = fields.Many2one(
|
98
|
+
comodel_name="l10n_br_fiscal.document",
|
99
|
+
string="Fiscal Document",
|
100
|
+
index=True,
|
101
|
+
)
|
102
|
+
|
103
|
+
document_type_id = fields.Many2one(
|
104
|
+
comodel_name="l10n_br_fiscal.document.type",
|
105
|
+
string="Fiscal Document Type",
|
106
|
+
index=True,
|
107
|
+
required=True,
|
108
|
+
)
|
109
|
+
|
110
|
+
document_serie_id = fields.Many2one(
|
111
|
+
comodel_name="l10n_br_fiscal.document.serie",
|
112
|
+
required=True,
|
113
|
+
)
|
114
|
+
|
115
|
+
document_number = fields.Char(
|
116
|
+
required=True,
|
117
|
+
)
|
118
|
+
|
119
|
+
partner_id = fields.Many2one(
|
120
|
+
comodel_name="res.partner",
|
121
|
+
string="Partner",
|
122
|
+
index=True,
|
123
|
+
)
|
124
|
+
|
125
|
+
invalidate_number_id = fields.Many2one(
|
126
|
+
comodel_name="l10n_br_fiscal.invalidate.number",
|
127
|
+
string="Invalidate Number",
|
128
|
+
index=True,
|
129
|
+
)
|
130
|
+
|
131
|
+
company_id = fields.Many2one(
|
132
|
+
comodel_name="res.company",
|
133
|
+
string="Company",
|
134
|
+
index=True,
|
135
|
+
required=True,
|
136
|
+
)
|
137
|
+
|
138
|
+
sequence = fields.Char(
|
139
|
+
help="Fiscal Document Event Sequence",
|
140
|
+
)
|
141
|
+
|
142
|
+
justification = fields.Char()
|
143
|
+
|
144
|
+
display_name = fields.Char(
|
145
|
+
string="name",
|
146
|
+
compute="_compute_display_name",
|
147
|
+
store=True,
|
148
|
+
)
|
149
|
+
|
150
|
+
file_request_id = fields.Many2one(
|
151
|
+
comodel_name="ir.attachment",
|
152
|
+
string="XML",
|
153
|
+
copy=False,
|
154
|
+
readonly=True,
|
155
|
+
)
|
156
|
+
|
157
|
+
file_response_id = fields.Many2one(
|
158
|
+
comodel_name="ir.attachment",
|
159
|
+
string="XML Response",
|
160
|
+
copy=False,
|
161
|
+
readonly=True,
|
162
|
+
)
|
163
|
+
|
164
|
+
file_path = fields.Char(
|
165
|
+
readonly=True,
|
166
|
+
)
|
167
|
+
|
168
|
+
status_code = fields.Char(
|
169
|
+
readonly=True,
|
170
|
+
)
|
171
|
+
|
172
|
+
response = fields.Char(
|
173
|
+
string="Response Message",
|
174
|
+
readonly=True,
|
175
|
+
)
|
176
|
+
|
177
|
+
message = fields.Char(
|
178
|
+
readonly=True,
|
179
|
+
)
|
180
|
+
|
181
|
+
protocol_date = fields.Datetime(
|
182
|
+
readonly=True,
|
183
|
+
index=True,
|
184
|
+
)
|
185
|
+
|
186
|
+
protocol_number = fields.Char()
|
187
|
+
|
188
|
+
lot_receipt_number = fields.Char(
|
189
|
+
help=(
|
190
|
+
"In asynchronous processing, a lot receipt number is generated, "
|
191
|
+
"which is used for later consultation."
|
192
|
+
),
|
193
|
+
)
|
194
|
+
|
195
|
+
state = fields.Selection(
|
196
|
+
selection=[
|
197
|
+
("draft", _("Draft")),
|
198
|
+
("send", _("Sending")),
|
199
|
+
("wait", _("Waiting Response")),
|
200
|
+
("done", _("Response received")),
|
201
|
+
],
|
202
|
+
string="Status",
|
203
|
+
readonly=True,
|
204
|
+
index=True,
|
205
|
+
default="draft",
|
206
|
+
)
|
207
|
+
|
208
|
+
environment = fields.Selection(
|
209
|
+
selection=EVENT_ENVIRONMENT,
|
210
|
+
)
|
211
|
+
|
212
|
+
@api.constrains("justification")
|
213
|
+
def _check_justification(self):
|
214
|
+
if len(self.justification) < 15:
|
215
|
+
raise UserError(_("Justification must be at least 15 characters."))
|
216
|
+
return True
|
217
|
+
|
218
|
+
def _save_event_2disk(self, arquivo, file_name):
|
219
|
+
self.ensure_one()
|
220
|
+
tipo_documento = self.document_type_id.prefix
|
221
|
+
serie = self.document_serie_id.code
|
222
|
+
numero = self.document_number
|
223
|
+
|
224
|
+
if self.document_id:
|
225
|
+
ano = self.document_id.document_date.strftime("%Y")
|
226
|
+
mes = self.document_id.document_date.strftime("%m")
|
227
|
+
elif self.invalidate_number_id:
|
228
|
+
ano = self.invalidate_number_id.date.strftime("%Y")
|
229
|
+
mes = self.invalidate_number_id.date.strftime("%m")
|
230
|
+
|
231
|
+
save_dir = build_edoc_path(
|
232
|
+
ambiente=self.environment,
|
233
|
+
company_id=self.company_id,
|
234
|
+
tipo_documento=tipo_documento,
|
235
|
+
ano=ano,
|
236
|
+
mes=mes,
|
237
|
+
serie=serie,
|
238
|
+
numero=numero,
|
239
|
+
)
|
240
|
+
file_path = os.path.join(save_dir, file_name)
|
241
|
+
try:
|
242
|
+
if not os.path.exists(save_dir):
|
243
|
+
os.makedirs(save_dir)
|
244
|
+
f = open(file_path, "w")
|
245
|
+
except IOError as e:
|
246
|
+
raise UserError(
|
247
|
+
_("Erro!"),
|
248
|
+
_(
|
249
|
+
"""Não foi possível salvar o arquivo
|
250
|
+
em disco, verifique as permissões de escrita
|
251
|
+
e o caminho da pasta"""
|
252
|
+
),
|
253
|
+
) from e
|
254
|
+
else:
|
255
|
+
f.write(arquivo)
|
256
|
+
f.close()
|
257
|
+
return save_dir
|
258
|
+
|
259
|
+
def _compute_file_name(self):
|
260
|
+
self.ensure_one()
|
261
|
+
if (
|
262
|
+
self.document_id
|
263
|
+
and self.document_id.document_key
|
264
|
+
and self.document_id.document_electronic
|
265
|
+
and self.document_id.document_type_id
|
266
|
+
and self.document_id.document_type_id.prefix
|
267
|
+
):
|
268
|
+
file_name = (
|
269
|
+
self.document_id.document_type_id.prefix + self.document_id.document_key
|
270
|
+
)
|
271
|
+
else:
|
272
|
+
file_name = self.document_number
|
273
|
+
return file_name
|
274
|
+
|
275
|
+
def _save_event_file(
|
276
|
+
self, file, file_extension, authorization=False, rejected=False
|
277
|
+
):
|
278
|
+
self.ensure_one()
|
279
|
+
file_name = self._compute_file_name()
|
280
|
+
|
281
|
+
if authorization:
|
282
|
+
file_name += "-proc"
|
283
|
+
if rejected:
|
284
|
+
file_name += "-rej"
|
285
|
+
|
286
|
+
if self.type:
|
287
|
+
file_name += "-" + FILE_SUFIX_EVENT[self.type]
|
288
|
+
|
289
|
+
if self.sequence:
|
290
|
+
file_name += "-" + str(self.sequence)
|
291
|
+
if file_extension:
|
292
|
+
file_name += "." + file_extension
|
293
|
+
|
294
|
+
if self.company_id.document_save_disk:
|
295
|
+
file_path = self._save_event_2disk(file, file_name)
|
296
|
+
self.file_path = file_path
|
297
|
+
|
298
|
+
attachment_id = self.env["ir.attachment"].create(
|
299
|
+
{
|
300
|
+
"name": file_name,
|
301
|
+
"res_model": self._name,
|
302
|
+
"res_id": self.id,
|
303
|
+
"datas": base64.b64encode(file.encode("utf-8")),
|
304
|
+
"mimetype": "application/" + file_extension,
|
305
|
+
"type": "binary",
|
306
|
+
}
|
307
|
+
)
|
308
|
+
|
309
|
+
if authorization:
|
310
|
+
# Não deletamos um aquivo de autorização já
|
311
|
+
# Existente por segurança
|
312
|
+
self.file_response_id = False
|
313
|
+
self.file_response_id = attachment_id
|
314
|
+
else:
|
315
|
+
self.file_request_id.unlink()
|
316
|
+
self.file_request_id = attachment_id
|
317
|
+
return attachment_id
|
318
|
+
|
319
|
+
def set_done(
|
320
|
+
self, status_code, response, protocol_date, protocol_number, file_response_xml
|
321
|
+
):
|
322
|
+
if file_response_xml:
|
323
|
+
self._save_event_file(file_response_xml, "xml", authorization=True)
|
324
|
+
self.write(
|
325
|
+
{
|
326
|
+
"state": "done",
|
327
|
+
"status_code": status_code,
|
328
|
+
"response": response,
|
329
|
+
"protocol_date": protocol_date,
|
330
|
+
"protocol_number": protocol_number,
|
331
|
+
}
|
332
|
+
)
|
333
|
+
|
334
|
+
def create_event_save_xml(
|
335
|
+
self,
|
336
|
+
company_id,
|
337
|
+
environment,
|
338
|
+
event_type,
|
339
|
+
xml_file,
|
340
|
+
document_id=False,
|
341
|
+
invalidate_number_id=False,
|
342
|
+
sequence=False,
|
343
|
+
justification=False,
|
344
|
+
):
|
345
|
+
vals = {
|
346
|
+
"company_id": company_id.id,
|
347
|
+
"environment": environment,
|
348
|
+
"type": event_type,
|
349
|
+
}
|
350
|
+
if sequence:
|
351
|
+
vals["sequence"] = sequence
|
352
|
+
if document_id:
|
353
|
+
#
|
354
|
+
# Aplicado para envio, cancelamento, carta de correcao
|
355
|
+
# e outras operações em que o documento esta presente.
|
356
|
+
#
|
357
|
+
vals["document_id"] = document_id.id
|
358
|
+
vals["document_type_id"] = document_id.document_type_id.id
|
359
|
+
vals["document_serie_id"] = document_id.document_serie_id.id
|
360
|
+
|
361
|
+
if document_id.rps_number:
|
362
|
+
vals["document_number"] = document_id.rps_number
|
363
|
+
if document_id.document_number:
|
364
|
+
vals["document_number"] += "-" + document_id.document_number
|
365
|
+
else:
|
366
|
+
vals["document_number"] = document_id.document_number
|
367
|
+
|
368
|
+
if invalidate_number_id:
|
369
|
+
#
|
370
|
+
# Aplicado para inutilização
|
371
|
+
#
|
372
|
+
vals["invalidate_number_id"] = invalidate_number_id.id
|
373
|
+
vals["document_type_id"] = invalidate_number_id.document_type_id.id
|
374
|
+
vals["document_serie_id"] = invalidate_number_id.document_serie_id.id
|
375
|
+
if invalidate_number_id.number_end != invalidate_number_id.number_start:
|
376
|
+
vals["document_number"] = (
|
377
|
+
str(invalidate_number_id.number_start)
|
378
|
+
+ "-"
|
379
|
+
+ str(invalidate_number_id.number_end)
|
380
|
+
)
|
381
|
+
else:
|
382
|
+
vals["document_number"] = invalidate_number_id.number_start
|
383
|
+
if justification:
|
384
|
+
vals["justification"] = justification
|
385
|
+
event_id = self.create(vals)
|
386
|
+
event_id._save_event_file(xml_file, "xml")
|
387
|
+
return event_id
|
388
|
+
|
389
|
+
def print_document_event(self):
|
390
|
+
return self.env.ref(
|
391
|
+
"l10n_br_fiscal.action_report_document_event"
|
392
|
+
).report_action(self)
|