From feb510ae9347b18656b7403ed3d6b937c2cd9027 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Tue, 31 Aug 2021 14:03:13 +0000 Subject: [PATCH] [IMP] sms: improve synchronization of SMS actions with notifications Improve cancel / set outgoing actions on sms model. This notably allows to synchronize notifications when hitting action buttons on sms form view. Also add an action to set as error. This will be used when having IAP feedback on SMS sending. Task-2634957 Prepares Task-2535005 (SMS view pimp) and Task-2560666 (IAP feedback) PR odoo/odoo#75798 --- addons/sms/models/sms_sms.py | 43 +++++++-- addons/sms/views/sms_sms_views.xml | 4 +- .../tests/test_sms_management.py | 87 ++++++++++++++++++- 3 files changed, 124 insertions(+), 10 deletions(-) diff --git a/addons/sms/models/sms_sms.py b/addons/sms/models/sms_sms.py index e9b4c900838..349ecee2777 100644 --- a/addons/sms/models/sms_sms.py +++ b/addons/sms/models/sms_sms.py @@ -45,6 +45,43 @@ class SmsSms(models.Model): ('sms_optout', 'Opted Out'), ], copy=False) + def action_set_canceled(self): + self.state = 'canceled' + notifications = self.env['mail.notification'].sudo().search([ + ('sms_id', 'in', self.ids), + # sent is sent -> cannot reset + ('notification_status', 'not in', ['canceled', 'sent']), + ]) + if notifications: + notifications.write({'notification_status': 'canceled'}) + if not self._context.get('sms_skip_msg_notification', False): + notifications.mail_message_id._notify_message_notification_update() + + def action_set_error(self, failure_type): + self.state = 'error' + self.failure_type = failure_type + notifications = self.env['mail.notification'].sudo().search([ + ('sms_id', 'in', self.ids), + # sent can be set to error due to IAP feedback + ('notification_status', '!=', 'exception'), + ]) + if notifications: + notifications.write({'notification_status': 'exception', 'failure_type': failure_type}) + if not self._context.get('sms_skip_msg_notification', False): + notifications.mail_message_id._notify_message_notification_update() + + def action_set_outgoing(self): + self.state = 'outgoing' + notifications = self.env['mail.notification'].sudo().search([ + ('sms_id', 'in', self.ids), + # sent is sent -> cannot reset + ('notification_status', 'not in', ['ready', 'sent']), + ]) + if notifications: + notifications.write({'notification_status': 'ready', 'failure_type': False}) + if not self._context.get('sms_skip_msg_notification', False): + notifications.mail_message_id._notify_message_notification_update() + def send(self, delete_all=False, auto_commit=False, raise_exception=False): """ Main API method to send SMS. @@ -59,9 +96,6 @@ class SmsSms(models.Model): if auto_commit is True and not getattr(threading.currentThread(), 'testing', False): self._cr.commit() - def set_outgoing(self): - self.state = 'outgoing' - def resend_failed(self): sms_to_send = self.filtered(lambda sms: sms.state == 'error') notification_title = _('Warning') @@ -88,9 +122,6 @@ class SmsSms(models.Model): } } - def cancel(self): - self.state = 'canceled' - @api.model def _process_queue(self, ids=None): """ Send immediately queued messages, committing after each message is sent. diff --git a/addons/sms/views/sms_sms_views.xml b/addons/sms/views/sms_sms_views.xml index 19f4811d15f..4229eb3896e 100644 --- a/addons/sms/views/sms_sms_views.xml +++ b/addons/sms/views/sms_sms_views.xml @@ -7,8 +7,8 @@
diff --git a/addons/test_mail_full/tests/test_sms_management.py b/addons/test_mail_full/tests/test_sms_management.py index 9a745ff5cbd..af7602d62a8 100644 --- a/addons/test_mail_full/tests/test_sms_management.py +++ b/addons/test_mail_full/tests/test_sms_management.py @@ -2,36 +2,116 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. from odoo.addons.test_mail_full.tests.common import TestMailFullCommon, TestMailFullRecipients +from odoo.tests import tagged +from odoo.tools import mute_logger -class TestSMSWizards(TestMailFullCommon, TestMailFullRecipients): +class TestSMSActionsCommon(TestMailFullCommon, TestMailFullRecipients): @classmethod def setUpClass(cls): - super(TestSMSWizards, cls).setUpClass() + super(TestSMSActionsCommon, cls).setUpClass() cls.test_record = cls.env['mail.test.sms'].with_context(**cls._test_context).create({ 'name': 'Test', 'customer_id': cls.partner_1.id, }) cls.test_record = cls._reset_mail_context(cls.test_record) cls.msg = cls.test_record.message_post(body='TEST BODY', author_id=cls.partner_employee.id) + cls.sms_p1 = cls.env['sms.sms'].create({ + 'body': 'TEST BODY', + 'failure_type': 'sms_number_format', + 'mail_message_id': cls.msg.id, + 'number': cls.partner_1.mobile, + 'partner_id': cls.partner_1.id, + 'state': 'error', + }) cls.notif_p1 = cls.env['mail.notification'].create({ 'mail_message_id': cls.msg.id, 'res_partner_id': cls.partner_1.id, + 'sms_id': cls.sms_p1.id, 'sms_number': cls.partner_1.mobile, 'notification_type': 'sms', 'notification_status': 'exception', 'failure_type': 'sms_number_format', }) + cls.sms_p2 = cls.env['sms.sms'].create({ + 'body': 'TEST BODY', + 'failure_type': 'sms_credit', + 'mail_message_id': cls.msg.id, + 'number': cls.partner_2.mobile, + 'partner_id': cls.partner_2.id, + 'state': 'error', + }) cls.notif_p2 = cls.env['mail.notification'].create({ 'mail_message_id': cls.msg.id, 'res_partner_id': cls.partner_2.id, + 'sms_id': cls.sms_p2.id, 'sms_number': cls.partner_2.mobile, 'notification_type': 'sms', 'notification_status': 'exception', 'failure_type': 'sms_credit', }) + +@tagged('sms_management') +class TestSMSActions(TestSMSActionsCommon): + + def test_sms_set_cancel(self): + self._reset_bus() + self.sms_p1.action_set_canceled() + self.assertEqual(self.sms_p1.state, 'canceled') + + self.assertMessageBusNotifications(self.msg) + self.assertSMSNotification([ + {'partner': self.partner_1, 'number': self.notif_p1.sms_number, 'state': 'canceled', 'failure_type': 'sms_number_format'}, + {'partner': self.partner_2, 'number': self.notif_p2.sms_number, 'state': 'exception', 'failure_type': 'sms_credit'} + ], 'TEST BODY', self.msg, check_sms=False) # do not check new sms as they already exist + + self._reset_bus() + self.sms_p2.with_context(sms_skip_msg_notification=True).action_set_canceled() + self.assertEqual(self.sms_p2.state, 'canceled') + + self.assertEqual(self.env['bus.bus'].search([]), self.env['bus.bus'], 'SMS: no bus notifications unless asked') + self.assertSMSNotification([ + {'partner': self.partner_1, 'number': self.notif_p1.sms_number, 'state': 'canceled', 'failure_type': 'sms_number_format'}, + {'partner': self.partner_2, 'number': self.notif_p2.sms_number, 'state': 'canceled', 'failure_type': 'sms_credit'} + ], 'TEST BODY', self.msg, check_sms=False) # do not check new sms as they already exist + + + def test_sms_set_error(self): + self._reset_bus() + (self.sms_p1 + self.sms_p2).with_context(sms_skip_msg_notification=True).action_set_canceled() + self.assertEqual(self.sms_p1.state, 'canceled') + self.assertEqual(self.sms_p2.state, 'canceled') + self.assertEqual(self.env['bus.bus'].search([]), self.env['bus.bus'], 'SMS: no bus notifications unless asked') + + (self.sms_p1 + self.sms_p2).action_set_error('sms_server') + self.assertEqual(self.sms_p1.state, 'error') + self.assertEqual(self.sms_p2.state, 'error') + + self.assertMessageBusNotifications(self.msg) + self.assertSMSNotification([ + {'partner': self.partner_1, 'number': self.notif_p1.sms_number, 'state': 'exception', 'failure_type': 'sms_server'}, + {'partner': self.partner_2, 'number': self.notif_p2.sms_number, 'state': 'exception', 'failure_type': 'sms_server'} + ], 'TEST BODY', self.msg, check_sms=False) # do not check new sms as they already exist + + def test_sms_set_outgoing(self): + self._reset_bus() + (self.sms_p1 + self.sms_p2).action_set_outgoing() + self.assertEqual(self.sms_p1.state, 'outgoing') + self.assertEqual(self.sms_p2.state, 'outgoing') + + self.assertMessageBusNotifications(self.msg) + self.assertSMSNotification([ + {'partner': self.partner_1, 'number': self.notif_p1.sms_number, 'state': 'ready'}, + {'partner': self.partner_2, 'number': self.notif_p2.sms_number, 'state': 'ready'} + ], 'TEST BODY', self.msg, check_sms=False) # do not check new sms as they already exist + + +@tagged('sms_management') +class TestSMSWizards(TestSMSActionsCommon): + + @mute_logger('odoo.addons.sms.models.sms_sms') def test_sms_resend(self): self._reset_bus() @@ -47,6 +127,7 @@ class TestSMSWizards(TestMailFullCommon, TestMailFullRecipients): ], 'TEST BODY', self.msg, check_sms=True) self.assertMessageBusNotifications(self.msg) + @mute_logger('odoo.addons.sms.models.sms_sms') def test_sms_resend_update_number(self): self._reset_bus() @@ -76,6 +157,7 @@ class TestSMSWizards(TestMailFullCommon, TestMailFullRecipients): ], 'TEST BODY', self.msg, check_sms=False) self.assertMessageBusNotifications(self.msg) + @mute_logger('odoo.addons.sms.models.sms_sms') def test_sms_resend_internals(self): self._reset_bus() self.assertSMSNotification([ @@ -91,6 +173,7 @@ class TestSMSWizards(TestMailFullCommon, TestMailFullRecipients): with self.mockSMSGateway(): wizard.action_resend() + @mute_logger('odoo.addons.sms.models.sms_sms') def test_sms_resend_w_cancel(self): self._reset_bus()