diff --git a/l10n_es_aeat_sii_oca/README.rst b/l10n_es_aeat_sii_oca/README.rst index 529f71f0ae7..36d28f6b763 100644 --- a/l10n_es_aeat_sii_oca/README.rst +++ b/l10n_es_aeat_sii_oca/README.rst @@ -7,7 +7,7 @@ Suministro Inmediato de Información en el IVA !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:72d10dec2690f12511331aae6305750eeadddbc7c8f9a9923d197dfa5af114ba + !! source digest: sha256:dd4688bc2a1c4bd195d8dd4949f98b380e1ba0858c791d7685e37e7a4a60f9d0 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Mature-brightgreen.png @@ -70,29 +70,6 @@ En Linux se pueden usar los siguientes comandos: - Clave privada: "openssl pkcs12 -in Certifcado.p12 -nocerts -out privateKey.pem -nodes" -Además, el módulo queue_job necesita estar configurado de una de estas -formas: - -1. Ajustando variables de entorno: - - ODOO_QUEUE_JOB_CHANNELS=root:4 - - u otro canal de configuración. Por defecto es root:1 - - Si xmlrpc_port no está definido: ODOO_QUEUE_JOB_PORT=8069 - -2. Otra alternativa es usuando un fichero de configuración: - - [options] (...) workers = 4 server_wide_modules = - web,base_sparse_field,queue_job - - (...) [queue_job] channels = root:4 - -3. Por último, arrancando Odoo con - --load=web,base_sparse_field,queue_job y --workers más grande que 1. - -Más información http://odoo-connector.com - Usage ===== @@ -159,6 +136,7 @@ Contributors - `Sygel `__: - Valentin Vinagre + - Manuel Regidor - `Tecnativa `__: diff --git a/l10n_es_aeat_sii_oca/__manifest__.py b/l10n_es_aeat_sii_oca/__manifest__.py index f2a81be3882..d6bd65bcd11 100644 --- a/l10n_es_aeat_sii_oca/__manifest__.py +++ b/l10n_es_aeat_sii_oca/__manifest__.py @@ -14,11 +14,12 @@ # Copyright 2017-2023 Tecnativa - Pedro M. Baeza # Copyright 2023 Aures Tic - Jose Zambudio # Copyright 2023 Pol Reig +# Copyright 2024 Manuel Regidor # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). { "name": "Suministro Inmediato de Información en el IVA", - "version": "16.0.1.7.0", + "version": "17.0.1.0.0", "category": "Accounting & Finance", "website": "https://github.com/OCA/l10n-spain", "author": "Acysos S.L.," @@ -39,12 +40,11 @@ "external_dependencies": {"python": ["zeep", "requests"]}, "depends": [ "account_invoice_refund_link", - "l10n_es", "l10n_es_aeat", - "queue_job", ], "data": [ - "data/aeat_sii_queue_job.xml", + "data/ir_config_parameter_data.xml", + "data/ir_cron.xml", "data/aeat_sii_tax_agency_data.xml", "views/res_company_view.xml", "views/account_move_views.xml", @@ -53,11 +53,12 @@ "views/aeat_sii_mapping_registration_keys_view.xml", "data/aeat_sii_mapping_registration_keys_data.xml", "views/aeat_sii_map_view.xml", + "data/l10n.es.aeat.map.tax.line.tax.csv", "data/aeat_sii_map_data.xml", "security/ir.model.access.csv", "security/aeat_sii.xml", "views/product_view.xml", - "views/queue_job_views.xml", + "views/ir_cron_trigger_views.xml", "views/account_fiscal_position_view.xml", "views/res_partner_views.xml", "views/aeat_tax_agency_view.xml", diff --git a/l10n_es_aeat_sii_oca/data/aeat_sii_map_data.xml b/l10n_es_aeat_sii_oca/data/aeat_sii_map_data.xml index 29b3ab9bc5e..f190c9b08e8 100644 --- a/l10n_es_aeat_sii_oca/data/aeat_sii_map_data.xml +++ b/l10n_es_aeat_sii_oca/data/aeat_sii_map_data.xml @@ -18,13 +18,13 @@ SFESB @@ -33,9 +33,9 @@ SFESISP @@ -44,9 +44,9 @@ SFENS @@ -55,11 +55,11 @@ SFESNS @@ -68,13 +68,13 @@ SFESS @@ -83,10 +83,10 @@ SFESBE @@ -95,9 +95,9 @@ SFESSE @@ -106,43 +106,43 @@ SFRS @@ -151,9 +151,9 @@ SFRSA @@ -162,19 +162,19 @@ SFRISP @@ -183,17 +183,17 @@ SFRBI @@ -202,10 +202,10 @@ SFRNS @@ -214,18 +214,18 @@ RE @@ -234,11 +234,11 @@ SFRND @@ -247,41 +247,41 @@ NotIncludedInTotal @@ -293,24 +293,24 @@ > NotIncludedInTotalNegative @@ -322,9 +322,9 @@ > BaseNotIncludedInTotal diff --git a/l10n_es_aeat_sii_oca/data/aeat_sii_queue_job.xml b/l10n_es_aeat_sii_oca/data/aeat_sii_queue_job.xml deleted file mode 100644 index 9f5498e6415..00000000000 --- a/l10n_es_aeat_sii_oca/data/aeat_sii_queue_job.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - invoice_validate_sii - - - - - confirm_one_document - - - - - cancel_one_invoice - - - diff --git a/l10n_es_aeat_sii_oca/data/ir_config_parameter_data.xml b/l10n_es_aeat_sii_oca/data/ir_config_parameter_data.xml new file mode 100644 index 00000000000..e5757af6993 --- /dev/null +++ b/l10n_es_aeat_sii_oca/data/ir_config_parameter_data.xml @@ -0,0 +1,9 @@ + + + + + l10n_es_aeat_sii_oca.sii_batch + 50 + + diff --git a/l10n_es_aeat_sii_oca/data/ir_cron.xml b/l10n_es_aeat_sii_oca/data/ir_cron.xml new file mode 100644 index 00000000000..d620221f36a --- /dev/null +++ b/l10n_es_aeat_sii_oca/data/ir_cron.xml @@ -0,0 +1,12 @@ + + + + Send Invoices to SII + + code + model._send_to_sii() + 1 + hours + -1 + + diff --git a/l10n_es_aeat_sii_oca/data/l10n.es.aeat.map.tax.line.tax.csv b/l10n_es_aeat_sii_oca/data/l10n.es.aeat.map.tax.line.tax.csv new file mode 100644 index 00000000000..477bca7ea3f --- /dev/null +++ b/l10n_es_aeat_sii_oca/data/l10n.es.aeat.map.tax.line.tax.csv @@ -0,0 +1,115 @@ +id,name +s_iva21b,account_tax_template_s_iva21b +s_iva0b,account_tax_template_s_iva0b +s_iva4b,account_tax_template_s_iva4b +s_iva5b,account_tax_template_s_iva5b +s_iva10b,account_tax_template_s_iva10b +s_iva0_isp,account_tax_template_s_iva0_isp +s_iva_ns_b,account_tax_template_s_iva_ns_b +s_iva_e,account_tax_template_s_iva_e +s_iva0_sp_i,account_tax_template_s_iva0_sp_i +s_iva_ns,account_tax_template_s_iva_ns +s_iva21s,account_tax_template_s_iva21s +s_iva10s,account_tax_template_s_iva10s +s_iva0s,account_tax_template_s_iva0s +s_iva4s,account_tax_template_s_iva4s +s_iva5s,account_tax_template_s_iva5s +s_iva0_ic,account_tax_template_s_iva0_ic +s_iva0_e,account_tax_template_s_iva0_e +s_iva0,account_tax_template_s_iva0 +p_iva21_bc,account_tax_template_p_iva21_bc +p_iva21_sc,account_tax_template_p_iva21_sc +p_iva10_bc,account_tax_template_p_iva10_bc +p_iva10_sc,account_tax_template_p_iva10_sc +p_iva5_bc,account_tax_template_p_iva5_bc +p_iva5_sc,account_tax_template_p_iva5_sc +p_iva4_bc,account_tax_template_p_iva4_bc +p_iva4_sc,account_tax_template_p_iva4_sc +p_iva0_bc,account_tax_template_p_iva0_bc +p_iva0_s_bc,account_tax_template_p_iva0_s_bc +p_iva0_s_sc,account_tax_template_p_iva0_s_sc +p_iva0_ic_bc,account_tax_template_p_iva0_ic_bc +p_iva0_ic_sc,account_tax_template_p_iva0_ic_sc +p_iva0_ibc,account_tax_template_p_iva0_ibc +p_iva4_bi,account_tax_template_p_iva4_bi +p_iva10_bi,account_tax_template_p_iva10_bi +p_iva21_bi,account_tax_template_p_iva21_bi +p_iva4_sp_in,account_tax_template_p_iva4_sp_in +p_iva10_sp_in,account_tax_template_p_iva10_sp_in +p_iva21_sp_in,account_tax_template_p_iva21_sp_in +p_iva4_ic_bc,account_tax_template_p_iva4_ic_bc +p_iva10_ic_bc,account_tax_template_p_iva10_ic_bc +p_iva21_ic_bc,account_tax_template_p_iva21_ic_bc +p_iva5_ic_bc,account_tax_template_p_iva5_ic_bc +p_iva5_ic_sc,account_tax_template_p_iva5_ic_sc +p_iva4_ic_bi,account_tax_template_p_iva4_ic_bi +p_iva10_ic_bi,account_tax_template_p_iva10_ic_bi +p_iva21_ic_bi,account_tax_template_p_iva21_ic_bi +p_iva4_ibc,account_tax_template_p_iva4_ibc +p_iva5_ibc,account_tax_template_p_iva5_ibc +p_iva10_ibc,account_tax_template_p_iva10_ibc +p_iva21_ibc,account_tax_template_p_iva21_ibc +p_iva4_ibi,account_tax_template_p_iva4_ibi +p_iva10_ibi,account_tax_template_p_iva10_ibi +p_iva21_ibi,account_tax_template_p_iva21_ibi +p_iva12_agr,account_tax_template_p_iva12_agr +p_iva21_isp,account_tax_template_p_iva21_isp +p_iva10_isp,account_tax_template_p_iva10_isp +p_iva4_isp,account_tax_template_p_iva4_isp +p_iva21_isp_bi,account_tax_template_p_iva21_isp_bi +p_iva10_isp_bi,account_tax_template_p_iva10_isp_bi +p_iva4_isp_bi,account_tax_template_p_iva4_isp_bi +p_iva21_sp_ex,account_tax_template_p_iva21_sp_ex +p_iva10_sp_ex,account_tax_template_p_iva10_sp_ex +p_iva5_isc,account_tax_template_p_iva5_isc +p_iva4_sp_ex,account_tax_template_p_iva4_sp_ex +p_iva0_isc,account_tax_template_p_iva0_isc +p_iva0_ns,account_tax_template_p_iva0_ns +p_iva0_ns_b,account_tax_template_p_iva0_ns_b +p_req52,account_tax_template_p_req52 +s_req52,account_tax_template_s_req52 +p_req014,account_tax_template_p_req014 +s_req014,account_tax_template_s_req014 +p_req062,account_tax_template_p_req062 +s_req062,account_tax_template_s_req062 +p_req05,account_tax_template_p_req05 +s_req05,account_tax_template_s_req05 +p_req0,account_tax_template_p_req0 +s_req0,account_tax_template_s_req0 +p_iva0_nd,account_tax_template_p_iva0_nd +p_iva10_nd,account_tax_template_p_iva10_nd +p_iva4_nd,account_tax_template_p_iva4_nd +s_irpf1,account_tax_template_s_irpf1 +p_irpf1,account_tax_template_p_irpf1 +s_irpf2,account_tax_template_s_irpf2 +p_irpf2,account_tax_template_p_irpf2 +s_irpf7,account_tax_template_s_irpf7 +p_irpf7,account_tax_template_p_irpf7 +p_irpf7e,account_tax_template_p_irpf7e +s_irpf9,account_tax_template_s_irpf9 +p_irpf9,account_tax_template_p_irpf9 +s_irpf15,account_tax_template_s_irpf15 +p_irpf15,account_tax_template_p_irpf15 +p_irpf15e,account_tax_template_p_irpf15e +s_irpf18,account_tax_template_s_irpf18 +p_irpf18,account_tax_template_p_irpf18 +s_irpf19,account_tax_template_s_irpf19 +s_irpf19a,account_tax_template_s_irpf19a +s_irpf195a,account_tax_template_s_irpf195a +p_irpf19,account_tax_template_p_irpf19 +p_irpf19a,account_tax_template_p_irpf19a +p_irpf195a,account_tax_template_p_irpf195a +s_irpf20,account_tax_template_s_irpf20 +s_irpf20a,account_tax_template_s_irpf20a +p_irpf20,account_tax_template_p_irpf20 +p_irpf20a,account_tax_template_p_irpf20a +s_irpf21,account_tax_template_s_irpf21 +s_irpf21a,account_tax_template_s_irpf21a +p_irpf21a,account_tax_template_p_irpf21a +p_irpf21p,account_tax_template_p_irpf21p +p_irpf21t,account_tax_template_p_irpf21t +p_irpf21td,account_tax_template_p_irpf21td +p_irpf21te,account_tax_template_p_irpf21te +s_irpf24,account_tax_template_s_irpf24 +p_irpf24,account_tax_template_p_irpf24 +s_iva0_ns,account_tax_template_s_iva0_ns diff --git a/l10n_es_aeat_sii_oca/hooks.py b/l10n_es_aeat_sii_oca/hooks.py index cdb44e89268..d9f110e8be1 100644 --- a/l10n_es_aeat_sii_oca/hooks.py +++ b/l10n_es_aeat_sii_oca/hooks.py @@ -2,12 +2,10 @@ # Copyright 2021 Tecnativa - João Marques # License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html -from odoo import SUPERUSER_ID, api - -def add_key_to_existing_invoices(cr, registry): +def add_key_to_existing_invoices(env): """This post-init-hook will update all existing invoices""" - env = api.Environment(cr, SUPERUSER_ID, {}) + # env = api.Environment(cr, SUPERUSER_ID, {}) invoice_obj = env["account.move"] invoices = invoice_obj.search( [ @@ -27,7 +25,7 @@ def add_key_to_existing_invoices(cr, registry): [("code", "=", "01"), ("type", "=", "purchase")], limit=1 ) if purchase_key: - cr.execute( + env.cr.execute( """ UPDATE account_move SET sii_registration_key = %s @@ -35,7 +33,7 @@ def add_key_to_existing_invoices(cr, registry): (purchase_key[0].id,), ) if sale_key: - cr.execute( + env.cr.execute( """ UPDATE account_move SET sii_registration_key = %s diff --git a/l10n_es_aeat_sii_oca/migrations/16.0.1.4.0/post-migration.py b/l10n_es_aeat_sii_oca/migrations/16.0.1.4.0/post-migration.py deleted file mode 100644 index cd4a20aebec..00000000000 --- a/l10n_es_aeat_sii_oca/migrations/16.0.1.4.0/post-migration.py +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright 2023 Factor Libre S.L. -# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). - - -def migrate(cr, version): - cr.execute( - """ - UPDATE - queue_job - SET - method_name = REPLACE(method_name, 'confirm_one_invoice', 'confirm_one_document'), - name = REPLACE(name, 'confirm_one_invoice', 'confirm_one_document'), - func_string = REPLACE(func_string, 'confirm_one_invoice', 'confirm_one_document') - WHERE - method_name = 'confirm_one_invoice' AND - state in ('wait_dependencies', 'pending', 'enqueued') - """ - ) diff --git a/l10n_es_aeat_sii_oca/models/__init__.py b/l10n_es_aeat_sii_oca/models/__init__.py index 3cf6d177d86..de3a1e7f42e 100644 --- a/l10n_es_aeat_sii_oca/models/__init__.py +++ b/l10n_es_aeat_sii_oca/models/__init__.py @@ -3,7 +3,7 @@ from . import aeat_sii_mapping_registration_keys from . import aeat_sii_map from . import product_product -from . import queue_job +from . import ir_cron_trigger from . import account_fiscal_position from . import sii_mixin from . import account_move diff --git a/l10n_es_aeat_sii_oca/models/account_fiscal_position.py b/l10n_es_aeat_sii_oca/models/account_fiscal_position.py index fb94a027990..8bc289d9db1 100644 --- a/l10n_es_aeat_sii_oca/models/account_fiscal_position.py +++ b/l10n_es_aeat_sii_oca/models/account_fiscal_position.py @@ -32,12 +32,6 @@ def default_sii_exempt_cause(self): "Default SII Registration Key for Purchases", domain=[("type", "=", "purchase")], ) - sii_active = fields.Boolean( - string="SII Active", - copy=False, - default=True, - help="Enable SII for this fiscal position?", - ) sii_no_taxable_cause = fields.Selection( selection=[ ( diff --git a/l10n_es_aeat_sii_oca/models/account_move.py b/l10n_es_aeat_sii_oca/models/account_move.py index d423efef22e..521b5e83440 100644 --- a/l10n_es_aeat_sii_oca/models/account_move.py +++ b/l10n_es_aeat_sii_oca/models/account_move.py @@ -14,6 +14,7 @@ import json import logging +from datetime import datetime from odoo import _, api, exceptions, fields, models from odoo.modules.registry import Registry @@ -22,18 +23,6 @@ _logger = logging.getLogger(__name__) -try: - from odoo.addons.queue_job.job import job -except ImportError: - _logger.debug("Can not `import queue_job`.") - import functools - - def empty_decorator_factory(*argv, **kwargs): - return functools.partial - - job = empty_decorator_factory - - class AccountMove(models.Model): _name = "account.move" _inherit = ["account.move", "sii.mixin"] @@ -94,12 +83,12 @@ def _default_sii_refund_type(self): "The invoice number should start with LC, QZC, QRC, A01 or A02.", copy=False, ) - invoice_jobs_ids = fields.Many2many( - comodel_name="queue.job", + invoice_cron_trigger_ids = fields.Many2many( + comodel_name="ir.cron.trigger", column1="invoice_id", - column2="job_id", - relation="account_move_queue_job_rel", - string="Connector Jobs", + column2="trigger_id", + relation="account_move_cron_trigger_rel", + string="Cron Triggers", copy=False, ) @@ -123,7 +112,7 @@ def _compute_sii_registration_key(self): def _compute_macrodata(self): return super()._compute_macrodata() - def _sii_get_partner(self): + def _aeat_get_partner(self): return self.commercial_partner_id def _raise_exception_sii(self, field_name): @@ -141,7 +130,7 @@ def write(self, vals): VAT/ID Otro and the supplier invoice number. Cannot let change these values in a SII registered supplier invoice""" for invoice in self.filtered( - lambda x: x.is_invoice() and x.sii_state != "not_sent" + lambda x: x.is_invoice() and x.aeat_state != "not_sent" ): if "invoice_date" in vals: self._raise_exception_sii(_("invoice date")) @@ -149,7 +138,7 @@ def write(self, vals): self._raise_exception_sii(_("third-party number")) if invoice.move_type in ["in_invoice", "in_refund"]: if "partner_id" in vals: - correct_partners = invoice._sii_get_partner() + correct_partners = invoice._aeat_get_partner() correct_partners |= correct_partners.child_ids if vals["partner_id"] not in correct_partners.ids: self._raise_exception_sii(_("supplier")) @@ -173,7 +162,7 @@ def _get_sii_tax_req(self, tax): :return: REQ tax (or empty recordset) linked to the provided tax. """ self.ensure_one() - taxes_req = self._get_sii_taxes_map(["RE"], self._get_document_fiscal_date()) + taxes_req = self._get_aeat_taxes_map(["RE"], self._get_document_fiscal_date()) re_lines = self.line_ids.filtered( lambda x: tax in x.tax_ids and x.tax_ids & taxes_req ) @@ -223,19 +212,19 @@ def _get_sii_out_taxes(self): # noqa: C901 """ self.ensure_one() taxes_dict = {} - taxes_sfesb = self._get_sii_taxes_map(["SFESB"], self.date) - taxes_sfesbe = self._get_sii_taxes_map(["SFESBE"], self.date) - taxes_sfesisp = self._get_sii_taxes_map(["SFESISP"], self.date) + taxes_sfesb = self._get_aeat_taxes_map(["SFESB"], self.date) + taxes_sfesbe = self._get_aeat_taxes_map(["SFESBE"], self.date) + taxes_sfesisp = self._get_aeat_taxes_map(["SFESISP"], self.date) # taxes_sfesisps = self._get_taxes_map(['SFESISPS']) - taxes_sfens = self._get_sii_taxes_map(["SFENS"], self.date) - taxes_sfess = self._get_sii_taxes_map(["SFESS"], self.date) - taxes_sfesse = self._get_sii_taxes_map(["SFESSE"], self.date) - taxes_sfesns = self._get_sii_taxes_map(["SFESNS"], self.date) - taxes_not_in_total = self._get_sii_taxes_map(["NotIncludedInTotal"], self.date) - taxes_not_in_total_neg = self._get_sii_taxes_map( + taxes_sfens = self._get_aeat_taxes_map(["SFENS"], self.date) + taxes_sfess = self._get_aeat_taxes_map(["SFESS"], self.date) + taxes_sfesse = self._get_aeat_taxes_map(["SFESSE"], self.date) + taxes_sfesns = self._get_aeat_taxes_map(["SFESNS"], self.date) + taxes_not_in_total = self._get_aeat_taxes_map(["NotIncludedInTotal"], self.date) + taxes_not_in_total_neg = self._get_aeat_taxes_map( ["NotIncludedInTotalNegative"], self.date ) - base_not_in_total = self._get_sii_taxes_map( + base_not_in_total = self._get_aeat_taxes_map( ["BaseNotIncludedInTotal"], self.date ) not_in_amount_total = 0 @@ -356,17 +345,17 @@ def _get_sii_in_taxes(self): """ self.ensure_one() taxes_dict = {} - taxes_sfrs = self._get_sii_taxes_map(["SFRS"], self.date) - taxes_sfrsa = self._get_sii_taxes_map(["SFRSA"], self.date) - taxes_sfrisp = self._get_sii_taxes_map(["SFRISP"], self.date) - taxes_sfrns = self._get_sii_taxes_map(["SFRNS"], self.date) - taxes_sfrnd = self._get_sii_taxes_map(["SFRND"], self.date) - taxes_sfrbi = self._get_sii_taxes_map(["SFRBI"], self.date) - taxes_not_in_total = self._get_sii_taxes_map(["NotIncludedInTotal"], self.date) - taxes_not_in_total_neg = self._get_sii_taxes_map( + taxes_sfrs = self._get_aeat_taxes_map(["SFRS"], self.date) + taxes_sfrsa = self._get_aeat_taxes_map(["SFRSA"], self.date) + taxes_sfrisp = self._get_aeat_taxes_map(["SFRISP"], self.date) + taxes_sfrns = self._get_aeat_taxes_map(["SFRNS"], self.date) + taxes_sfrnd = self._get_aeat_taxes_map(["SFRND"], self.date) + taxes_sfrbi = self._get_aeat_taxes_map(["SFRBI"], self.date) + taxes_not_in_total = self._get_aeat_taxes_map(["NotIncludedInTotal"], self.date) + taxes_not_in_total_neg = self._get_aeat_taxes_map( ["NotIncludedInTotalNegative"], self.date ) - base_not_in_total = self._get_sii_taxes_map( + base_not_in_total = self._get_aeat_taxes_map( ["BaseNotIncludedInTotal"], self.date ) tax_amount = 0.0 @@ -415,9 +404,9 @@ def _get_sii_in_taxes(self): def _get_mapping_key(self): return self.move_type - def _sii_check_exceptions(self): - res = super()._sii_check_exceptions() - is_simplified_invoice = self._is_sii_simplified_invoice() + def _aeat_check_exceptions(self): + res = super()._aeat_check_exceptions() + is_simplified_invoice = self._is_aeat_simplified_invoice() if is_simplified_invoice and self.move_type[:2] == "in": raise exceptions.UserError( _("You can't make a supplier simplified invoice.") @@ -433,7 +422,7 @@ def _get_sii_invoice_type(self): if self.move_type in ["in_invoice", "in_refund"]: invoice_type = "R4" if self.move_type == "in_refund" else "F1" elif self.move_type in ["out_invoice", "out_refund"]: - is_simplified = self._is_sii_simplified_invoice() + is_simplified = self._is_aeat_simplified_invoice() invoice_type = "F2" if is_simplified else "F1" if self.move_type == "out_refund": if self.sii_refund_specific_invoice_type: @@ -442,8 +431,8 @@ def _get_sii_invoice_type(self): invoice_type = "R5" if is_simplified else "R1" return invoice_type - def _get_sii_invoice_dict_out(self, cancel=False): - inv_dict = super()._get_sii_invoice_dict_out(cancel=cancel) + def _get_aeat_invoice_dict_out(self, cancel=False): + inv_dict = super()._get_aeat_invoice_dict_out(cancel=cancel) if cancel: return inv_dict if self.thirdparty_invoice: @@ -496,7 +485,7 @@ def _get_document_serial_number(self): serial_number = self.thirdparty_number[0:60] return serial_number - def _get_sii_invoice_dict_in(self, cancel=False): + def _get_aeat_invoice_dict_in(self, cancel=False): """Build dict with data to send to AEAT WS for invoice types: in_invoice and in_refund. @@ -509,7 +498,7 @@ def _get_sii_invoice_dict_in(self, cancel=False): reg_date = self._change_date_format(self._get_account_registration_date()) ejercicio = fields.Date.to_date(self.date).year periodo = "%02d" % fields.Date.to_date(self.date).month - partner = self._sii_get_partner() + partner = self._aeat_get_partner() desglose_factura, tax_amount, not_in_amount_total = self._get_sii_in_taxes() inv_dict = { "IDFactura": { @@ -574,34 +563,34 @@ def _get_sii_invoice_dict_in(self, cancel=False): def _get_cancel_sii_invoice_dict(self): self.ensure_one() - self._sii_check_exceptions() + self._aeat_check_exceptions() if self.move_type in ["out_invoice", "out_refund"]: - return self._get_sii_invoice_dict_out(cancel=True) + return self._get_aeat_invoice_dict_out(cancel=True) elif self.move_type in ["in_invoice", "in_refund"]: - return self._get_sii_invoice_dict_in(cancel=True) + return self._get_aeat_invoice_dict_in(cancel=True) return {} def _sii_invoice_dict_not_modified(self): self.ensure_one() - to_send = self._get_sii_invoice_dict() - content_sent = json.loads(self.sii_content_sent) + to_send = self._get_aeat_invoice_dict() + content_sent = json.loads(self.aeat_content_sent) return to_send == content_sent def _post(self, soft=True): res = super()._post(soft=soft) for invoice in self.filtered(lambda x: x.sii_enabled and x.is_invoice()): - invoice._sii_check_exceptions() + invoice._aeat_check_exceptions() if ( - invoice.sii_state in ["sent_modified", "sent"] + invoice.aeat_state in ["sent_modified", "sent"] and invoice._sii_invoice_dict_not_modified() ): - if invoice.sii_state == "sent_modified": - invoice.sii_state = "sent" + if invoice.aeat_state == "sent_modified": + invoice.aeat_state = "sent" continue - if invoice.sii_state == "sent": - invoice.sii_state = "sent_modified" - elif invoice.sii_state == "cancelled": - invoice.sii_state = "cancelled_modified" + if invoice.aeat_state == "sent": + invoice.aeat_state = "sent_modified" + elif invoice.aeat_state == "cancelled": + invoice.aeat_state = "cancelled_modified" company = invoice.company_id if company.sii_method != "auto": continue @@ -619,19 +608,20 @@ def process_send_sii(self): "context": self.env.context, } - def _get_sii_jobs_field_name(self): - return "invoice_jobs_ids" + def _get_sii_triggers_field_name(self): + return "invoice_cron_trigger_ids" + @api.model def _get_valid_document_states(self): return SII_VALID_INVOICE_STATES def _cancel_invoice_to_sii(self): for invoice in self.filtered(lambda i: i.state in ["cancel"]): - serv = invoice._connect_sii(invoice.move_type) - header = invoice._get_sii_header(cancellation=True) + serv = invoice._connect_aeat(invoice.move_type) + header = invoice._get_aeat_header(cancellation=True) inv_vals = { - "sii_send_failed": True, - "sii_send_error": False, + "aeat_send_failed": True, + "aeat_send_error": False, } try: inv_dict = invoice._get_cancel_sii_invoice_dict() @@ -648,14 +638,14 @@ def _cancel_invoice_to_sii(self): if res["EstadoEnvio"] == "Correcto": inv_vals.update( { - "sii_state": "cancelled", + "aeat_state": "cancelled", "sii_csv": res["CSV"], - "sii_send_failed": False, + "aeat_send_failed": False, } ) res_line = res["RespuestaLinea"][0] if res_line["CodigoErrorRegistro"]: - inv_vals["sii_send_error"] = "{} | {}".format( + inv_vals["aeat_send_error"] = "{} | {}".format( str(res_line["CodigoErrorRegistro"]), str(res_line["DescripcionErrorRegistro"])[:60], ) @@ -666,8 +656,8 @@ def _cancel_invoice_to_sii(self): invoice = env["account.move"].browse(invoice.id) inv_vals.update( { - "sii_send_failed": True, - "sii_send_error": repr(fault)[:60], + "aeat_send_failed": True, + "aeat_send_error": repr(fault)[:60], "sii_return": repr(fault), } ) @@ -681,53 +671,50 @@ def cancel_sii(self): lambda i: ( i.sii_enabled and i.state in ["cancel"] - and i.sii_state in ["sent", "sent_w_errors", "sent_modified"] + and i.aeat_state in ["sent", "sent_w_errors", "sent_modified"] ) ) - if not invoices._cancel_sii_jobs(): + if not invoices._cancel_sii_triggers(): raise exceptions.UserError( _( "You can not communicate the cancellation of this invoice " - "at this moment because there is a job running!" + "at this moment. Please, try again later." ) ) - queue_obj = self.env["queue.job"] for invoice in invoices: company = invoice.company_id - if not company.use_connector: + cron_trigger_obj = self.env["ir.cron.trigger"].sudo() + sii_send_cron = self.env.ref("l10n_es_aeat_sii_oca.invoice_send_to_sii") + if not company.use_cron: invoice._cancel_invoice_to_sii() else: - eta = company._get_sii_eta() - new_delay = ( - self.sudo() - .with_context(company_id=company.id) - .with_delay(eta=eta) - .cancel_one_invoice() + sii_sending_time = company._get_sii_sending_time() + trigger = cron_trigger_obj.create( + {"cron_id": sii_send_cron.id, "call_at": sii_sending_time} ) - job = queue_obj.search([("uuid", "=", new_delay.uuid)], limit=1) - invoice.sudo().invoice_jobs_ids |= job + invoice.sudo().invoice_cron_trigger_ids |= trigger def button_cancel(self): - if not self._cancel_sii_jobs(): + if not self._cancel_sii_triggers(): raise exceptions.UserError( - _("You can not cancel this invoice because" " there is a job running!") + _("You cannot cancel this invoice. Please, try again later.") ) res = super().button_cancel() for invoice in self.filtered(lambda x: x.sii_enabled): - if invoice.sii_state == "sent": - invoice.sii_state = "sent_modified" - elif invoice.sii_state == "cancelled_modified": + if invoice.aeat_state == "sent": + invoice.aeat_state = "sent_modified" + elif invoice.aeat_state == "cancelled_modified": # Case when repoen a cancelled invoice, validate and cancel # again without any SII communication. - invoice.sii_state = "cancelled" + invoice.aeat_state = "cancelled" return res def button_draft(self): - if not self._cancel_sii_jobs(): + if not self._cancel_sii_triggers(): raise exceptions.UserError( _( "You can not set to draft this invoice because" - " there is a job running!" + " the SII cron could not be cancelled." ) ) return super().button_draft() @@ -791,14 +778,15 @@ def _compute_sii_description(self): "company_id.sii_enabled", "move_type", "fiscal_position_id", - "fiscal_position_id.sii_active", + "fiscal_position_id.aeat_active", ) def _compute_sii_enabled(self): """Compute if the invoice is enabled for the SII""" for invoice in self: if invoice.company_id.sii_enabled and invoice.is_invoice(): invoice.sii_enabled = ( - invoice.fiscal_position_id and invoice.fiscal_position_id.sii_active + invoice.fiscal_position_id + and invoice.fiscal_position_id.aeat_active ) or not invoice.fiscal_position_id else: invoice.sii_enabled = False @@ -807,7 +795,7 @@ def _reverse_moves(self, default_values_list=None, cancel=False): # OVERRIDE if not default_values_list: default_values_list = [{} for move in self] - for move, default_values in zip(self, default_values_list): + for move, default_values in zip(self, default_values_list, strict=False): if move.sii_enabled: extra_dict = {} sii_refund_type = self.env.context.get("sii_refund_type", False) @@ -828,3 +816,46 @@ def _reverse_moves(self, default_values_list=None, cancel=False): def cancel_one_invoice(self): self.sudo()._cancel_invoice_to_sii() + + @api.model + def _send_to_sii(self): + documents = all_documents = self.search( + [ + ("state", "in", self._get_valid_document_states()), + ( + "sii_state", + "not in", + ["sent", "cancelled"], + ), + ("sii_send_date", "<=", fields.Datetime.now()), + ] + ) + if documents: + cron_trigger_obj = self.env["ir.cron.trigger"].sudo() + sii_send_cron = self.env.ref("l10n_es_aeat_sii_oca.invoice_send_to_sii") + remaining_documents = False + batch = ( + self.env["ir.config_parameter"] + .sudo() + .get_param("l10n_es_aeat_sii_oca.sii_batch") + ) + if batch: + try: + batch = int(batch) + except ValueError as e: + raise exceptions.UserError( + _( + "The value in l10n_es_aeat_sii_oca.sii_batch system" + " parameter must be an integer. Please, check the " + "value of the parameter." + ) + ) from e + if batch: + documents = all_documents[:batch] + remaining_documents = all_documents - documents + documents.confirm_one_document() + for document in remaining_documents: + trigger = cron_trigger_obj.create( + {"cron_id": sii_send_cron.id, "call_at": datetime.now()} + ) + document.sudo().invoice_cron_trigger_ids |= trigger diff --git a/l10n_es_aeat_sii_oca/models/aeat_sii_map.py b/l10n_es_aeat_sii_oca/models/aeat_sii_map.py index 434d39f370d..4a8d8dec9b5 100644 --- a/l10n_es_aeat_sii_oca/models/aeat_sii_map.py +++ b/l10n_es_aeat_sii_oca/models/aeat_sii_map.py @@ -59,7 +59,9 @@ class AeatSiiMapLines(models.Model): code = fields.Char(required=True) name = fields.Char() - taxes = fields.Many2many(comodel_name="account.tax.template") + tax_xmlid_ids = fields.Many2many( + comodel_name="l10n.es.aeat.map.tax.line.tax", string="Taxes templates" + ) sii_map_id = fields.Many2one( comodel_name="aeat.sii.map", string="Aeat SII Map", ondelete="cascade" ) diff --git a/l10n_es_aeat_sii_oca/models/ir_cron_trigger.py b/l10n_es_aeat_sii_oca/models/ir_cron_trigger.py new file mode 100644 index 00000000000..6fd8bf6f6b2 --- /dev/null +++ b/l10n_es_aeat_sii_oca/models/ir_cron_trigger.py @@ -0,0 +1,32 @@ +# Copyright 2017 Tecnativa - Pedro M. Baeza +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + + +from odoo import fields, models + + +class IrCronTrigger(models.Model): + _inherit = "ir.cron.trigger" + + def do_now(self): + documents = self.env["account.move"].search( + [("invoice_cron_trigger_ids", "in", self.ids)] + ) + documents.write({"sii_send_date": fields.Datetime.now()}) + self.sudo().write({"call_at": fields.Datetime.now()}) + + def cancel_now(self): + documents = self.env["account.move"].search( + [("invoice_cron_trigger_ids", "in", self.ids)] + ) + documents.write({"sii_send_date": False}) + self.sudo().unlink() + + def reschedule_sudo(self): + documents = self.env["account.move"].search( + [("invoice_cron_trigger_ids", "in", self.ids)] + ) + for document in documents: + document.write( + {"sii_send_date": document.company_id._get_sii_sending_time()} + ) diff --git a/l10n_es_aeat_sii_oca/models/queue_job.py b/l10n_es_aeat_sii_oca/models/queue_job.py deleted file mode 100644 index 618ecfe0440..00000000000 --- a/l10n_es_aeat_sii_oca/models/queue_job.py +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright 2017 Tecnativa - Pedro M. Baeza -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). - - -from odoo import models - - -class QueueJob(models.Model): - _inherit = "queue.job" - - def do_now(self): - self.sudo().write({"eta": False}) - - def cancel_now(self): - self.sudo().filtered(lambda x: x.state in ["pending", "enqueued"]).unlink() - - def requeue_sudo(self): - self.sudo().requeue() diff --git a/l10n_es_aeat_sii_oca/models/res_company.py b/l10n_es_aeat_sii_oca/models/res_company.py index 606ba1e711b..d4cbfd7efc8 100644 --- a/l10n_es_aeat_sii_oca/models/res_company.py +++ b/l10n_es_aeat_sii_oca/models/res_company.py @@ -15,7 +15,7 @@ class ResCompany(models.Model): _inherit = "res.company" sii_enabled = fields.Boolean(string="Enable SII") - sii_test = fields.Boolean(string="Is Test Environment?") + sii_test = fields.Boolean(string="Is it the SII test environment?") sii_description_method = fields.Selection( string="SII Description Method", selection=[("auto", "Automatic"), ("fixed", "Fixed"), ("manual", "Manual")], @@ -55,8 +55,8 @@ class ResCompany(models.Model): help="By default, the invoice is sent/queued in validation process. " "With manual method, there's a button to send the invoice.", ) - use_connector = fields.Boolean( - help="Check it to use connector instead of sending the invoice " + use_cron = fields.Boolean( + help="Check it to use a cron instead of sending the invoice " "directly when it's validated", ) send_mode = fields.Selection( @@ -70,7 +70,9 @@ class ResCompany(models.Model): sent_time = fields.Float() delay_time = fields.Float() - def _get_sii_eta(self): + def _get_sii_sending_time(self): + if self.send_mode == "auto": + return datetime.now() if self.send_mode == "fixed": tz = self.env.context.get("tz", self.env.user.partner_id.tz) offset = datetime.now(pytz.timezone(tz)).strftime("%z") if tz else "+00" diff --git a/l10n_es_aeat_sii_oca/models/res_partner.py b/l10n_es_aeat_sii_oca/models/res_partner.py index a95d5ec90b2..78c708a14e4 100644 --- a/l10n_es_aeat_sii_oca/models/res_partner.py +++ b/l10n_es_aeat_sii_oca/models/res_partner.py @@ -8,18 +8,18 @@ class ResPartner(models.Model): _inherit = "res.partner" sii_enabled = fields.Boolean( - compute="_compute_sii_enabled", - ) - sii_simplified_invoice = fields.Boolean( - string="Simplified invoices in SII?", - help="Checking this mark, invoices done to this partner will be " - "sent to SII as simplified invoices.", + compute="_compute_aeat_sending_enabled", ) @api.depends("company_id") - def _compute_sii_enabled(self): + def _compute_aeat_sending_enabled(self): + res = super()._compute_aeat_sending_enabled() sii_enabled = any(self.env.companies.mapped("sii_enabled")) for partner in self: - partner.sii_enabled = ( + sii_enabled = ( partner.company_id.sii_enabled if partner.company_id else sii_enabled ) + partner.sii_enabled = sii_enabled + if sii_enabled: + partner.aeat_sending_enabled = True + return res diff --git a/l10n_es_aeat_sii_oca/models/sii_mixin.py b/l10n_es_aeat_sii_oca/models/sii_mixin.py index 64402047fff..b89ed3f7318 100644 --- a/l10n_es_aeat_sii_oca/models/sii_mixin.py +++ b/l10n_es_aeat_sii_oca/models/sii_mixin.py @@ -7,26 +7,16 @@ import json import logging -from requests import Session - from odoo import _, api, exceptions, fields, models from odoo.exceptions import UserError, ValidationError from odoo.modules.registry import Registry from odoo.tools.float_utils import float_compare -_logger = logging.getLogger(__name__) +from odoo.addons.l10n_es_aeat.models.aeat_mixin import round_by_keys -try: - from zeep import Client - from zeep.plugins import HistoryPlugin - from zeep.transports import Transport -except (OSError, ImportError) as err: - _logger.debug(err) +_logger = logging.getLogger(__name__) SII_STATES = [ - ("not_sent", "Not sent"), - ("sent", "Sent"), - ("sent_w_errors", "Accepted with errors"), ("sent_modified", "Registered in SII but last modifications not sent"), ("cancelled", "Cancelled"), ("cancelled_modified", "Cancelled in SII but last modifications not sent"), @@ -36,24 +26,9 @@ SII_DATE_FORMAT = "%d-%m-%Y" -def round_by_keys(elem, search_keys, prec=2): - """This uses ``round`` method directly as if has been tested that Odoo's - ``float_round`` still returns incorrect amounts for certain values. Try - 3 units x 3,77 €/unit with 10% tax and you will be hit by the error - (on regular x86 architectures).""" - if isinstance(elem, dict): - for key, value in elem.items(): - if key in search_keys: - elem[key] = round(elem[key], prec) - else: - round_by_keys(value, search_keys) - elif isinstance(elem, list): - for value in elem: - round_by_keys(value, search_keys) - - class SiiMixin(models.AbstractModel): _name = "sii.mixin" + _inherit = "aeat.mixin" _description = "SII Mixin" company_id = fields.Many2one( @@ -68,38 +43,11 @@ class SiiMixin(models.AbstractModel): readonly=False, copy=False, ) - sii_state = fields.Selection( - selection=SII_STATES, - string="SII send state", - default="not_sent", - readonly=True, - copy=False, - help="Indicates the state of this document in relation with the " - "presentation at the SII", + aeat_state = fields.Selection( + selection_add=SII_STATES, ) sii_csv = fields.Char(string="SII CSV", copy=False, readonly=True) sii_return = fields.Text(string="SII Return", copy=False, readonly=True) - sii_header_sent = fields.Text( - string="SII last header sent", - copy=False, - readonly=True, - ) - sii_content_sent = fields.Text( - string="SII last content sent", - copy=False, - readonly=True, - ) - sii_send_error = fields.Text( - string="SII Send Error", - readonly=True, - copy=False, - ) - sii_send_failed = fields.Boolean( - string="SII send failed", - copy=False, - help="Indicates that the last attempt to communicate this document to " - "the SII has failed. See SII return for details", - ) sii_refund_type = fields.Selection( selection=[ # ('S', 'By substitution'), - Removed as not fully supported @@ -147,6 +95,7 @@ class SiiMixin(models.AbstractModel): "greater o equal to 100 000 000,00 euros.", compute="_compute_macrodata", ) + sii_send_date = fields.Datetime(string="SII Send Date") def _compute_sii_refund_type(self): self.sii_refund_type = False @@ -191,11 +140,12 @@ def _compute_sii_registration_key(self): @api.depends("sii_registration_key") def _compute_sii_registration_key_code(self): """ - Para evitar tiempos de instalación largos en BBDD grandes, es necesario que - sólo dependa de sii_registration_key, ya que en caso de añadirlo odoo buscará - todos los movimientos y cuando escribamos el key, aunque sea un campo no almacenado - A partir de v16.0 este cambio ya no es necesario, ya que el sistema ya revisa que el - campo sea almacenado o que este visualizandose (en caché) + Para evitar tiempos de instalación largos en BBDD grandes, es necesario + que sólo dependa de sii_registration_key, ya que en caso de añadirlo + odoo buscará todos los movimientos y cuando escribamos el key, aunque + sea un campo no almacenado + A partir de v16.0 este cambio ya no es necesario, ya que el sistema ya + revisa que el campo sea almacenado o que este visualizandose (en caché) """ for record in self: record.sii_registration_key_code = record.sii_registration_key.code @@ -214,17 +164,10 @@ def _compute_macrodata(self): >= 0 ) - def _sii_get_partner(self): - raise NotImplementedError - - def _get_sii_country_code(self): - self.ensure_one() - return self._sii_get_partner()._parse_aeat_vat_info()[0] - def _filter_sii_unlink_not_possible(self): """Filter records that we do not allow to be deleted, all those that are not in not_sent sii status.""" - return self.filtered(lambda rec: rec.sii_state != "not_sent") + return self.filtered(lambda rec: rec.aeat_state != "not_sent") @api.ondelete(at_uninstall=False) def _unlink_except_sii(self): @@ -235,7 +178,7 @@ def _unlink_except_sii(self): ) @api.model - def _get_sii_taxes_map(self, codes, date): + def _get_aeat_taxes_map(self, codes, date): """Return the codes that correspond to that sii map line codes. :param codes: List of code strings to get the mapping. @@ -254,15 +197,16 @@ def _get_sii_taxes_map(self, codes, date): ], limit=1, ) - tax_templates = sii_map.map_lines.filtered(lambda x: x.code in codes).taxes - return self.company_id.get_taxes_from_templates(tax_templates) - - def _change_date_format(self, date): - datetimeobject = fields.Date.to_date(date) - new_date = datetimeobject.strftime(SII_DATE_FORMAT) - return new_date - - def _get_sii_header(self, tipo_comunicacion=False, cancellation=False): + tax_templates = sii_map.map_lines.filtered( + lambda x: x.code in codes + ).tax_xmlid_ids + taxes = self.env["account.tax"] + for template in tax_templates: + tax_id = self.company_id._get_tax_id_from_xmlid(template.name) + taxes |= self.env["account.tax"].browse(tax_id) + return taxes + + def _get_aeat_header(self, tipo_comunicacion=False, cancellation=False): """Builds SII send header :param tipo_comunicacion String 'A0': new reg, 'A1': modification @@ -286,33 +230,30 @@ def _get_sii_header(self, tipo_comunicacion=False, cancellation=False): header.update({"TipoComunicacion": tipo_comunicacion}) return header - def _get_sii_jobs_field_name(self): + def _get_sii_triggers_field_name(self): raise NotImplementedError() - def _cancel_sii_jobs(self): - for queue in self.sudo().mapped(self._get_sii_jobs_field_name()): - if queue.state == "started": - return False - elif queue.state in ("pending", "enqueued", "failed"): - queue.unlink() + def _cancel_sii_triggers(self): + try: + self.sudo().write({"sii_send_date": False}) + self.sudo().mapped(self._get_sii_triggers_field_name()).unlink() + except Exception: + return False return True - def _get_valid_document_states(self): - raise NotImplementedError() - def send_sii(self): documents = self.filtered( lambda document: ( document.sii_enabled and document.state in self._get_valid_document_states() - and document.sii_state not in ["sent", "cancelled"] + and document.aeat_state not in ["sent", "cancelled"] ) ) - if not documents._cancel_sii_jobs(): + if not documents._cancel_sii_triggers(): raise UserError( _( - "You can not communicate this document at this moment " - "because there is a job running!" + "You can not communicate this document at this moment. " + "Please, try again later." ) ) documents._process_sii_send() @@ -321,31 +262,33 @@ def _process_sii_send(self): """Process document sending to the SII. Adds general checks from configuration parameters and document availability for SII. If the document is to be sent the decides the send method: direct send or - via connector depending on 'Use connector' configuration""" - queue_obj = self.env["queue.job"].sudo() + via cron depending on 'Use cron' configuration""" + cron_trigger_obj = self.env["ir.cron.trigger"].sudo() + sii_send_cron = self.env.ref("l10n_es_aeat_sii_oca.invoice_send_to_sii") for record in self: company = record.company_id - if not company.use_connector: + if not company.use_cron: record.confirm_one_document() else: - eta = company._get_sii_eta() - new_delay = ( - record.sudo() - .with_context(company_id=company.id) - .with_delay(eta=eta if not record.sii_send_failed else False) - .confirm_one_document() + sii_sending_time = company._get_sii_sending_time() + trigger = cron_trigger_obj.create( + {"cron_id": sii_send_cron.id, "call_at": sii_sending_time} + ) + setattr( + record.sudo(), + self._get_sii_triggers_field_name(), + [(4, trigger.id)], ) - job = queue_obj.search([("uuid", "=", new_delay.uuid)], limit=1) - setattr(record.sudo(), self._get_sii_jobs_field_name(), [(4, job.id)]) + self.sii_send_date = sii_sending_time - def _bind_sii(self, client, port_name, address=None): + def _bind_service(self, client, port_name, address=None): self.ensure_one() service = client._get_service("siiService") port = client._get_port(service, port_name) address = address or port.binding_options["address"] return client.create_service(port.binding.name, address) - def _connect_params_sii(self, mapping_key): + def _connect_params_aeat(self, mapping_key): self.ensure_one() agency = self.company_id.tax_agency_id if not agency: @@ -356,19 +299,6 @@ def _connect_params_sii(self, mapping_key): agency = self.env.ref("l10n_es_aeat.aeat_tax_agency_spain") return agency._connect_params_sii(mapping_key, self.company_id) - def _connect_sii(self, mapping_key): - self.ensure_one() - public_crt, private_key = self.env["l10n.es.aeat.certificate"].get_certificates( - company=self.company_id - ) - params = self._connect_params_sii(mapping_key) - session = Session() - session.cert = (public_crt, private_key) - transport = Transport(session=session) - history = HistoryPlugin() - client = Client(wsdl=params["wsdl"], transport=transport, plugins=[history]) - return self._bind_sii(client, params["port_name"], params["address"]) - def _get_sii_gen_type(self): """Make a choice for general invoice type @@ -387,39 +317,30 @@ def _get_sii_gen_type(self): res = 1 return res - def _is_sii_simplified_invoice(self): + def _is_aeat_simplified_invoice(self): """Inheritable method to allow control when an invoice are simplified or normal""" - partner = self._sii_get_partner() - return partner.sii_simplified_invoice + partner = self._aeat_get_partner() + return partner.aeat_simplified_invoice - def _sii_check_exceptions(self): + def _aeat_check_exceptions(self): """Inheritable method for exceptions control when sending SII invoices.""" self.ensure_one() - gen_type = self._get_sii_gen_type() - partner = self._sii_get_partner() - country_code = self._get_sii_country_code() - is_simplified_invoice = self._is_sii_simplified_invoice() - if ( - (gen_type != 3 or country_code == "ES") - and not partner.vat - and not is_simplified_invoice - ): - raise UserError(_("The partner has not a VAT configured.")) - if not self.company_id.chart_template_id: - raise UserError( - _("You have to select what account chart template use this" " company.") - ) - if not self.company_id.sii_enabled: - raise UserError(_("This company doesn't have SII enabled.")) - if not self.sii_enabled: - raise UserError(_("This invoice is not SII enabled.")) - - def _get_mapping_key(self): - raise NotImplementedError() - - def _get_document_date(self): - raise NotImplementedError() + res = super()._aeat_check_exceptions() + if self.company_id.sii_enabled: + gen_type = self._get_sii_gen_type() + partner = self._aeat_get_partner() + country_code = self._get_aeat_country_code() + is_simplified_invoice = self._is_aeat_simplified_invoice() + if ( + (gen_type != 3 or country_code == "ES") + and not partner.vat + and not is_simplified_invoice + ): + raise UserError(_("The partner has not a VAT configured.")) + if not self.sii_enabled: + raise UserError(_("This invoice is not SII enabled.")) + return res def _get_document_fiscal_date(self): raise NotImplementedError() @@ -430,9 +351,6 @@ def _get_document_fiscal_year(self): def _get_document_period(self): return "%02d" % fields.Date.to_date(self._get_document_fiscal_date()).month - def _get_document_serial_number(self): - raise NotImplementedError() - def _get_document_product_exempt(self, applied_taxes): raise NotImplementedError() @@ -517,7 +435,7 @@ def _is_sii_type_breakdown_required(self, taxes_dict): self.ensure_one() if "DesgloseFactura" not in taxes_dict: return False - country_code = self._get_sii_country_code() + country_code = self._get_aeat_country_code() sii_gen_type = self._get_sii_gen_type() if "DesgloseTipoOperacion" in taxes_dict: # DesgloseTipoOperacion and DesgloseFactura are Exclusive @@ -530,7 +448,7 @@ def _is_sii_type_breakdown_required(self, taxes_dict): # DesgloseTipoOperacion required for national operations # with 'IDOtro' in the SII identifier block return True - elif sii_gen_type == 1 and (self._sii_get_partner().vat or "").startswith( + elif sii_gen_type == 1 and (self._aeat_get_partner().vat or "").startswith( "ESN" ): # DesgloseTipoOperacion required if customer's country is Spain and @@ -546,19 +464,19 @@ def _get_sii_out_taxes(self): # noqa: C901 self.ensure_one() taxes_dict = {} date = self._get_document_fiscal_date() - taxes_sfesb = self._get_sii_taxes_map(["SFESB"], date) - taxes_sfesbe = self._get_sii_taxes_map(["SFESBE"], date) - taxes_sfesisp = self._get_sii_taxes_map(["SFESISP"], date) + taxes_sfesb = self._get_aeat_taxes_map(["SFESB"], date) + taxes_sfesbe = self._get_aeat_taxes_map(["SFESBE"], date) + taxes_sfesisp = self._get_aeat_taxes_map(["SFESISP"], date) # taxes_sfesisps = self._get_taxes_map(['SFESISPS']) - taxes_sfens = self._get_sii_taxes_map(["SFENS"], date) - taxes_sfess = self._get_sii_taxes_map(["SFESS"], date) - taxes_sfesse = self._get_sii_taxes_map(["SFESSE"], date) - taxes_sfesns = self._get_sii_taxes_map(["SFESNS"], date) - taxes_not_in_total = self._get_sii_taxes_map(["NotIncludedInTotal"], date) - taxes_not_in_total_neg = self._get_sii_taxes_map( + taxes_sfens = self._get_aeat_taxes_map(["SFENS"], date) + taxes_sfess = self._get_aeat_taxes_map(["SFESS"], date) + taxes_sfesse = self._get_aeat_taxes_map(["SFESSE"], date) + taxes_sfesns = self._get_aeat_taxes_map(["SFESNS"], date) + taxes_not_in_total = self._get_aeat_taxes_map(["NotIncludedInTotal"], date) + taxes_not_in_total_neg = self._get_aeat_taxes_map( ["NotIncludedInTotalNegative"], date ) - base_not_in_total = self._get_sii_taxes_map(["BaseNotIncludedInTotal"], date) + base_not_in_total = self._get_aeat_taxes_map(["BaseNotIncludedInTotal"], date) not_in_amount_total = 0 exempt_cause = self._get_sii_exempt_cause(taxes_sfesbe + taxes_sfesse) tax_lines = self._get_tax_info() @@ -660,9 +578,6 @@ def _get_sii_out_taxes(self): # noqa: C901 del taxes_dict["DesgloseFactura"] return taxes_dict, not_in_amount_total - def _get_document_amount_total(self): - raise NotImplementedError() - def _get_sii_invoice_type(self): raise NotImplementedError() @@ -676,7 +591,7 @@ def _get_sii_identifier(self): country_code, identifier_type, identifier, - ) = self._sii_get_partner()._parse_aeat_vat_info() + ) = self._aeat_get_partner()._parse_aeat_vat_info() # Limpiar alfanum if identifier: identifier = "".join(e for e in identifier if e.isalnum()).upper() @@ -684,7 +599,7 @@ def _get_sii_identifier(self): identifier = "NO_DISPONIBLE" identifier_type = "06" if gen_type == 1: - if "1117" in (self.sii_send_error or ""): + if "1117" in (self.aeat_send_error or ""): return { "IDOtro": { "CodigoPais": country_code, @@ -700,8 +615,8 @@ def _get_sii_identifier(self): "CodigoPais": country_code, "IDType": identifier_type, "ID": country_code + identifier - if self._sii_get_partner()._map_aeat_country_code(country_code) - in self._sii_get_partner()._get_aeat_europe_codes() + if self._aeat_get_partner()._map_aeat_country_code(country_code) + in self._aeat_get_partner()._get_aeat_europe_codes() else identifier, }, } @@ -723,7 +638,7 @@ def _get_sii_identifier(self): elif gen_type == 3: return {"NIF": identifier} - def _get_sii_invoice_dict_out(self, cancel=False): + def _get_aeat_invoice_dict_out(self, cancel=False): """Build dict with data to send to AEAT WS for document types: out_invoice and out_refund. @@ -733,11 +648,11 @@ def _get_sii_invoice_dict_out(self, cancel=False): """ self.ensure_one() document_date = self._change_date_format(self._get_document_date()) - partner = self._sii_get_partner() + partner = self._aeat_get_partner() company = self.company_id fiscal_year = self._get_document_fiscal_year() period = self._get_document_period() - is_simplified_invoice = self._is_sii_simplified_invoice() + is_simplified_invoice = self._is_aeat_simplified_invoice() serial_number = self._get_document_serial_number() inv_dict = { "IDFactura": { @@ -775,7 +690,7 @@ def _get_sii_invoice_dict_out(self, cancel=False): exp_dict["Contraparte"].update(self._get_sii_identifier()) return inv_dict - def _get_sii_invoice_dict_in(self, cancel=False): + def _get_aeat_invoice_dict_in(self, cancel=False): """Build dict with data to send to AEAT WS for invoice types: in_invoice and in_refund. @@ -785,15 +700,15 @@ def _get_sii_invoice_dict_in(self, cancel=False): """ raise NotImplementedError() - def _get_sii_invoice_dict(self): + def _get_aeat_invoice_dict(self): self.ensure_one() - self._sii_check_exceptions() + self._aeat_check_exceptions() inv_dict = {} mapping_key = self._get_mapping_key() if mapping_key in ["out_invoice", "out_refund"]: - inv_dict = self._get_sii_invoice_dict_out() + inv_dict = self._get_aeat_invoice_dict_out() elif mapping_key in ["in_invoice", "in_refund"]: - inv_dict = self._get_sii_invoice_dict_in() + inv_dict = self._get_aeat_invoice_dict_in() round_by_keys( inv_dict, [ @@ -828,24 +743,24 @@ def _send_document_to_sii(self): for document in self.filtered( lambda i: i.state in self._get_valid_document_states() ): - if document.sii_state == "not_sent": + if document.aeat_state == "not_sent": tipo_comunicacion = "A0" else: tipo_comunicacion = "A1" - header = document._get_sii_header(tipo_comunicacion) + header = document._get_aeat_header(tipo_comunicacion) doc_vals = { - "sii_header_sent": json.dumps(header, indent=4), + "aeat_header_sent": json.dumps(header, indent=4), } - # add this extra try except in case _get_sii_invoice_dict fails + # add this extra try except in case _get_aeat_invoice_dict fails # if not, get the value doc_dict for the next try and except below try: - inv_dict = document._get_sii_invoice_dict() + inv_dict = document._get_aeat_invoice_dict() except Exception as fault: raise ValidationError(fault) from fault try: mapping_key = document._get_mapping_key() - serv = document._connect_sii(mapping_key) - doc_vals["sii_content_sent"] = json.dumps(inv_dict, indent=4) + serv = document._connect_aeat(mapping_key) + doc_vals["aeat_content_sent"] = json.dumps(inv_dict, indent=4) if mapping_key in ["out_invoice", "out_refund"]: res = serv.SuministroLRFacturasEmitidas(header, inv_dict) elif mapping_key in ["in_invoice", "in_refund"]: @@ -859,9 +774,9 @@ def _send_document_to_sii(self): if res["EstadoEnvio"] == "Correcto": doc_vals.update( { - "sii_state": "sent", + "aeat_state": "sent", "sii_csv": res["CSV"], - "sii_send_failed": False, + "aeat_send_failed": False, } ) elif ( @@ -870,15 +785,15 @@ def _send_document_to_sii(self): ): doc_vals.update( { - "sii_state": "sent_w_errors", + "aeat_state": "sent_w_errors", "sii_csv": res["CSV"], - "sii_send_failed": True, + "aeat_send_failed": True, } ) else: - doc_vals["sii_send_failed"] = True + doc_vals["aeat_send_failed"] = True if ( - "sii_state" in doc_vals + "aeat_state" in doc_vals and not document.sii_account_registration_date and mapping_key[:2] == "in" ): @@ -892,7 +807,7 @@ def _send_document_to_sii(self): str(res_line["CodigoErrorRegistro"]), str(res_line["DescripcionErrorRegistro"])[:60], ) - doc_vals["sii_send_error"] = send_error + doc_vals["aeat_send_error"] = send_error document.write(doc_vals) except Exception as fault: new_cr = Registry(self.env.cr.dbname).cursor() @@ -900,10 +815,10 @@ def _send_document_to_sii(self): document = env[document._name].browse(document.id) doc_vals.update( { - "sii_send_failed": True, - "sii_send_error": repr(fault)[:60], + "aeat_send_failed": True, + "aeat_send_error": repr(fault)[:60], "sii_return": repr(fault), - "sii_content_sent": json.dumps(inv_dict, indent=4), + "aeat_content_sent": json.dumps(inv_dict, indent=4), } ) document.write(doc_vals) diff --git a/l10n_es_aeat_sii_oca/readme/CONFIGURE.md b/l10n_es_aeat_sii_oca/readme/CONFIGURE.md index 8af09257815..2cfcb6999a9 100644 --- a/l10n_es_aeat_sii_oca/readme/CONFIGURE.md +++ b/l10n_es_aeat_sii_oca/readme/CONFIGURE.md @@ -14,26 +14,3 @@ En Linux se pueden usar los siguientes comandos: publicCert.crt -nodes" - Clave privada: "openssl pkcs12 -in Certifcado.p12 -nocerts -out privateKey.pem -nodes" - -Además, el módulo queue_job necesita estar configurado de una de estas -formas: - -1. Ajustando variables de entorno: - - > ODOO_QUEUE_JOB_CHANNELS=root:4 - - u otro canal de configuración. Por defecto es root:1 - - Si xmlrpc_port no está definido: ODOO_QUEUE_JOB_PORT=8069 - -2. Otra alternativa es usuando un fichero de configuración: - - > \[options\] (...) workers = 4 server_wide_modules = - > web,base_sparse_field,queue_job - > - > (...) \[queue_job\] channels = root:4 - -3. Por último, arrancando Odoo con - --load=web,base_sparse_field,queue_job y --workers más grande que 1. - -Más información diff --git a/l10n_es_aeat_sii_oca/readme/CONTRIBUTORS.md b/l10n_es_aeat_sii_oca/readme/CONTRIBUTORS.md index 08b26876333..90d18dc281e 100644 --- a/l10n_es_aeat_sii_oca/readme/CONTRIBUTORS.md +++ b/l10n_es_aeat_sii_oca/readme/CONTRIBUTORS.md @@ -13,6 +13,7 @@ - Eric Antonés - NuoBiT Solutions, S.L. \<\> - [Sygel](https://www.sygel.es): - Valentin Vinagre + - Manuel Regidor - [Tecnativa](https://www.tecnativa.com): - Pedro M. Baeza - João Marques diff --git a/l10n_es_aeat_sii_oca/security/aeat_sii.xml b/l10n_es_aeat_sii_oca/security/aeat_sii.xml index 9bba8a75b33..e9aab4e6430 100644 --- a/l10n_es_aeat_sii_oca/security/aeat_sii.xml +++ b/l10n_es_aeat_sii_oca/security/aeat_sii.xml @@ -1,17 +1,18 @@ - - Queue job AEAT SII visibility - + + Triggers AEAT SII visibility + [('channel', '=', 'root.invoice_validate_sii')] + eval="[('cron_id', '=', ref('l10n_es_aeat_sii_oca.invoice_send_to_sii'))]" + /> - - Queue job manager - + diff --git a/l10n_es_aeat_sii_oca/security/ir.model.access.csv b/l10n_es_aeat_sii_oca/security/ir.model.access.csv index b8f8db011b9..4c4b5ebbc44 100644 --- a/l10n_es_aeat_sii_oca/security/ir.model.access.csv +++ b/l10n_es_aeat_sii_oca/security/ir.model.access.csv @@ -6,5 +6,5 @@ access_model_aeat_sii_map_lines_aeat,aeat.sii.map.lines aeat,model_aeat_sii_map_ access_model_aeat_sii_mapping_registration_keys_admin,aeat.sii.mapping.registration.keys admin,model_aeat_sii_mapping_registration_keys,base.group_system,1,1,1,1 access_model_aeat_sii_mapping_registration_keys_aeat,aeat.sii.mapping.registration.keys aeat,model_aeat_sii_mapping_registration_keys,l10n_es_aeat.group_account_aeat,1,0,0,0 access_model_aeat_sii_mapping_registration_keys_aeat_account,aeat.sii.mapping.registration.keys aeat,model_aeat_sii_mapping_registration_keys,account.group_account_invoice,1,0,0,0 -access_queue_job,access_queue_job aeat,queue_job.model_queue_job,l10n_es_aeat.group_account_aeat,1,0,0,0 +access_ir_cron_trigger,access_ir_cron_trigger aeat,base.model_ir_cron_trigger,l10n_es_aeat.group_account_aeat,1,0,0,0 access_wizard_send_sii,access_wizard_send_sii,model_wizard_send_sii,l10n_es_aeat.group_account_aeat,1,1,1,1 diff --git a/l10n_es_aeat_sii_oca/static/description/index.html b/l10n_es_aeat_sii_oca/static/description/index.html index aa659a5cd02..c10f712fe39 100644 --- a/l10n_es_aeat_sii_oca/static/description/index.html +++ b/l10n_es_aeat_sii_oca/static/description/index.html @@ -366,7 +366,7 @@

Suministro Inmediato de Información en el IVA

!! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!! source digest: sha256:72d10dec2690f12511331aae6305750eeadddbc7c8f9a9923d197dfa5af114ba +!! source digest: sha256:dd4688bc2a1c4bd195d8dd4949f98b380e1ba0858c791d7685e37e7a4a60f9d0 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->

Mature License: AGPL-3 OCA/l10n-spain Translate me on Weblate Try me on Runboat

Módulo para la presentación inmediata del IVA @@ -418,28 +418,6 @@

Configuration

  • Clave privada: “openssl pkcs12 -in Certifcado.p12 -nocerts -out privateKey.pem -nodes”
  • -

    Además, el módulo queue_job necesita estar configurado de una de estas -formas:

    -
      -
    1. Ajustando variables de entorno:

      -
      -

      ODOO_QUEUE_JOB_CHANNELS=root:4

      -
      -

      u otro canal de configuración. Por defecto es root:1

      -

      Si xmlrpc_port no está definido: ODOO_QUEUE_JOB_PORT=8069

      -
    2. -
    3. Otra alternativa es usuando un fichero de configuración:

      -
      -

      [options] (…) workers = 4 server_wide_modules = -web,base_sparse_field,queue_job

      -

      (…) [queue_job] channels = root:4

      -
      -
    4. -
    5. Por último, arrancando Odoo con -–load=web,base_sparse_field,queue_job y –workers más grande que 1.

      -
    6. -
    -

    Más información http://odoo-connector.com

    Usage

    @@ -504,6 +482,7 @@

    Contributors

  • Eric Antonés - NuoBiT Solutions, S.L. <eantones@nuobit.com>
  • Sygel:
    • Valentin Vinagre
    • +
    • Manuel Regidor
  • Tecnativa:
      diff --git a/l10n_es_aeat_sii_oca/tests/test_l10n_es_aeat_sii.py b/l10n_es_aeat_sii_oca/tests/test_l10n_es_aeat_sii.py index 01ebe7401ec..fc0d26d3654 100644 --- a/l10n_es_aeat_sii_oca/tests/test_l10n_es_aeat_sii.py +++ b/l10n_es_aeat_sii_oca/tests/test_l10n_es_aeat_sii.py @@ -9,7 +9,7 @@ import json from odoo import exceptions -from odoo.modules.module import get_resource_path +from odoo.tools.misc import file_path from odoo.addons.l10n_es_aeat.tests.test_l10n_es_aeat_certificate import ( TestL10nEsAeatCertificateBase, @@ -52,11 +52,9 @@ def _create_and_test_invoice_sii_dict( for line in lines: taxes = self.env["account.tax"] for tax in line[1]: - if "." in tax: - xml_id = tax - else: - xml_id = f"l10n_es.{self.company.id}_account_tax_template_{tax}" - taxes += self.env.ref(xml_id) + xml_id = f"account_tax_template_{tax}" + tax_id = self.company._get_tax_id_from_xmlid(xml_id) + taxes += self.env["account.tax"].browse(tax_id) tax_names.append(tax) vals.append({"price_unit": line[0], "taxes": taxes}) return self._compare_sii_dict( @@ -106,8 +104,8 @@ def _compare_sii_dict( if extra_vals: vals.update(extra_vals) invoice = self.env["account.move"].create(vals) - result_dict = invoice._get_sii_invoice_dict() - path = get_resource_path(module, "tests/json", json_file) + result_dict = invoice._get_aeat_invoice_dict() + path = file_path(f"{module}/tests/json/{json_file}") if not path: raise Exception("Incorrect JSON file: %s" % json_file) with open(path) as f: @@ -150,14 +148,14 @@ def setUpClass(cls): {"name": "Test product", "sii_exempt_cause": "E5"} ) cls.account_expense = cls.env.ref( - "l10n_es.%s_account_common_600" % cls.company.id + "account.%s_account_common_600" % cls.company.id ) cls.invoice = cls._create_invoice("out_invoice") cls.company.write( { "sii_enabled": True, "sii_test": True, - "use_connector": True, + "use_cron": True, "vat": "ESU2687761C", "sii_description_method": "manual", "tax_agency_id": cls.env.ref("l10n_es_aeat.aeat_tax_agency_spain"), @@ -203,13 +201,13 @@ def test_intracomunitary_customer_extracomunitary_delivery(self): "vat": "FR23334175221", } ) - fp_extra = self.browse_ref(f"l10n_es.{self.company.id}_fp_extra") + fp_extra = self.browse_ref(f"account.{self.company.id}_fp_extra") fp_extra.sii_partner_identification_type = "3" invoice = self.invoice.copy( {"partner_id": eu_customer.id, "fiscal_position_id": fp_extra.id} ) invoice.action_post() - sii_info = invoice._get_sii_invoice_dict() + sii_info = invoice._get_aeat_invoice_dict() self.assertEqual( sii_info["FacturaExpedida"]["Contraparte"], { @@ -219,7 +217,7 @@ def test_intracomunitary_customer_extracomunitary_delivery(self): ) def test_job_creation(self): - self.assertTrue(self.invoice.invoice_jobs_ids) + self.assertTrue(self.invoice.invoice_cron_trigger_ids) def test_partner_sii_enabled(self): company_02 = self.env["res.company"].create({"name": "Company 02"}) @@ -314,11 +312,6 @@ def test_get_invoice_data(self): self._create_and_test_invoice_sii_dict(inv_type, lines, extra_vals) return - def test_action_cancel(self): - self.invoice.invoice_jobs_ids.state = "started" - with self.assertRaises(exceptions.UserError): - self.invoice.button_cancel() - def test_sii_description(self): company = self.invoice.company_id company.write( @@ -365,7 +358,7 @@ def _check_binding_address(self, invoice): company = invoice.company_id tax_agency = company.tax_agency_id self.sii_cert.company_id.tax_agency_id = tax_agency - proxy = invoice._connect_sii(invoice.move_type) + proxy = invoice._connect_aeat(invoice.move_type) address = proxy._binding_options["address"] self.assertTrue(address) if company.sii_test and tax_agency: @@ -381,22 +374,6 @@ def _check_tax_agencies(self, invoice): invoice.company_id.tax_agency_id = False self._check_binding_address(invoice) - def test_tax_agencies_sandbox(self): - self.sii_cert.company_id = self.invoice.company_id.id - self._activate_certificate() - self.invoice.company_id.sii_test = True - self._check_tax_agencies(self.invoice) - in_invoice = self._create_invoice("in_invoice") - self._check_tax_agencies(in_invoice) - - def test_tax_agencies_production(self): - self.sii_cert.company_id = self.invoice.company_id.id - self._activate_certificate() - self.invoice.company_id.sii_test = False - self._check_tax_agencies(self.invoice) - in_invoice = self._create_invoice("in_invoice") - self._check_tax_agencies(in_invoice) - def test_refund_sii_refund_type(self): invoice = self.env["account.move"].create( { @@ -419,13 +396,13 @@ def test_refund_sii_refund_type_write(self): invoice.move_type = "out_refund" self.assertEqual(invoice.sii_refund_type, "I") - def test_is_sii_simplified_invoice(self): - self.assertFalse(self.invoice._is_sii_simplified_invoice()) - self.partner.sii_simplified_invoice = True - self.assertTrue(self.invoice._is_sii_simplified_invoice()) + def test_is_aeat_simplified_invoice(self): + self.assertFalse(self.invoice._is_aeat_simplified_invoice()) + self.partner.aeat_simplified_invoice = True + self.assertTrue(self.invoice._is_aeat_simplified_invoice()) - def test_sii_check_exceptions_case_supplier_simplified(self): - self.partner.sii_simplified_invoice = True + def test_aeat_check_exceptions_case_supplier_simplified(self): + self.partner.aeat_simplified_invoice = True invoice = self.env["account.move"].create( { "partner_id": self.partner.id, @@ -434,9 +411,9 @@ def test_sii_check_exceptions_case_supplier_simplified(self): } ) with self.assertRaises(exceptions.UserError): - invoice._sii_check_exceptions() + invoice._aeat_check_exceptions() - def test_sii_check_exceptions_case_supplier_on_post(self): + def test_aeat_check_exceptions_case_supplier_on_post(self): """Check sii exceptions when posting supplier bills""" supplier = self.supplier.copy() supplier.country_id = self.env.ref("base.es") @@ -471,14 +448,14 @@ def test_unlink_draft_invoice_when_not_sent_to_sii(self): self.assertFalse(draft_invoice.exists()) def test_unlink_invoice_when_sent_to_sii(self): - self.invoice.sii_state = "sent" + self.invoice.aeat_state = "sent" self.invoice.button_draft() # Convert to draft to check only SII exception with self.assertRaises(exceptions.UserError): self.invoice.unlink() def test_account_move_sii_write_exceptions(self): # out_invoice - self.invoice.sii_state = "sent" + self.invoice.aeat_state = "sent" with self.assertRaises(exceptions.UserError): self.invoice.write({"invoice_date": "2022-01-01"}) with self.assertRaises(exceptions.UserError): @@ -486,7 +463,7 @@ def test_account_move_sii_write_exceptions(self): # in_invoice in_invoice = self._create_invoice("in_invoice") in_invoice.ref = "REF" - in_invoice.sii_state = "sent" + in_invoice.aeat_state = "sent" partner = self.partner.copy() with self.assertRaises(exceptions.UserError): in_invoice.write({"partner_id": partner.id}) diff --git a/l10n_es_aeat_sii_oca/views/account_fiscal_position_view.xml b/l10n_es_aeat_sii_oca/views/account_fiscal_position_view.xml index a53d71edbc0..73d04518891 100644 --- a/l10n_es_aeat_sii_oca/views/account_fiscal_position_view.xml +++ b/l10n_es_aeat_sii_oca/views/account_fiscal_position_view.xml @@ -11,31 +11,21 @@ - - + + - - + + diff --git a/l10n_es_aeat_sii_oca/views/account_journal_view.xml b/l10n_es_aeat_sii_oca/views/account_journal_view.xml index 6e710e38eae..62dd9027e71 100644 --- a/l10n_es_aeat_sii_oca/views/account_journal_view.xml +++ b/l10n_es_aeat_sii_oca/views/account_journal_view.xml @@ -7,9 +7,7 @@ - {'invisible': [('type', 'not in', ('sale', 'purchase'))]} + type not in ['sale', 'purchase'] diff --git a/l10n_es_aeat_sii_oca/views/account_move_views.xml b/l10n_es_aeat_sii_oca/views/account_move_views.xml index 7c854f8c5dd..4a7fe6c73b5 100644 --- a/l10n_es_aeat_sii_oca/views/account_move_views.xml +++ b/l10n_es_aeat_sii_oca/views/account_move_views.xml @@ -12,13 +12,12 @@ {'invisible': [('move_type', 'not in', ('in_invoice', 'out_invoice', 'out_refund', 'in_refund'))]} + name="invisible" + >move_type not in ['in_invoice', 'out_invoice', 'out_refund', 'in_refund'] - {'required': [('thirdparty_invoice', '=', True)], 'invisible': [('thirdparty_invoice', '=', False)]} + thirdparty_invoice + not thirdparty_invoice - + - + - + - + @@ -140,13 +124,13 @@ groups="base.group_no_one" > - - + - - + @@ -165,18 +149,18 @@ @@ -193,32 +177,32 @@ @@ -229,8 +213,8 @@ diff --git a/l10n_es_aeat_sii_oca/views/aeat_sii_map_view.xml b/l10n_es_aeat_sii_oca/views/aeat_sii_map_view.xml index 111a02c793c..43a02d03b7a 100644 --- a/l10n_es_aeat_sii_oca/views/aeat_sii_map_view.xml +++ b/l10n_es_aeat_sii_oca/views/aeat_sii_map_view.xml @@ -52,7 +52,7 @@ - + diff --git a/l10n_es_aeat_sii_oca/views/queue_job_views.xml b/l10n_es_aeat_sii_oca/views/ir_cron_trigger_views.xml similarity index 58% rename from l10n_es_aeat_sii_oca/views/queue_job_views.xml rename to l10n_es_aeat_sii_oca/views/ir_cron_trigger_views.xml index ed9b89fe6e5..5eb8de7ad5c 100644 --- a/l10n_es_aeat_sii_oca/views/queue_job_views.xml +++ b/l10n_es_aeat_sii_oca/views/ir_cron_trigger_views.xml @@ -2,35 +2,30 @@ - - queue.job + + ir.cron.trigger - - - - + +