diff --git a/edi_oca/models/edi_exchange_record.py b/edi_oca/models/edi_exchange_record.py index 419e425b3..5a7949182 100644 --- a/edi_oca/models/edi_exchange_record.py +++ b/edi_oca/models/edi_exchange_record.py @@ -488,7 +488,7 @@ def notify_action_complete(self, action, message=None): Implementers can hook to this method to do something after any action ends. """ if message: - self._notify_related_record(message) + self._notify_related_record(message, action=action) # Trigger generic action complete event on exchange record event_name = f"{action}_complete" @@ -497,8 +497,14 @@ def notify_action_complete(self, action, message=None): # Trigger specific event on related record self._trigger_edi_event(event_name, target=self.record) - def _notify_related_record(self, message, level="info"): - """Post notification on the original records.""" + def _notify_related_record(self, message, level="info", action=None): + """Post notification on the original records. + + When `action` is given, the related-record note is gated by the exchange + type's `notify_related_record_on_` toggle; `action=None` always posts. + """ + if action and not self.type_id._notify_related_record_on(action): + return for rec in self.related_record_ids: rec._notify_related_record(message, level) @@ -515,13 +521,16 @@ def _trigger_edi_event(self, name, suffix=None, target=None, **kw): target._event(name).notify(self, **kw) def _notify_done(self): - self._notify_related_record(self._exchange_status_message("process_ok")) + self._notify_related_record( + self._exchange_status_message("process_ok"), action="process" + ) self._trigger_edi_event("done") def _notify_error(self, message_key): self._notify_related_record( self._exchange_status_message(message_key), level="error", + action="process", ) self._trigger_edi_event("error") diff --git a/edi_oca/models/edi_exchange_type.py b/edi_oca/models/edi_exchange_type.py index 56fa5d48f..afdbd017f 100644 --- a/edi_oca/models/edi_exchange_type.py +++ b/edi_oca/models/edi_exchange_type.py @@ -185,6 +185,26 @@ class EDIExchangeType(models.Model): "(default is always 'Raise Error').", ) allow_empty_files_on_receive = fields.Boolean(string="Allow Empty Files") + notify_related_record_on_generate = fields.Boolean( + string="Notify related record on generate", + default=True, + help="Post a note on the related record when the exchange is generated.", + ) + notify_related_record_on_send = fields.Boolean( + string="Notify related record on send", + default=True, + help="Post a note on the related record when the exchange is sent.", + ) + notify_related_record_on_process = fields.Boolean( + string="Notify related record on process", + default=True, + help="Post a note on the related record when the exchange is processed.", + ) + notify_related_record_on_receive = fields.Boolean( + string="Notify related record on receive", + default=True, + help="Post a note on the related record when the exchange is received.", + ) _sql_constraints = [ ( @@ -286,6 +306,18 @@ def _get_record_name(self, exchange_record): return exchange_record.record._get_edi_exchange_record_name(exchange_record) return slugify(exchange_record.record.display_name) + def _notify_related_record_on(self, action): + """Whether a chatter note should be posted on the related record. + + Gated per stage via the `notify_related_record_on_*` toggles. Actions without a + dedicated toggle (e.g. `ack`) keep notifying to preserve legacy behavior. + """ + self.ensure_one() + field_name = "notify_related_record_on_%s" % action + if field_name not in self._fields: + return True + return self[field_name] + def is_partner_enabled(self, partner): """Check if given partner record is allowed for the current type. diff --git a/edi_oca/tests/test_backend_output.py b/edi_oca/tests/test_backend_output.py index acf521032..6650abdff 100644 --- a/edi_oca/tests/test_backend_output.py +++ b/edi_oca/tests/test_backend_output.py @@ -109,6 +109,25 @@ def test_send_not_generated_record(self): ) mocked.assert_not_called() + def test_notify_related_record_on_generate_default(self): + before = len(self.partner.message_ids) + self.record.with_context(fake_output="yeah!").action_exchange_generate() + messages = self.partner.message_ids + self.assertEqual(len(messages) - before, 1) + self.assertIn("Exchange data generated", messages[:1].body) + + def test_notify_related_record_on_generate_disabled(self): + self.record.type_id.notify_related_record_on_generate = False + before = len(self.partner.message_ids) + self.record.with_context(fake_output="yeah!").action_exchange_generate() + # Generate no longer posts a note on the related record... + self.assertEqual(len(self.partner.message_ids), before) + # ...but send still does. + self.record.action_exchange_send() + messages = self.partner.message_ids + self.assertEqual(len(messages) - before, 1) + self.assertIn("Exchange sent", messages[:1].body) + class EDIBackendTestOutputJobsCase(EDIBackendCommonComponentRegistryTestCase): @classmethod diff --git a/edi_oca/views/edi_exchange_type_views.xml b/edi_oca/views/edi_exchange_type_views.xml index 99d08a88d..a27d2c6d2 100644 --- a/edi_oca/views/edi_exchange_type_views.xml +++ b/edi_oca/views/edi_exchange_type_views.xml @@ -39,32 +39,66 @@ - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +