odoo-addon-l10n-it-edi-extension 18.0.1.0.0.30__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_it_edi_extension/README.rst +493 -0
- odoo/addons/l10n_it_edi_extension/__init__.py +951 -0
- odoo/addons/l10n_it_edi_extension/__manifest__.py +37 -0
- odoo/addons/l10n_it_edi_extension/controllers/__init__.py +1 -0
- odoo/addons/l10n_it_edi_extension/controllers/portal.py +27 -0
- odoo/addons/l10n_it_edi_extension/data/FoglioStileAssoSoftware.xsl +3150 -0
- odoo/addons/l10n_it_edi_extension/data/invoice_it_template.xml +50 -0
- odoo/addons/l10n_it_edi_extension/data/res.city.it.code.csv +13898 -0
- odoo/addons/l10n_it_edi_extension/i18n/l10n_it_edi_extension.pot +1167 -0
- odoo/addons/l10n_it_edi_extension/i18n/l10n_it_edi_fatturapa.pot +44 -0
- odoo/addons/l10n_it_edi_extension/models/__init__.py +15 -0
- odoo/addons/l10n_it_edi_extension/models/account_journal.py +152 -0
- odoo/addons/l10n_it_edi_extension/models/account_move.py +765 -0
- odoo/addons/l10n_it_edi_extension/models/account_move_line.py +10 -0
- odoo/addons/l10n_it_edi_extension/models/ir_attachment.py +37 -0
- odoo/addons/l10n_it_edi_extension/models/l10n_it_edi_activity_progress.py +14 -0
- odoo/addons/l10n_it_edi_extension/models/l10n_it_edi_article_code.py +15 -0
- odoo/addons/l10n_it_edi_extension/models/l10n_it_edi_discount_rise_price.py +25 -0
- odoo/addons/l10n_it_edi_extension/models/l10n_it_edi_line.py +48 -0
- odoo/addons/l10n_it_edi_extension/models/l10n_it_edi_line_other_data.py +17 -0
- odoo/addons/l10n_it_edi_extension/models/l10n_it_edi_summary_data.py +77 -0
- odoo/addons/l10n_it_edi_extension/models/res_city_it_code.py +83 -0
- odoo/addons/l10n_it_edi_extension/models/res_company.py +62 -0
- odoo/addons/l10n_it_edi_extension/models/res_partner.py +64 -0
- odoo/addons/l10n_it_edi_extension/readme/CONFIGURE.md +45 -0
- odoo/addons/l10n_it_edi_extension/readme/CONTRIBUTORS.md +5 -0
- odoo/addons/l10n_it_edi_extension/readme/DESCRIPTION.md +160 -0
- odoo/addons/l10n_it_edi_extension/security/ir.model.access.csv +14 -0
- odoo/addons/l10n_it_edi_extension/static/description/icon.png +0 -0
- odoo/addons/l10n_it_edi_extension/static/description/index.html +832 -0
- odoo/addons/l10n_it_edi_extension/tests/__init__.py +2 -0
- odoo/addons/l10n_it_edi_extension/tests/import_xmls/IT01234567890_FPR03.xml +166 -0
- odoo/addons/l10n_it_edi_extension/tests/import_xmls/IT02780790107_11004.xml +216 -0
- odoo/addons/l10n_it_edi_extension/tests/import_xmls/IT02780790107_11005.xml +224 -0
- odoo/addons/l10n_it_edi_extension/tests/import_xmls/IT05979361218_003.xml +107 -0
- odoo/addons/l10n_it_edi_extension/tests/import_xmls/test.png +0 -0
- odoo/addons/l10n_it_edi_extension/tests/import_xmls/xml_import.zip +0 -0
- odoo/addons/l10n_it_edi_extension/tests/test_fiscalcode.py +126 -0
- odoo/addons/l10n_it_edi_extension/tests/test_import_edi_extension_xml.py +350 -0
- odoo/addons/l10n_it_edi_extension/views/company_view.xml +41 -0
- odoo/addons/l10n_it_edi_extension/views/l10n_it_view.xml +164 -0
- odoo/addons/l10n_it_edi_extension/views/res_partner_view.xml +19 -0
- odoo/addons/l10n_it_edi_extension/wizards/__init__.py +2 -0
- odoo/addons/l10n_it_edi_extension/wizards/compute_fc.py +176 -0
- odoo/addons/l10n_it_edi_extension/wizards/compute_fc_view.xml +65 -0
- odoo/addons/l10n_it_edi_extension/wizards/l10n_it_edi_import_file_wizard.py +98 -0
- odoo/addons/l10n_it_edi_extension/wizards/l10n_it_edi_import_file_wizard.xml +46 -0
- odoo_addon_l10n_it_edi_extension-18.0.1.0.0.30.dist-info/METADATA +513 -0
- odoo_addon_l10n_it_edi_extension-18.0.1.0.0.30.dist-info/RECORD +51 -0
- odoo_addon_l10n_it_edi_extension-18.0.1.0.0.30.dist-info/WHEEL +5 -0
- odoo_addon_l10n_it_edi_extension-18.0.1.0.0.30.dist-info/top_level.txt +1 -0
@@ -0,0 +1,44 @@
|
|
1
|
+
# Translation of Odoo Server.
|
2
|
+
# This file contains the translation of the following modules:
|
3
|
+
# * l10n_it_edi_fatturapa
|
4
|
+
#
|
5
|
+
msgid ""
|
6
|
+
msgstr ""
|
7
|
+
"Project-Id-Version: Odoo Server 18.0\n"
|
8
|
+
"Report-Msgid-Bugs-To: \n"
|
9
|
+
"POT-Creation-Date: 2024-04-26 09:19+0000\n"
|
10
|
+
"PO-Revision-Date: 2024-04-26 09:19+0000\n"
|
11
|
+
"Last-Translator: \n"
|
12
|
+
"Language-Team: \n"
|
13
|
+
"MIME-Version: 1.0\n"
|
14
|
+
"Content-Type: text/plain; charset=UTF-8\n"
|
15
|
+
"Content-Transfer-Encoding: \n"
|
16
|
+
"Plural-Forms: \n"
|
17
|
+
|
18
|
+
#. module: l10n_it_edi_fatturapa
|
19
|
+
#: model:ir.model,name:l10n_it_edi_fatturapa.model_ir_attachment
|
20
|
+
msgid "Attachment"
|
21
|
+
msgstr ""
|
22
|
+
|
23
|
+
#. module: l10n_it_edi_fatturapa
|
24
|
+
#. odoo-python
|
25
|
+
#: code:addons/l10n_it_edi_fatturapa/models/ir_attachment.py:0
|
26
|
+
msgid "Invalid xml %s."
|
27
|
+
msgstr ""
|
28
|
+
|
29
|
+
#. module: l10n_it_edi_fatturapa
|
30
|
+
#: model:ir.model,name:l10n_it_edi_fatturapa.model_account_move
|
31
|
+
msgid "Journal Entry"
|
32
|
+
msgstr ""
|
33
|
+
|
34
|
+
#. module: l10n_it_edi_fatturapa
|
35
|
+
#: model_terms:ir.ui.view,arch_db:l10n_it_edi_fatturapa.account_invoice_form_l10n_it_inherit_view
|
36
|
+
msgid "Preview FPA"
|
37
|
+
msgstr ""
|
38
|
+
|
39
|
+
#. module: l10n_it_edi_fatturapa
|
40
|
+
#: model:ir.model.fields,field_description:l10n_it_edi_fatturapa.field_account_bank_statement_line__l10n_it_edi_attachment_preview_link
|
41
|
+
#: model:ir.model.fields,field_description:l10n_it_edi_fatturapa.field_account_move__l10n_it_edi_attachment_preview_link
|
42
|
+
#: model:ir.model.fields,field_description:l10n_it_edi_fatturapa.field_account_payment__l10n_it_edi_attachment_preview_link
|
43
|
+
msgid "Preview link"
|
44
|
+
msgstr ""
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
2
|
+
|
3
|
+
from . import res_partner
|
4
|
+
from . import res_company
|
5
|
+
from . import res_city_it_code
|
6
|
+
from . import l10n_it_edi_article_code
|
7
|
+
from . import l10n_it_edi_discount_rise_price
|
8
|
+
from . import l10n_it_edi_line_other_data
|
9
|
+
from . import l10n_it_edi_activity_progress
|
10
|
+
from . import l10n_it_edi_summary_data
|
11
|
+
from . import l10n_it_edi_line
|
12
|
+
from . import account_move_line
|
13
|
+
from . import account_move
|
14
|
+
from . import ir_attachment
|
15
|
+
from . import account_journal
|
@@ -0,0 +1,152 @@
|
|
1
|
+
# Copyright 2025 Simone Rubino
|
2
|
+
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
|
3
|
+
|
4
|
+
import logging
|
5
|
+
|
6
|
+
from lxml import etree
|
7
|
+
|
8
|
+
from odoo import api, models
|
9
|
+
|
10
|
+
from odoo.addons.l10n_it_edi.tools.remove_signature import remove_signature
|
11
|
+
|
12
|
+
_logger = logging.getLogger(__name__)
|
13
|
+
|
14
|
+
|
15
|
+
class AccountJournal(models.Model):
|
16
|
+
_inherit = "account.journal"
|
17
|
+
|
18
|
+
@api.model
|
19
|
+
def _l10n_it_edi_extension_e_invoice_parser(self):
|
20
|
+
"""Parser used to parse an e-invoice attachment."""
|
21
|
+
# Expose the parser used by `l10n_it_edi`.
|
22
|
+
return etree.XMLParser(
|
23
|
+
recover=True,
|
24
|
+
resolve_entities=False,
|
25
|
+
)
|
26
|
+
|
27
|
+
@api.model
|
28
|
+
def _l10n_it_edi_extension_parse_e_invoice_content(self, content):
|
29
|
+
"""Parse the `content` of an e-invoice to a XML tree.
|
30
|
+
|
31
|
+
Return None if the parsing fails.
|
32
|
+
"""
|
33
|
+
parser = self._l10n_it_edi_extension_e_invoice_parser()
|
34
|
+
try:
|
35
|
+
parsed_xml = etree.fromstring(content, parser)
|
36
|
+
except (etree.ParseError, ValueError):
|
37
|
+
parsed_xml = None
|
38
|
+
return parsed_xml
|
39
|
+
|
40
|
+
@api.model
|
41
|
+
def _l10n_it_edi_extension_parse_e_invoice(self, attachment):
|
42
|
+
"""Parse the e-invoice `attachment` to a XML tree, decoding it if needed."""
|
43
|
+
parse_content = self._l10n_it_edi_extension_parse_e_invoice_content
|
44
|
+
if (xml_tree := parse_content(attachment.raw)) is None:
|
45
|
+
xml_tree = parse_content(remove_signature(attachment.raw))
|
46
|
+
return xml_tree
|
47
|
+
|
48
|
+
@api.model
|
49
|
+
def _l10n_it_edi_extension_split_content(self, attachment):
|
50
|
+
"""
|
51
|
+
Break down the content of `attachment`
|
52
|
+
if contains multiple FatturaElettronicaBody.
|
53
|
+
|
54
|
+
If `attachment` is an e-invoice that contains N FatturaElettronicaBody:
|
55
|
+
|
56
|
+
<FatturaElettronica>
|
57
|
+
<FatturaElettronicaHeader/>
|
58
|
+
<FatturaElettronicaBody>
|
59
|
+
// Content of 1st invoice
|
60
|
+
</FatturaElettronicaBody>
|
61
|
+
// ...
|
62
|
+
<FatturaElettronicaBody>
|
63
|
+
// Content of N-th invoice
|
64
|
+
</FatturaElettronicaBody>
|
65
|
+
</FatturaElettronica>
|
66
|
+
|
67
|
+
return a list of N strings (bytes) with the same FatturaElettronicaHeader:
|
68
|
+
|
69
|
+
<FatturaElettronica>
|
70
|
+
<FatturaElettronicaHeader/>
|
71
|
+
<FatturaElettronicaBody>
|
72
|
+
// Content of N-th invoice
|
73
|
+
</FatturaElettronicaBody>
|
74
|
+
</FatturaElettronica>
|
75
|
+
"""
|
76
|
+
attachment.ensure_one()
|
77
|
+
|
78
|
+
if (
|
79
|
+
xml_tree := self._l10n_it_edi_extension_parse_e_invoice(attachment)
|
80
|
+
) is not None:
|
81
|
+
header = xml_tree.xpath("//FatturaElettronicaHeader")[0]
|
82
|
+
bodies = xml_tree.xpath("//FatturaElettronicaBody")
|
83
|
+
result = []
|
84
|
+
for body in bodies:
|
85
|
+
e_invoice_root = etree.Element("FatturaElettronica")
|
86
|
+
e_invoice_root.insert(0, header)
|
87
|
+
e_invoice_root.insert(1, body)
|
88
|
+
result.append(etree.tostring(e_invoice_root))
|
89
|
+
else:
|
90
|
+
result = [attachment.raw]
|
91
|
+
return result
|
92
|
+
|
93
|
+
def _l10n_it_edi_extension_split_attachments(self, attachment_ids):
|
94
|
+
"""
|
95
|
+
Split the attachments that contain multiple invoices
|
96
|
+
in multiple attachments containing one invoice each.
|
97
|
+
|
98
|
+
Do not touch the attachments that do not need splitting.
|
99
|
+
|
100
|
+
Return the IDs of the splitted attachments and of the unaffected ones.
|
101
|
+
"""
|
102
|
+
attachment_model = self.env["ir.attachment"]
|
103
|
+
attachments = attachment_model.browse(attachment_ids)
|
104
|
+
l10n_it_edi_format = next(
|
105
|
+
filter(
|
106
|
+
lambda fmt: fmt["format"] == "l10n_it_edi",
|
107
|
+
attachment_model._get_edi_supported_formats(),
|
108
|
+
)
|
109
|
+
)
|
110
|
+
l10n_it_edi_check, l10n_it_edi_decoder = (
|
111
|
+
l10n_it_edi_format["check"],
|
112
|
+
l10n_it_edi_format["decoder"],
|
113
|
+
)
|
114
|
+
|
115
|
+
e_invoice_attachments = attachment_model.browse()
|
116
|
+
splitted_attachments_values = dict()
|
117
|
+
other_attachments = attachment_model.browse()
|
118
|
+
for attachment in attachments:
|
119
|
+
if l10n_it_edi_check(attachment):
|
120
|
+
parsed_xml_bodies = l10n_it_edi_decoder(attachment.name, attachment.raw)
|
121
|
+
if len(parsed_xml_bodies) >= 2:
|
122
|
+
# In this e-invoice there are multiple invoices,
|
123
|
+
# extract the content of the splitted e-invoice
|
124
|
+
# containing only one FatturaElettronicaBody each
|
125
|
+
splitted_attachments_values[attachment] = {
|
126
|
+
"original_attachment": attachment,
|
127
|
+
"contents": self._l10n_it_edi_extension_split_content(
|
128
|
+
attachment
|
129
|
+
),
|
130
|
+
}
|
131
|
+
else:
|
132
|
+
e_invoice_attachments |= attachment
|
133
|
+
else:
|
134
|
+
other_attachments |= attachment
|
135
|
+
|
136
|
+
if splitted_attachments_values:
|
137
|
+
e_invoice_attachments |= attachment_model.create(
|
138
|
+
[
|
139
|
+
{
|
140
|
+
"name": f"Partial {attachment.name}",
|
141
|
+
"raw": content,
|
142
|
+
}
|
143
|
+
for attachment, att_data in splitted_attachments_values.items()
|
144
|
+
for content in att_data["contents"]
|
145
|
+
]
|
146
|
+
)
|
147
|
+
|
148
|
+
return (e_invoice_attachments | other_attachments).ids
|
149
|
+
|
150
|
+
def _create_document_from_attachment(self, attachment_ids):
|
151
|
+
attachment_ids = self._l10n_it_edi_extension_split_attachments(attachment_ids)
|
152
|
+
return super()._create_document_from_attachment(attachment_ids)
|