Reorganize code to ease future additions understanding and setting code at the right place. Rename some compute methods to have understandable names. Remove dead imports. Fix pytz.utc usage. No functional change comes with this commit. This is only code move. Task-2631873 PR odoo/odoo#75571
122 lines
5.0 KiB
Python
122 lines
5.0 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
from dateutil.relativedelta import relativedelta
|
|
|
|
from odoo import api, fields, models
|
|
from odoo.exceptions import AccessError
|
|
from odoo.tools.translate import _
|
|
|
|
|
|
class MailNotification(models.Model):
|
|
_name = 'mail.notification'
|
|
_table = 'mail_notification'
|
|
_rec_name = 'res_partner_id'
|
|
_log_access = False
|
|
_description = 'Message Notifications'
|
|
|
|
# origin
|
|
mail_message_id = fields.Many2one('mail.message', 'Message', index=True, ondelete='cascade', required=True)
|
|
mail_mail_id = fields.Many2one('mail.mail', 'Mail', index=True, help='Optional mail_mail ID. Used mainly to optimize searches.')
|
|
# recipient
|
|
res_partner_id = fields.Many2one('res.partner', 'Recipient', index=True, ondelete='cascade')
|
|
# status
|
|
notification_type = fields.Selection([
|
|
('inbox', 'Inbox'), ('email', 'Email')
|
|
], string='Notification Type', default='inbox', index=True, required=True)
|
|
notification_status = fields.Selection([
|
|
('ready', 'Ready to Send'),
|
|
('sent', 'Sent'),
|
|
('bounce', 'Bounced'),
|
|
('exception', 'Exception'),
|
|
('canceled', 'Canceled')
|
|
], string='Status', default='ready', index=True)
|
|
is_read = fields.Boolean('Is Read', index=True)
|
|
read_date = fields.Datetime('Read Date', copy=False)
|
|
failure_type = fields.Selection(selection=[
|
|
# generic
|
|
("unknown", "Unknown error"),
|
|
# mail
|
|
("mail_email_invalid", "Invalid email address"),
|
|
("mail_email_missing", "Missing email addresss"),
|
|
("mail_smtp", "Connection failed (outgoing mail server problem)"),
|
|
], string='Failure type')
|
|
failure_reason = fields.Text('Failure reason', copy=False)
|
|
|
|
_sql_constraints = [
|
|
# email notification;: partner is required
|
|
('notification_partner_required',
|
|
"CHECK(notification_type NOT IN ('email', 'inbox') OR res_partner_id IS NOT NULL)",
|
|
'Customer is required for inbox / email notification'),
|
|
]
|
|
|
|
# ------------------------------------------------------------
|
|
# CRUD
|
|
# ------------------------------------------------------------
|
|
|
|
def init(self):
|
|
self._cr.execute("""
|
|
CREATE INDEX IF NOT EXISTS mail_notification_res_partner_id_is_read_notification_status_mail_message_id
|
|
ON mail_notification (res_partner_id, is_read, notification_status, mail_message_id)
|
|
""")
|
|
|
|
@api.model_create_multi
|
|
def create(self, vals_list):
|
|
messages = self.env['mail.message'].browse(vals['mail_message_id'] for vals in vals_list)
|
|
messages.check_access_rights('read')
|
|
messages.check_access_rule('read')
|
|
for vals in vals_list:
|
|
if vals.get('is_read'):
|
|
vals['read_date'] = fields.Datetime.now()
|
|
return super(MailNotification, self).create(vals_list)
|
|
|
|
def write(self, vals):
|
|
if ('mail_message_id' in vals or 'res_partner_id' in vals) and not self.env.is_admin():
|
|
raise AccessError(_("Can not update the message or recipient of a notification."))
|
|
if vals.get('is_read'):
|
|
vals['read_date'] = fields.Datetime.now()
|
|
return super(MailNotification, self).write(vals)
|
|
|
|
@api.model
|
|
def _gc_notifications(self, max_age_days=180):
|
|
domain = [
|
|
('is_read', '=', True),
|
|
('read_date', '<', fields.Datetime.now() - relativedelta(days=max_age_days)),
|
|
('res_partner_id.partner_share', '=', False),
|
|
('notification_status', 'in', ('sent', 'canceled'))
|
|
]
|
|
return self.search(domain).unlink()
|
|
|
|
# ------------------------------------------------------------
|
|
# TOOLS
|
|
# ------------------------------------------------------------
|
|
|
|
def format_failure_reason(self):
|
|
self.ensure_one()
|
|
if self.failure_type != 'unknown':
|
|
return dict(type(self).failure_type.selection).get(self.failure_type, _('No Error'))
|
|
else:
|
|
return _("Unknown error") + ": %s" % (self.failure_reason or '')
|
|
|
|
# ------------------------------------------------------------
|
|
# DISCUSS
|
|
# ------------------------------------------------------------
|
|
|
|
def _filtered_for_web_client(self):
|
|
"""Returns only the notifications to show on the web client."""
|
|
return self.filtered(lambda n:
|
|
n.notification_type != 'inbox' and
|
|
(n.notification_status in ['bounce', 'exception', 'canceled'] or n.res_partner_id.partner_share)
|
|
)
|
|
|
|
def _notification_format(self):
|
|
"""Returns the current notifications in the format expected by the web
|
|
client."""
|
|
return [{
|
|
'id': notif.id,
|
|
'notification_type': notif.notification_type,
|
|
'notification_status': notif.notification_status,
|
|
'failure_type': notif.failure_type,
|
|
'res_partner_id': [notif.res_partner_id.id, notif.res_partner_id.display_name] if notif.res_partner_id else False,
|
|
} for notif in self]
|