Purpose of this commit is to improve notification recipients computation.
Code cleaning
* make it batch enabled. Currently it works only for a single record. It
should evolve towards real multi computation, allowing to prepare post
and notification in batch;
* better manage multi users. Now when several users are linked to the same
partner, we try to find an internal user or fallback on share user. This
is cleaned compared to a distinct done previously;
* support recipients without subtype (pids + records) as a new case to
include follower computation;
Improvements
* include follower status if linked to records (is_follower can be used
notably in link computation to redirect to the portal);
* fetch partner lang directly in the SQL query. While fetching partner data
let us add its lang. That way it will be easier to improve lang support
in layouts;
Task-2739294 (Mail: Batch recipients fetch and improve its usage)
Part-of: odoo/odoo#82167
122 lines
5.7 KiB
Python
122 lines
5.7 KiB
Python
# -*- 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='Try Again', default=True)
|
|
failure_type = fields.Selection(
|
|
related='notification_id.failure_type', string='Error Message', related_sudo=True, readonly=True)
|
|
partner_id = fields.Many2one('res.partner', 'Partner', related='notification_id.res_partner_id', readonly=True)
|
|
partner_name = fields.Char(string='Recipient Name', readonly='True')
|
|
sms_number = fields.Char(string='Phone 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 'recipient_ids' in fields and 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')
|
|
can_cancel = fields.Boolean(compute='_compute_can_cancel')
|
|
can_resend = fields.Boolean(compute='_compute_can_resend')
|
|
has_insufficient_credit = fields.Boolean(compute='_compute_has_insufficient_credit')
|
|
has_unregistered_account = fields.Boolean(compute='_compute_has_unregistered_account')
|
|
|
|
@api.depends("recipient_ids.failure_type")
|
|
def _compute_has_unregistered_account(self):
|
|
self.has_unregistered_account = self.recipient_ids.filtered(lambda p: p.failure_type == 'sms_acc')
|
|
|
|
@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_can_cancel(self):
|
|
self.can_cancel = self.recipient_ids.filtered(lambda p: not p.resend)
|
|
|
|
@api.depends('recipient_ids.resend')
|
|
def _compute_can_resend(self):
|
|
self.can_resend = any([recipient.resend for recipient in self.recipient_ids])
|
|
|
|
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')
|
|
|
|
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]
|
|
|
|
recipients_data = []
|
|
all_recipients_data = self.env['mail.followers']._get_recipient_data(record, 'sms', False, pids=pids)[record.id]
|
|
for pid, pdata in all_recipients_data.items():
|
|
if pid and pdata['notif'] == 'sms':
|
|
recipients_data.append(pdata)
|
|
if recipients_data or numbers:
|
|
record._notify_thread_by_sms(
|
|
self.mail_message_id, recipients_data,
|
|
sms_numbers=numbers, sms_pid_to_number=sms_pid_to_number,
|
|
check_existing=True, put_in_queue=False
|
|
)
|
|
|
|
self.mail_message_id._notify_message_notification_update()
|
|
return {'type': 'ir.actions.act_window_close'}
|
|
|
|
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_message_notification_update()
|
|
return {'type': 'ir.actions.act_window_close'}
|
|
|
|
def action_buy_credits(self):
|
|
url = self.env['iap.account'].get_credits_url(service_name='sms')
|
|
return {
|
|
'type': 'ir.actions.act_url',
|
|
'url': url,
|
|
}
|