odoo-addon-l10n-es-verifactu-oca 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.

Potentially problematic release.


This version of odoo-addon-l10n-es-verifactu-oca might be problematic. Click here for more details.

Files changed (74) hide show
  1. odoo/addons/l10n_es_verifactu_oca/README.rst +154 -0
  2. odoo/addons/l10n_es_verifactu_oca/__init__.py +3 -0
  3. odoo/addons/l10n_es_verifactu_oca/__manifest__.py +48 -0
  4. odoo/addons/l10n_es_verifactu_oca/data/account_fiscal_position_template_data.xml +129 -0
  5. odoo/addons/l10n_es_verifactu_oca/data/ir_config_parameter.xml +9 -0
  6. odoo/addons/l10n_es_verifactu_oca/data/ir_cron.xml +14 -0
  7. odoo/addons/l10n_es_verifactu_oca/data/mail_activity_data.xml +11 -0
  8. odoo/addons/l10n_es_verifactu_oca/data/verifactu_map_data.xml +120 -0
  9. odoo/addons/l10n_es_verifactu_oca/data/verifactu_registration_key_data.xml +207 -0
  10. odoo/addons/l10n_es_verifactu_oca/data/verifactu_tax_agency_data.xml +19 -0
  11. odoo/addons/l10n_es_verifactu_oca/hooks.py +43 -0
  12. odoo/addons/l10n_es_verifactu_oca/i18n/ca.po +1630 -0
  13. odoo/addons/l10n_es_verifactu_oca/i18n/ca_ES.po +1599 -0
  14. odoo/addons/l10n_es_verifactu_oca/i18n/es.po +1640 -0
  15. odoo/addons/l10n_es_verifactu_oca/i18n/l10n_es_verifactu_oca.pot +1673 -0
  16. odoo/addons/l10n_es_verifactu_oca/models/__init__.py +16 -0
  17. odoo/addons/l10n_es_verifactu_oca/models/account_fiscal_position.py +40 -0
  18. odoo/addons/l10n_es_verifactu_oca/models/account_fiscal_position_template.py +18 -0
  19. odoo/addons/l10n_es_verifactu_oca/models/account_journal.py +64 -0
  20. odoo/addons/l10n_es_verifactu_oca/models/account_move.py +556 -0
  21. odoo/addons/l10n_es_verifactu_oca/models/aeat_mixin.py +163 -0
  22. odoo/addons/l10n_es_verifactu_oca/models/aeat_tax_agency.py +30 -0
  23. odoo/addons/l10n_es_verifactu_oca/models/res_company.py +48 -0
  24. odoo/addons/l10n_es_verifactu_oca/models/res_partner.py +33 -0
  25. odoo/addons/l10n_es_verifactu_oca/models/verifactu_chaining.py +30 -0
  26. odoo/addons/l10n_es_verifactu_oca/models/verifactu_developer.py +16 -0
  27. odoo/addons/l10n_es_verifactu_oca/models/verifactu_invoice_entry.py +401 -0
  28. odoo/addons/l10n_es_verifactu_oca/models/verifactu_invoice_entry_response.py +121 -0
  29. odoo/addons/l10n_es_verifactu_oca/models/verifactu_invoice_entry_response_line.py +35 -0
  30. odoo/addons/l10n_es_verifactu_oca/models/verifactu_map.py +66 -0
  31. odoo/addons/l10n_es_verifactu_oca/models/verifactu_mixin.py +449 -0
  32. odoo/addons/l10n_es_verifactu_oca/models/verifactu_registration_key.py +24 -0
  33. odoo/addons/l10n_es_verifactu_oca/readme/CONFIGURE.rst +18 -0
  34. odoo/addons/l10n_es_verifactu_oca/readme/CONTRIBUTORS.rst +19 -0
  35. odoo/addons/l10n_es_verifactu_oca/readme/DESCRIPTION.rst +1 -0
  36. odoo/addons/l10n_es_verifactu_oca/readme/INSTALL.rst +4 -0
  37. odoo/addons/l10n_es_verifactu_oca/readme/ROADMAP.rst +15 -0
  38. odoo/addons/l10n_es_verifactu_oca/readme/USAGE.rst +1 -0
  39. odoo/addons/l10n_es_verifactu_oca/security/ir.model.access.csv +22 -0
  40. odoo/addons/l10n_es_verifactu_oca/security/verifactu_security.xml +6 -0
  41. odoo/addons/l10n_es_verifactu_oca/static/description/icon.png +0 -0
  42. odoo/addons/l10n_es_verifactu_oca/static/description/index.html +508 -0
  43. odoo/addons/l10n_es_verifactu_oca/tests/__init__.py +5 -0
  44. odoo/addons/l10n_es_verifactu_oca/tests/common.py +304 -0
  45. odoo/addons/l10n_es_verifactu_oca/tests/json/verifactu_mocked_response_1.json +35 -0
  46. odoo/addons/l10n_es_verifactu_oca/tests/json/verifactu_mocked_response_2.json +35 -0
  47. odoo/addons/l10n_es_verifactu_oca/tests/json/verifactu_out_invoice_s_iva10b_s_iva21s_dict.json +59 -0
  48. odoo/addons/l10n_es_verifactu_oca/tests/json/verifactu_out_invoice_s_iva21s_s_req52_dict.json +58 -0
  49. odoo/addons/l10n_es_verifactu_oca/tests/json/verifactu_out_refund_s_iva10b_s_iva10b_s_iva21s_dict.json +66 -0
  50. odoo/addons/l10n_es_verifactu_oca/tests/test_10n_es_verifactu.py +451 -0
  51. odoo/addons/l10n_es_verifactu_oca/tests/test_account_journal.py +78 -0
  52. odoo/addons/l10n_es_verifactu_oca/tests/test_account_move_reversal.py +93 -0
  53. odoo/addons/l10n_es_verifactu_oca/tests/test_res_partner.py +48 -0
  54. odoo/addons/l10n_es_verifactu_oca/tests/test_verifactu_invoice.py +350 -0
  55. odoo/addons/l10n_es_verifactu_oca/views/account_fiscal_position_view.xml +30 -0
  56. odoo/addons/l10n_es_verifactu_oca/views/account_journal_view.xml +28 -0
  57. odoo/addons/l10n_es_verifactu_oca/views/account_move_view.xml +219 -0
  58. odoo/addons/l10n_es_verifactu_oca/views/aeat_tax_agency_view.xml +31 -0
  59. odoo/addons/l10n_es_verifactu_oca/views/report_invoice.xml +55 -0
  60. odoo/addons/l10n_es_verifactu_oca/views/res_company_view.xml +50 -0
  61. odoo/addons/l10n_es_verifactu_oca/views/res_partner_view.xml +27 -0
  62. odoo/addons/l10n_es_verifactu_oca/views/verifactu_chaining_view.xml +47 -0
  63. odoo/addons/l10n_es_verifactu_oca/views/verifactu_developer_view.xml +48 -0
  64. odoo/addons/l10n_es_verifactu_oca/views/verifactu_invoice_entry_response_view.xml +149 -0
  65. odoo/addons/l10n_es_verifactu_oca/views/verifactu_invoice_entry_view.xml +124 -0
  66. odoo/addons/l10n_es_verifactu_oca/views/verifactu_map_lines_view.xml +20 -0
  67. odoo/addons/l10n_es_verifactu_oca/views/verifactu_map_view.xml +53 -0
  68. odoo/addons/l10n_es_verifactu_oca/views/verifactu_registration_keys_view.xml +42 -0
  69. odoo/addons/l10n_es_verifactu_oca/wizards/__init__.py +1 -0
  70. odoo/addons/l10n_es_verifactu_oca/wizards/account_move_reversal.py +16 -0
  71. odoo_addon_l10n_es_verifactu_oca-15.0.1.0.0.2.dist-info/METADATA +171 -0
  72. odoo_addon_l10n_es_verifactu_oca-15.0.1.0.0.2.dist-info/RECORD +74 -0
  73. odoo_addon_l10n_es_verifactu_oca-15.0.1.0.0.2.dist-info/WHEEL +5 -0
  74. odoo_addon_l10n_es_verifactu_oca-15.0.1.0.0.2.dist-info/top_level.txt +1 -0
@@ -0,0 +1,163 @@
1
+ # Copyright 2021 Tecnativa - João Marques
2
+ # Copyright 2022 ForgeFlow - Lois Rilo
3
+ # Copyright 2011-2023 Tecnativa - Pedro M. Baeza
4
+ # Copyright 2023 Aures Tic - Almudena de la Puente <almudena@aurestic.es>
5
+ # Copyright 2023-2024 Aures Tic - Jose Zambudio <jose@aurestic.es>
6
+ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
7
+ import logging
8
+
9
+ from requests import Session
10
+
11
+ from odoo import _, api, fields, models
12
+ from odoo.exceptions import UserError
13
+
14
+ _logger = logging.getLogger(__name__)
15
+
16
+ try:
17
+ from zeep import Client
18
+ from zeep.plugins import HistoryPlugin
19
+ from zeep.transports import Transport
20
+ except (ImportError, IOError) as err:
21
+ _logger.debug(err)
22
+
23
+ AEAT_DATE_FORMAT = "%d-%m-%Y"
24
+ AEAT_STATES = [
25
+ ("not_sent", "Not sent"),
26
+ ("sent", "Sent"),
27
+ ("sent_w_errors", "Accepted with errors"),
28
+ ]
29
+
30
+
31
+ def round_by_keys(elem, search_keys, prec=2):
32
+ """This uses ``round`` method directly as if has been tested that Odoo's
33
+ ``float_round`` still returns incorrect amounts for certain values. Try
34
+ 3 units x 3,77 €/unit with 10% tax and you will be hit by the error
35
+ (on regular x86 architectures)."""
36
+ if isinstance(elem, dict):
37
+ for key, value in elem.items():
38
+ if key in search_keys:
39
+ elem[key] = round(elem[key], prec)
40
+ else:
41
+ round_by_keys(value, search_keys)
42
+ elif isinstance(elem, list):
43
+ for value in elem:
44
+ round_by_keys(value, search_keys)
45
+
46
+
47
+ class AeatMixin(models.AbstractModel):
48
+ _name = "aeat.mixin"
49
+ _description = "Aeat Mixin"
50
+
51
+ aeat_state = fields.Selection(
52
+ selection=AEAT_STATES,
53
+ string="AEAT send state",
54
+ default="not_sent",
55
+ readonly=True,
56
+ copy=False,
57
+ help="Indicates the state of this document in relation with the "
58
+ "presentation at the AEAT",
59
+ )
60
+ aeat_send_error = fields.Text(
61
+ string="AEAT Send Error",
62
+ readonly=True,
63
+ copy=False,
64
+ )
65
+ aeat_send_failed = fields.Boolean(
66
+ string="SII send failed",
67
+ copy=False,
68
+ help="Indicates that the last attempt to communicate this document to "
69
+ "the SII has failed. See SII return for details",
70
+ )
71
+ aeat_header_sent = fields.Text(
72
+ string="AEAT last header sent",
73
+ copy=False,
74
+ readonly=True,
75
+ )
76
+ aeat_content_sent = fields.Text(
77
+ string="AEAT last content sent",
78
+ copy=False,
79
+ readonly=True,
80
+ )
81
+
82
+ def _get_document_date(self):
83
+ raise NotImplementedError()
84
+
85
+ def _get_document_serial_number(self):
86
+ raise NotImplementedError()
87
+
88
+ def _aeat_get_partner(self):
89
+ raise NotImplementedError()
90
+
91
+ def _get_document_fiscal_date(self):
92
+ raise NotImplementedError()
93
+
94
+ def _get_document_fiscal_year(self):
95
+ return fields.Date.to_date(self._get_document_fiscal_date()).year
96
+
97
+ def _change_date_format(self, date):
98
+ datetimeobject = fields.Date.to_date(date)
99
+ new_date = datetimeobject.strftime(AEAT_DATE_FORMAT)
100
+ return new_date
101
+
102
+ def _get_document_period(self):
103
+ return "%02d" % fields.Date.to_date(self._get_document_fiscal_date()).month
104
+
105
+ def _is_aeat_simplified_invoice(self):
106
+ """Inheritable method to allow control when an
107
+ invoice are simplified or normal"""
108
+ return self._aeat_get_partner().aeat_simplified_invoice
109
+
110
+ def _get_document_amount_total(self):
111
+ raise NotImplementedError()
112
+
113
+ def _get_mapping_key(self):
114
+ raise NotImplementedError()
115
+
116
+ def _get_aeat_invoice_dict(self):
117
+ raise NotImplementedError()
118
+
119
+ @api.model
120
+ def _get_aeat_taxes_map(self, codes, date):
121
+ raise NotImplementedError()
122
+
123
+ def _get_valid_document_states(self):
124
+ raise NotImplementedError()
125
+
126
+ def _get_aeat_header(self, tipo_comunicacion=False, cancellation=False):
127
+ raise NotImplementedError()
128
+
129
+ def _bind_service(self, client, port_name, address=None):
130
+ raise NotImplementedError()
131
+
132
+ def _connect_params_aeat(self, mapping_key):
133
+ raise NotImplementedError()
134
+
135
+ def _connect_aeat(self, mapping_key):
136
+ self.ensure_one()
137
+ public_crt, private_key = self.env["l10n.es.aeat.certificate"].get_certificates(
138
+ company=self.company_id
139
+ )
140
+ params = self._connect_params_aeat(mapping_key)
141
+ session = Session()
142
+ session.cert = (public_crt, private_key)
143
+ transport = Transport(session=session)
144
+ history = HistoryPlugin()
145
+ client = Client(wsdl=params["wsdl"], transport=transport, plugins=[history])
146
+ return self._bind_service(client, params["port_name"], params["address"])
147
+
148
+ def _get_aeat_country_code(self):
149
+ self.ensure_one()
150
+ return self._aeat_get_partner()._parse_aeat_vat_info()[0]
151
+
152
+ def _aeat_check_exceptions(self):
153
+ """Inheritable method for exceptions control when sending AEAT documentss."""
154
+ self.ensure_one()
155
+ partner = self._aeat_get_partner()
156
+ country_code = self._get_aeat_country_code()
157
+ is_simplified_invoice = self._is_aeat_simplified_invoice()
158
+ if country_code == "ES" and not partner.vat and not is_simplified_invoice:
159
+ raise UserError(_("The partner has not a VAT configured."))
160
+ if not self.company_id.chart_template_id:
161
+ raise UserError(
162
+ _("You have to select what account chart template use this" " company.")
163
+ )
@@ -0,0 +1,30 @@
1
+ # Copyright 2024 Aures Tic - Jose Zambudio <jose@aurestic.es>
2
+ # Copyright 2024 Aures TIC - Almudena de La Puente <almudena@aurestic.es>
3
+ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
4
+
5
+ from odoo import fields, models
6
+
7
+
8
+ class AeatTaxAgency(models.Model):
9
+ _inherit = "aeat.tax.agency"
10
+
11
+ verifactu_wsdl_out = fields.Char(string="VERI*FACTU WSDL")
12
+ verifactu_wsdl_out_test_address = fields.Char(string="VERI*FACTU Test Address")
13
+ verifactu_qr_base_url = fields.Char(string="VERI*FACTU QR Base URL")
14
+ verifactu_qr_base_url_test_address = fields.Char(
15
+ string="VERI*FACTU QR Base URL Test"
16
+ )
17
+
18
+ def _connect_params_verifactu(self, company):
19
+ self.ensure_one()
20
+ wsdl_field = "verifactu_wsdl_out"
21
+ wsdl_test_field = wsdl_field + "_test_address"
22
+ port_name = "SistemaVerifactu"
23
+ address = self[wsdl_test_field] if company.verifactu_test else False
24
+ if not address and company.verifactu_test:
25
+ port_name += "Pruebas"
26
+ return {
27
+ "wsdl": self[wsdl_field],
28
+ "address": address,
29
+ "port_name": port_name,
30
+ }
@@ -0,0 +1,48 @@
1
+ # Copyright 2024 Aures TIC - Jose Zambudio
2
+ # Copyright 2025 Tecnativa - Pedro M. Baeza
3
+ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
4
+
5
+ from odoo import fields, models
6
+
7
+
8
+ class ResCompany(models.Model):
9
+ _inherit = "res.company"
10
+
11
+ verifactu_enabled = fields.Boolean(string="VERI*FACTU enabled", tracking=True)
12
+ verifactu_test = fields.Boolean(
13
+ string="VERI*FACTU test environment?", tracking=True
14
+ )
15
+ verifactu_description = fields.Text(
16
+ string="VERI*FACTU description",
17
+ default="/",
18
+ help="The description for VERI*FACTU invoices if not set",
19
+ tracking=True,
20
+ )
21
+ verifactu_developer_id = fields.Many2one(
22
+ comodel_name="verifactu.developer",
23
+ string="VERI*FACTU developer",
24
+ ondelete="restrict",
25
+ tracking=True,
26
+ )
27
+ verifactu_start_date = fields.Date(
28
+ string="VERI*FACTU start date",
29
+ help="If this field is set, the VERI*FACTU won't be enabled on invoices with "
30
+ "lower invoice date. If not set, it can be enabled on all invoice dates",
31
+ tracking=True,
32
+ )
33
+ verifactu_chaining_id = fields.Many2one(
34
+ comodel_name="verifactu.chaining",
35
+ string="VERI*FACTU chaining",
36
+ ondelete="restrict",
37
+ tracking=True,
38
+ )
39
+
40
+ def write(self, vals):
41
+ # As the compute is not triggered automatically, we need to manually trigger it
42
+ # rewriting the flag at journal level.
43
+ res = super().write(vals)
44
+ if vals.get("verifactu_enabled"):
45
+ self.env["account.journal"].search(
46
+ [("company_id", "in", self.ids), ("type", "=", "sale")]
47
+ ).verifactu_enabled = True
48
+ return res
@@ -0,0 +1,33 @@
1
+ # Copyright 2024 Aures TIC - Jose Zambudio
2
+ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
3
+
4
+ from odoo import api, fields, models
5
+
6
+
7
+ class ResPartner(models.Model):
8
+ _inherit = "res.partner"
9
+
10
+ verifactu_enabled = fields.Boolean(
11
+ compute="_compute_aeat_sending_enabled", string="VERI*FACTU enabled"
12
+ )
13
+ aeat_simplified_invoice = fields.Boolean(
14
+ string="Simplified invoices in AEAT?",
15
+ help="Checking this mark, invoices done to this partner will be "
16
+ "sent to AEAT as simplified invoices.",
17
+ )
18
+ aeat_sending_enabled = fields.Boolean(
19
+ compute="_compute_aeat_sending_enabled",
20
+ )
21
+
22
+ @api.depends("company_id")
23
+ def _compute_aeat_sending_enabled(self):
24
+ verifactu_enabled = any(self.env.companies.mapped("verifactu_enabled"))
25
+ for partner in self:
26
+ partner.aeat_sending_enabled = False
27
+ partner.verifactu_enabled = (
28
+ partner.company_id.verifactu_enabled
29
+ if partner.company_id
30
+ else verifactu_enabled
31
+ )
32
+ if partner.verifactu_enabled:
33
+ partner.aeat_sending_enabled = True
@@ -0,0 +1,30 @@
1
+ # Copyright 2024 Aures TIC - Almudena de La Puente <almudena@aurestic.es>
2
+ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
3
+
4
+ from odoo import fields, models
5
+
6
+
7
+ class VerifactuChaining(models.Model):
8
+ _name = "verifactu.chaining"
9
+ _inherit = "mail.thread"
10
+ _description = "VERI*FACTU chaining"
11
+
12
+ name = fields.Char(required=True, tracking=True)
13
+ last_verifactu_invoice_entry_id = fields.Many2one(
14
+ comodel_name="verifactu.invoice.entry",
15
+ string="Last invoice entry",
16
+ help="Reference to the last VERI*FACTU invoice entry for this company. "
17
+ "Used for atomic chaining.",
18
+ copy=False,
19
+ readonly=True,
20
+ )
21
+ sif_id = fields.Char(string="SIF ID", required=True, tracking=True)
22
+ installation_number = fields.Integer(default=1, required=True, tracking=True)
23
+
24
+ _sql_constraints = [
25
+ (
26
+ "verifactu_chaining_name_uniq",
27
+ "unique(name)",
28
+ "A chaining with the same name already exists!",
29
+ )
30
+ ]
@@ -0,0 +1,16 @@
1
+ # Copyright 2024 Aures TIC - Almudena de La Puente
2
+ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
3
+
4
+ from odoo import fields, models
5
+
6
+
7
+ class VerifactuDeveloper(models.Model):
8
+ _name = "verifactu.developer"
9
+ _description = "VERI*FACTU developer"
10
+ _inherit = "mail.thread"
11
+
12
+ name = fields.Char(string="Developer Name", required=True, tracking=True)
13
+ vat = fields.Char(string="Developer VAT", required=True, tracking=True)
14
+ sif_name = fields.Char("SIF Name", required=True, tracking=True)
15
+ version = fields.Char(default="1.0", required=True, tracking=True)
16
+ responsibility_declaration = fields.Binary(attachment=True, copy=False)