[IMP] sms: allow to create a sms context action
In the SMS template, we add the ability to create (and remove) a contextual action on the targeted model from a sms template. We change the sms composer to guess the composition mode, and then to be usable by contextual action. The guess compostion mode works differently if there are multiple target selected (mass) or a single target (comment). TASK_ID : 2053631
This commit is contained in:
@@ -24,6 +24,9 @@ class SMSTemplate(models.Model):
|
||||
model = fields.Char('Related Document Model', related='model_id.model', index=True, store=True, readonly=True)
|
||||
body = fields.Char('Body', translate=True, required=True)
|
||||
lang = fields.Char('Language', placeholder="${object.partner_id.lang}")
|
||||
sidebar_action_id = fields.Many2one('ir.actions.act_window', 'Sidebar action', readonly=True, copy=False,
|
||||
help="Sidebar action to make this template available on records "
|
||||
"of the related document model")
|
||||
# Fake fields used to implement the placeholder assistant
|
||||
model_object_field = fields.Many2one('ir.model.fields', string="Field", store=False,
|
||||
help="Select target field from the related document model.\n"
|
||||
@@ -86,6 +89,32 @@ class SMSTemplate(models.Model):
|
||||
name=_("%s (copy)") % self.name)
|
||||
return super(SMSTemplate, self).copy(default=default)
|
||||
|
||||
def action_create_sidebar_action(self):
|
||||
ActWindow = self.env['ir.actions.act_window']
|
||||
view = self.env.ref('sms.sms_composer_view_form')
|
||||
|
||||
for template in self:
|
||||
button_name = _('Send SMS (%s)') % template.name
|
||||
action = ActWindow.create({
|
||||
'name': button_name,
|
||||
'type': 'ir.actions.act_window',
|
||||
'res_model': 'sms.composer',
|
||||
# Add default_composition_mode to guess to determine if need to use mass or comment composer
|
||||
'context': "{'default_template_id' : %d, 'default_composition_mode': 'guess', 'default_res_ids': active_ids, 'default_res_id': active_id}" % (template.id),
|
||||
'view_mode': 'form',
|
||||
'view_id': view.id,
|
||||
'target': 'new',
|
||||
'binding_model_id': template.model_id.id,
|
||||
})
|
||||
template.write({'sidebar_action_id': action.id})
|
||||
return True
|
||||
|
||||
def action_unlink_sidebar_action(self):
|
||||
for template in self:
|
||||
if template.sidebar_action_id:
|
||||
template.sidebar_action_id.unlink()
|
||||
return True
|
||||
|
||||
def _get_context_lang_per_id(self, res_ids):
|
||||
self.ensure_one()
|
||||
if res_ids is None:
|
||||
@@ -96,8 +125,7 @@ class SMSTemplate(models.Model):
|
||||
results = dict((res_id, self.with_context(lang=lang)) for res_id in res_ids)
|
||||
else:
|
||||
rendered_langs = self._render_template(self.lang, self.model, res_ids)
|
||||
results = dict(
|
||||
(res_id, self.with_context(lang=lang) if lang else self)
|
||||
results = dict((res_id, self.with_context(lang=lang) if lang else self)
|
||||
for res_id, lang in rendered_langs.items())
|
||||
|
||||
return results
|
||||
@@ -112,6 +140,16 @@ class SMSTemplate(models.Model):
|
||||
|
||||
return tpl_to_rids
|
||||
|
||||
def _get_translated_bodies(self, res_ids):
|
||||
""" return sms translated bodies into a dict {'res_id':'body'} """
|
||||
self.ensure_one()
|
||||
lang_to_rids = self._get_ids_per_lang(res_ids)
|
||||
all_bodies = {}
|
||||
for lang, rids in lang_to_rids.items():
|
||||
template = self.with_context(lang=lang)
|
||||
all_bodies.update(template._render_template(template.body, self.model, rids))
|
||||
return all_bodies
|
||||
|
||||
@api.model
|
||||
def _render_template(self, template_txt, model, res_ids):
|
||||
""" Render the jinja template """
|
||||
|
||||
@@ -7,9 +7,28 @@
|
||||
<form string="SMS Templates">
|
||||
<sheet>
|
||||
<div class="oe_button_box" name="button_box">
|
||||
<button class="oe_stat_button" name="%(sms_template_preview_action)d" icon="fa-search-plus" string="Preview"
|
||||
type="action" target="new"
|
||||
context="{'template_id':active_id}"/>
|
||||
<field name="sidebar_action_id" invisible="1"/>
|
||||
<button name="action_create_sidebar_action" type="object"
|
||||
groups="base.group_system"
|
||||
class="oe_stat_button"
|
||||
attrs="{'invisible':[('sidebar_action_id','!=',False)]}" icon="fa-plus"
|
||||
help="Add a contextual action on the related model to open a sms composer with this template">
|
||||
<div class="o_field_widget o_stat_info">
|
||||
<span class="o_stat_text">Add</span>
|
||||
<span class="o_stat_text">Context Action</span>
|
||||
</div>
|
||||
</button>
|
||||
<button name="action_unlink_sidebar_action" type="object"
|
||||
groups="base.group_system"
|
||||
class="oe_stat_button" icon="fa-minus"
|
||||
attrs="{'invisible':[('sidebar_action_id','=',False)]}"
|
||||
help="Remove the contextual action of the related model" widget="statinfo">
|
||||
<div class="o_field_widget o_stat_info">
|
||||
<span class="o_stat_text">Remove</span>
|
||||
<span class="o_stat_text">Context Action</span>
|
||||
</div>
|
||||
</button>
|
||||
<button class="oe_stat_button" name="%(sms_template_preview_action)d" icon="fa-search-plus" string="Preview" type="action" target="new"/>
|
||||
</div>
|
||||
<div class="oe_title">
|
||||
<label for="name" class="oe_edit_only" string="SMS Template"/>
|
||||
|
||||
@@ -21,7 +21,16 @@ class SendSMS(models.TransientModel):
|
||||
return result
|
||||
|
||||
result['res_model'] = result.get('res_model') or self.env.context.get('active_model')
|
||||
result['composition_mode'] = result.get('composition_mode') or 'comment'
|
||||
result['composition_mode'] = result.get('composition_mode')
|
||||
|
||||
# guess the composition mode, if multiples ids => mass composition else comment
|
||||
if self.env.context.get('default_composition_mode') and self.env.context.get('default_composition_mode') == "guess":
|
||||
if self.env.context.get('active_ids') and len(self.env.context.get('active_ids')) > 1:
|
||||
result['composition_mode'] = 'mass'
|
||||
result['res_id'] = False
|
||||
else:
|
||||
result['composition_mode'] = 'comment'
|
||||
result['res_ids'] = False
|
||||
|
||||
if not result.get('active_domain'):
|
||||
result['active_domain'] = repr(self.env.context.get('active_domain', []))
|
||||
@@ -124,7 +133,7 @@ class SendSMS(models.TransientModel):
|
||||
@api.onchange('composition_mode', 'res_model', 'res_id', 'template_id')
|
||||
def _onchange_template_id(self):
|
||||
if self.template_id and self.composition_mode == 'comment' and self.res_id:
|
||||
self.body = self.template_id._render_template(self.template_id.body, self.res_model, [self.res_id])[self.res_id]
|
||||
self.body = self.template_id._get_translated_bodies([self.res_id])[self.res_id]
|
||||
elif self.template_id:
|
||||
self.body = self.template_id.body
|
||||
|
||||
@@ -216,11 +225,7 @@ class SendSMS(models.TransientModel):
|
||||
|
||||
def _prepare_body_values(self, records):
|
||||
if self.template_id and self.body == self.template_id.body:
|
||||
lang_to_rids = self.template_id._get_ids_per_lang(records.ids)
|
||||
all_bodies = {}
|
||||
for lang, rids in lang_to_rids.items():
|
||||
template = self.template_id.with_context(lang=lang)
|
||||
all_bodies.update(template._render_template(template.body, records._name, rids))
|
||||
all_bodies = self.template_id._get_translated_bodies(records.ids)
|
||||
else:
|
||||
all_bodies = self.env['mail.template']._render_template(self.body, records._name, records.ids)
|
||||
return all_bodies
|
||||
|
||||
@@ -420,3 +420,79 @@ class TestSMSComposerMass(test_mail_full_common.BaseFunctionalTest, sms_common.M
|
||||
for record in self.records:
|
||||
self.assertSMSOutgoing(record.customer_id, None, '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.ref('base.lang_fr').write({'active': True})
|
||||
self.env['ir.translation'].create({
|
||||
'type': 'model',
|
||||
'name': 'sms.template,body',
|
||||
'lang': 'fr_FR',
|
||||
'res_id': self.sms_template.id,
|
||||
'src': self.sms_template.body,
|
||||
'value': "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.sudo('employee'):
|
||||
composer = self.env['sms.composer'].with_context(
|
||||
default_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,
|
||||
})
|
||||
# Call manually the onchange
|
||||
composer._onchange_template_id()
|
||||
self.assertEquals(composer.composition_mode, "comment")
|
||||
self.assertEquals(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.sudo('employee'):
|
||||
composer = self.env['sms.composer'].with_context(
|
||||
default_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,
|
||||
})
|
||||
# Call manually the onchange
|
||||
composer._onchange_template_id()
|
||||
self.assertEquals(composer.composition_mode, "mass")
|
||||
# In english because by default but when sinding depending of record
|
||||
self.assertEquals(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, 'Dear %s this is an SMS.' % test_record_1.display_name)
|
||||
self.assertSMSOutgoing(test_record_2.customer_id, None, "Hello %s ceci est en français." % test_record_2.display_name)
|
||||
|
||||
Reference in New Issue
Block a user