[FIX] base_automation: allow multiple automation rules for same trigger

Steps to reproduce:
- Install base_automation_hr_contract and helpdesk
- Setup two automation rules with model "Helpdesk Ticket" and "On
  incoming message" as trigger
- Create a ticket in helpdesk

Issues:
Traceback is shown because `_message_post` doesn't have the origin
attributes. This is due to the closure being wrong as explained here: https://github.com/odoo/odoo/blob/e2ad568e6cd4de2d721149eb76d04f58c8510191/addons/base_automation/models/base_automation.py#L686-L691

Solution:
Encapsulate the `_message_post` function definition, so that each times
we patch message_post we patch it with a new function.
This wasn't the case before since `_message_post` wasn't isolated.
This solution is similar to the other method patched.
https://github.com/odoo/odoo/blob/e2ad568e6cd4de2d721149eb76d04f58c8510191/addons/base_automation/models/base_automation.py#L711-L734

opw-3758851

closes odoo/odoo#155596

Signed-off-by: Raphael Collet <rco@odoo.com>
This commit is contained in:
Mattis Megevand (mmeg)
2024-03-06 14:30:38 +00:00
parent d387f3d0d5
commit 5fc24f84ea
2 changed files with 51 additions and 21 deletions
@@ -810,6 +810,28 @@ class BaseAutomation(models.Model):
return base_automation_onchange
def make_message_post():
def _message_post(self, *args, **kwargs):
message = _message_post.origin(self, *args, **kwargs)
# Don't execute automations for a message emitted during
# the run of automations for a real message
# Don't execute if we know already that a message is only internal
message_sudo = message.sudo().with_context(active_test=False)
if "__action_done" in self.env.context or message_sudo.is_internal or message_sudo.subtype_id.internal:
return message
if message_sudo.message_type in ('notification', 'auto_comment', 'user_notification'):
return message
# always execute actions when the author is a customer
mail_trigger = "on_message_received" if message_sudo.author_id.partner_share else "on_message_sent"
automations = self.env['base.automation']._get_actions(self, [mail_trigger])
for automation in automations.with_context(old_values=None):
records = automation._filter_pre(self)
automation._process(records)
return message
return _message_post
patched_models = defaultdict(set)
def patch(model, name, method):
@@ -853,27 +875,7 @@ class BaseAutomation(models.Model):
self.env.registry.clear_cache('templates')
if automation_rule.model_id.is_mail_thread and automation_rule.trigger in MAIL_TRIGGERS:
def _message_post(self, *args, **kwargs):
message = _message_post.origin(self, *args, **kwargs)
# Don't execute automations for a message emitted during
# the run of automations for a real message
# Don't execute if we know already that a message is only internal
message_sudo = message.sudo().with_context(active_test=False)
if "__action_done" in self.env.context or message_sudo.is_internal or message_sudo.subtype_id.internal:
return message
if message_sudo.message_type in ('notification', 'auto_comment', 'user_notification'):
return message
# always execute actions when the author is a customer
mail_trigger = "on_message_received" if message_sudo.author_id.partner_share else "on_message_sent"
automations = self.env['base.automation']._get_actions(self, [mail_trigger])
for automation in automations.with_context(old_values=None):
records = automation._filter_pre(self)
automation._process(records)
return message
patch(Model, "message_post", _message_post)
patch(Model, "message_post", make_message_post())
def _unregister_hook(self):
""" Remove the patches installed by _register_hook() """
@@ -1027,6 +1027,34 @@ class TestCompute(common.TransactionCase):
obj.message_post(author_id=ext_partner.id, subtype_xmlid="mail.mt_comment")
self.assertTrue(obj.active)
def test_multiple_mail_triggers(self):
lead_model = self.env["ir.model"]._get("base.automation.lead.test")
with self.assertRaises(ValidationError):
create_automation(self, trigger="on_message_sent", model_id=lead_model.id)
lead_thread_model = self.env["ir.model"]._get("base.automation.lead.thread.test")
create_automation(self, trigger="on_message_sent", model_id=lead_thread_model.id, _actions={
"state": "object_write",
"update_path": "active",
"update_boolean_value": "false"
})
create_automation(self, trigger="on_message_sent", model_id=lead_thread_model.id, _actions={
"state": "object_write",
"evaluation_type": "equation",
"update_path": "name",
"value": "record.name + '!'"
})
ext_partner = self.env["res.partner"].create({"name": "ext", "email": "email@server.com"})
internal_partner = self.env["res.users"].browse(2).partner_id
obj = self.env["base.automation.lead.thread.test"].create({"name": "test"})
obj.message_subscribe([ext_partner.id, internal_partner.id])
obj.message_post(author_id=internal_partner.id, message_type="comment", subtype_xmlid="mail.mt_comment")
self.assertFalse(obj.active)
self.assertEqual(obj.name, "test!")
@common.tagged("post_install", "-at_install")
class TestHttp(common.HttpCase):