[IMP] sms: allow to send SMS from server (and automated) actions

PURPOSE

Send SMS from server/automated actions. Indeed we can already send emails from
server actions. The goal is to have the same thing for the sms.

SPECIFICATION

Purpose of this commit is to add support of sending batch SMS through
server actions. This means sending SMS will be available also for
automated (base automation) and scheduled actions (cron).

A new type of server action is added: sms. User choose an sms.template
to use to send SMS in batch. An option allow to choose to keep archive on
selected records. If no archive is kept, a batch of sms is created. With
archive a _message_sms is performed with note subtype, allowing to have
a discuss messages with only sms customer being notified.

Linked to task 1935280
Part of PR #34864
This commit is contained in:
Thibault Delavallée
2019-07-18 09:57:47 +00:00
parent ed4c67adb2
commit 16b3bf78a0
7 changed files with 152 additions and 14 deletions
+1
View File
@@ -16,6 +16,7 @@ The service is provided by the In App Purchase Odoo platform.
'wizard/sms_cancel_views.xml',
'wizard/sms_composer_views.xml',
'wizard/sms_resend_views.xml',
'views/ir_actions_views.xml',
'views/res_config_settings_views.xml',
'views/res_partner_views.xml',
'views/assets.xml',
+1
View File
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from . import ir_actions
from . import mail_followers
from . import mail_message
from . import mail_notification
+47
View File
@@ -0,0 +1,47 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import _, api, fields, models
from odoo.exceptions import ValidationError
class ServerActions(models.Model):
""" Add SMS option in server actions. """
_name = 'ir.actions.server'
_inherit = ['ir.actions.server']
state = fields.Selection(selection_add=[
('sms', 'Send SMS Text Message'),
])
# SMS
sms_template_id = fields.Many2one(
'sms.template', 'SMS Template', ondelete='set null',
domain="[('model_id', '=', model_id)]",
)
sms_mass_keep_log = fields.Boolean('Log a note', default=True)
@api.constrains('state', 'model_id')
def _check_sms_capability(self):
for action in self:
if action.state == 'sms' and not action.model_id.is_mail_thread:
raise ValidationError(_("Sending SMS can only be done on a mail.thread model"))
@api.model
def run_action_sms_multi(self, action, eval_context=None):
# TDE CLEANME: when going to new api with server action, remove action
if not action.sms_template_id or self._is_recompute(action):
return False
records = eval_context.get('records') or eval_context.get('record')
if not records:
return False
composer = self.env['sms.composer'].with_context(
default_res_model=records._name,
default_res_ids=records.ids,
default_composition_mode='mass',
default_template_id=action.sms_template_id.id,
default_mass_keep_log=action.sms_mass_keep_log,
).create({})
composer.action_send_sms()
return False
+19
View File
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo><data>
<record id="ir_actions_server_view_form" model="ir.ui.view">
<field name="name">ir.actions.server.view.form.inherit.sms</field>
<field name="model">ir.actions.server</field>
<field name="inherit_id" ref="base.view_server_action_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='link_field_id']" position="after">
<field name="sms_template_id"
attrs="{'invisible': [('state', '!=', 'sms')],
'required': [('state', '=', 'sms')]}"/>
<field name="sms_mass_keep_log"
attrs="{'invisible': [('state', '!=', 'sms')]}"/>
</xpath>
</field>
</record>
</data></odoo>
+1
View File
@@ -5,5 +5,6 @@ from . import test_sms_composer
from . import test_sms_management
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
@@ -0,0 +1,71 @@
# -*- 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 import common as test_mail_common
from odoo.addons.test_mail_full.tests import common as test_mail_full_common
class TestSmsTemplate(test_mail_full_common.BaseFunctionalTest, sms_common.MockSMS, test_mail_common.TestRecipients):
@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_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],
})
model_id = cls.env['ir.model']._get('mail.test.sms').id
cls.sms_template = cls.env['sms.template'].create({
'name': 'Test Template',
'model_id': model_id,
'body': 'Dear ${object.display_name} this is an SMS.'
})
cls.action = cls.env['ir.actions.server'].create({
'name': 'Test SMS Action',
'model_id': model_id,
'state': 'sms',
'sms_template_id': cls.sms_template.id,
})
def test_action_sms(self):
context = {
'active_model': 'mail.test.sms',
'active_ids': (self.test_record | self.test_record_2).ids,
}
with self.sudo('employee'), self.mockSMSGateway():
self.action.with_user(self.env.user).with_context(**context).run()
self.assertSMSOutgoing(self.test_record.customer_id, None, 'Dear %s this is an SMS.' % self.test_record.display_name)
self.assertSMSOutgoing(self.env['res.partner'], self.test_numbers_san[0], '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.sudo('employee'), self.mockSMSGateway():
self.action.with_user(self.env.user).with_context(**context).run()
self.assertSMSOutgoing(self.test_record.customer_id, None, 'Dear %s this is an SMS.' % self.test_record.display_name)
def test_action_sms_w_log(self):
self.action.sms_mass_keep_log = True
context = {
'active_model': 'mail.test.sms',
'active_ids': (self.test_record | self.test_record_2).ids,
}
with self.sudo('employee'), self.mockSMSGateway():
self.action.with_user(self.env.user).with_context(**context).run()
self.assertSMSNotification([{'partner': self.test_record.customer_id, 'state': 'ready'}], 'Dear %s this is an SMS.' % self.test_record.display_name)
self.assertSMSNotification([{'partner': self.env['res.partner'], 'number': self.test_numbers_san[0], 'state': 'ready'}], 'Dear %s this is an SMS.' % self.test_record_2.display_name)
+12 -14
View File
@@ -12,20 +12,18 @@
</xpath>
<xpath expr="//button[@name='unlink_action']" position="replace">
</xpath>
<xpath expr="//group[@name='action_wrapper']" position="inside">
<group>
<field name="user_id"/>
<label for="interval_number" string="Execute Every"/>
<div>
<field name="interval_number" class="oe_inline"/>
<field name="interval_type" class="oe_inline"/>
</div>
<field name="active" invisible="1"/>
<field name="nextcall"/>
<field name="numbercall"/>
<field name="priority"/>
<field name="doall"/>
</group>
<xpath expr="//group[@name='action_content']" position="inside">
<field name="user_id"/>
<label for="interval_number" string="Execute Every"/>
<div>
<field name="interval_number" class="oe_inline"/>
<field name="interval_type" class="oe_inline"/>
</div>
<field name="active" invisible="1"/>
<field name="nextcall"/>
<field name="numbercall"/>
<field name="priority"/>
<field name="doall"/>
</xpath>
</field>
</record>