From eb1ea7f0e022bc2d7cc3459135d98296fb7f4e46 Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Thu, 21 May 2026 21:33:11 +0200 Subject: [PATCH] [FIX] edi_core_oca: use savepoint to prevent state corruption on errors Some errors such as ValueError, FileNotFoundError, exceptions.UserError, exceptions.ValidationError, are caught, never re-raised, and the transaction is finally committed. Which means a UserError/ValidationError gets committed, leading to corruption of the processed data. --- edi_core_oca/models/edi_backend.py | 23 ++++++++++++++--------- edi_core_oca/tests/test_consumer_mixin.py | 8 +++++++- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/edi_core_oca/models/edi_backend.py b/edi_core_oca/models/edi_backend.py index 037ead3e9..de323684d 100644 --- a/edi_core_oca/models/edi_backend.py +++ b/edi_core_oca/models/edi_backend.py @@ -143,7 +143,8 @@ def exchange_generate(self, exchange_record, store=True, force=False, **kw): if output: message = exchange_record._exchange_status_message("generate_ok") try: - self._validate_data(exchange_record, output) + with self.env.cr.savepoint(): + self._validate_data(exchange_record, output) except EDIValidationError as err: traceback = _get_exception_traceback() error = _get_exception_msg(err) @@ -231,8 +232,9 @@ def exchange_send(self, exchange_record): message = None res = "" try: - self._exchange_send(exchange_record) - _logger.debug("%s sent", exchange_record.identifier) + with self.env.cr.savepoint(): + self._exchange_send(exchange_record) + _logger.debug("%s sent", exchange_record.identifier) except self._send_retryable_exceptions() as err: traceback = _get_exception_traceback() error = _get_exception_msg(err) @@ -459,7 +461,8 @@ def exchange_process(self, exchange_record): message = None res = None try: - res = self._exchange_process(exchange_record) + with self.env.cr.savepoint(): + res = self._exchange_process(exchange_record) except self._swallable_exceptions() as err: if self.env.context.get("_edi_process_break_on_error"): raise @@ -515,12 +518,14 @@ def exchange_receive(self, exchange_record): error = traceback = False message = None content = None + res = None try: - content = self._exchange_receive(exchange_record) - # Ignore result of FileNotFoundError/OSError - if content is not None: - exchange_record._set_file_content(content) - self._validate_data(exchange_record) + with self.env.cr.savepoint(): + content = self._exchange_receive(exchange_record) + # Ignore result of FileNotFoundError/OSError + if content is not None: + exchange_record._set_file_content(content) + self._validate_data(exchange_record) except EDIValidationError as err: traceback = _get_exception_traceback() error = _get_exception_msg(err) diff --git a/edi_core_oca/tests/test_consumer_mixin.py b/edi_core_oca/tests/test_consumer_mixin.py index b078aff4e..b5c508c45 100644 --- a/edi_core_oca/tests/test_consumer_mixin.py +++ b/edi_core_oca/tests/test_consumer_mixin.py @@ -29,6 +29,9 @@ def setUp(self): self.consumer_record = self.env["edi.exchange.consumer.test"].create( {"name": "Test Consumer"} ) + self.exchange_type_in.exchange_filename_pattern = ( + "{record_name}-{type.code}-{dt}" + ) self.exchange_type_out.exchange_filename_pattern = "{record.id}" rule_vals = { @@ -46,7 +49,7 @@ def setUp(self): direction="output", exchange_file_ext="csv", backend_id=False, - exchange_filename_pattern="{record.ref}-{type.code}-{dt}", + exchange_filename_pattern="{record_name}-{type.code}-{dt}", rule_ids=[(0, 0, rule_vals)], ) rule_vals = { @@ -249,6 +252,9 @@ def test_edi_send_via_edi_invalid_ack( "model": self.consumer_record._name, "res_id": self.consumer_record.id, } + self.exchange_type_in.exchange_filename_pattern = ( + "{record_name}-{type.code}-{dt}" + ) origin_exchange_record = self.backend.create_record( self.exchange_type_in.code, vals )