diff options
| author | Thibault Delavallée <tde@odoo.com> | 2019-05-27 15:10:54 +0000 |
|---|---|---|
| committer | Thibault Delavallée <tde@odoo.com> | 2019-07-12 14:54:11 +0000 |
| commit | 45555bdd1fddb988bfa54ff54f1bc1887d0dc1df (patch) | |
| tree | f7dee4cff2568873abe9d01b76b38e4ca167854e /addons/sms/wizard | |
| parent | 14ccc770bba873f591a0a556d2c28e36ccc78d1e (diff) | |
[IMP] sms: allow to resend and cancel SMS notifications
Purpose of this commit is to allow SMS notification management. It is based
on what has been done in mail for notification: resend and cancel.
In this commit we add wizards allowing users to resend and cancel failed
SMS notifications. Resend allow to change the contact number, as well as
resending only a subset of notifications.
Future commits will improve the UX itself.
Related to task 1922163
Linked to PR #33510
Co-Authored-By: Thibault Delavallee <tde@odoo.com>
Co-Authored-By: Pierre Rousseau <pro@odoo.com>
Diffstat (limited to 'addons/sms/wizard')
| -rw-r--r-- | addons/sms/wizard/__init__.py | 2 | ||||
| -rw-r--r-- | addons/sms/wizard/sms_cancel.py | 40 | ||||
| -rw-r--r-- | addons/sms/wizard/sms_cancel_views.xml | 27 | ||||
| -rw-r--r-- | addons/sms/wizard/sms_resend.py | 116 | ||||
| -rw-r--r-- | addons/sms/wizard/sms_resend_views.xml | 41 |
5 files changed, 226 insertions, 0 deletions
diff --git a/addons/sms/wizard/__init__.py b/addons/sms/wizard/__init__.py index 3b5c1a8895f..e6669ba5997 100644 --- a/addons/sms/wizard/__init__.py +++ b/addons/sms/wizard/__init__.py @@ -1,3 +1,5 @@ # -*- coding: utf-8 -*- +from . import sms_cancel from . import sms_composer +from . import sms_resend diff --git a/addons/sms/wizard/sms_cancel.py b/addons/sms/wizard/sms_cancel.py new file mode 100644 index 00000000000..2b27b237920 --- /dev/null +++ b/addons/sms/wizard/sms_cancel.py @@ -0,0 +1,40 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import _, api, fields, models + + +class SMSCancel(models.TransientModel): + _name = 'sms.cancel' + _description = 'Dismiss notification for resend by model' + + model = fields.Char(string='Model', required=True) + help_message = fields.Char(string='Help message', compute='_compute_help_message') + + @api.multi + @api.depends('model') + def _compute_help_message(self): + for wizard in self: + wizard.help_message = _("Are you sure you want to discard %s SMS delivery failures. You won't be able to re-send these SMS later!") % (wizard._context.get('unread_counter')) + + @api.multi + def action_cancel(self): + # TDE CHECK: delete pending SMS + author_id = self.env.user.partner_id.id + for wizard in self: + self._cr.execute(""" +SELECT notif.id, msg.id +FROM mail_message_res_partner_needaction_rel notif +JOIN mail_message msg + ON notif.mail_message_id = msg.id +WHERE notif.notification_type = 'sms' IS TRUE AND notif.notification_status IN ('bounce', 'exception') + AND msg.model = %s + AND msg.author_id = %s """, (wizard.model, author_id)) + res = self._cr.fetchall() + notif_ids = [row[0] for row in res] + message_ids = list(set([row[1] for row in res])) + if notif_ids: + self.env['mail.notification'].browse(notif_ids).sudo().write({'notification_status': 'canceled'}) + if message_ids: + self.env['mail.message'].browse(message_ids)._notify_sms_update() + return {'type': 'ir.actions.act_window_close'} diff --git a/addons/sms/wizard/sms_cancel_views.xml b/addons/sms/wizard/sms_cancel_views.xml new file mode 100644 index 00000000000..74208e5fd4c --- /dev/null +++ b/addons/sms/wizard/sms_cancel_views.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<odoo><data> + <record id="sms_cancel" model="ir.ui.view"> + <field name="name">sms.cancel.form</field> + <field name="model">sms.cancel</field> + <field name="groups_id" eval="[(4,ref('base.group_user'))]"/> + <field name="arch" type="xml"> + <form string="Cancel notification in failure"> + <field name="model" invisible='1'/> + <field name="help_message"/> + <p>If you want to re-send them, click Cancel now, then click on the notification and review them one by one by clicking on the red icon next to each message.</p> + <footer> + <button string="Discard delivery failures" name="cancel_resend_action" type="object" class="btn-primary" /> + <button string="Cancel" class="btn-secondary" special="cancel" /> + </footer> + </form> + </field> + </record> + + <record id="sms_cancel_action" model="ir.actions.act_window"> + <field name="name">Discard SMS delivery failures</field> + <field name="res_model">sms.cancel</field> + <field name="type">ir.actions.act_window</field> + <field name="view_mode">form</field> + <field name="target">new</field> + </record> +</data></odoo> diff --git a/addons/sms/wizard/sms_resend.py b/addons/sms/wizard/sms_resend.py new file mode 100644 index 00000000000..10ae893fab8 --- /dev/null +++ b/addons/sms/wizard/sms_resend.py @@ -0,0 +1,116 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import _, api, exceptions, fields, models + + +class SMSRecipient(models.TransientModel): + _name = 'sms.resend.recipient' + _description = 'Resend Notification' + _rec_name = 'sms_resend_id' + + sms_resend_id = fields.Many2one('sms.resend', required=True) + notification_id = fields.Many2one('mail.notification', required=True, ondelete='cascade') + resend = fields.Boolean(string="Resend", default=True) + failure_type = fields.Selection([ + ('sms_number_missing', 'Missing Number'), + ('sms_number_format', 'Wrong Number Format'), + ('sms_credit', 'Insufficient Credit'), + ('sms_server', 'Server Error')], related='notification_id.failure_type', related_sudo=True, readonly=True) + partner_id = fields.Many2one('res.partner', 'Partner', related='notification_id.res_partner_id', readonly=True) + partner_name = fields.Char('Recipient', readonly='True') + sms_number = fields.Char('Number') + + +class SMSResend(models.TransientModel): + _name = 'sms.resend' + _description = 'SMS Resend' + _rec_name = 'mail_message_id' + + @api.model + def default_get(self, fields): + result = super(SMSResend, self).default_get(fields) + if result.get('mail_message_id'): + mail_message_id = self.env['mail.message'].browse(result['mail_message_id']) + result['recipient_ids'] = [(0, 0, { + 'notification_id': notif.id, + 'resend': True, + 'failure_type': notif.failure_type, + 'partner_name': notif.res_partner_id.display_name or mail_message_id.record_name, + 'sms_number': notif.sms_number, + }) for notif in mail_message_id.notification_ids if notif.notification_type == 'sms' and notif.notification_status in ('exception', 'bounce')] + return result + + mail_message_id = fields.Many2one('mail.message', 'Message', readonly=True, required=True) + recipient_ids = fields.One2many('sms.resend.recipient', 'sms_resend_id', string='Recipients') + has_cancel = fields.Boolean(compute='_compute_has_cancel') + has_insufficient_credit = fields.Boolean(compute='_compute_has_insufficient_credit') + + @api.depends("recipient_ids.failure_type") + def _compute_has_insufficient_credit(self): + self.has_insufficient_credit = self.recipient_ids.filtered(lambda p: p.failure_type == 'sms_credit') + + @api.depends("recipient_ids.resend") + def _compute_has_cancel(self): + self.has_cancel = self.recipient_ids.filtered(lambda p: not p.resend) + + def _check_access(self): + if not self.mail_message_id or not self.mail_message_id.model or not self.mail_message_id.res_id: + raise exceptions.UserError(_('You do not have access to the message and/or related document.')) + record = self.env[self.mail_message_id.model].browse(self.mail_message_id.res_id) + record.check_access_rights('read') + record.check_access_rule('read') + + @api.multi + def action_resend(self): + self._check_access() + + all_notifications = self.env['mail.notification'].sudo().search([ + ('mail_message_id', '=', self.mail_message_id.id), + ('notification_type', '=', 'sms'), + ('notification_status', 'in', ('exception', 'bounce')) + ]) + sudo_self = self.sudo() + to_cancel_ids = [r.notification_id.id for r in sudo_self.recipient_ids if not r.resend] + to_resend_ids = [r.notification_id.id for r in sudo_self.recipient_ids if r.resend] + + if to_cancel_ids: + all_notifications.filtered(lambda n: n.id in to_cancel_ids).write({'notification_status': 'canceled'}) + + if to_resend_ids: + record = self.env[self.mail_message_id.model].browse(self.mail_message_id.res_id) + + sms_pid_to_number = dict((r.partner_id.id, r.sms_number) for r in self.recipient_ids if r.resend and r.partner_id) + pids = list(sms_pid_to_number.keys()) + numbers = [r.sms_number for r in self.recipient_ids if r.resend and not r.partner_id] + + rdata = [] + for pid, cid, active, pshare, ctype, notif, groups in self.env['mail.followers']._get_recipient_data(record, 'sms', False, pids=pids): + if pid and notif == 'sms': + rdata.append({'id': pid, 'share': pshare, 'active': active, 'notif': notif, 'groups': groups or [], 'type': 'customer' if pshare else 'user'}) + if rdata or numbers: + record._notify_record_by_sms( + self.mail_message_id, {'partners': rdata}, check_existing=True, + sms_numbers=numbers, sms_pid_to_number=sms_pid_to_number, + put_in_queue=False + ) + + self.mail_message_id._notify_sms_update() + return {'type': 'ir.actions.act_window_close'} + + @api.multi + def action_cancel(self): + self._check_access() + + sudo_self = self.sudo() + sudo_self.mapped('recipient_ids.notification_id').write({'notification_status': 'canceled'}) + self.mail_message_id._notify_sms_update() + return {'type': 'ir.actions.act_window_close'} + + @api.multi + def action_buy_credits(self): + url = self.env['iap.account'].get_credits_url(service_name='sms') + return { + 'type': 'ir.actions.act_url', + 'url': url, + } diff --git a/addons/sms/wizard/sms_resend_views.xml b/addons/sms/wizard/sms_resend_views.xml new file mode 100644 index 00000000000..ba090626840 --- /dev/null +++ b/addons/sms/wizard/sms_resend_views.xml @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="utf-8"?> +<odoo><data> + <record id="mail_resend_message_view_form" model="ir.ui.view"> + <field name="name">sms.resend.form</field> + <field name="model">sms.resend</field> + <field name="groups_id" eval="[(4,ref('base.group_user'))]"/> + <field name="arch" type="xml"> + <form string="Edit Partners"> + <field name="mail_message_id" invisible="1"/> + <field name="has_cancel" invisible="1"/> + <field name="has_insufficient_credit" invisible="1"/> + <field name="recipient_ids"> + <tree string="Recipient" editable="top" create="0" delete="0"> + <field name="partner_name"/> + <field name="sms_number"/> + <field name="failure_type" string="Reason"/> + <field name="resend" widget="boolean_toggle"/> + </tree> + </field> + <div class="alert alert-warning" role="alert" attrs="{'invisible': [('has_cancel', '=', False)]}"> + <span class="fa fa-info-circle"/> Caution: It won't be possible to send this SMS again to the recipients you did not select. + </div> + <footer> + <button string="Buy credits" name="action_buy_credits" type="object" class="btn-primary o_mail_send" + attrs="{'invisible': [('has_insufficient_credit', '=', False)]}"/> + <button string="Resend" name="action_resend" type="object" class="btn-primary o_mail_send"/> + <button string="Ignore all" name="action_cancel" type="object" class="btn-secondary" /> + <button string="Cancel" class="btn-secondary" special="cancel" /> + </footer> + </form> + </field> + </record> + + <record id="sms_resend_action" model="ir.actions.act_window"> + <field name="name">Sending Failures</field> + <field name="res_model">sms.resend</field> + <field name="type">ir.actions.act_window</field> + <field name="view_mode">form</field> + <field name="target">new</field> + </record> +</data></odoo> |
