summaryrefslogtreecommitdiff
path: root/addons/test_mail
diff options
context:
space:
mode:
authorXavierDo <xdo@odoo.com>2018-04-27 16:50:03 +0200
committerXavierDo <xdo@odoo.com>2018-06-07 11:46:28 +0200
commit133eeb1bbf52e9a9ee58f83be8e7f0aba3c6d1ad (patch)
treecd7c6b0a3c931705158c9af590206130480426f6 /addons/test_mail
parentaa7fb8c72317e330bbeb6ce29b4aace8627ef1d7 (diff)
[ADD] mail, mass_mailing: allow a user to resend a mail with failures
When a mail is in failure state, a red envelope appears next to the message in a thread but it was difficult to send the mail again. This tasks will allow users to send mail again easily, or mark notification as cancelled if the user want to ignore this failure. A notification will appear in sender systray while mail are in failure. Task: #46158 PR: #24628
Diffstat (limited to 'addons/test_mail')
-rw-r--r--addons/test_mail/tests/__init__.py1
-rw-r--r--addons/test_mail/tests/test_mail_resend.py141
2 files changed, 142 insertions, 0 deletions
diff --git a/addons/test_mail/tests/__init__.py b/addons/test_mail/tests/__init__.py
index 411d73d5694..2d63b95f205 100644
--- a/addons/test_mail/tests/__init__.py
+++ b/addons/test_mail/tests/__init__.py
@@ -4,6 +4,7 @@ from . import test_mail_activity
from . import test_mail_followers
from . import test_mail_message
from . import test_mail_mail
+from . import test_mail_resend
from . import test_mail_channel
from . import test_mail_gateway
from . import test_mail_template
diff --git a/addons/test_mail/tests/test_mail_resend.py b/addons/test_mail/tests/test_mail_resend.py
new file mode 100644
index 00000000000..21790062488
--- /dev/null
+++ b/addons/test_mail/tests/test_mail_resend.py
@@ -0,0 +1,141 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+import itertools
+from unittest.mock import patch
+
+from odoo.addons.test_mail.tests import common
+from odoo.tests import tagged
+from odoo.tools import mute_logger
+from odoo import api
+from odoo.addons.base.models.ir_mail_server import IrMailServer
+
+
+@tagged('resend_test')
+class TestMailResend(common.BaseFunctionalTest, common.MockEmails):
+
+ @classmethod
+ def setUpClass(cls):
+ super(TestMailResend, cls).setUpClass()
+ #Two users
+ cls.user1 = cls.env['res.users'].with_context(cls._quick_create_user_ctx).create({
+ 'name': 'Employee 1',
+ 'login': 'e1',
+ 'email': 'e1', # invalid email
+ 'notification_type': 'email',
+ 'groups_id': [(6, 0, [cls.env.ref('base.group_user').id])]
+ })
+ cls.user2 = cls.env['res.users'].with_context(cls._quick_create_user_ctx).create({
+ 'name': 'Employee 2',
+ 'login': 'e2',
+ 'email': 'e2@example.com',
+ 'notification_type': 'email',
+ 'groups_id': [(6, 0, [cls.env.ref('base.group_user').id])]
+ })
+ #Two partner
+ cls.partner1 = cls.env['res.partner'].with_context(cls._quick_create_user_ctx).create({
+ 'name': 'Partner 1',
+ 'email': 'p1' # invalid email
+ })
+ cls.partner2 = cls.env['res.partner'].with_context(cls._quick_create_user_ctx).create({
+ 'name': 'Partner 2',
+ 'email': 'p2@example.com'
+ })
+
+ @api.model
+ def send_email(self, message, *args, **kwargs):
+ assert '@' in message['To'], self.NO_VALID_RECIPIENT
+ return message['Message-Id']
+ cls.bus_update_failure = []
+ def sendone(self, channel, message):
+ if 'type' in message and message['type'] == 'mail_failure':
+ cls.bus_update_failure.append((channel, message))
+ cls.env['ir.mail_server']._patch_method('send_email', send_email)
+ cls.env['bus.bus']._patch_method('sendone', sendone)
+ cls.partners = cls.env['res.partner'].concat(cls.user1.partner_id, cls.user2.partner_id, cls.partner1, cls.partner2)
+ cls.invalid_email_partners = cls.env['res.partner'].concat(cls.user1.partner_id, cls.partner1)
+
+ def setUp(self):
+ super(TestMailResend, self).setUp()
+ TestMailResend.bus_update_failure = []
+
+ def assertNotifStates(self, states, message):
+ notif = self.env['mail.notification'].search([('mail_message_id', '=', message.id)], order="res_partner_id asc")
+ self.assertEquals(tuple(notif.mapped('email_status')), states)
+ return notif
+
+ def assertBusMessage(self, partners):
+ partner_ids = [elem[0][2] for elem in self.bus_update_failure]
+ self.assertEquals(partner_ids, [partner.id for partner in partners])
+ self.bus_update_failure.clear()
+
+ @classmethod
+ def tearDownClass(cls):
+ # Remove mocks
+ cls.env['ir.mail_server']._revert_method('send_email')
+ cls.env['bus.bus']._revert_method('sendone')
+ super(TestMailResend, cls).tearDownClass()
+
+ def assertEmails(self, *args, **kwargs):
+ res = super(TestMailResend, self).assertEmails(*args, **kwargs)
+ self._mails.clear()
+
+ @mute_logger('odoo.addons.mail.models.mail_mail')
+ def test_mail_resend_workflow(self):
+ cls = TestMailResend
+ #missconfigured server
+ @api.model
+ def connect_failure(**kwargs):
+ raise Exception
+ with patch.object(IrMailServer, 'connect', side_effect=connect_failure):
+ message = self.test_record.sudo().message_post(partner_ids=self.partners.ids, subtype='mail.mt_comment', message_type='notification')
+ self.assertBusMessage([self.partner_admin])
+ self.assertEmails(self.partner_admin, [])
+ self.assertNotifStates(('exception', 'exception', 'exception', 'exception'), message)
+ wizard = self.env['mail.resend.message'].with_context({'mail_message_to_resend': message.id}).create({})
+ self.assertEqual(wizard.notification_ids.mapped('res_partner_id'), self.partners, "wizard should manage notifications for each failed partner")
+ wizard.resend_mail_action()
+ self.assertBusMessage([self.partner_admin] * 3) # three more failure sent on bus, one for each mail in failure and one for resend
+ self.assertEmails(self.partner_admin, self.partners)
+ self.assertNotifStates(('exception', 'sent', 'exception', 'sent'), message)
+ self.user1.write({"email": 'u1@example.com'})
+ self.env['mail.resend.message'].with_context({'mail_message_to_resend': message.id}).create({}).resend_mail_action()
+ self.assertBusMessage([self.partner_admin] * 2) # two more failure update sent on bus, one for failed mail and one for resend
+ self.assertEmails(self.partner_admin, self.invalid_email_partners)
+ self.assertNotifStates(('sent', 'sent', 'exception', 'sent'), message)
+ self.partner1.write({"email": 'p1@example.com'})
+ self.env['mail.resend.message'].with_context({'mail_message_to_resend': message.id}).create({}).resend_mail_action()
+ self.assertBusMessage([self.partner_admin]) # A success update should be sent on bus once the email has no more failure
+ self.assertEmails(self.partner_admin, self.partner1)
+ self.assertNotifStates(('sent', 'sent', 'sent', 'sent'), message)
+
+ @mute_logger('odoo.addons.mail.models.mail_mail')
+ def test_mail_send_no_failure(self):
+ self.user1.write({"email": 'u1@example.com'})
+ self.partner1.write({"email": 'p1@example.com'})
+ message = self.test_record.sudo().message_post(partner_ids=self.partners.ids, subtype='mail.mt_comment', message_type='notification')
+ self.assertBusMessage([]) # one update for cancell
+
+ @mute_logger('odoo.addons.mail.models.mail_mail')
+ def test_remove_mail_become_canceled(self):
+ message = self.test_record.sudo().message_post(partner_ids=self.partners.ids, subtype='mail.mt_comment', message_type='notification')
+ self.assertEmails(self.partner_admin, self.partners)
+ self.assertBusMessage([self.partner_admin] * 2) # two failure sent on bus, one for each mail
+ wizard = self.env['mail.resend.message'].with_context({'mail_message_to_resend': message.id}).create({})
+ partners = wizard.partner_ids.mapped("partner_id")
+ self.assertEqual(self.invalid_email_partners, partners)
+ wizard.partner_ids.filtered(lambda p: p.partner_id == self.partner1).write({"resend": False})
+ wizard.resend_mail_action()
+ self.assertEmails(self.partner_admin, self.user1)
+ self.assertBusMessage([self.partner_admin] * 2) # two more failure sent on bus, one for failure, one for resend
+ self.assertNotifStates(('exception', 'sent', 'canceled', 'sent'), message)
+
+ @mute_logger('odoo.addons.mail.models.mail_mail')
+ def test_cancel_all(self):
+ message = self.test_record.sudo().message_post(partner_ids=self.partners.ids, subtype='mail.mt_comment', message_type='notification')
+ self.assertNotifStates(('exception', 'sent', 'exception', 'sent'), message)
+ self.assertBusMessage([self.partner_admin] * 2)
+ wizard = self.env['mail.resend.message'].with_context({'mail_message_to_resend': message.id}).create({})
+ wizard.cancel_mail_action()
+ self.assertNotifStates(('canceled', 'sent', 'canceled', 'sent'), message)
+ self.assertBusMessage([self.partner_admin]) # one update for cancell