1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
|
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import json
import logging
from datetime import datetime
from odoo import api, fields, models
_logger = logging.getLogger(__name__)
class MailMessageSchedule(models.Model):
""" Mail message notification schedule queue.
This model is used to store the mail messages scheduled. So we can
delay the sending of the notifications. A scheduled date field already
exists on the <mail.mail> but it does not allow us to delay the sending
of the <bus.bus> notifications.
"""
_name = 'mail.message.schedule'
_description = 'Scheduled Messages'
_order = 'scheduled_datetime DESC, id DESC'
_rec_name = 'mail_message_id'
mail_message_id = fields.Many2one(
'mail.message', string='Message',
ondelete='cascade', required=True)
notification_parameters = fields.Text('Notification Parameter')
scheduled_datetime = fields.Datetime(
'Scheduled Send Date', required=True,
help='Datetime at which notification should be sent.')
@api.model_create_multi
def create(self, vals_list):
schedules = super().create(vals_list)
if schedules:
self.env.ref('mail.ir_cron_send_scheduled_message')._trigger_list(
set(schedules.mapped('scheduled_datetime'))
)
return schedules
@api.model
def _send_notifications_cron(self):
messages_scheduled = self.env['mail.message.schedule'].search(
[('scheduled_datetime', '<=', datetime.utcnow())]
)
if messages_scheduled:
_logger.info('Send %s scheduled messages', len(messages_scheduled))
messages_scheduled._send_notifications()
def force_send(self):
""" Launch notification process independently from the expected date. """
return self._send_notifications()
def _send_notifications(self, default_notify_kwargs=None):
""" Send notification for scheduled messages.
:param dict default_notify_kwargs: optional parameters to propagate to
``notify_thread``. Those are default values overridden by content of
``notification_parameters`` field.
"""
for model, schedules in self._group_by_model().items():
if model:
records = self.env[model].browse(schedules.mapped('mail_message_id.res_id'))
else:
records = [self.env['mail.thread']] * len(schedules)
for record, schedule in zip(records, schedules):
notify_kwargs = dict(default_notify_kwargs or {}, skip_existing=True)
try:
schedule_notify_kwargs = json.loads(schedule.notification_parameters)
except Exception:
pass
else:
schedule_notify_kwargs.pop('scheduled_date', None)
notify_kwargs.update(schedule_notify_kwargs)
record._notify_thread(schedule.mail_message_id, msg_vals=False, **notify_kwargs)
self.unlink()
return True
@api.model
def _send_message_notifications(self, messages, default_notify_kwargs=None):
""" Send scheduled notification for given messages.
:param <mail.message> messages: scheduled sending related to those messages
will be sent now;
:param dict default_notify_kwargs: optional parameters to propagate to
``notify_thread``. Those are default values overridden by content of
``notification_parameters`` field.
:return bool: False if no schedule has been found, True otherwise
"""
messages_scheduled = self.search(
[('mail_message_id', 'in', messages.ids)]
)
if not messages_scheduled:
return False
messages_scheduled._send_notifications(default_notify_kwargs=default_notify_kwargs)
return True
@api.model
def _update_message_scheduled_datetime(self, messages, new_datetime):
""" Update scheduled datetime for scheduled sending related to messages.
:param <mail.message> messages: scheduled sending related to those messages
will be updated. Missing one are skipped;
:param datetime new_datetime: new datetime for sending. New triggers
are created based on it;
:return bool: False if no schedule has been found, True otherwise
"""
messages_scheduled = self.search(
[('mail_message_id', 'in', messages.ids)]
)
if not messages_scheduled:
return False
messages_scheduled.scheduled_datetime = new_datetime
self.env.ref('mail.ir_cron_send_scheduled_message')._trigger(new_datetime)
return True
def _group_by_model(self):
grouped = {}
for schedule in self:
model = schedule.mail_message_id.model if schedule.mail_message_id.model and schedule.mail_message_id.res_id else False
if model not in grouped:
grouped[model] = schedule
else:
grouped[model] += schedule
return grouped
|