From 72c84e2e9db690e8120d8402813f2b8d22a2b7aa Mon Sep 17 00:00:00 2001 From: Aritz Olea Date: Tue, 25 Feb 2025 11:35:51 +0100 Subject: [PATCH] [FIX] l10n_es_aeat_verifactu_pos: Adapt module to chain on create and pre-commit stuff --- .../models/account_move.py | 16 ++++- .../models/pos_order.py | 60 +++++++++++-------- .../tests/test_l10n_es_aeat_verifactu_pos.py | 14 ++++- 3 files changed, 61 insertions(+), 29 deletions(-) diff --git a/l10n_es_aeat_verifactu_pos/models/account_move.py b/l10n_es_aeat_verifactu_pos/models/account_move.py index f9185019b3e..6bd039faaae 100644 --- a/l10n_es_aeat_verifactu_pos/models/account_move.py +++ b/l10n_es_aeat_verifactu_pos/models/account_move.py @@ -4,13 +4,27 @@ class AccountMove(models.Model): _inherit = "account.move" - def _get_chaining_invoice_dict(self): + def _set_chaining_invoice(self): """PoS Config has a different chain for VERI*FACTU""" if self.pos_order_ids and len(self.pos_order_ids.ids) == 1: # TODO: use cases # * The Invoice is created from the PoS # * The Invoice is created later after some time, in this case # the PoS order (simplified invoice) is already in the chain + pos_order = self.pos_order_ids + if not pos_order.verifactu_previous_invoice_id: + return pos_order._set_chaining_invoice() + elif len(self.pos_order_ids) > 1: + # TODO: is possible to have multiple PoS orders for the same Invoice? + raise exceptions.UserError( + _("VERI*FACTU: multiple PoS Orders not supported") + ) + else: + return super()._set_chaining_invoice() + + def _get_chaining_invoice_dict(self): + """Get the chaining invoice dictionary for POS orders""" + if self.pos_order_ids and len(self.pos_order_ids.ids) == 1: pos_order = self.pos_order_ids return pos_order._get_chaining_invoice_dict() elif len(self.pos_order_ids) > 1: diff --git a/l10n_es_aeat_verifactu_pos/models/pos_order.py b/l10n_es_aeat_verifactu_pos/models/pos_order.py index 2ff79a60d36..eaee76bd20e 100644 --- a/l10n_es_aeat_verifactu_pos/models/pos_order.py +++ b/l10n_es_aeat_verifactu_pos/models/pos_order.py @@ -55,7 +55,7 @@ def _process_order(self, order, draft, existing_order): pos_order_id = super()._process_order(order, draft, existing_order) pos_order = self.env["pos.order"].browse(pos_order_id) - if not self._should_send_to_verifactu(pos_order): + if not self._is_verifactu_order(pos_order): return pos_order_id # TODO: review retry strategy @@ -63,7 +63,7 @@ def _process_order(self, order, draft, existing_order): # from the same PoS Config for attempt in range(SEND_TO_VERIFACTU_MAX_RETRIES): try: - pos_order.send_verifactu() + pos_order._set_chaining_invoice() break except OperationalError: if attempt == SEND_TO_VERIFACTU_MAX_RETRIES - 1: @@ -76,16 +76,26 @@ def _process_order(self, order, draft, existing_order): pos_order.id, SEND_TO_VERIFACTU_MAX_RETRIES, ) + raise else: sleep(1) # Wait 1 second before next try + + if self._should_send_to_verifactu(pos_order): + pos_order.send_verifactu() + return pos_order_id - def _should_send_to_verifactu(self, pos_order): + def _is_verifactu_order(self, pos_order): return ( - not config["test_enable"] - and pos_order.exists() + pos_order.exists() and not pos_order.to_invoice and pos_order.verifactu_enabled + ) + + def _should_send_to_verifactu(self, pos_order): + return ( + self._is_verifactu_order(pos_order) + and not config["test_enable"] and pos_order.state in VERIFACTU_VALID_POS_STATES ) @@ -204,9 +214,9 @@ def _get_verifactu_invoice_dict_out(self, cancel=False): registroAlta.setdefault("RegistroAlta", inv_dict) return registroAlta - def _get_chaining_invoice_dict(self): - """Get the chaining invoice dictionary for POS orders""" - inv_dict = {} + def _set_chaining_invoice(self): + """Set the chaining order""" + prev_order = False try: self.config_id.flush_model(["verifactu_last_invoice_id"]) self._cr.execute( @@ -218,22 +228,6 @@ def _get_chaining_invoice_dict(self): prev_order = self.env["pos.order"].browse(result[0]) if result else False if prev_order and prev_order.exists(): self.verifactu_previous_invoice_id = prev_order - if prev_order.is_invoiced and prev_order.account_move.exists(): - prev_inv = prev_order.account_move - else: - prev_inv = prev_order - inv_dict = { - "RegistroAnterior": { - "IDEmisorFactura": prev_inv._get_verifactu_issuer(), - "NumSerieFactura": prev_inv._get_document_serial_number(), - "FechaExpedicionFactura": prev_inv._change_date_format( - prev_inv._get_document_date() - ), - "Huella": prev_inv.verifactu_hash, - } - } - else: - inv_dict = {"PrimerRegistro": "S"} self._cr.execute( "UPDATE pos_config SET verifactu_last_invoice_id = %s WHERE id = %s", (self.id, self.config_id.id), @@ -248,7 +242,23 @@ def _get_chaining_invoice_dict(self): self.id, ) raise - return inv_dict + return prev_order + + def _get_chaining_invoice_dict(self): + """Get the chaining invoice dictionary for POS orders""" + if self.verifactu_previous_invoice_id: + prev_order = self.verifactu_previous_invoice_id + return { + "RegistroAnterior": { + "IDEmisorFactura": prev_order._get_verifactu_issuer(), + "NumSerieFactura": prev_order._get_document_serial_number(), + "FechaExpedicionFactura": prev_order._change_date_format( + prev_order._get_document_date() + ), + "Huella": prev_order.verifactu_hash, + } + } + return {"PrimerRegistro": "S"} def _get_verifactu_taxes_and_total(self): """Get the tax breakdown for Verifactu from POS order lines. diff --git a/l10n_es_aeat_verifactu_pos/tests/test_l10n_es_aeat_verifactu_pos.py b/l10n_es_aeat_verifactu_pos/tests/test_l10n_es_aeat_verifactu_pos.py index c127788a85e..963a2fa0277 100644 --- a/l10n_es_aeat_verifactu_pos/tests/test_l10n_es_aeat_verifactu_pos.py +++ b/l10n_es_aeat_verifactu_pos/tests/test_l10n_es_aeat_verifactu_pos.py @@ -331,14 +331,14 @@ def mock_execute(*args, **kwargs): second_order_data["data"]["name"] = "Order 0002" second_order_data["data"]["uid"] = str(uuid.uuid4()) # New unique ID second_order_data["id"] = second_order_data["data"]["uid"] - second_order_ids = self.env["pos.order"].create_from_ui([second_order_data]) - second_order = self.env["pos.order"].browse(second_order_ids[0]["id"]) old_execute = self.cr.execute with self.assertRaises(OperationalError): with self.cr.savepoint(): self.cr.execute = mock_execute - second_order._get_chaining_invoice_dict() + second_order_ids = self.env["pos.order"].create_from_ui( + [second_order_data] + ) self.cr.execute = old_execute self.assertEqual( @@ -347,6 +347,14 @@ def mock_execute(*args, **kwargs): "Should not update config's last order reference on error", ) + second_order_ids = self.env["pos.order"].create_from_ui([second_order_data]) + second_order = self.env["pos.order"].browse(second_order_ids[0]["id"]) + self.assertEqual( + self.pos_config.verifactu_last_invoice_id.id, + second_order.id, + "Should have updates config's last order to second_order", + ) + def test_verifactu_chaining_invoiced_pos_order(self): """Test that invoiced POS orders are added to POS config chain""" orders_data = [self._create_ui_order_data()]