From 381127248279b0246e92a52d5c1df5fd4050c3f0 Mon Sep 17 00:00:00 2001 From: Jairo Llopis Date: Mon, 3 Jun 2024 14:40:32 +0100 Subject: [PATCH] [FIX] mail_post_defer: notify from non-thread models and to author In some places of Odoo, there are direct calls to `self.env["mail.thread"].message_notify()` where the target model isn't extending `mail.thread`. These cases were failing, due to the grouping done by `mail.message.schedule`. In some of those cases, mails were sent with the special `mail_notify_author=True` context, which got lost after the deferring step. In those cases, if the author's message was expected to arrive at the author's inbox, it wouldn't happen anymore. @moduon MT-6337 --- .../models/mail_message_schedule.py | 11 ++++++ mail_post_defer/models/mail_thread.py | 13 +++++-- mail_post_defer/tests/test_mail.py | 34 +++++++++++++++++++ 3 files changed, 56 insertions(+), 2 deletions(-) diff --git a/mail_post_defer/models/mail_message_schedule.py b/mail_post_defer/models/mail_message_schedule.py index eba9a0340..1adf977b8 100644 --- a/mail_post_defer/models/mail_message_schedule.py +++ b/mail_post_defer/models/mail_message_schedule.py @@ -13,3 +13,14 @@ class MailMessageSchedule(models.Model): return super(MailMessageSchedule, _self)._send_notifications( default_notify_kwargs=default_notify_kwargs ) + + def _group_by_model(self): + """Make sure only mail.thread children are grouped with model.""" + result = super()._group_by_model() + for model, records in result.copy().items(): + # Move records without mail.thread mixin to a False key + if model and not hasattr(model, "_notify_thread"): + result.pop(model) + result.setdefault(False, self.browse()) + result[False] += records + return result diff --git a/mail_post_defer/models/mail_thread.py b/mail_post_defer/models/mail_thread.py index bb657c5b2..20c7737bd 100644 --- a/mail_post_defer/models/mail_thread.py +++ b/mail_post_defer/models/mail_thread.py @@ -1,4 +1,4 @@ -# Copyright 2022-2023 Moduon Team S.L. +# Copyright 2022-2024 Moduon Team S.L. # License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl). from datetime import datetime, timedelta @@ -12,7 +12,15 @@ class MailThread(models.AbstractModel): def _notify_thread(self, message, msg_vals=False, **kwargs): """Defer emails by default.""" - _self = self + # Remember if the author should be notified when deferring + kwargs.setdefault( + "mail_post_defer_notify_author", + self.env.context.get("mail_notify_author", False), + ) + _self = self.with_context( + mail_notify_author=kwargs["mail_post_defer_notify_author"] + ) + # Don't defer automatically if forcing send if "mail_defer_seconds" not in _self.env.context: force_send = _self.env.context.get("mail_notify_force_send") or kwargs.get( "force_send", False @@ -21,6 +29,7 @@ class MailThread(models.AbstractModel): if not force_send: # If deferring message, give the user some minimal time to revert it _self = _self.with_context(mail_defer_seconds=30) + # Apply deferring defer_seconds = _self.env.context.get("mail_defer_seconds") if defer_seconds: kwargs.setdefault( diff --git a/mail_post_defer/tests/test_mail.py b/mail_post_defer/tests/test_mail.py index 3d717feb4..84a87fd09 100644 --- a/mail_post_defer/tests/test_mail.py +++ b/mail_post_defer/tests/test_mail.py @@ -182,6 +182,40 @@ class MessagePostCase(MailPostDeferCommon): with self.assertRaises(UserError): self.partner_portal._message_update_content(msg, "", []) + def test_model_without_threading(self): + """When models don't inherit from mail.thread, they still work.""" + self.partner_portal.email = "portal@example.com" + with self.mock_mail_gateway(): + self.env["mail.thread"].with_context( + mail_notify_author=True + ).message_notify( + author_id=self.partner_employee.id, + body="test body", + model="res.country", + partner_ids=(self.partner_employee | self.partner_portal).ids, + res_id=self.ref("base.es"), + ) + self.assertNoMail(self.partner_employee | self.partner_portal) + # One minute later, the cron sends the mail + with freezegun.freeze_time("2023-01-02 10:01:00"): + self.env["mail.message.schedule"]._send_notifications_cron() + self.env["mail.mail"].process_email_queue() + self.assertMailMail( + self.partner_portal, + "sent", + author=self.partner_employee, + content="test body", + ) + self.assertMailMail( + self.partner_employee, + "sent", + author=self.partner_employee, + content="test body", + ) + # Safety belt to avoid false positives in this test + self.assertFalse(hasattr(self.env["res.country"], "_notify_thread")) + self.assertTrue(hasattr(self.env["res.partner"], "_notify_thread")) + @tagged("-at_install", "post_install") @freezegun.freeze_time("2023-01-02 10:00:00")