summaryrefslogtreecommitdiff
path: root/addons/test_mail_full/tests/test_mass_sms.py
diff options
context:
space:
mode:
authorstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
committerstephanchrst <stephanchrst@gmail.com>2022-05-10 21:51:50 +0700
commit3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch)
treea44932296ef4a9b71d5f010906253d8c53727726 /addons/test_mail_full/tests/test_mass_sms.py
parent0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff)
initial commit 2
Diffstat (limited to 'addons/test_mail_full/tests/test_mass_sms.py')
-rw-r--r--addons/test_mail_full/tests/test_mass_sms.py405
1 files changed, 405 insertions, 0 deletions
diff --git a/addons/test_mail_full/tests/test_mass_sms.py b/addons/test_mail_full/tests/test_mass_sms.py
new file mode 100644
index 00000000..dbc91b95
--- /dev/null
+++ b/addons/test_mail_full/tests/test_mass_sms.py
@@ -0,0 +1,405 @@
+# -*- coding: utf-8 -*-
+# Part of Odoo. See LICENSE file for full copyright and licensing details.
+
+from ast import literal_eval
+
+from odoo.addons.phone_validation.tools import phone_validation
+from odoo.addons.test_mail_full.tests.common import TestMailFullCommon
+from odoo import exceptions
+from odoo.tests import tagged
+from odoo.tests.common import users
+from odoo.tools import mute_logger
+
+
+@tagged('mass_mailing')
+class TestMassSMSCommon(TestMailFullCommon):
+
+ @classmethod
+ def setUpClass(cls):
+ super(TestMassSMSCommon, cls).setUpClass()
+ cls._test_body = 'Mass SMS in your face'
+
+ records = cls.env['mail.test.sms']
+ partners = cls.env['res.partner']
+ country_be_id = cls.env.ref('base.be').id,
+ country_us_id = cls.env.ref('base.us').id,
+
+ for x in range(10):
+ partners += cls.env['res.partner'].with_context(**cls._test_context).create({
+ 'name': 'Partner_%s' % (x),
+ 'email': '_test_partner_%s@example.com' % (x),
+ 'country_id': country_be_id,
+ 'mobile': '045600%s%s99' % (x, x)
+ })
+ records += cls.env['mail.test.sms'].with_context(**cls._test_context).create({
+ 'name': 'MassSMSTest_%s' % (x),
+ 'customer_id': partners[x].id,
+ 'phone_nbr': '045600%s%s44' % (x, x)
+ })
+ cls.records = cls._reset_mail_context(records)
+ cls.records_numbers = [phone_validation.phone_format(r.phone_nbr, 'BE', '32', force_format='E164') for r in cls.records]
+ cls.partners = partners
+
+ cls.sms_template = cls.env['sms.template'].create({
+ 'name': 'Test Template',
+ 'model_id': cls.env['ir.model']._get('mail.test.sms').id,
+ 'body': 'Dear ${object.display_name} this is a mass SMS.',
+ })
+
+ cls.partner_numbers = [
+ phone_validation.phone_format(partner.mobile, partner.country_id.code, partner.country_id.phone_code, force_format='E164')
+ for partner in partners
+ ]
+
+ cls.mailing = cls.env['mailing.mailing'].with_user(cls.user_marketing).create({
+ 'name': 'Xmas Spam',
+ 'subject': 'Xmas Spam',
+ 'mailing_model_id': cls.env['ir.model']._get('mail.test.sms').id,
+ 'mailing_type': 'sms',
+ 'mailing_domain': '%s' % repr([('name', 'ilike', 'MassSMSTest')]),
+ 'sms_template_id': cls.sms_template.id,
+ 'sms_allow_unsubscribe': False,
+ })
+
+
+@tagged('mass_mailing')
+class TestMassSMSInternals(TestMassSMSCommon):
+
+ @users('user_marketing')
+ def test_mass_sms_domain(self):
+ mailing = self.env['mailing.mailing'].create({
+ 'name': 'Xmas Spam',
+ 'subject': 'Xmas Spam',
+ 'mailing_model_id': self.env['ir.model']._get('mail.test.sms').id,
+ 'mailing_type': 'sms',
+ })
+ self.assertEqual(literal_eval(mailing.mailing_domain), [])
+
+ mailing = self.env['mailing.mailing'].create({
+ 'name': 'Xmas Spam',
+ 'subject': 'Xmas Spam',
+ 'mailing_model_id': self.env['ir.model']._get('mail.test.sms.bl').id,
+ 'mailing_type': 'sms',
+ })
+ self.assertEqual(literal_eval(mailing.mailing_domain), [('phone_sanitized_blacklisted', '=', False)])
+
+ @users('user_marketing')
+ def test_mass_sms_internals(self):
+ with self.with_user('user_marketing'):
+ mailing = self.env['mailing.mailing'].create({
+ 'name': 'Xmas Spam',
+ 'subject': 'Xmas Spam',
+ 'mailing_model_id': self.env['ir.model']._get('mail.test.sms').id,
+ 'mailing_type': 'sms',
+ 'mailing_domain': '%s' % repr([('name', 'ilike', 'MassSMSTest')]),
+ 'sms_template_id': self.sms_template.id,
+ 'sms_allow_unsubscribe': False,
+ })
+
+ self.assertEqual(mailing.mailing_model_real, 'mail.test.sms')
+ self.assertEqual(mailing.medium_id, self.env.ref('mass_mailing_sms.utm_medium_sms'))
+ self.assertEqual(mailing.body_plaintext, self.sms_template.body)
+
+ remaining_res_ids = mailing._get_remaining_recipients()
+ self.assertEqual(set(remaining_res_ids), set(self.records.ids))
+
+ with self.mockSMSGateway():
+ mailing.action_send_sms()
+
+ self.assertSMSTraces(
+ [{'partner': record.customer_id,
+ 'number': self.records_numbers[i],
+ 'content': 'Dear %s this is a mass SMS.' % record.display_name
+ } for i, record in enumerate(self.records)],
+ mailing, self.records,
+ )
+
+ def test_mass_sms_internals_errors(self):
+ # same customer, specific different number on record -> should be valid
+ new_record_1 = self.env['mail.test.sms'].create({
+ 'name': 'MassSMSTest_nr1',
+ 'customer_id': self.partners[0].id,
+ 'phone_nbr': '0456999999',
+ })
+ void_record = self.env['mail.test.sms'].create({
+ 'name': 'MassSMSTest_void',
+ 'customer_id': False,
+ 'phone_nbr': '',
+ })
+ falsy_record_1 = self.env['mail.test.sms'].create({
+ 'name': 'MassSMSTest_falsy_1',
+ 'customer_id': False,
+ 'phone_nbr': 'abcd',
+ })
+ falsy_record_2 = self.env['mail.test.sms'].create({
+ 'name': 'MassSMSTest_falsy_2',
+ 'customer_id': False,
+ 'phone_nbr': '04561122',
+ })
+ bl_record_1 = self.env['mail.test.sms'].create({
+ 'name': 'MassSMSTest_bl_1',
+ 'customer_id': False,
+ 'phone_nbr': '0456110011',
+ })
+ self.env['phone.blacklist'].create({'number': '0456110011'})
+ # new customer, number already on record -> should be ignored
+ country_be_id = self.env.ref('base.be').id
+ nr2_partner = self.env['res.partner'].create({
+ 'name': 'Partner_nr2',
+ 'country_id': country_be_id,
+ 'mobile': '0456449999',
+ })
+ new_record_2 = self.env['mail.test.sms'].create({
+ 'name': 'MassSMSTest_nr2',
+ 'customer_id': nr2_partner.id,
+ 'phone_nbr': self.records[0].phone_nbr,
+ })
+ records_numbers = self.records_numbers + ['+32456999999']
+
+ with self.with_user('user_marketing'):
+ with self.mockSMSGateway():
+ self.mailing.action_send_sms()
+
+ self.assertSMSTraces(
+ [{'partner': record.customer_id, 'number': records_numbers[i],
+ 'content': 'Dear %s this is a mass SMS.' % record.display_name}
+ for i, record in enumerate(self.records | new_record_1)],
+ self.mailing, self.records | new_record_1,
+ )
+ # duplicates
+ self.assertSMSTraces(
+ [{'partner': new_record_2.customer_id, 'number': self.records_numbers[0],
+ 'content': 'Dear %s this is a mass SMS.' % new_record_2.display_name, 'state': 'ignored',
+ 'failure_type': 'sms_duplicate'}],
+ self.mailing, new_record_2,
+ )
+ # blacklist
+ self.assertSMSTraces(
+ [{'partner': self.env['res.partner'], 'number': phone_validation.phone_format(bl_record_1.phone_nbr, 'BE', '32', force_format='E164'),
+ 'content': 'Dear %s this is a mass SMS.' % bl_record_1.display_name, 'state': 'ignored',
+ 'failure_type': 'sms_blacklist'}],
+ self.mailing, bl_record_1,
+ )
+ # missing number
+ self.assertSMSTraces(
+ [{'partner': self.env['res.partner'], 'number': False,
+ 'content': 'Dear %s this is a mass SMS.' % void_record.display_name, 'state': 'exception',
+ 'failure_type': 'sms_number_missing'}],
+ self.mailing, void_record,
+ )
+ # wrong values
+ self.assertSMSTraces(
+ [{'partner': self.env['res.partner'], 'number': record.phone_nbr,
+ 'content': 'Dear %s this is a mass SMS.' % record.display_name, 'state': 'bounced',
+ 'failure_type': 'sms_number_format'}
+ for record in falsy_record_1 + falsy_record_2],
+ self.mailing, falsy_record_1 + falsy_record_2,
+ )
+
+ def test_mass_sms_internals_done_ids(self):
+ with self.with_user('user_marketing'):
+ with self.mockSMSGateway():
+ self.mailing.action_send_sms(res_ids=self.records[:5].ids)
+
+ traces = self.env['mailing.trace'].search([('mass_mailing_id', 'in', self.mailing.ids)])
+ self.assertEqual(len(traces), 5)
+ # new traces generated
+ self.assertSMSTraces(
+ [{'partner': record.customer_id, 'number': self.records_numbers[i],
+ 'content': 'Dear %s this is a mass SMS.' % record.display_name}
+ for i, record in enumerate(self.records[:5])],
+ self.mailing, self.records[:5],
+ )
+
+ with self.with_user('user_marketing'):
+ with self.mockSMSGateway():
+ self.mailing.action_send_sms(res_ids=self.records.ids)
+
+ # delete old traces (for testing purpose: ease check by deleting old ones)
+ traces.unlink()
+ # new failed traces generated for duplicates
+ self.assertSMSTraces(
+ [{'partner': record.customer_id, 'number': self.records_numbers[i],
+ 'content': 'Dear %s this is a mass SMS.' % record.display_name, 'state': 'ignored',
+ 'failure_type': 'sms_duplicate'}
+ for i, record in enumerate(self.records[:5])],
+ self.mailing, self.records[:5],
+ )
+ # new traces generated
+ self.assertSMSTraces(
+ [{'partner': record.customer_id, 'number': self.records_numbers[i+5],
+ 'content': 'Dear %s this is a mass SMS.' % record.display_name}
+ for i, record in enumerate(self.records[5:])],
+ self.mailing, self.records[5:],
+ )
+
+ @mute_logger('odoo.addons.mail.models.mail_render_mixin')
+ def test_mass_sms_test_button(self):
+ mailing = self.env['mailing.mailing'].create({
+ 'name': 'TestButton',
+ 'subject': 'Subject ${object.name}',
+ 'preview': 'Preview ${object.name}',
+ 'state': 'draft',
+ 'mailing_type': 'sms',
+ 'body_plaintext': 'Hello ${object.name}',
+ 'mailing_model_id': self.env['ir.model']._get('res.partner').id,
+ })
+ mailing_test = self.env['mailing.sms.test'].with_user(self.user_marketing).create({
+ 'numbers': '+32456001122',
+ 'mailing_id': mailing.id,
+ })
+
+ with self.with_user('user_marketing'):
+ with self.mockSMSGateway():
+ mailing_test.action_send_sms()
+
+ # Test if bad jinja in the body raises an error
+ mailing.write({
+ 'body_plaintext': 'Hello ${object.name_id.id}',
+ })
+
+ with self.with_user('user_marketing'):
+ with self.mock_mail_gateway(), self.assertRaises(Exception):
+ mailing_test.action_send_sms()
+
+
+@tagged('mass_mailing', 'mass_mailing_sms')
+class TestMassSMS(TestMassSMSCommon):
+
+ @users('user_marketing')
+ def test_mass_sms_links(self):
+ mailing = self.env['mailing.mailing'].browse(self.mailing.ids)
+ mailing.write({
+ 'body_plaintext': 'Dear ${object.display_name} this is a mass SMS with two links http://www.odoo.com/smstest and http://www.odoo.com/smstest/${object.name}',
+ 'sms_template_id': False,
+ 'sms_force_send': True,
+ 'sms_allow_unsubscribe': True,
+ })
+
+ with self.mockSMSGateway():
+ mailing.action_send_sms()
+
+ self.assertSMSTraces(
+ [{'partner': record.customer_id,
+ 'number': self.records_numbers[i],
+ 'state': 'sent',
+ 'content': 'Dear %s this is a mass SMS with two links' % record.display_name
+ } for i, record in enumerate(self.records)],
+ mailing, self.records,
+ sms_links_info=[[
+ ('http://www.odoo.com/smstest', True, {}),
+ ('http://www.odoo.com/smstest/%s' % record.name, True, {}),
+ # unsubscribe is not shortened and parsed at sending
+ ('unsubscribe', False, {}),
+ ] for record in self.records],
+ )
+
+ @users('user_marketing')
+ @mute_logger('odoo.addons.mail.models.mail_mail')
+ def test_mass_sms_partner_only(self):
+ """ Check sending SMS marketing on models having only a partner_id fields
+ set is working. """
+ mailing = self.env['mailing.mailing'].browse(self.mailing_sms.ids)
+ mailing.write({
+ 'mailing_model_id': self.env['ir.model']._get('mail.test.sms.partner').id,
+ })
+
+ records = self.env['mail.test.sms.partner'].create([
+ {'name': 'SMSTest on %s' % partner.name,
+ 'customer_id': partner.id,
+ } for partner in self.partners
+ ])
+
+ with self.mockSMSGateway():
+ mailing.action_send_sms()
+
+ self.assertEqual(len(mailing.mailing_trace_ids), 10)
+ self.assertSMSTraces(
+ [{'partner': record.customer_id,
+ 'number': record.customer_id.phone_sanitized,
+ 'state': 'sent',
+ 'content': 'Dear %s this is a mass SMS with two links' % record.display_name
+ } for record in records],
+ mailing, records,
+ sms_links_info=[[
+ ('http://www.odoo.com/smstest', True, {}),
+ ('http://www.odoo.com/smstest/%s' % record.id, True, {}),
+ # unsubscribe is not shortened and parsed at sending
+ ('unsubscribe', False, {}),
+ ] for record in records],
+ )
+
+ # add a new record, send -> sent list should not resend traces
+ new_record = self.env['mail.test.sms.partner'].create([
+ {'name': 'Duplicate SMS on %s' % self.partners[0].name,
+ 'customer_id': self.partners[0].id,
+ }
+ ])
+ with self.mockSMSGateway():
+ mailing.action_send_sms()
+
+ self.assertEqual(len(mailing.mailing_trace_ids), 11)
+ self.assertSMSTraces(
+ [{'partner': new_record.customer_id,
+ 'number': new_record.customer_id.phone_sanitized,
+ 'state': 'sent',
+ 'content': 'Dear %s this is a mass SMS with two links' % new_record.display_name
+ }],
+ mailing, new_record,
+ sms_links_info=[[
+ ('http://www.odoo.com/smstest', True, {}),
+ ('http://www.odoo.com/smstest/%s' % new_record.id, True, {}),
+ # unsubscribe is not shortened and parsed at sending
+ ('unsubscribe', False, {}),
+ ]],
+ )
+
+ @users('user_marketing')
+ @mute_logger('odoo.addons.mail.models.mail_mail')
+ def test_mass_sms_partner_only_m2m(self):
+ """ Check sending SMS marketing on models having only a m2m to partners
+ is currently not suppored. """
+ mailing = self.env['mailing.mailing'].browse(self.mailing_sms.ids)
+ mailing.write({
+ 'mailing_model_id': self.env['ir.model']._get('mail.test.sms.partner.2many').id,
+ })
+
+ records = self.env['mail.test.sms.partner.2many'].create([
+ {'name': 'SMSTest on %s' % partner.name,
+ 'customer_ids': [(4, partner.id)],
+ } for partner in self.partners
+ ])
+
+ with self.assertRaises(exceptions.UserError), self.mockSMSGateway():
+ mailing.action_send_sms()
+
+
+ @users('user_marketing')
+ @mute_logger('odoo.addons.mail.models.mail_mail')
+ def test_mass_sms_w_opt_out(self):
+ mailing = self.env['mailing.mailing'].browse(self.mailing_sms.ids)
+ recipients = self._create_mailing_sms_test_records(model='mail.test.sms.bl.optout', count=5)
+
+ # optout records 0 and 1
+ (recipients[0] | recipients[1]).write({'opt_out': True})
+ # blacklist records 4
+ # TDE FIXME: sudo should not be necessary
+ self.env['phone.blacklist'].sudo().create({'number': recipients[4].phone_nbr})
+
+ mailing.write({
+ 'mailing_model_id': self.env['ir.model']._get('mail.test.sms.bl.optout'),
+ 'mailing_domain': [('id', 'in', recipients.ids)],
+ })
+
+ with self.mockSMSGateway():
+ mailing.action_send_sms()
+
+ self.assertSMSTraces(
+ [{'number': '+32456000000', 'state': 'ignored', 'failure_type': 'sms_blacklist'}, # TDE FIXME: should be opt_out
+ {'number': '+32456000101', 'state': 'ignored', 'failure_type': 'sms_blacklist'}, # TDE FIXME: should be opt_out
+ {'number': '+32456000202', 'state': 'sent'},
+ {'number': '+32456000303', 'state': 'sent'},
+ {'number': '+32456000404', 'state': 'ignored', 'failure_type': 'sms_blacklist'}],
+ mailing, recipients
+ )
+ self.assertEqual(mailing.ignored, 3)