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
103 lines
5.4 KiB
Python
103 lines
5.4 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
from odoo import api, fields, models, _, Command
|
|
from odoo.exceptions import UserError
|
|
|
|
|
|
class MailResendMessage(models.TransientModel):
|
|
_name = 'mail.resend.message'
|
|
_description = 'Email resend wizard'
|
|
|
|
mail_message_id = fields.Many2one('mail.message', 'Message', readonly=True)
|
|
partner_ids = fields.One2many('mail.resend.partner', 'resend_wizard_id', string='Recipients')
|
|
notification_ids = fields.Many2many('mail.notification', string='Notifications', readonly=True)
|
|
can_cancel = fields.Boolean(compute='_compute_can_cancel')
|
|
can_resend = fields.Boolean(compute='_compute_can_resend')
|
|
partner_readonly = fields.Boolean(compute='_compute_partner_readonly')
|
|
|
|
@api.depends("partner_ids")
|
|
def _compute_can_cancel(self):
|
|
self.can_cancel = self.partner_ids.filtered(lambda p: not p.resend)
|
|
|
|
@api.depends('partner_ids.resend')
|
|
def _compute_can_resend(self):
|
|
self.can_resend = any([partner.resend for partner in self.partner_ids])
|
|
|
|
def _compute_partner_readonly(self):
|
|
self.partner_readonly = not self.env['res.partner'].check_access_rights('write', raise_exception=False)
|
|
|
|
@api.model
|
|
def default_get(self, fields):
|
|
rec = super(MailResendMessage, self).default_get(fields)
|
|
message_id = self._context.get('mail_message_to_resend')
|
|
if message_id:
|
|
mail_message_id = self.env['mail.message'].browse(message_id)
|
|
notification_ids = mail_message_id.notification_ids.filtered(lambda notif: notif.notification_type == 'email' and notif.notification_status in ('exception', 'bounce'))
|
|
partner_ids = [Command.create({
|
|
"partner_id": notif.res_partner_id.id,
|
|
"name": notif.res_partner_id.name,
|
|
"email": notif.res_partner_id.email,
|
|
"resend": True,
|
|
"message": notif.format_failure_reason(),
|
|
}) for notif in notification_ids]
|
|
has_user = any(notif.res_partner_id.user_ids for notif in notification_ids)
|
|
if has_user:
|
|
partner_readonly = not self.env['res.users'].check_access_rights('write', raise_exception=False)
|
|
else:
|
|
partner_readonly = not self.env['res.partner'].check_access_rights('write', raise_exception=False)
|
|
rec['partner_readonly'] = partner_readonly
|
|
rec['notification_ids'] = [Command.set(notification_ids.ids)]
|
|
rec['mail_message_id'] = mail_message_id.id
|
|
rec['partner_ids'] = partner_ids
|
|
else:
|
|
raise UserError(_('No message_id found in context'))
|
|
return rec
|
|
|
|
def resend_mail_action(self):
|
|
""" Process the wizard content and proceed with sending the related
|
|
email(s), rendering any template patterns on the fly if needed. """
|
|
for wizard in self:
|
|
"If a partner disappeared from partner list, we cancel the notification"
|
|
to_cancel = wizard.partner_ids.filtered(lambda p: not p.resend).mapped("partner_id")
|
|
to_send = wizard.partner_ids.filtered(lambda p: p.resend).mapped("partner_id")
|
|
notif_to_cancel = wizard.notification_ids.filtered(lambda notif: notif.notification_type == 'email' and notif.res_partner_id in to_cancel and notif.notification_status in ('exception', 'bounce'))
|
|
notif_to_cancel.sudo().write({'notification_status': 'canceled'})
|
|
if to_send:
|
|
message = wizard.mail_message_id
|
|
record = self.env[message.model].browse(message.res_id) if message.is_thread_message() else self.env['mail.thread']
|
|
|
|
email_partners_data = []
|
|
recipients_data = self.env['mail.followers']._get_recipient_data(None, 'comment', False, pids=to_send.ids)[0]
|
|
for pid, pdata in recipients_data.items():
|
|
if pid and pdata.get('notif', 'email') == 'email':
|
|
email_partners_data.append(pdata)
|
|
|
|
record._notify_thread_by_email(
|
|
message, email_partners_data,
|
|
check_existing=True,
|
|
send_after_commit=False
|
|
)
|
|
|
|
self.mail_message_id._notify_message_notification_update()
|
|
return {'type': 'ir.actions.act_window_close'}
|
|
|
|
def cancel_mail_action(self):
|
|
for wizard in self:
|
|
for notif in wizard.notification_ids:
|
|
notif.filtered(lambda notif: notif.notification_type == 'email' and notif.notification_status in ('exception', 'bounce')).sudo().write({'notification_status': 'canceled'})
|
|
wizard.mail_message_id._notify_message_notification_update()
|
|
return {'type': 'ir.actions.act_window_close'}
|
|
|
|
|
|
class PartnerResend(models.TransientModel):
|
|
_name = 'mail.resend.partner'
|
|
_description = 'Partner with additional information for mail resend'
|
|
|
|
partner_id = fields.Many2one('res.partner', string='Partner', required=True, ondelete='cascade')
|
|
name = fields.Char(related='partner_id.name', string='Recipient Name', related_sudo=False, readonly=False)
|
|
email = fields.Char(related='partner_id.email', string='Email Address', related_sudo=False, readonly=False)
|
|
resend = fields.Boolean(string='Try Again', default=True)
|
|
resend_wizard_id = fields.Many2one('mail.resend.message', string="Resend wizard")
|
|
message = fields.Char(string='Error message')
|