diff --git a/README.md b/README.md index c5a5ead17..300bc3a5b 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ Available addons addon | version | maintainers | summary --- | --- | --- | --- [edi_component_oca](edi_component_oca/) | 19.0.1.1.0 | simahawk etobella | Allow to use Connector as a source in EDI -[edi_core_oca](edi_core_oca/) | 19.0.1.2.0 | simahawk etobella | Define backends, exchange types, exchange records, basic automation and views for handling EDI exchanges. +[edi_core_oca](edi_core_oca/) | 19.0.1.2.1 | simahawk etobella | Define backends, exchange types, exchange records, basic automation and views for handling EDI exchanges. [edi_endpoint_oca](edi_endpoint_oca/) | 19.0.1.1.1 | | Base module allowing configuration of custom endpoints for EDI framework. [edi_product_oca](edi_product_oca/) | 19.0.1.0.0 | | EDI framework configuration and base logic for products and units of measure [edi_purchase_oca](edi_purchase_oca/) | 19.0.1.0.0 | | Define EDI Configuration for Purchase Orders diff --git a/edi_core_oca/README.rst b/edi_core_oca/README.rst index dfe98e764..c1bd89935 100644 --- a/edi_core_oca/README.rst +++ b/edi_core_oca/README.rst @@ -11,7 +11,7 @@ EDI !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:46139d4cc31684944b8784e2503633ab59a96d8b072b42ee5ab30cd8f2177930 + !! source digest: sha256:de90b9bf70f5e4c8e52326e5549c47a2a3d9b91843ffb0a101d442d6fce3f8c3 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png diff --git a/edi_core_oca/__manifest__.py b/edi_core_oca/__manifest__.py index 5496b6981..7537474e2 100644 --- a/edi_core_oca/__manifest__.py +++ b/edi_core_oca/__manifest__.py @@ -9,7 +9,7 @@ Define backends, exchange types, exchange records, basic automation and views for handling EDI exchanges. """, - "version": "19.0.1.2.0", + "version": "19.0.1.2.1", "website": "https://github.com/OCA/edi-framework", "development_status": "Beta", "license": "LGPL-3", diff --git a/edi_core_oca/i18n/it.po b/edi_core_oca/i18n/it.po index 86758cb0d..b039537a1 100644 --- a/edi_core_oca/i18n/it.po +++ b/edi_core_oca/i18n/it.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: Odoo Server 17.0\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2026-05-25 22:46+0000\n" +"PO-Revision-Date: 2026-06-05 09:46+0000\n" "Last-Translator: mymage \n" "Language-Team: none\n" "Language: it\n" @@ -157,7 +157,7 @@ msgstr "" #. module: edi_core_oca #: model:ir.model.fields,field_description:edi_core_oca.field_edi_exchange_type__exchange_record_count msgid "# Exchange Records" -msgstr "" +msgstr "N° record scambio" #. module: edi_core_oca #: model_terms:ir.ui.view,arch_db:edi_core_oca.edi_exchange_consumer_mixin_buttons @@ -319,7 +319,7 @@ msgstr "Applica a questo modello" #. module: edi_core_oca #: model:ir.actions.server,name:edi_core_oca.ir_cron_archive_old_edi_records_ir_actions_server msgid "Archive Old EDI Exchange Records" -msgstr "" +msgstr "Archivia i vecchi record EDI" #. module: edi_core_oca #: model_terms:ir.ui.view,arch_db:edi_core_oca.edi_backend_view_form @@ -352,12 +352,12 @@ msgstr "" #. module: edi_core_oca #: model:ir.model.fields,field_description:edi_core_oca.field_edi_backend__auto_archive_records_after_days msgid "Auto-archive records after (days)" -msgstr "" +msgstr "Auto archivia i record dopo (giorni)" #. module: edi_core_oca #: model:ir.model.fields,field_description:edi_core_oca.field_edi_backend__auto_delete_records_after_days msgid "Auto-delete archived records after (days)" -msgstr "" +msgstr "Auto cancella i record archiviati dopo (giorni)" #. module: edi_core_oca #: model:ir.model.fields,help:edi_core_oca.field_edi_backend__auto_archive_records_after_days @@ -365,6 +365,8 @@ msgid "" "Automatically archive EDI exchange records after X days. Set to <= 0 to " "disable auto-archiving." msgstr "" +"Archivia automaticamente i record di scambio EDI dopo X giorni. Impostare " +"inferiore o uguale a 0 per disabilitare l'auto archiviazione." #. module: edi_core_oca #: model:ir.model.fields,help:edi_core_oca.field_edi_backend__auto_delete_records_after_days @@ -372,6 +374,8 @@ msgid "" "Automatically delete archived EDI exchange records after X days. Set to <= 0 " "to disable auto-deletion." msgstr "" +"Cancella automaticamente i record di scambio EDI archiviati dopo X giorni. " +"Impostare inferiore o uguale a 0 per disabilitare l'auto cancellazione." #. module: edi_core_oca #: model:ir.model.fields,field_description:edi_core_oca.field_edi_configuration__backend_id @@ -528,7 +532,7 @@ msgstr "Gestore errore decodifica" #. module: edi_core_oca #: model:ir.actions.server,name:edi_core_oca.ir_cron_delete_old_archived_edi_records_ir_actions_server msgid "Delete Old Archived EDI Exchange Records" -msgstr "" +msgstr "Cancella i vecchi record di scambio EDI archiviati" #. module: edi_core_oca #: model:ir.model.fields,help:edi_core_oca.field_edi_configuration__description @@ -1547,7 +1551,7 @@ msgstr "Record ID=%d non è previsto che sia inviato!" #. module: edi_core_oca #: model_terms:ir.ui.view,arch_db:edi_core_oca.edi_backend_view_form msgid "Records retention" -msgstr "" +msgstr "Cancellazione record" #. module: edi_core_oca #: model_terms:ir.ui.view,arch_db:edi_core_oca.edi_exchange_record_view_form @@ -1808,6 +1812,10 @@ msgid "" "waiting for the cron to pass by. Requires auto generate flag to be active as " "well. The cron will skip these records unless forced." msgstr "" +"Quando attivi, i record di questo tipo verranno elaborati immediatamente, " +"senza attendere il completamento del cron. Richiede che anche il flag di " +"generazione automatica sia attivo. Il cron ignorerà questi record, a meno " +"che non venga forzato." #. module: edi_core_oca #: model:ir.model.fields,help:edi_core_oca.field_edi_exchange_consumer_mixin__edi_disable_auto diff --git a/edi_core_oca/models/edi_backend.py b/edi_core_oca/models/edi_backend.py index 6a065ae34..0f004b822 100644 --- a/edi_core_oca/models/edi_backend.py +++ b/edi_core_oca/models/edi_backend.py @@ -121,6 +121,7 @@ def exchange_generate(self, exchange_record, store=True, force=False, **kw): :param kw: keyword args to be propagated to output generate handler """ self.ensure_one() + old_state = exchange_record.edi_exchange_state if force and exchange_record.exchange_file: # Remove file to regenerate exchange_record.exchange_file = False @@ -148,7 +149,6 @@ def exchange_generate(self, exchange_record, store=True, force=False, **kw): traceback = _get_exception_traceback() error = _get_exception_msg(err) state = "validate_error" - message = exchange_record._exchange_status_message("validate_ko") exchange_record.update( { "edi_exchange_state": state, @@ -156,6 +156,15 @@ def exchange_generate(self, exchange_record, store=True, force=False, **kw): "exchange_error_traceback": traceback, } ) + if old_state != state: + exchange_record._notify_error("validate_ko") + # At this point `message` still holds the "generate_ok" success + # text set before validation ran. Generation succeeded but + # validation failed, so clear it: `_notify_error` has already + # posted the validation error (and fired the error event), and + # we must not let `notify_action_complete` below post the stale + # success message on top of it. + message = None exchange_record.notify_action_complete("generate", message=message) return message @@ -228,7 +237,7 @@ def exchange_send(self, exchange_record): check = self._output_check_send(exchange_record) if not check: return self._failed_output_check_send_msg() - state = exchange_record.edi_exchange_state + old_state = state = exchange_record.edi_exchange_state error = traceback = False message = None res = "" @@ -248,7 +257,6 @@ def exchange_send(self, exchange_record): traceback = _get_exception_traceback() error = _get_exception_msg(err) state = "output_error_on_send" - message = exchange_record._exchange_status_message("send_ko") res = f"Error: {error}" _logger.debug( "%s send failed. Marked as errored.", exchange_record.identifier @@ -281,6 +289,8 @@ def exchange_send(self, exchange_record): "exchanged_on": fields.Datetime.now(), } ) + if old_state != state and state == "output_error_on_send": + exchange_record._notify_error("send_ko") exchange_record.notify_action_complete("send", message=message) return res @@ -514,7 +524,7 @@ def exchange_receive(self, exchange_record): check = self._exchange_receive_check(exchange_record) if not check: return "Nothing to do. Likely already received." - state = exchange_record.edi_exchange_state + old_state = state = exchange_record.edi_exchange_state error = traceback = False message = None content = None @@ -528,7 +538,6 @@ def exchange_receive(self, exchange_record): traceback = _get_exception_traceback() error = _get_exception_msg(err) state = "validate_error" - message = exchange_record._exchange_status_message("validate_ko") res = f"Validation error: {error}" except self._swallable_exceptions() as err: if self.env.context.get("_edi_receive_break_on_error"): @@ -536,7 +545,6 @@ def exchange_receive(self, exchange_record): traceback = _get_exception_traceback() error = _get_exception_msg(err) state = "input_receive_error" - message = exchange_record._exchange_status_message("receive_ko") res = f"Input error: {error}" except (OperationalError, IntegrityError): # We don't want the finally block to be executed in this case as @@ -561,6 +569,10 @@ def exchange_receive(self, exchange_record): "exchanged_on": fields.Datetime.now(), } ) + if old_state != state and state == "input_receive_error": + exchange_record._notify_error("receive_ko") + if old_state != state and state == "validate_error": + exchange_record._notify_error("validate_ko") exchange_record.notify_action_complete("receive", message=message) return res diff --git a/edi_core_oca/static/description/index.html b/edi_core_oca/static/description/index.html index 03d5c155b..b06702882 100644 --- a/edi_core_oca/static/description/index.html +++ b/edi_core_oca/static/description/index.html @@ -372,7 +372,7 @@

EDI

!! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!! source digest: sha256:46139d4cc31684944b8784e2503633ab59a96d8b072b42ee5ab30cd8f2177930 +!! source digest: sha256:de90b9bf70f5e4c8e52326e5549c47a2a3d9b91843ffb0a101d442d6fce3f8c3 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->

Beta License: LGPL-3 OCA/edi-framework Translate me on Weblate Try me on Runboat

Base EDI backend.

diff --git a/edi_core_oca/tests/common.py b/edi_core_oca/tests/common.py index fe9bdb9d1..8f74be261 100644 --- a/edi_core_oca/tests/common.py +++ b/edi_core_oca/tests/common.py @@ -100,3 +100,26 @@ def setUpClass(cls): super().setUpClass() cls._setup_env() cls._setup_records() + + def _make_global_error_conf(self, exchange_type): + """Register a global ``edi.configuration`` bound to the + ``on_edi_exchange_error`` event. + + Its snippet writes a marker on the configuration so a test can assert + the error event actually fired. This is the observable behaviour that + distinguishes an errored exchange (which must notify, e.g. create the + activities handled by ``edi_notification_oca``) from one that merely + posts a chatter message via ``notify_action_complete``. + """ + trigger = self.env.ref("edi_core_oca.edi_config_trigger_record_error") + return self.env["edi.configuration"].create( + { + "name": "Test notify on error", + "active": True, + "backend_id": self.backend.id, + "type_id": exchange_type.id, + "trigger_id": trigger.id, + "is_global": True, + "snippet_do": "conf.write({'description': 'error-event-fired'})", + } + ) diff --git a/edi_core_oca/tests/test_backend_input.py b/edi_core_oca/tests/test_backend_input.py index 44065c927..eb9a04752 100644 --- a/edi_core_oca/tests/test_backend_input.py +++ b/edi_core_oca/tests/test_backend_input.py @@ -77,6 +77,16 @@ def test_receive_no_allow_empty_file_record(self): self.record, [{"edi_exchange_state": "input_receive_error"}] ) + def test_receive_no_allow_empty_file_triggers_notify_error(self): + self.record.edi_exchange_state = "input_pending" + conf = self._make_global_error_conf(self.record.type_id) + self.backend.with_context( + fake_output="", _edi_receive_break_on_error=False + ).exchange_receive(self.record) + # The error event must fire so downstream notifications (e.g. + # edi_notification_oca activities) are triggered. + self.assertEqual(conf.description, "error-event-fired") + def test_receive_allow_empty_file_record(self): self.record.edi_exchange_state = "input_pending" self.record.type_id.allow_empty_files_on_receive = True diff --git a/edi_core_oca/tests/test_backend_output.py b/edi_core_oca/tests/test_backend_output.py index 39f2d57a8..2b5ea7d41 100644 --- a/edi_core_oca/tests/test_backend_output.py +++ b/edi_core_oca/tests/test_backend_output.py @@ -100,6 +100,17 @@ def test_send_record_with_error(self): "OOPS! Something went wrong :(", self.record.exchange_error_traceback ) + def test_send_record_with_error_triggers_notify_error(self): + self.record.write({"edi_exchange_state": "output_pending"}) + self.record._set_file_content(f"TEST {self.record.id}") + conf = self._make_global_error_conf(self.record.type_id) + self.record.with_context( + test_break_send="OOPS! Something went wrong :(" + ).action_exchange_send() + # The error event must fire so downstream notifications (e.g. + # edi_notification_oca activities) are triggered. + self.assertEqual(conf.description, "error-event-fired") + def test_send_invalid_direction(self): vals = { "model": self.partner._name, diff --git a/edi_core_oca/tests/test_backend_validate.py b/edi_core_oca/tests/test_backend_validate.py index d3c585f8b..3c082e454 100644 --- a/edi_core_oca/tests/test_backend_validate.py +++ b/edi_core_oca/tests/test_backend_validate.py @@ -85,6 +85,17 @@ def test_receive_validate_record_error(self): ) self.assertIn("Data seems wrong!", self.record_in.exchange_error_traceback) + def test_receive_validate_record_error_triggers_notify_error(self): + self.record_in.write({"edi_exchange_state": "input_pending"}) + exc = EDIValidationError("Data seems wrong!") + conf = self._make_global_error_conf(self.record_in.type_id) + self.backend.with_context(test_break_input_validate=exc).exchange_receive( + self.record_in + ) + # The error event must fire so downstream notifications (e.g. + # edi_notification_oca activities) are triggered. + self.assertEqual(conf.description, "error-event-fired") + def test_generate_validate_record(self): self.record_out.write({"edi_exchange_state": "new"}) self.backend.exchange_generate(self.record_out) @@ -119,6 +130,17 @@ def test_generate_validate_record_error(self): ) self.assertIn("Data seems wrong!", self.record_out.exchange_error_traceback) + def test_generate_validate_record_error_triggers_notify_error(self): + self.record_out.write({"edi_exchange_state": "new"}) + exc = EDIValidationError("Data seems wrong!") + conf = self._make_global_error_conf(self.record_out.type_id) + self.backend.with_context(test_break_output_validate=exc).exchange_generate( + self.record_out + ) + # The error event must fire so downstream notifications (e.g. + # edi_notification_oca activities) are triggered. + self.assertEqual(conf.description, "error-event-fired") + def test_validate_record_error_regenerate(self): self.record_out.write({"edi_exchange_state": "new"}) exc = EDIValidationError("Data seems wrong!") diff --git a/edi_endpoint_oca/i18n/it.po b/edi_endpoint_oca/i18n/it.po index 18eeab1e1..aaa9dda9e 100644 --- a/edi_endpoint_oca/i18n/it.po +++ b/edi_endpoint_oca/i18n/it.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: Odoo Server 16.0\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2026-05-25 22:46+0000\n" +"PO-Revision-Date: 2026-06-05 09:46+0000\n" "Last-Translator: mymage \n" "Language-Team: none\n" "Language: it\n" @@ -71,7 +71,7 @@ msgstr "Documenti esempio codice" #. module: edi_endpoint_oca #: model:ir.model.fields,help:edi_endpoint_oca.field_edi_endpoint__cors msgid "Comma-separated list of allowed origins" -msgstr "" +msgstr "Elenco separato da virgola delle origini consentite" #. module: edi_endpoint_oca #: model:ir.model.fields,field_description:edi_endpoint_oca.field_edi_endpoint__company_id @@ -81,7 +81,7 @@ msgstr "Azienda" #. module: edi_endpoint_oca #: model:ir.model.fields,field_description:edi_endpoint_oca.field_edi_endpoint__cors msgid "Cors" -msgstr "" +msgstr "Cors" #. module: edi_endpoint_oca #. odoo-python