summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThibault Delavallée <tde@odoo.com>2019-07-02 15:07:09 +0000
committerThibault Delavallée <tde@odoo.com>2019-07-18 09:57:47 +0000
commit16b3bf78a05425cc1f5f267fcbfe90fea26fafb7 (patch)
treed4705d6d786f7e222ba1550dd328762973f3c34e
parented4c67adb2dc1eb821a72f5286452b8c5889f4fe (diff)
[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
-rw-r--r--addons/sms/__manifest__.py1
-rw-r--r--addons/sms/models/__init__.py1
-rw-r--r--addons/sms/models/ir_actions.py47
-rw-r--r--addons/sms/views/ir_actions_views.xml19
-rw-r--r--addons/test_mail_full/tests/__init__.py1
-rw-r--r--addons/test_mail_full/tests/test_sms_server_actions.py71
-rw-r--r--odoo/addons/base/views/ir_cron_views.xml26
7 files changed, 152 insertions, 14 deletions
diff --git a/addons/sms/__manifest__.py b/addons/sms/__manifest__.py
index ccfae7f9049..9be1a884b13 100644
--- a/addons/sms/__manifest__.py
+++ b/addons/sms/__manifest__.py
@@ -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',
diff --git a/addons/sms/models/__init__.py b/addons/sms/models/__init__.py
index 4adcd67ab64..aab4ae27445 100644
--- a/addons/sms/models/__init__.py
+++ b/addons/sms/models/__init__.py
@@ -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
diff --git a/addons/sms/models/ir_actions.py b/addons/sms/models/ir_actions.py
new file mode 100644
index 00000000000..60abc9e0520
--- /dev/null
+++ b/addons/sms/models/ir_actions.py
@@ -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
diff --git a/addons/sms/views/ir_actions_views.xml b/addons/sms/views/ir_actions_views.xml
new file mode 100644
index 00000000000..8c6e3b72c5c
--- /dev/null
+++ b/addons/sms/views/ir_actions_views.xml
@@ -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>
diff --git a/addons/test_mail_full/tests/__init__.py b/addons/test_mail_full/tests/__init__.py
index 8c7cd81f4ae..b64df4304a9 100644
--- a/addons/test_mail_full/tests/__init__.py
+++ b/addons/test_mail_full/tests/__init__.py
@@ -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
diff --git a/addons/test_mail_full/tests/test_sms_server_actions.py b/addons/test_mail_full/tests/test_sms_server_actions.py
new file mode 100644
index 00000000000..506513c524a
--- /dev/null
+++ b/addons/test_mail_full/tests/test_sms_server_actions.py
@@ -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)
diff --git a/odoo/addons/base/views/ir_cron_views.xml b/odoo/addons/base/views/ir_cron_views.xml
index 562f15e02d6..97e801e2fd8 100644
--- a/odoo/addons/base/views/ir_cron_views.xml
+++ b/odoo/addons/base/views/ir_cron_views.xml
@@ -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>