Initial commit: Mail packages

This commit is contained in:
Ernad Husremovic 2025-08-29 15:20:51 +02:00
commit 4e53507711
1948 changed files with 751201 additions and 0 deletions

View file

@ -0,0 +1,13 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import test_mail_thread_phone
from . import test_phone_blacklist
from . import test_sms_composer
from . import test_sms_management
from . import test_sms_mixin
from . import test_sms_performance
from . import test_sms_post
from . import test_sms_server_actions
from . import test_sms_sms
from . import test_sms_template

View file

@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.addons.phone_validation.tools import phone_validation
from odoo.addons.sms.tests.common import SMSCommon
from odoo.addons.test_mail.tests.common import TestMailCommon, TestRecipients
class TestSMSCommon(SMSCommon, TestMailCommon):
""" Main entry point for functional tests. Kept to ease backward
compatibility and updating common. """
class TestSMSRecipients(TestRecipients):
@classmethod
def setUpClass(cls):
super(TestSMSRecipients, cls).setUpClass()
cls.partner_numbers = [
phone_validation.phone_format(partner.mobile, partner.country_id.code, partner.country_id.phone_code, force_format='E164')
for partner in (cls.partner_1 | cls.partner_2)
]

View file

@ -0,0 +1,110 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.addons.test_mail_sms.tests.common import TestSMSCommon, TestSMSRecipients
from odoo.tests import tagged, users
@tagged('mail_thread')
class TestSMSActionsCommon(TestSMSCommon, TestSMSRecipients):
""" Test mail.thread.phone mixin, its tools and API """
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.test_phone_records, cls.test_phone_partners = cls._create_records_for_batch(
'mail.test.sms.bl',
5,
)
cls.test_phone_records += cls.env['mail.test.sms.bl'].create([
{
'phone_nbr': '+32475110505',
'mobile_nbr': '+32475000505',
}, {
'phone_nbr': '0032475110606',
'mobile_nbr': '0032475000606',
}, {
'phone_nbr': '0032475110707',
'mobile_nbr': False,
}, {
'phone_nbr': False,
'mobile_nbr': False,
},
])
def test_initial_data(self):
""" Test initial data for this class, allowing to be sure of I/O of tests. """
self.assertEqual(
self.test_phone_records.mapped('mobile_nbr'),
['0475000000', '0475000101', '0475000202', '0475000303', '0475000404',
'+32475000505', '0032475000606',
False, False,
]
)
self.assertEqual(
self.test_phone_records.mapped('phone_nbr'),
[False] * 5 + ['+32475110505', '0032475110606', '0032475110707', False]
)
@users('employee')
def test_search_phone_mobile_search_boolean(self):
test_phone_records = self.test_phone_records.with_env(self.env)
# test Falsy -> is set / is not set
for test_values in [False, '', ' ']:
# test is not set -> both fields should be not set
results = self.env['mail.test.sms.bl'].search([('phone_mobile_search', '=', test_values)])
self.assertEqual(results, test_phone_records[-1],
'Search on phone_mobile_search: = False: record with two void values')
# test is set -> at least one field should be set
results = self.env['mail.test.sms.bl'].search([('phone_mobile_search', '!=', test_values)])
self.assertEqual(results, test_phone_records[:-1],
'Search on phone_mobile_search: != False: record at least one value set')
# test Truthy -> is set / is not set
results = self.env['mail.test.sms.bl'].search([('phone_mobile_search', '=', True)])
self.assertEqual(results, test_phone_records[:-1],
'Search on phone_mobile_search: = True: record at least one value set')
results = self.env['mail.test.sms.bl'].search([('phone_mobile_search', '!=', True)])
self.assertEqual(results, test_phone_records[-1],
'Search on phone_mobile_search: != True: record with two void values')
@users('employee')
def test_search_phone_mobile_search_equal(self):
""" Test searching by phone/mobile with direct search """
test_phone_records = self.test_phone_records.with_env(self.env)
# test "=" search
results = self.env['mail.test.sms.bl'].search([('phone_mobile_search', '=', '0475')])
self.assertFalse(results, 'Search on phone_mobile_search: = should return only matching results')
results = self.env['mail.test.sms.bl'].search([('phone_mobile_search', '=', '0475000000')])
self.assertEqual(results, test_phone_records[0])
results = self.env['mail.test.sms.bl'].search([('phone_mobile_search', '=', '0032475110606')])
self.assertEqual(results, test_phone_records[6])
results = self.env['mail.test.sms.bl'].search([('phone_mobile_search', '=', '+32475110606')])
self.assertEqual(results, test_phone_records[6])
@users('employee')
def test_search_phone_mobile_search_ilike(self):
""" Test searching by phone/mobile on various ilike combinations """
test_phone_records = self.test_phone_records.with_env(self.env)
# test ilike search
results = self.env['mail.test.sms.bl'].search([('phone_mobile_search', 'ilike', '0475')])
self.assertEqual(results, test_phone_records[:5])
results = self.env['mail.test.sms.bl'].search([('phone_mobile_search', 'ilike', '101')])
self.assertEqual(results, test_phone_records[1])
# test search using +32/0032
results = self.env['mail.test.sms.bl'].search([('phone_mobile_search', 'ilike', '+32475')])
self.assertEqual(results, test_phone_records[5:8],
'Search on phone_mobile_search: +32/0032 likeliness')
results = self.env['mail.test.sms.bl'].search([('phone_mobile_search', 'ilike', '0032475')])
self.assertEqual(results, test_phone_records[5:8],
'Search on phone_mobile_search: +32/0032 likeliness')
# test inverse ilike search
results = self.env['mail.test.sms.bl'].search([('phone_mobile_search', 'not ilike', '0475')])
self.assertEqual(results, test_phone_records - test_phone_records[:5])
results = self.env['mail.test.sms.bl'].search([('phone_mobile_search', 'not ilike', '101')])
self.assertEqual(results, test_phone_records - test_phone_records[1])

View file

@ -0,0 +1,112 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.addons.test_mail_sms.tests.common import TestSMSCommon, TestSMSRecipients
class TestPhoneBlacklist(TestSMSCommon, TestSMSRecipients):
""" Test phone blacklist management """
@classmethod
def setUpClass(cls):
super(TestPhoneBlacklist, cls).setUpClass()
cls._test_body = 'VOID CONTENT'
cls.test_record = cls.env['mail.test.sms.bl'].with_context(**cls._test_context).create({
'name': 'Test',
'customer_id': cls.partner_1.id,
'mobile_nbr': cls.test_numbers[0],
'phone_nbr': cls.test_numbers[1],
})
cls.test_record = cls._reset_mail_context(cls.test_record)
def test_phone_blacklist_create_unblacklisted(self):
"""Ensure that the API allows creating unblacklisted records."""
phone_number = self.test_numbers[0]
unblacklisted_record = self.env['phone.blacklist'].sudo().create([{'number': phone_number, 'active': False}])
self.assertFalse(unblacklisted_record.active, "Creating an unblacklisted record resulted in a blacklisted one")
# Make sure that an attempt to re-create unblacklisted number will leave the number as it was (unblacklisted)
still_unblacklisted_record = self.env['phone.blacklist'].sudo().create([{'number': phone_number, 'active': False}])
self.assertFalse(still_unblacklisted_record.active, "Attempt to re-create the unblacklisted record made it blacklisted")
def test_phone_blacklist_internals(self):
with self.with_user('employee'):
test_record = self.env['mail.test.sms.bl'].browse(self.test_record.id)
self.assertEqual(test_record.phone_sanitized, self.test_numbers_san[1])
self.assertFalse(test_record.phone_sanitized_blacklisted)
bl_record = self.env['phone.blacklist'].sudo().create([{'number': self.test_numbers_san[1]}])
test_record.invalidate_recordset()
self.assertTrue(test_record.phone_sanitized_blacklisted)
self.env['phone.blacklist'].sudo().remove(self.test_numbers_san[1])
self.assertFalse(bl_record.active)
test_record.invalidate_recordset()
self.assertFalse(test_record.phone_sanitized_blacklisted)
self.env['phone.blacklist'].sudo().add(self.test_numbers_san[1])
self.assertTrue(bl_record.active)
test_record.invalidate_recordset()
self.assertTrue(test_record.phone_sanitized_blacklisted)
bl_record_2 = self.env['phone.blacklist'].sudo().create([{'number': self.test_numbers_san[1]}])
self.assertEqual(bl_record, bl_record_2)
rec = self.env['mail.test.sms.bl'].search([('phone_sanitized_blacklisted', '=', True)])
self.assertEqual(rec, test_record)
bl_record.unlink()
rec = self.env['mail.test.sms.bl'].search([('phone_sanitized_blacklisted', '=', True)])
self.assertEqual(rec, self.env['mail.test.sms.bl'])
def test_phone_blacklist_unblacklisted(self):
""" This test check for scenario where user:
1. Blacklists a number -> creating new active record)
2. Unblacklists it -> making record unactive (archived)
3. Blacklists it again (by attempting to create new record)
Last step should just make existing record active again, and this test checks it.
"""
phone_number = self.test_numbers[0]
bl_record = self.env['phone.blacklist'].sudo().create([{'number': phone_number, 'active': True}])
num_of_records = self.env['phone.blacklist'].with_context(active_test=False).search_count([])
bl_record.action_archive()
# Attempt to blacklist unblacklisted
self.env['phone.blacklist'].sudo().create([{'number': phone_number}])
self.assertTrue(bl_record.active, "Attempting to blacklist already-unblacklisted, should make the record active again")
self.assertEqual(num_of_records, self.env['phone.blacklist'].with_context(active_test=False).search_count([]),
"Number of records shouldn't change. (Records probably were recreated, instead of activated)")
def test_phone_sanitize_api(self):
with self.with_user('employee'):
test_record = self.env['mail.test.sms.bl'].browse(self.test_record.id)
self.assertFalse(test_record.phone_sanitized_blacklisted)
test_record._phone_set_blacklisted()
test_record.invalidate_recordset()
self.assertTrue(test_record.phone_sanitized_blacklisted)
test_record._phone_reset_blacklisted()
test_record.invalidate_recordset()
self.assertFalse(test_record.phone_sanitized_blacklisted)
def test_phone_sanitize_internals(self):
with self.with_user('employee'):
test_record = self.env['mail.test.sms.bl'].browse(self.test_record.id)
self.assertEqual(test_record.phone_nbr, self.test_numbers[1])
self.assertEqual(test_record.phone_sanitized, self.test_numbers_san[1])
test_record.write({'phone_nbr': 'incorrect'})
self.assertEqual(test_record.phone_nbr, 'incorrect')
self.assertEqual(test_record.phone_sanitized, self.test_numbers_san[0])
test_record.write({'mobile_nbr': 'incorrect'})
self.assertEqual(test_record.mobile_nbr, 'incorrect')
self.assertEqual(test_record.phone_sanitized, False)
test_record.write({'phone_nbr': self.test_numbers[1]})
self.assertEqual(test_record.phone_nbr, self.test_numbers[1])
self.assertEqual(test_record.phone_sanitized, self.test_numbers_san[1])

View file

@ -0,0 +1,625 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.addons.test_mail_sms.tests.common import TestSMSCommon, TestSMSRecipients
from odoo.tests import tagged
@tagged('sms_composer')
class TestSMSComposerComment(TestSMSCommon, TestSMSRecipients):
""" TODO LIST
* add test for default_res_model / default_res_id and stuff like that;
* add test for comment put in queue;
* add test for language support (set template lang context);
* add test for sanitized / wrong numbers;
"""
@classmethod
def setUpClass(cls):
super(TestSMSComposerComment, cls).setUpClass()
cls._test_body = 'VOID CONTENT'
cls.test_record = cls.env['mail.test.sms'].with_context(**cls._test_context).create({
'name': 'Test',
'customer_id': cls.partner_1.id,
'mobile_nbr': cls.test_numbers[0],
'phone_nbr': cls.test_numbers[1],
})
cls.test_record = cls._reset_mail_context(cls.test_record)
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 an SMS.',
})
def test_composer_comment_not_mail_thread(self):
with self.with_user('employee'):
record = self.env['test_performance.base'].create({'name': 'TestBase'})
composer = self.env['sms.composer'].with_context(
active_model='test_performance.base', active_id=record.id
).create({
'body': self._test_body,
'numbers': ','.join(self.random_numbers),
})
with self.mockSMSGateway():
composer._action_send_sms()
# use sms.api directly, does not create sms.sms
self.assertNoSMS()
self.assertSMSIapSent(self.random_numbers_san, self._test_body)
def test_composer_comment_default(self):
with self.with_user('employee'):
composer = self.env['sms.composer'].with_context(
active_model='mail.test.sms', active_id=self.test_record.id
).create({
'body': self._test_body,
})
with self.mockSMSGateway():
messages = composer._action_send_sms()
self.assertSMSNotification([{'partner': self.test_record.customer_id, 'number': self.test_numbers_san[1]}], self._test_body, messages)
def test_composer_comment_field_1(self):
with self.with_user('employee'):
composer = self.env['sms.composer'].with_context(
active_model='mail.test.sms', active_id=self.test_record.id,
).create({
'body': self._test_body,
'number_field_name': 'mobile_nbr',
})
with self.mockSMSGateway():
messages = composer._action_send_sms()
self.assertSMSNotification([{'partner': self.test_record.customer_id, 'number': self.test_numbers_san[0]}], self._test_body, messages)
def test_composer_comment_field_2(self):
with self.with_user('employee'):
composer = self.env['sms.composer'].with_context(
active_model='mail.test.sms', active_id=self.test_record.id,
).create({
'body': self._test_body,
'number_field_name': 'phone_nbr',
})
with self.mockSMSGateway():
messages = composer._action_send_sms()
self.assertSMSNotification([{'partner': self.test_record.customer_id, 'number': self.test_numbers_san[1]}], self._test_body, messages)
def test_composer_comment_field_w_numbers(self):
with self.with_user('employee'):
composer = self.env['sms.composer'].with_context(
active_model='mail.test.sms', active_id=self.test_record.id,
default_number_field_name='mobile_nbr',
).create({
'body': self._test_body,
'numbers': ','.join(self.random_numbers),
})
with self.mockSMSGateway():
messages = composer._action_send_sms()
self.assertSMSNotification([
{'partner': self.test_record.customer_id, 'number': self.test_record.mobile_nbr},
{'number': self.random_numbers_san[0]}, {'number': self.random_numbers_san[1]}], self._test_body, messages)
def test_composer_comment_field_w_template(self):
with self.with_user('employee'):
composer = self.env['sms.composer'].with_context(
active_model='mail.test.sms', active_id=self.test_record.id,
default_template_id=self.sms_template.id,
default_number_field_name='mobile_nbr',
).create({})
with self.mockSMSGateway():
messages = composer._action_send_sms()
self.assertSMSNotification([{'partner': self.test_record.customer_id, 'number': self.test_record.mobile_nbr}], 'Dear %s this is an SMS.' % self.test_record.display_name, messages)
def test_composer_comment_invalid_field(self):
""" Test the Send Message in SMS Composer when a Model does not contain a number field name """
test_record = self.env['mail.test.sms.partner'].create({
'name': 'Test',
'customer_id': self.partner_1.id,
})
sms_composer = self.env['sms.composer'].create({
'body': self._test_body,
'number_field_name': 'phone_nbr',
'recipient_single_number_itf': self.random_numbers_san[0],
'res_id': test_record.id,
'res_model': 'mail.test.sms.partner'
})
self.assertNotIn(','.join(test_record._fields), 'phone_nbr')
with self.mockSMSGateway():
sms_composer._action_send_sms()
self.assertSMSNotification([{'number': self.random_numbers_san[0]}], self._test_body)
def test_composer_comment_nofield(self):
""" Test the Send Message in SMS Composer when a Model does not contain any phone number related field """
test_record = self.env['mail.test.sms.partner'].create({'name': 'Test'})
sms_composer = self.env['sms.composer'].create({
'body': self._test_body,
'recipient_single_number_itf': self.random_numbers_san[0],
'res_id': test_record.id,
'res_model': 'mail.test.sms.partner'
})
with self.mockSMSGateway():
sms_composer._action_send_sms()
self.assertSMSNotification([{'number': self.random_numbers_san[0]}], self._test_body)
def test_composer_default_recipient(self):
""" Test default description of SMS composer must be partner name"""
self.test_record.write({
'phone_nbr': '0123456789',
})
with self.with_user('employee'):
composer = self.env['sms.composer'].with_context(
default_res_model='mail.test.sms', default_res_id=self.test_record.id,
).create({
'body': self._test_body,
'number_field_name': 'phone_nbr',
})
self.assertEqual(composer.recipient_single_description, self.test_record.customer_id.display_name)
def test_composer_nofield_w_customer(self):
""" Test SMS composer without number field, the number on partner must be used instead"""
with self.with_user('employee'):
composer = self.env['sms.composer'].with_context(
default_res_model='mail.test.sms', default_res_id=self.test_record.id,
).create({
'body': self._test_body,
})
self.assertTrue(composer.recipient_single_valid)
self.assertEqual(composer.recipient_single_number, self.test_numbers_san[1])
self.assertEqual(composer.recipient_single_number_itf, self.test_numbers_san[1])
def test_composer_internals(self):
with self.with_user('employee'):
composer = self.env['sms.composer'].with_context(
default_res_model='mail.test.sms', default_res_id=self.test_record.id,
).create({
'body': self._test_body,
'number_field_name': 'phone_nbr',
})
self.assertEqual(composer.res_model, self.test_record._name)
self.assertEqual(composer.res_id, self.test_record.id)
self.assertEqual(composer.number_field_name, 'phone_nbr')
self.assertTrue(composer.comment_single_recipient)
self.assertEqual(composer.recipient_single_description, self.test_record.customer_id.display_name)
self.assertEqual(composer.recipient_single_number, self.test_numbers_san[1])
self.assertEqual(composer.recipient_single_number_itf, self.test_numbers_san[1])
self.assertTrue(composer.recipient_single_valid)
self.assertEqual(composer.recipient_valid_count, 1)
self.assertEqual(composer.recipient_invalid_count, 0)
with self.with_user('employee'):
composer.update({'recipient_single_number_itf': '0123456789'})
self.assertFalse(composer.recipient_single_valid)
with self.with_user('employee'):
composer.update({'recipient_single_number_itf': self.random_numbers[0]})
self.assertTrue(composer.recipient_single_valid)
with self.with_user('employee'):
with self.mockSMSGateway():
composer.action_send_sms()
self.test_record.flush_recordset()
self.assertEqual(self.test_record.phone_nbr, self.random_numbers[0])
def test_composer_comment_wo_partner_wo_value_update(self):
""" Test record without partner and without phone values: should allow updating first found phone field """
self.test_record.write({
'customer_id': False,
'phone_nbr': False,
'mobile_nbr': False,
})
default_field_name = self.env['mail.test.sms']._sms_get_number_fields()[0]
with self.with_user('employee'):
composer = self.env['sms.composer'].with_context(
active_model='mail.test.sms', active_id=self.test_record.id,
default_composition_mode='comment',
).create({
'body': self._test_body,
})
self.assertFalse(composer.recipient_single_number_itf)
self.assertFalse(composer.recipient_single_number)
self.assertEqual(composer.number_field_name, default_field_name)
composer.write({
'recipient_single_number_itf': self.random_numbers_san[0],
})
self.assertEqual(composer.recipient_single_number_itf, self.random_numbers_san[0])
self.assertFalse(composer.recipient_single_number)
with self.mockSMSGateway():
messages = composer._action_send_sms()
self.assertEqual(self.test_record[default_field_name], self.random_numbers_san[0])
self.assertSMSNotification([{'partner': self.env['res.partner'], 'number': self.random_numbers_san[0]}], self._test_body, messages)
def test_composer_numbers_no_model(self):
with self.with_user('employee'):
composer = self.env['sms.composer'].with_context(
default_composition_mode='numbers'
).create({
'body': self._test_body,
'numbers': ','.join(self.random_numbers),
})
with self.mockSMSGateway():
composer._action_send_sms()
# use sms.api directly, does not create sms.sms
self.assertNoSMS()
self.assertSMSIapSent(self.random_numbers_san, self._test_body)
def test_composer_sending_with_no_number_field(self):
test_record = self.env['mail.test.sms.partner'].create({'name': 'Test'})
sms_composer = self.env['sms.composer'].create({
'body': self._test_body,
'composition_mode': 'comment',
'mass_force_send': False,
'mass_keep_log': True,
'number_field_name': False,
'numbers': False,
'recipient_single_number_itf': self.random_numbers_san[0],
'res_id': test_record.id,
'res_model': 'mail.test.sms.partner'
})
with self.mockSMSGateway():
sms_composer._action_send_sms()
self.assertSMSNotification([{'number': self.random_numbers_san[0]}], self._test_body)
@tagged('sms_composer')
class TestSMSComposerBatch(TestSMSCommon):
@classmethod
def setUpClass(cls):
super(TestSMSComposerBatch, cls).setUpClass()
cls._test_body = 'Hello {{ object.name }} zizisse an SMS.'
cls._create_records_for_batch('mail.test.sms', 3)
cls.sms_template = cls._create_sms_template('mail.test.sms')
def test_composer_batch_active_ids(self):
with self.with_user('employee'):
composer = self.env['sms.composer'].with_context(
default_composition_mode='comment',
default_res_model='mail.test.sms',
active_ids=self.records.ids
).create({
'body': self._test_body,
})
with self.mockSMSGateway():
messages = composer._action_send_sms()
for record, message in zip(self.records, messages):
self.assertSMSNotification(
[{'partner': record.customer_id}],
'Hello %s zizisse an SMS.' % record.name,
message
)
def test_composer_batch_res_ids(self):
with self.with_user('employee'):
composer = self.env['sms.composer'].with_context(
default_composition_mode='comment',
default_res_model='mail.test.sms',
default_res_ids=repr(self.records.ids),
).create({
'body': self._test_body,
})
with self.mockSMSGateway():
messages = composer._action_send_sms()
for record, message in zip(self.records, messages):
self.assertSMSNotification(
[{'partner': record.customer_id}],
'Hello %s zizisse an SMS.' % record.name,
message
)
@tagged('sms_composer')
class TestSMSComposerMass(TestSMSCommon):
@classmethod
def setUpClass(cls):
super(TestSMSComposerMass, cls).setUpClass()
cls._test_body = 'Hello {{ object.name }} zizisse an SMS.'
cls._create_records_for_batch('mail.test.sms', 10)
cls.sms_template = cls._create_sms_template('mail.test.sms')
def test_composer_mass_active_ids(self):
with self.with_user('employee'):
composer = self.env['sms.composer'].with_context(
default_composition_mode='mass',
default_res_model='mail.test.sms',
active_ids=self.records.ids,
).create({
'body': self._test_body,
'mass_keep_log': False,
})
with self.mockSMSGateway():
composer.action_send_sms()
for partner, record in zip(self.partners, self.records):
self.assertSMSOutgoing(
partner, None,
content='Hello %s zizisse an SMS.' % record.name
)
def test_composer_mass_active_ids_w_blacklist(self):
self.env['phone.blacklist'].create([{
'number': p.phone_sanitized,
'active': True,
} for p in self.partners[:5]])
with self.with_user('employee'):
composer = self.env['sms.composer'].with_context(
default_composition_mode='mass',
default_res_model='mail.test.sms',
active_ids=self.records.ids,
).create({
'body': self._test_body,
'mass_keep_log': False,
'mass_use_blacklist': True,
})
with self.mockSMSGateway():
composer.action_send_sms()
for partner, record in zip(self.partners[5:], self.records[5:]):
self.assertSMSOutgoing(
partner, partner.phone_sanitized,
content='Hello %s zizisse an SMS.' % record.name
)
for partner, record in zip(self.partners[:5], self.records[:5]):
self.assertSMSCanceled(
partner, partner.phone_sanitized,
failure_type='sms_blacklist',
content='Hello %s zizisse an SMS.' % record.name
)
def test_composer_mass_active_ids_wo_blacklist(self):
self.env['phone.blacklist'].create([{
'number': p.phone_sanitized,
'active': True,
} for p in self.partners[:5]])
with self.with_user('employee'):
composer = self.env['sms.composer'].with_context(
default_composition_mode='mass',
default_res_model='mail.test.sms',
active_ids=self.records.ids,
).create({
'body': self._test_body,
'mass_keep_log': False,
'mass_use_blacklist': False,
})
with self.mockSMSGateway():
composer.action_send_sms()
for partner, record in zip(self.partners, self.records):
self.assertSMSOutgoing(
partner, partner.phone_sanitized,
content='Hello %s zizisse an SMS.' % record.name
)
def test_composer_mass_active_ids_w_blacklist_and_done(self):
""" Create some duplicates + blacklist. record[5] will have duplicated
number on 6 and 7. """
self.env['phone.blacklist'].create([{
'number': p.phone_sanitized,
'active': True,
} for p in self.partners[:5]])
for p in self.partners[5:8]:
p.mobile = self.partners[5].mobile
self.assertEqual(p.phone_sanitized, self.partners[5].phone_sanitized)
with self.with_user('employee'):
composer = self.env['sms.composer'].with_context(
default_composition_mode='mass',
default_res_model='mail.test.sms',
active_ids=self.records.ids,
).create({
'body': self._test_body,
'mass_keep_log': False,
'mass_use_blacklist': True,
})
with self.mockSMSGateway():
composer.action_send_sms()
self.assertSMSOutgoing(
self.partners[5], self.partners[5].phone_sanitized,
content='Hello %s zizisse an SMS.' % self.records[5].name
)
for partner, record in zip(self.partners[8:], self.records[8:]):
self.assertSMSOutgoing(
partner, partner.phone_sanitized,
content='Hello %s zizisse an SMS.' % record.name
)
# duplicates
for partner, record in zip(self.partners[6:8], self.records[6:8]):
self.assertSMSCanceled(
partner, partner.phone_sanitized,
failure_type='sms_duplicate',
content='Hello %s zizisse an SMS.' % record.name
)
# blacklist
for partner, record in zip(self.partners[:5], self.records[:5]):
self.assertSMSCanceled(
partner, partner.phone_sanitized,
failure_type='sms_blacklist',
content='Hello %s zizisse an SMS.' % record.name
)
def test_composer_mass_active_ids_w_template(self):
with self.with_user('employee'):
composer = self.env['sms.composer'].with_context(
default_composition_mode='mass',
default_res_model='mail.test.sms',
active_ids=self.records.ids,
default_template_id=self.sms_template.id,
).create({
'mass_keep_log': False,
})
with self.mockSMSGateway():
composer.action_send_sms()
for record in self.records:
self.assertSMSOutgoing(
record.customer_id, None,
content='Dear %s this is an SMS.' % record.display_name
)
def test_composer_mass_active_ids_w_template_and_lang(self):
self.env['res.lang']._activate_lang('fr_FR')
self.sms_template.with_context(lang='fr_FR').body = 'Cher·e· {{ object.display_name }} ceci est un SMS.'
# set template to try to use customer lang
self.sms_template.write({
'lang': '{{ object.customer_id.lang }}',
})
# set one customer as french speaking
self.partners[2].write({'lang': 'fr_FR'})
with self.with_user('employee'):
composer = self.env['sms.composer'].with_context(
default_composition_mode='mass',
default_res_model='mail.test.sms',
active_ids=self.records.ids,
default_template_id=self.sms_template.id,
).create({
'mass_keep_log': False,
})
with self.mockSMSGateway():
composer.action_send_sms()
for record in self.records:
if record.customer_id == self.partners[2]:
self.assertSMSOutgoing(
record.customer_id, None,
content='Cher·e· %s ceci est un SMS.' % record.display_name
)
else:
self.assertSMSOutgoing(
record.customer_id, None,
content='Dear %s this is an SMS.' % record.display_name
)
def test_composer_mass_active_ids_w_template_and_log(self):
with self.with_user('employee'):
composer = self.env['sms.composer'].with_context(
default_composition_mode='mass',
default_res_model='mail.test.sms',
active_ids=self.records.ids,
default_template_id=self.sms_template.id,
).create({
'mass_keep_log': True,
})
with self.mockSMSGateway():
composer.action_send_sms()
for record in self.records:
self.assertSMSOutgoing(
record.customer_id, None,
content='Dear %s this is an SMS.' % record.display_name
)
self.assertSMSLogged(record, 'Dear %s this is an SMS.' % record.display_name)
def test_composer_template_context_action(self):
""" Test the context action from a SMS template (Add context action button)
and the usage with the sms composer """
# Create the lang info
self.env['res.lang']._activate_lang('fr_FR')
self.sms_template.with_context(lang='fr_FR').body = 'Hello {{ object.display_name }} ceci est en français.'
# set template to try to use customer lang
self.sms_template.write({
'lang': '{{ object.customer_id.lang }}',
})
# create a second record linked to a customer in another language
self.partners[2].write({'lang': 'fr_FR'})
test_record_2 = self.env['mail.test.sms'].create({
'name': 'Test',
'customer_id': self.partners[2].id,
})
test_record_1 = self.env['mail.test.sms'].create({
'name': 'Test',
'customer_id': self.partners[1].id,
})
# Composer creation with context from a template context action (simulate) - comment (single recipient)
with self.with_user('employee'):
composer = self.env['sms.composer'].with_context(
sms_composition_mode='guess',
default_res_ids=[test_record_2.id],
default_res_id=test_record_2.id,
active_ids=[test_record_2.id],
active_id=test_record_2.id,
active_model='mail.test.sms',
default_template_id=self.sms_template.id,
).create({
'mass_keep_log': False,
})
self.assertEqual(composer.composition_mode, "comment")
self.assertEqual(composer.body, "Hello %s ceci est en français." % test_record_2.display_name)
with self.mockSMSGateway():
messages = composer._action_send_sms()
number = self.partners[2].phone_get_sanitized_number()
self.assertSMSNotification(
[{'partner': test_record_2.customer_id, 'number': number}],
"Hello %s ceci est en français." % test_record_2.display_name, messages
)
# Composer creation with context from a template context action (simulate) - mass (multiple recipient)
with self.with_user('employee'):
composer = self.env['sms.composer'].with_context(
sms_composition_mode='guess',
default_res_ids=[test_record_1.id, test_record_2.id],
default_res_id=test_record_1.id,
active_ids=[test_record_1.id, test_record_2.id],
active_id=test_record_1.id,
active_model='mail.test.sms',
default_template_id=self.sms_template.id,
).create({
'mass_keep_log': True,
})
self.assertEqual(composer.composition_mode, "mass")
# In english because by default but when sinding depending of record
self.assertEqual(composer.body, "Dear {{ object.display_name }} this is an SMS.")
with self.mockSMSGateway():
composer.action_send_sms()
self.assertSMSOutgoing(
test_record_1.customer_id, None,
content='Dear %s this is an SMS.' % test_record_1.display_name
)
self.assertSMSOutgoing(
test_record_2.customer_id, None,
content="Hello %s ceci est en français." % test_record_2.display_name
)

View file

@ -0,0 +1,199 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.addons.test_mail_sms.tests.common import TestSMSCommon, TestSMSRecipients
from odoo.tests import tagged
from odoo.tools import mute_logger
class TestSMSActionsCommon(TestSMSCommon, TestSMSRecipients):
@classmethod
def setUpClass(cls):
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({
'author_id': cls.msg.author_id.id,
'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({
'author_id': cls.msg.author_id.id,
'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_notify_cancel(self):
self._reset_bus()
with self.with_user('employee'):
self.test_record.with_user(self.env.user).notify_cancel_by_type('sms')
self.assertEqual((self.notif_p1 | self.notif_p2).mapped('notification_status'), ['canceled', 'canceled'])
self.assertMessageBusNotifications(self.msg)
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()
with self.with_user('employee'):
wizard = self.env['sms.resend'].with_context(default_mail_message_id=self.msg.id).create({})
wizard.write({'recipient_ids': [(1, r.id, {'resend': True}) for r in wizard.recipient_ids]})
with self.mockSMSGateway():
wizard.action_resend()
self.assertSMSNotification([
{'partner': self.partner_1, 'state': 'sent'},
{'partner': self.partner_2, 'state': 'sent'}
], '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()
with self.with_user('employee'):
wizard = self.env['sms.resend'].with_context(default_mail_message_id=self.msg.id).create({})
wizard.write({'recipient_ids': [(1, r.id, {'resend': True, 'sms_number': self.random_numbers[idx]}) for idx, r in enumerate(wizard.recipient_ids.sorted())]})
with self.mockSMSGateway():
wizard.action_resend()
self.assertSMSNotification([
{'partner': self.partner_1, 'state': 'sent', 'number': self.random_numbers_san[0]},
{'partner': self.partner_2, 'state': 'sent', 'number': self.random_numbers_san[1]}
], 'TEST BODY', self.msg, check_sms=True)
self.assertMessageBusNotifications(self.msg)
def test_sms_resend_cancel(self):
self._reset_bus()
with self.with_user('employee'):
wizard = self.env['sms.resend'].with_context(default_mail_message_id=self.msg.id).create({})
with self.mockSMSGateway():
wizard.action_cancel()
self.assertSMSNotification([
{'partner': self.partner_1, 'state': 'canceled', 'number': self.notif_p1.sms_number, 'failure_type': 'sms_number_format'},
{'partner': self.partner_2, 'state': 'canceled', 'number': self.notif_p2.sms_number, 'failure_type': 'sms_credit'}
], '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([
{'partner': self.partner_1, 'state': 'exception', 'number': self.notif_p1.sms_number, 'failure_type': 'sms_number_format'},
{'partner': self.partner_2, 'state': 'exception', 'number': self.notif_p2.sms_number, 'failure_type': 'sms_credit'}
], 'TEST BODY', self.msg, check_sms=False)
with self.with_user('employee'):
wizard = self.env['sms.resend'].with_context(default_mail_message_id=self.msg.id).create({})
self.assertTrue(wizard.has_insufficient_credit)
self.assertEqual(set(wizard.mapped('recipient_ids.partner_name')), set((self.partner_1 | self.partner_2).mapped('display_name')))
wizard.write({'recipient_ids': [(1, r.id, {'resend': True}) for r in wizard.recipient_ids]})
with self.mockSMSGateway():
wizard.action_resend()
@mute_logger('odoo.addons.sms.models.sms_sms')
def test_sms_resend_w_cancel(self):
self._reset_bus()
with self.with_user('employee'):
wizard = self.env['sms.resend'].with_context(default_mail_message_id=self.msg.id).create({})
wizard.write({'recipient_ids': [(1, r.id, {'resend': True if r.partner_id == self.partner_1 else False}) for r in wizard.recipient_ids]})
with self.mockSMSGateway():
wizard.action_resend()
self.assertSMSNotification([{'partner': self.partner_1, 'state': 'sent'}], 'TEST BODY', self.msg, check_sms=True)
self.assertSMSNotification([{'partner': self.partner_2, 'state': 'canceled', 'number': self.notif_p2.sms_number, 'failure_type': 'sms_credit'}], 'TEST BODY', self.msg, check_sms=False)
self.assertMessageBusNotifications(self.msg)

View file

@ -0,0 +1,108 @@
from odoo.addons.test_mail_sms.tests.common import TestSMSCommon, TestSMSRecipients
from odoo.tests import Form, tagged
@tagged('sms_composer')
class TestSMSNoThread(TestSMSCommon, TestSMSRecipients):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls._test_body_dyn = 'Hello {{ object.name }} zizisse an SMS.'
cls._test_body_sta = 'Hello Zboing'
cls.test_nothreads = cls.env['sms.test.nothread'].create([
{
'name': 'Test',
'customer_id': cls.partner_1.id,
}, {
'name': 'Test',
'customer_id': cls.partner_2.id,
}, {
'name': 'Test (no partner)',
'customer_id': False,
},
])
cls.sms_template = cls._create_sms_template(
cls.test_nothreads._name,
body=cls._test_body_dyn,
)
def test_composer_comment(self):
with self.with_user('employee'):
test_record = self.test_nothreads[0].with_env(self.env)
composer_form = Form(self.env['sms.composer'].with_context(
default_res_id=test_record.id,
default_res_model=test_record._name,
))
composer_form.body = self._test_body_sta
composer = composer_form.save()
self.assertTrue(composer.comment_single_recipient)
self.assertEqual(composer.composition_mode, 'comment')
self.assertEqual(composer.recipient_valid_count, 0)
self.assertEqual(composer.recipient_invalid_count, 1)
self.assertEqual(composer.recipient_single_description, self.partner_1.name)
self.assertEqual(composer.recipient_single_number, '+32456001122')
self.assertEqual(composer.recipient_single_number_itf, '+32456001122')
self.assertTrue(composer.recipient_single_valid)
self.assertEqual(composer.number_field_name, 'mobile')
self.assertFalse(composer.numbers)
self.assertFalse(composer.sanitized_numbers)
with self.mockSMSGateway():
composer._action_send_sms()
def test_composer_comment_res_ids(self):
with self.with_user('employee'):
test_record = self.test_nothreads[0].with_env(self.env)
composer_form = Form(self.env['sms.composer'].with_context(
default_res_ids=test_record.ids,
default_res_model=test_record._name,
))
composer_form.body = self._test_body_sta
composer = composer_form.save()
# TDE FIXME: mono/mass mode should be fixed
self.assertFalse(composer.comment_single_recipient)
self.assertEqual(composer.composition_mode, 'comment')
self.assertEqual(composer.recipient_valid_count, 1)
self.assertEqual(composer.recipient_invalid_count, 0)
self.assertFalse(composer.recipient_single_description)
self.assertFalse(composer.recipient_single_number)
self.assertFalse(composer.recipient_single_number_itf)
self.assertFalse(composer.recipient_single_valid)
self.assertFalse(composer.number_field_name)
self.assertFalse(composer.numbers)
self.assertFalse(composer.sanitized_numbers)
with self.mockSMSGateway():
composer._action_send_sms()
def test_composer_comment_res_users(self):
for ctx, expected in [
({}, {}),
({'default_number_field_name': 'mobile'}, {}),
]:
with self.subTest(ctx=ctx):
with self.with_user('employee'):
ctx['default_res_id'] = self.user_admin.id
ctx['default_res_model'] = self.user_admin._name
composer_form = Form(self.env['sms.composer'].with_context(**ctx))
composer_form.body = self._test_body_sta
composer = composer_form.save()
self.assertTrue(composer.comment_single_recipient)
self.assertEqual(composer.composition_mode, 'comment')
if ctx.get('default_number_field_name') == 'mobile':
self.assertEqual(composer.recipient_valid_count, 0)
self.assertEqual(composer.recipient_invalid_count, 1)
else:
self.assertEqual(composer.recipient_valid_count, 1)
self.assertEqual(composer.recipient_invalid_count, 0)
self.assertEqual(composer.recipient_single_description, self.user_admin.name)
self.assertEqual(composer.recipient_single_number, '+32455135790')
self.assertEqual(composer.recipient_single_number_itf, '+32455135790')
self.assertTrue(composer.recipient_single_valid)
self.assertEqual(composer.number_field_name, ctx.get('default_number_field_name', 'phone'))
self.assertFalse(composer.numbers)
self.assertFalse(composer.sanitized_numbers)
with self.mockSMSGateway():
composer._action_send_sms()

View file

@ -0,0 +1,137 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.addons.sms.tests import common as sms_common
from odoo.addons.test_mail.tests.test_performance import BaseMailPerformance
from odoo.tests.common import users, warmup
from odoo.tests import tagged
from odoo.tools import mute_logger
@tagged('mail_performance', 'post_install', '-at_install')
class TestSMSPerformance(BaseMailPerformance, sms_common.SMSCase):
def setUp(self):
super(TestSMSPerformance, self).setUp()
self.test_record = self.env['mail.test.sms'].with_context(self._test_context).create({
'name': 'Test',
'customer_id': self.customer.id,
'phone_nbr': '0456999999',
})
# prepare recipients to test for more realistic workload
self.partners = self.env['res.partner'].with_context(self._test_context).create([
{'name': 'Test %s' % x,
'email': 'test%s@example.com' % x,
'mobile': '0456%s%s0000' % (x, x),
'country_id': self.env.ref('base.be').id,
} for x in range(0, 10)
])
@mute_logger('odoo.addons.sms.models.sms_sms')
@users('employee')
@warmup
def test_message_sms_record_1_partner(self):
record = self.test_record.with_user(self.env.user)
pids = self.customer.ids
with self.mockSMSGateway(sms_allow_unlink=True), self.assertQueryCount(employee=26):
messages = record._message_sms(
body='Performance Test',
partner_ids=pids,
)
self.assertEqual(record.message_ids[0].body, '<p>Performance Test</p>')
self.assertSMSNotification([{'partner': self.customer}], 'Performance Test', messages, sent_unlink=True)
@mute_logger('odoo.addons.sms.models.sms_sms')
@users('employee')
@warmup
def test_message_sms_record_10_partners(self):
record = self.test_record.with_user(self.env.user)
pids = self.partners.ids
with self.mockSMSGateway(sms_allow_unlink=True), self.assertQueryCount(employee=26):
messages = record._message_sms(
body='Performance Test',
partner_ids=pids,
)
self.assertEqual(record.message_ids[0].body, '<p>Performance Test</p>')
self.assertSMSNotification([{'partner': partner} for partner in self.partners], 'Performance Test', messages, sent_unlink=True)
@mute_logger('odoo.addons.sms.models.sms_sms')
@users('employee')
@warmup
def test_message_sms_record_default(self):
record = self.test_record.with_user(self.env.user)
with self.mockSMSGateway(sms_allow_unlink=True), self.assertQueryCount(employee=28):
messages = record._message_sms(
body='Performance Test',
)
self.assertEqual(record.message_ids[0].body, '<p>Performance Test</p>')
self.assertSMSNotification([{'partner': self.customer}], 'Performance Test', messages, sent_unlink=True)
@tagged('mail_performance', 'post_install', '-at_install')
class TestSMSMassPerformance(BaseMailPerformance, sms_common.MockSMS):
def setUp(self):
super(TestSMSMassPerformance, self).setUp()
be_country_id = self.env.ref('base.be').id
self._test_body = 'MASS SMS'
records = self.env['mail.test.sms']
partners = self.env['res.partner']
for x in range(50):
partners += self.env['res.partner'].with_context(**self._test_context).create({
'name': 'Partner_%s' % (x),
'email': '_test_partner_%s@example.com' % (x),
'country_id': be_country_id,
'mobile': '047500%02d%02d' % (x, x)
})
records += self.env['mail.test.sms'].with_context(**self._test_context).create({
'name': 'Test_%s' % (x),
'customer_id': partners[x].id,
})
self.partners = partners
self.records = records
self.sms_template = self.env['sms.template'].create({
'name': 'Test Template',
'model_id': self.env['ir.model']._get('mail.test.sms').id,
'body': 'Dear {{ object.display_name }} this is an SMS.',
})
@mute_logger('odoo.addons.sms.models.sms_sms')
@users('employee')
@warmup
def test_sms_composer_mass(self):
composer = self.env['sms.composer'].with_context(
default_composition_mode='mass',
default_res_model='mail.test.sms',
active_ids=self.records.ids,
).create({
'body': self._test_body,
'mass_keep_log': False,
})
with self.mockSMSGateway(sms_allow_unlink=True), self.assertQueryCount(employee=56):
composer.action_send_sms()
@mute_logger('odoo.addons.sms.models.sms_sms')
@users('employee')
@warmup
def test_sms_composer_mass_w_log(self):
composer = self.env['sms.composer'].with_context(
default_composition_mode='mass',
default_res_model='mail.test.sms',
active_ids=self.records.ids,
).create({
'body': self._test_body,
'mass_keep_log': True,
})
with self.mockSMSGateway(sms_allow_unlink=True), self.assertQueryCount(employee=58):
composer.action_send_sms()

View file

@ -0,0 +1,455 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.addons.test_mail_sms.tests.common import TestSMSCommon, TestSMSRecipients
class TestSMSPost(TestSMSCommon, TestSMSRecipients):
""" TODO
* add tests for new mail.message and mail.thread fields;
"""
@classmethod
def setUpClass(cls):
super(TestSMSPost, cls).setUpClass()
cls._test_body = 'VOID CONTENT'
cls.test_record = cls.env['mail.test.sms'].with_context(**cls._test_context).create({
'name': 'Test',
'customer_id': cls.partner_1.id,
'mobile_nbr': cls.test_numbers[0],
'phone_nbr': cls.test_numbers[1],
})
cls.test_record = cls._reset_mail_context(cls.test_record)
def test_message_sms_internals_body(self):
with self.with_user('employee'), self.mockSMSGateway():
test_record = self.env['mail.test.sms'].browse(self.test_record.id)
messages = test_record._message_sms('<p>Mega SMS<br/>Top moumoutte</p>', partner_ids=self.partner_1.ids)
self.assertEqual(messages.body, '<p>&lt;p&gt;Mega SMS&lt;br/&gt;Top moumoutte&lt;/p&gt;</p>') # html should not be interpreted
self.assertEqual(messages.subtype_id, self.env.ref('mail.mt_note'))
self.assertSMSNotification([{'partner': self.partner_1}], '<p>Mega SMS<br/>Top moumoutte</p>', messages)
def test_message_sms_internals_resend_existingd(self):
with self.with_user('employee'), self.mockSMSGateway(sim_error='wrong_number_format'):
test_record = self.env['mail.test.sms'].browse(self.test_record.id)
messages = test_record._message_sms(self._test_body, partner_ids=self.partner_1.ids)
self.assertSMSNotification([{'partner': self.partner_1, 'state': 'exception', 'failure_type': 'sms_number_format'}], self._test_body, messages)
with self.with_user('employee'), self.mockSMSGateway():
test_record = self.env['mail.test.sms'].browse(self.test_record.id)
test_record._notify_thread_by_sms(messages, [{'id': self.partner_1.id, 'notif': 'sms'}], resend_existing=True)
self.assertSMSNotification([{'partner': self.partner_1}], self._test_body, messages)
def test_message_sms_internals_sms_numbers(self):
with self.with_user('employee'), self.mockSMSGateway():
test_record = self.env['mail.test.sms'].browse(self.test_record.id)
messages = test_record._message_sms(self._test_body, partner_ids=self.partner_1.ids, sms_numbers=self.random_numbers)
self.assertSMSNotification([{'partner': self.partner_1}, {'number': self.random_numbers_san[0]}, {'number': self.random_numbers_san[1]}], self._test_body, messages)
def test_message_sms_internals_sms_numbers_duplicate(self):
""" _message_sms ( which uses _notify_thread_by_sms) allows for specifying additional number to send sms to
This test checks for situation where this additional number is the same as partner telephone number.
In that case sms shall NOT be sent twice."""
with self.with_user('employee'), self.mockSMSGateway():
test_record = self.env['mail.test.sms'].browse(self.test_record.id)
additional_number_same_as_partner_number = self.partner_1.mobile
subtype_id = self.env['ir.model.data']._xmlid_to_res_id('mail.mt_note')
test_record._message_sms(
body=self._test_body,
partner_ids=self.partner_1.ids,
subtype_id=subtype_id,
sms_numbers=[additional_number_same_as_partner_number],
number_field='mobile'
)
self.assertEqual(len(self._new_sms.filtered(lambda s: s.number == self.partner_numbers[0])), 1,
"There should be one message sent if additional number is the same as partner number")
def test_message_sms_internals_subtype(self):
with self.with_user('employee'), self.mockSMSGateway():
test_record = self.env['mail.test.sms'].browse(self.test_record.id)
messages = test_record._message_sms('<p>Mega SMS<br/>Top moumoutte</p>', subtype_id=self.env.ref('mail.mt_comment').id, partner_ids=self.partner_1.ids)
self.assertEqual(messages.body, '<p>&lt;p&gt;Mega SMS&lt;br/&gt;Top moumoutte&lt;/p&gt;</p>') # html should not be interpreted
self.assertEqual(messages.subtype_id, self.env.ref('mail.mt_comment'))
self.assertSMSNotification([{'partner': self.partner_1}], '<p>Mega SMS<br/>Top moumoutte</p>', messages)
def test_message_sms_internals_pid_to_number(self):
pid_to_number = {
self.partner_1.id: self.random_numbers[0],
self.partner_2.id: self.random_numbers[1],
}
with self.with_user('employee'), self.mockSMSGateway():
test_record = self.env['mail.test.sms'].browse(self.test_record.id)
messages = test_record._message_sms(self._test_body, partner_ids=(self.partner_1 | self.partner_2).ids, sms_pid_to_number=pid_to_number)
self.assertSMSNotification([
{'partner': self.partner_1, 'number': self.random_numbers_san[0]},
{'partner': self.partner_2, 'number': self.random_numbers_san[1]}],
self._test_body, messages)
def test_message_sms_model_partner(self):
with self.with_user('employee'), self.mockSMSGateway():
messages = self.partner_1._message_sms(self._test_body)
messages |= self.partner_2._message_sms(self._test_body)
self.assertSMSNotification([{'partner': self.partner_1}, {'partner': self.partner_2}], self._test_body, messages)
def test_message_sms_model_partner_fallback(self):
self.partner_1.write({'mobile': False, 'phone': self.random_numbers[0]})
with self.mockSMSGateway():
messages = self.partner_1._message_sms(self._test_body)
messages |= self.partner_2._message_sms(self._test_body)
self.assertSMSNotification([{'partner': self.partner_1, 'number': self.random_numbers_san[0]}, {'partner': self.partner_2}], self._test_body, messages)
def test_message_sms_model_w_partner_only(self):
with self.with_user('employee'):
record = self.env['mail.test.sms.partner'].create({'customer_id': self.partner_1.id})
with self.mockSMSGateway():
messages = record._message_sms(self._test_body)
self.assertSMSNotification([{'partner': self.partner_1}], self._test_body, messages)
def test_message_sms_model_w_partner_only_void(self):
with self.with_user('employee'):
record = self.env['mail.test.sms.partner'].create({'customer_id': False})
with self.mockSMSGateway():
messages = record._message_sms(self._test_body)
# should not crash but have a failed notification
self.assertSMSNotification([{'partner': self.env['res.partner'], 'number': False, 'state': 'exception', 'failure_type': 'sms_number_missing'}], self._test_body, messages)
def test_message_sms_model_w_partner_m2m_only(self):
with self.with_user('employee'):
record = self.env['mail.test.sms.partner.2many'].create({'customer_ids': [(4, self.partner_1.id)]})
with self.mockSMSGateway():
messages = record._message_sms(self._test_body)
self.assertSMSNotification([{'partner': self.partner_1}], self._test_body, messages)
# TDE: should take first found one according to partner ordering
with self.with_user('employee'):
record = self.env['mail.test.sms.partner.2many'].create({'customer_ids': [(4, self.partner_1.id), (4, self.partner_2.id)]})
with self.mockSMSGateway():
messages = record._message_sms(self._test_body)
self.assertSMSNotification([{'partner': self.partner_2}], self._test_body, messages)
def test_message_sms_on_field_w_partner(self):
with self.with_user('employee'), self.mockSMSGateway():
test_record = self.env['mail.test.sms'].browse(self.test_record.id)
messages = test_record._message_sms(self._test_body, number_field='mobile_nbr')
self.assertSMSNotification([{'partner': self.partner_1, 'number': self.test_record.mobile_nbr}], self._test_body, messages)
def test_message_sms_on_field_wo_partner(self):
self.test_record.write({'customer_id': False})
with self.with_user('employee'), self.mockSMSGateway():
test_record = self.env['mail.test.sms'].browse(self.test_record.id)
messages = test_record._message_sms(self._test_body, number_field='mobile_nbr')
self.assertSMSNotification([{'number': self.test_record.mobile_nbr}], self._test_body, messages)
def test_message_sms_on_field_wo_partner_wo_value(self):
""" Test record without a partner and without phone values. """
self.test_record.write({
'customer_id': False,
'phone_nbr': False,
'mobile_nbr': False,
})
with self.with_user('employee'), self.mockSMSGateway():
test_record = self.env['mail.test.sms'].browse(self.test_record.id)
messages = test_record._message_sms(self._test_body)
# should not crash but have a failed notification
self.assertSMSNotification([{'partner': self.env['res.partner'], 'number': False, 'state': 'exception', 'failure_type': 'sms_number_missing'}], self._test_body, messages)
def test_message_sms_on_field_wo_partner_default_field(self):
self.test_record.write({'customer_id': False})
with self.with_user('employee'), self.mockSMSGateway():
test_record = self.env['mail.test.sms'].browse(self.test_record.id)
messages = test_record._message_sms(self._test_body)
self.assertSMSNotification([{'number': self.test_numbers_san[1]}], self._test_body, messages)
def test_message_sms_on_field_wo_partner_default_field_2(self):
self.test_record.write({'customer_id': False, 'phone_nbr': False})
with self.with_user('employee'), self.mockSMSGateway():
test_record = self.env['mail.test.sms'].browse(self.test_record.id)
messages = test_record._message_sms(self._test_body)
self.assertSMSNotification([{'number': self.test_numbers_san[0]}], self._test_body, messages)
def test_message_sms_on_numbers(self):
with self.with_user('employee'), self.mockSMSGateway():
test_record = self.env['mail.test.sms'].browse(self.test_record.id)
messages = test_record._message_sms(self._test_body, sms_numbers=self.random_numbers_san)
self.assertSMSNotification([{'number': self.random_numbers_san[0]}, {'number': self.random_numbers_san[1]}], self._test_body, messages)
def test_message_sms_on_numbers_sanitization(self):
with self.with_user('employee'), self.mockSMSGateway():
test_record = self.env['mail.test.sms'].browse(self.test_record.id)
messages = test_record._message_sms(self._test_body, sms_numbers=self.random_numbers)
self.assertSMSNotification([{'number': self.random_numbers_san[0]}, {'number': self.random_numbers_san[1]}], self._test_body, messages)
def test_message_sms_on_partner_ids(self):
with self.with_user('employee'), self.mockSMSGateway():
test_record = self.env['mail.test.sms'].browse(self.test_record.id)
messages = test_record._message_sms(self._test_body, partner_ids=(self.partner_1 | self.partner_2).ids)
self.assertSMSNotification([{'partner': self.partner_1}, {'partner': self.partner_2}], self._test_body, messages)
def test_message_sms_on_partner_ids_default(self):
with self.with_user('employee'), self.mockSMSGateway():
test_record = self.env['mail.test.sms'].browse(self.test_record.id)
messages = test_record._message_sms(self._test_body)
self.assertSMSNotification([{'partner': self.test_record.customer_id, 'number': self.test_numbers_san[1]}], self._test_body, messages)
def test_message_sms_on_partner_ids_w_numbers(self):
with self.with_user('employee'), self.mockSMSGateway():
test_record = self.env['mail.test.sms'].browse(self.test_record.id)
messages = test_record._message_sms(self._test_body, partner_ids=self.partner_1.ids, sms_numbers=self.random_numbers[:1])
self.assertSMSNotification([{'partner': self.partner_1}, {'number': self.random_numbers_san[0]}], self._test_body, messages)
def test_message_sms_with_template(self):
sms_template = self.env['sms.template'].create({
'name': 'Test Template',
'model_id': self.env['ir.model']._get('mail.test.sms').id,
'body': 'Dear {{ object.display_name }} this is an SMS.',
})
with self.with_user('employee'):
with self.mockSMSGateway():
test_record = self.env['mail.test.sms'].browse(self.test_record.id)
messages = test_record._message_sms_with_template(template=sms_template)
self.assertSMSNotification([{'partner': self.partner_1, 'number': self.test_numbers_san[1]}], 'Dear %s this is an SMS.' % self.test_record.display_name, messages)
def test_message_sms_with_template_fallback(self):
with self.with_user('employee'):
with self.mockSMSGateway():
test_record = self.env['mail.test.sms'].browse(self.test_record.id)
messages = test_record._message_sms_with_template(template_xmlid='test_mail_full.this_should_not_exists', template_fallback='Fallback for {{ object.id }}')
self.assertSMSNotification([{'partner': self.partner_1, 'number': self.test_numbers_san[1]}], 'Fallback for %s' % self.test_record.id, messages)
def test_message_sms_with_template_xmlid(self):
sms_template = self.env['sms.template'].create({
'name': 'Test Template',
'model_id': self.env['ir.model']._get('mail.test.sms').id,
'body': 'Dear {{ object.display_name }} this is an SMS.',
})
self.env['ir.model.data'].create({
'name': 'this_should_exists',
'module': 'test_mail_full',
'model': sms_template._name,
'res_id': sms_template.id,
})
with self.with_user('employee'):
with self.mockSMSGateway():
test_record = self.env['mail.test.sms'].browse(self.test_record.id)
messages = test_record._message_sms_with_template(template_xmlid='test_mail_full.this_should_exists')
self.assertSMSNotification([{'partner': self.partner_1, 'number': self.test_numbers_san[1]}], 'Dear %s this is an SMS.' % self.test_record.display_name, messages)
class TestSMSPostException(TestSMSCommon, TestSMSRecipients):
@classmethod
def setUpClass(cls):
super(TestSMSPostException, cls).setUpClass()
cls._test_body = 'VOID CONTENT'
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.partner_3 = cls.env['res.partner'].with_context({
'mail_create_nolog': True,
'mail_create_nosubscribe': True,
'mail_notrack': True,
'no_reset_password': True,
}).create({
'name': 'Ernestine Loubine',
'email': 'ernestine.loubine@agrolait.com',
'country_id': cls.env.ref('base.be').id,
'mobile': '0475556644',
})
def test_message_sms_w_numbers_invalid(self):
random_numbers = self.random_numbers + ['6988754']
with self.with_user('employee'), self.mockSMSGateway():
test_record = self.env['mail.test.sms'].browse(self.test_record.id)
messages = test_record._message_sms(self._test_body, sms_numbers=random_numbers)
# invalid numbers are still given to IAP currently as they are
self.assertSMSNotification([{'number': self.random_numbers_san[0]}, {'number': self.random_numbers_san[1]}, {'number': random_numbers[2]}], self._test_body, messages)
def test_message_sms_w_partners_nocountry(self):
self.test_record.customer_id.write({
'mobile': self.random_numbers[0],
'phone': self.random_numbers[1],
'country_id': False,
})
with self.with_user('employee'), self.mockSMSGateway():
test_record = self.env['mail.test.sms'].browse(self.test_record.id)
messages = test_record._message_sms(self._test_body, partner_ids=self.test_record.customer_id.ids)
self.assertSMSNotification([{'partner': self.test_record.customer_id}], self._test_body, messages)
def test_message_sms_w_partners_falsy(self):
# TDE FIXME: currently sent to IAP
self.test_record.customer_id.write({
'mobile': 'youpie',
'phone': 'youpla',
})
with self.with_user('employee'), self.mockSMSGateway():
test_record = self.env['mail.test.sms'].browse(self.test_record.id)
messages = test_record._message_sms(self._test_body, partner_ids=self.test_record.customer_id.ids)
# self.assertSMSNotification({self.test_record.customer_id: {}}, {}, self._test_body, messages)
def test_message_sms_w_numbers_sanitization_duplicate(self):
pass
# TDE FIXME: not sure
# random_numbers = self.random_numbers + [self.random_numbers[1]]
# random_numbers_san = self.random_numbers_san + [self.random_numbers_san[1]]
# with self.with_user('employee'), self.mockSMSGateway():
# messages = self.test_record._message_sms(self._test_body, sms_numbers=random_numbers)
# self.assertSMSNotification({}, {random_numbers_san[0]: {}, random_numbers_san[1]: {}, random_numbers_san[2]: {}}, self._test_body, messages)
def test_message_sms_crash_credit(self):
with self.with_user('employee'), self.mockSMSGateway(sim_error='credit'):
test_record = self.env['mail.test.sms'].browse(self.test_record.id)
messages = test_record._message_sms(self._test_body, partner_ids=(self.partner_1 | self.partner_2).ids)
self.assertSMSNotification([
{'partner': self.partner_1, 'state': 'exception', 'failure_type': 'sms_credit'},
{'partner': self.partner_2, 'state': 'exception', 'failure_type': 'sms_credit'},
], self._test_body, messages)
def test_message_sms_crash_credit_single(self):
with self.with_user('employee'), self.mockSMSGateway(nbr_t_error={self.partner_2.phone_get_sanitized_number(): 'credit'}):
test_record = self.env['mail.test.sms'].browse(self.test_record.id)
messages = test_record._message_sms(self._test_body, partner_ids=(self.partner_1 | self.partner_2 | self.partner_3).ids)
self.assertSMSNotification([
{'partner': self.partner_1, 'state': 'sent'},
{'partner': self.partner_2, 'state': 'exception', 'failure_type': 'sms_credit'},
{'partner': self.partner_3, 'state': 'sent'},
], self._test_body, messages)
def test_message_sms_crash_server_crash(self):
with self.with_user('employee'), self.mockSMSGateway(sim_error='jsonrpc_exception'):
test_record = self.env['mail.test.sms'].browse(self.test_record.id)
messages = test_record._message_sms(self._test_body, partner_ids=(self.partner_1 | self.partner_2 | self.partner_3).ids)
self.assertSMSNotification([
{'partner': self.partner_1, 'state': 'exception', 'failure_type': 'sms_server'},
{'partner': self.partner_2, 'state': 'exception', 'failure_type': 'sms_server'},
{'partner': self.partner_3, 'state': 'exception', 'failure_type': 'sms_server'},
], self._test_body, messages)
def test_message_sms_crash_unregistered(self):
with self.with_user('employee'), self.mockSMSGateway(sim_error='unregistered'):
test_record = self.env['mail.test.sms'].browse(self.test_record.id)
messages = test_record._message_sms(self._test_body, partner_ids=(self.partner_1 | self.partner_2).ids)
self.assertSMSNotification([
{'partner': self.partner_1, 'state': 'exception', 'failure_type': 'sms_acc'},
{'partner': self.partner_2, 'state': 'exception', 'failure_type': 'sms_acc'},
], self._test_body, messages)
def test_message_sms_crash_unregistered_single(self):
with self.with_user('employee'), self.mockSMSGateway(nbr_t_error={self.partner_2.phone_get_sanitized_number(): 'unregistered'}):
test_record = self.env['mail.test.sms'].browse(self.test_record.id)
messages = test_record._message_sms(self._test_body, partner_ids=(self.partner_1 | self.partner_2 | self.partner_3).ids)
self.assertSMSNotification([
{'partner': self.partner_1, 'state': 'sent'},
{'partner': self.partner_2, 'state': 'exception', 'failure_type': 'sms_acc'},
{'partner': self.partner_3, 'state': 'sent'},
], self._test_body, messages)
def test_message_sms_crash_wrong_number(self):
with self.with_user('employee'), self.mockSMSGateway(sim_error='wrong_number_format'):
test_record = self.env['mail.test.sms'].browse(self.test_record.id)
messages = test_record._message_sms(self._test_body, partner_ids=(self.partner_1 | self.partner_2).ids)
self.assertSMSNotification([
{'partner': self.partner_1, 'state': 'exception', 'failure_type': 'sms_number_format'},
{'partner': self.partner_2, 'state': 'exception', 'failure_type': 'sms_number_format'},
], self._test_body, messages)
def test_message_sms_crash_wrong_number_single(self):
with self.with_user('employee'), self.mockSMSGateway(nbr_t_error={self.partner_2.phone_get_sanitized_number(): 'wrong_number_format'}):
test_record = self.env['mail.test.sms'].browse(self.test_record.id)
messages = test_record._message_sms(self._test_body, partner_ids=(self.partner_1 | self.partner_2 | self.partner_3).ids)
self.assertSMSNotification([
{'partner': self.partner_1, 'state': 'sent'},
{'partner': self.partner_2, 'state': 'exception', 'failure_type': 'sms_number_format'},
{'partner': self.partner_3, 'state': 'sent'},
], self._test_body, messages)
class TestSMSApi(TestSMSCommon):
@classmethod
def setUpClass(cls):
super(TestSMSApi, cls).setUpClass()
cls._test_body = 'Zizisse an SMS.'
cls._create_records_for_batch('mail.test.sms', 3)
cls.sms_template = cls._create_sms_template('mail.test.sms')
def test_message_schedule_sms(self):
with self.with_user('employee'):
with self.mockSMSGateway():
self.env['mail.test.sms'].browse(self.records.ids)._message_sms_schedule_mass(body=self._test_body, mass_keep_log=False)
for record in self.records:
self.assertSMSOutgoing(record.customer_id, None, content=self._test_body)
def test_message_schedule_sms_w_log(self):
with self.with_user('employee'):
with self.mockSMSGateway():
self.env['mail.test.sms'].browse(self.records.ids)._message_sms_schedule_mass(body=self._test_body, mass_keep_log=True)
for record in self.records:
self.assertSMSOutgoing(record.customer_id, None, content=self._test_body)
self.assertSMSLogged(record, self._test_body)
def test_message_schedule_sms_w_template(self):
with self.with_user('employee'):
with self.mockSMSGateway():
self.env['mail.test.sms'].browse(self.records.ids)._message_sms_schedule_mass(template=self.sms_template, mass_keep_log=False)
for record in self.records:
self.assertSMSOutgoing(record.customer_id, None, content='Dear %s this is an SMS.' % record.display_name)
def test_message_schedule_sms_w_template_and_log(self):
with self.with_user('employee'):
with self.mockSMSGateway():
self.env['mail.test.sms'].browse(self.records.ids)._message_sms_schedule_mass(template=self.sms_template, mass_keep_log=True)
for record in self.records:
self.assertSMSOutgoing(record.customer_id, None, content='Dear %s this is an SMS.' % record.display_name)
self.assertSMSLogged(record, 'Dear %s this is an SMS.' % record.display_name)

View file

@ -0,0 +1,94 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.addons.test_mail_sms.tests.common import TestSMSCommon, TestSMSRecipients
from odoo.tests import tagged
from odoo.tools import mute_logger
@tagged('ir_actions')
class TestServerAction(TestSMSCommon, TestSMSRecipients):
@classmethod
def setUpClass(cls):
super(TestServerAction, 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_2 = cls.env['mail.test.sms'].with_context(**cls._test_context).create({
'name': 'Test Record 2',
'customer_id': False,
'phone_nbr': cls.test_numbers[0],
})
cls.sms_template = cls._create_sms_template('mail.test.sms')
cls.action = cls.env['ir.actions.server'].create({
'name': 'Test SMS Action',
'model_id': cls.env['ir.model']._get('mail.test.sms').id,
'state': 'sms',
'sms_method': 'sms',
'sms_template_id': cls.sms_template.id,
'groups_id': cls.env.ref('base.group_user'),
})
def test_action_sms(self):
context = {
'active_model': 'mail.test.sms',
'active_ids': (self.test_record | self.test_record_2).ids,
}
with self.with_user('employee'), self.mockSMSGateway():
self.action.with_user(self.env.user).with_context(**context).run()
self.assertSMSOutgoing(self.test_record.customer_id, None, content='Dear %s this is an SMS.' % self.test_record.display_name)
self.assertSMSOutgoing(self.env['res.partner'], self.test_numbers_san[0], content='Dear %s this is an SMS.' % self.test_record_2.display_name)
def test_action_sms_single(self):
context = {
'active_model': 'mail.test.sms',
'active_id': self.test_record.id,
}
with self.with_user('employee'), self.mockSMSGateway():
self.action.with_user(self.env.user).with_context(**context).run()
self.assertSMSOutgoing(self.test_record.customer_id, None, content='Dear %s this is an SMS.' % self.test_record.display_name)
def test_action_sms_w_log(self):
self.action.sms_method = 'note'
context = {
'active_model': 'mail.test.sms',
'active_ids': (self.test_record | self.test_record_2).ids,
}
with self.with_user('employee'), self.mockSMSGateway():
self.action.with_user(self.env.user).with_context(**context).run()
self.assertSMSOutgoing(self.test_record.customer_id, None, content='Dear %s this is an SMS.' % self.test_record.display_name)
self.assertSMSLogged(self.test_record, 'Dear %s this is an SMS.' % self.test_record.display_name)
self.assertSMSOutgoing(self.env['res.partner'], self.test_numbers_san[0], content='Dear %s this is an SMS.' % self.test_record_2.display_name)
self.assertSMSLogged(self.test_record_2, 'Dear %s this is an SMS.' % self.test_record_2.display_name)
@mute_logger('odoo.addons.sms.models.sms_sms')
def test_action_sms_w_post(self):
self.action.sms_method = 'comment'
context = {
'active_model': 'mail.test.sms',
'active_ids': (self.test_record | self.test_record_2).ids,
}
with self.with_user('employee'), self.mockSMSGateway():
self.action.with_user(self.env.user).with_context(**context).run()
self.assertSMSNotification(
[{'partner': self.test_record.customer_id}],
'Dear %s this is an SMS.' % self.test_record.display_name,
messages=self.test_record.message_ids[-1]
)
self.assertSMSNotification(
[{'partner': self.env['res.partner'],
'number': self.test_numbers_san[0]}],
'Dear %s this is an SMS.' % self.test_record_2.display_name,
messages=self.test_record_2.message_ids[-1]
)

View file

@ -0,0 +1,105 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from unittest.mock import patch
from unittest.mock import DEFAULT
from odoo import exceptions
from odoo.addons.link_tracker.tests.common import MockLinkTracker
from odoo.addons.sms.models.sms_sms import SmsSms as SmsModel
from odoo.addons.test_mail_sms.tests.common import TestSMSCommon
from odoo.tests import tagged
@tagged('link_tracker')
class TestSMSPost(TestSMSCommon, MockLinkTracker):
@classmethod
def setUpClass(cls):
super(TestSMSPost, cls).setUpClass()
cls._test_body = 'VOID CONTENT'
cls.sms_all = cls.env['sms.sms']
for x in range(10):
cls.sms_all |= cls.env['sms.sms'].create({
'number': '+324560000%s%s' % (x, x),
'body': cls._test_body,
})
def test_sms_send_batch_size(self):
self.count = 0
def _send(sms_self, unlink_failed=False, unlink_sent=True, raise_exception=False):
self.count += 1
return DEFAULT
self.env['ir.config_parameter'].set_param('sms.session.batch.size', '3')
with patch.object(SmsModel, '_send', autospec=True, side_effect=_send) as _send_mock:
self.env['sms.sms'].browse(self.sms_all.ids).send()
self.assertEqual(self.count, 4)
def test_sms_send_crash_employee(self):
with self.assertRaises(exceptions.AccessError):
self.env['sms.sms'].with_user(self.user_employee).browse(self.sms_all.ids).send()
def test_sms_send_delete_all(self):
with self.mockSMSGateway(sms_allow_unlink=True, sim_error='jsonrpc_exception'):
self.env['sms.sms'].browse(self.sms_all.ids).send(unlink_failed=True, unlink_sent=True, raise_exception=False)
self.assertFalse(len(self.sms_all.exists()))
def test_sms_send_delete_default(self):
""" Test default send behavior: keep failed SMS, remove sent. """
with self.mockSMSGateway(sms_allow_unlink=True, nbr_t_error={
'+32456000011': 'wrong_number_format',
'+32456000022': 'credit',
'+32456000033': 'server_error',
'+32456000044': 'unregistered',
}):
self.env['sms.sms'].browse(self.sms_all.ids).send(raise_exception=False)
remaining = self.sms_all.exists()
self.assertEqual(len(remaining), 4)
self.assertTrue(all(sms.state == 'error') for sms in remaining)
def test_sms_send_delete_failed(self):
with self.mockSMSGateway(sms_allow_unlink=True, nbr_t_error={
'+32456000011': 'wrong_number_format',
'+32456000022': 'wrong_number_format',
}):
self.env['sms.sms'].browse(self.sms_all.ids).send(unlink_failed=True, unlink_sent=False, raise_exception=False)
remaining = self.sms_all.exists()
self.assertEqual(len(remaining), 8)
self.assertTrue(all(sms.state == 'sent') for sms in remaining)
def test_sms_send_delete_none(self):
with self.mockSMSGateway(sms_allow_unlink=True, nbr_t_error={
'+32456000011': 'wrong_number_format',
'+32456000022': 'wrong_number_format',
}):
self.env['sms.sms'].browse(self.sms_all.ids).send(unlink_failed=False, unlink_sent=False, raise_exception=False)
self.assertEqual(len(self.sms_all.exists()), 10)
success_sms = self.sms_all[:1] + self.sms_all[3:]
error_sms = self.sms_all[1:3]
self.assertTrue(all(sms.state == 'sent') for sms in success_sms)
self.assertTrue(all(sms.state == 'error') for sms in error_sms)
def test_sms_send_delete_sent(self):
with self.mockSMSGateway(sms_allow_unlink=True, nbr_t_error={
'+32456000011': 'wrong_number_format',
'+32456000022': 'wrong_number_format',
}):
self.env['sms.sms'].browse(self.sms_all.ids).send(unlink_failed=False, unlink_sent=True, raise_exception=False)
remaining = self.sms_all.exists()
self.assertEqual(len(remaining), 2)
self.assertTrue(all(sms.state == 'error') for sms in remaining)
def test_sms_send_raise(self):
with self.assertRaises(exceptions.AccessError):
with self.mockSMSGateway(sim_error='jsonrpc_exception'):
self.env['sms.sms'].browse(self.sms_all.ids).send(raise_exception=True)
self.assertEqual(set(self.sms_all.mapped('state')), set(['outgoing']))
def test_sms_send_raise_catch(self):
with self.mockSMSGateway(sim_error='jsonrpc_exception'):
self.env['sms.sms'].browse(self.sms_all.ids).send(raise_exception=False)
self.assertEqual(set(self.sms_all.mapped('state')), set(['error']))

View file

@ -0,0 +1,89 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo.addons.test_mail_sms.tests.common import TestSMSCommon, TestSMSRecipients
class TestSmsTemplate(TestSMSCommon, TestSMSRecipients):
@classmethod
def setUpClass(cls):
super(TestSmsTemplate, 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.body_en = 'Dear {{ object.display_name }} this is an SMS.'
cls.body_fr = u"Hello {{ object.display_name }} ceci est en français."
cls.sms_template = cls._create_sms_template('mail.test.sms', body=cls.body_en)
def test_sms_template_render(self):
rendered_body = self.sms_template._render_template(self.sms_template.body, self.sms_template.model, self.test_record.ids)
self.assertEqual(rendered_body[self.test_record.id], 'Dear %s this is an SMS.' % self.test_record.display_name)
rendered_body = self.sms_template._render_field('body', self.test_record.ids)
self.assertEqual(rendered_body[self.test_record.id], 'Dear %s this is an SMS.' % self.test_record.display_name)
def test_sms_template_lang(self):
self.env['res.lang']._activate_lang('fr_FR')
self.user_admin.write({'lang': 'en_US'})
self.sms_template.update_field_translations('body', {
'fr_FR': self.body_fr
})
# set template to try to use customer lang
self.sms_template.write({
'lang': '{{ object.customer_id.lang }}',
})
# create a second record linked to a customer in another language
self.partner_2.write({
'lang': 'fr_FR',
})
test_record_2 = self.env['mail.test.sms'].create({
'name': 'Test',
'customer_id': self.partner_2.id,
})
self.assertEqual(self.sms_template.body, self.body_en)
self.assertEqual(self.sms_template.with_context(lang='fr_FR').body, self.body_fr)
rid_to_lang = self.sms_template._render_lang((self.test_record | test_record_2).ids)
self.assertEqual(set(rid_to_lang.keys()), set((self.test_record | test_record_2).ids))
for rid, lang in rid_to_lang.items():
# TDE FIXME: False or en_US ?
if rid == self.test_record.id:
self.assertEqual(lang, 'en_US')
elif rid == test_record_2.id:
self.assertEqual(lang, 'fr_FR')
else:
self.assertTrue(False)
tpl_to_rids = self.sms_template._classify_per_lang((self.test_record | test_record_2).ids)
for lang, (tpl, rids) in tpl_to_rids.items():
# TDE FIXME: False or en_US ?
if lang == 'en_US':
self.assertEqual(rids, self.test_record.ids)
elif lang == 'fr_FR':
self.assertEqual(rids, test_record_2.ids)
else:
self.assertTrue(False, 'Should not return lang %s' % lang)
def test_sms_template_create_and_unlink_sidebar_action(self):
ActWindow = self.env['ir.actions.act_window']
self.sms_template.action_create_sidebar_action()
action_id = self.sms_template.sidebar_action_id.id
self.assertNotEqual(action_id, False)
self.assertEqual(ActWindow.search_count([('id', '=', action_id)]), 1)
self.sms_template.action_unlink_sidebar_action()
self.assertEqual(ActWindow.search_count([('id', '=', action_id)]), 0)
def test_sms_template_unlink_with_action(self):
ActWindow = self.env['ir.actions.act_window']
self.sms_template.action_create_sidebar_action()
action_id = self.sms_template.sidebar_action_id.id
self.sms_template.unlink()
self.assertEqual(ActWindow.search_count([('id', '=', action_id)]), 0)