From 2d611eae9453966a4d73233e70caad1a4e28949e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Wed, 24 Nov 2021 01:06:26 +0100 Subject: [PATCH] Add delay to sending email issue10919 review381321002 --- CHANGELOG | 2 ++ notification.py | 24 +++++++++++++++-- tests/test_notification_email.py | 44 +++++++++++++++++++++++++++++++- view/email_form.xml | 3 +++ 4 files changed, 70 insertions(+), 3 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 121bd4c357..bae41a4825 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,5 @@ +* Add delay to sending email + Version 6.2.0 - 2021-11-01 * Bug fixes (see mercurial logs for details) diff --git a/notification.py b/notification.py index 1046c3479c..0f60863be4 100644 --- a/notification.py +++ b/notification.py @@ -112,6 +112,10 @@ class Email(ModelSQL, ModelView): domain=[('model.model', '=', Eval('model'))], depends=['model'], help="Add a trigger for the notification.") + send_after = fields.TimeDelta( + "Send After", + help="The delay after which the email must be sent.\n" + "Applied if a worker queue is activated.") model = fields.Function( fields.Char("Model"), 'on_change_with_model', searcher='search_model') @@ -217,11 +221,27 @@ class Email(ModelSQL, ModelView): @classmethod def trigger(cls, records, trigger): "Action function for the triggers" - if not trigger.notification_email: + notification_email = trigger.notification_email + if not notification_email: raise ValueError( 'Trigger "%s" is not related to any email notification' % trigger.rec_name) - trigger.notification_email.send_email(records, trigger) + if notification_email.send_after: + with Transaction().set_context( + queue_name='notification_email', + queue_scheduled_at=trigger.notification_email.send_after): + notification_email.__class__.__queue__._send_email_queued( + notification_email, [r.id for r in records], trigger.id) + else: + notification_email.send_email(records, trigger) + + def _send_email_queued(self, ids, trigger_id): + pool = Pool() + Model = pool.get(self.model) + Trigger = pool.get('ir.trigger') + records = Model.browse(ids) + trigger = Trigger(trigger_id) + self.send_email(records, trigger) def send_email(self, records, trigger): pool = Pool() diff --git a/tests/test_notification_email.py b/tests/test_notification_email.py index b2b8df3943..0d836d82e3 100644 --- a/tests/test_notification_email.py +++ b/tests/test_notification_email.py @@ -1,5 +1,6 @@ # This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. +import datetime as dt import sys import unittest from unittest.mock import patch, ANY @@ -63,14 +64,19 @@ class NotificationEmailTestCase(CompanyTestMixin, ModuleTestCase): notification_email.content = report notification_email.save() - def run_tasks(self): + def run_tasks(self, count=None): pool = Pool() Queue = pool.get('ir.queue') transaction = Transaction() self.assertTrue(transaction.tasks) + i = 0 while transaction.tasks: task = Queue(transaction.tasks.pop()) task.run() + i += 1 + if count is not None: + if i >= count: + break @unittest.skipIf( (3, 5, 0) <= sys.version_info < (3, 5, 2), "python bug #25195") @@ -122,6 +128,42 @@ class NotificationEmailTestCase(CompanyTestMixin, ModuleTestCase): self.assertEqual(log.recipients_secondary, '') self.assertEqual(log.recipients_hidden, '') + @with_transaction() + def test_notification_email_delay(self): + "Test email notification is sent with delay" + pool = Pool() + User = pool.get('res.user') + Trigger = pool.get('ir.trigger') + Model = pool.get('ir.model') + NotificationEmail = pool.get('notification.email') + + self._setup_notification() + notification_email, = NotificationEmail.search([]) + notification_email.send_after = dt.timedelta(minutes=5) + notification_email.save() + + model, = Model.search([ + ('model', '=', User.__name__), + ]) + Trigger.create([{ + 'name': 'Test creation', + 'model': model.id, + 'on_create': True, + 'condition': 'true', + 'notification_email': notification_email.id, + 'action': 'notification.email|trigger', + }]) + + with patch.object( + notification_module, 'sendmail_transactional') as sendmail, \ + patch.object(notification_module, 'SMTPDataManager'): + User.create([{'name': "Michael Scott", 'login': "msc"}]) + self.run_tasks(1) + sendmail.assert_not_called() + self.run_tasks() + sendmail.assert_called_once_with( + FROM, ['user@example.com'], ANY, datamanager=ANY) + @with_transaction() def test_notification_email_attachment(self): "Test email notificiation with attachment" diff --git a/view/email_form.xml b/view/email_form.xml index 4790df4380..4bea0c5f16 100644 --- a/view/email_form.xml +++ b/view/email_form.xml @@ -22,6 +22,9 @@ this repository contains the full copyright notices and license terms. -->