social/mail_activity_reminder/models/mail_activity.py

142 lines
4.9 KiB
Python

# Copyright 2020 Brainbean Apps (https://brainbeanapps.com)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from datetime import datetime, time
from dateutil.relativedelta import relativedelta
from pytz import timezone, UTC
from odoo import _, api, fields, models
class MailActivity(models.Model):
_inherit = 'mail.activity'
next_reminder = fields.Datetime(
string='Next reminder',
compute='_compute_next_reminder',
compute_sudo=True,
store=True,
)
last_reminder_local = fields.Datetime(
string='Last reminder (local)',
)
deadline = fields.Datetime(
string='Deadline',
compute='_compute_deadline',
compute_sudo=True,
store=True,
)
@api.model
def _get_activities_to_remind_domain(self):
"""Hook for extensions"""
return [
('next_reminder', '<=', fields.Datetime.now()),
('deadline', '>=', fields.Datetime.now()),
]
@api.model
def _get_activities_to_remind(self):
return self \
.search(self._get_activities_to_remind_domain())
@api.model
def _process_reminders(self):
activities = self._get_activities_to_remind()
activities.action_remind()
return activities
@api.multi
@api.depends(
'user_id.tz',
'activity_type_id.reminders',
'deadline',
'last_reminder_local',
)
def _compute_next_reminder(self):
now = fields.Datetime.now()
for activity in self:
if activity.deadline < now:
activity.next_reminder = None
continue
reminders = activity.activity_type_id._get_reminder_offsets()
if not reminders:
activity.next_reminder = None
continue
reminders.sort(reverse=True)
tz = timezone(activity.user_id.sudo().tz or 'UTC')
last_reminder_local = tz.localize(
activity.last_reminder_local
) if activity.last_reminder_local else None
local_deadline = tz.localize(datetime.combine(
activity.date_deadline,
time.min # Schedule reminder based of beginning of day
))
for reminder in reminders:
next_reminder_local = local_deadline - relativedelta(
days=reminder,
)
if not last_reminder_local \
or next_reminder_local > last_reminder_local:
break
if last_reminder_local \
and next_reminder_local <= last_reminder_local:
activity.next_reminder = None
continue
activity.next_reminder = next_reminder_local \
.astimezone(UTC) \
.replace(tzinfo=None)
@api.multi
@api.depends('user_id.tz', 'date_deadline')
def _compute_deadline(self):
for activity in self:
tz = timezone(activity.user_id.sudo().tz or 'UTC')
activity.deadline = tz.localize(
datetime.combine(activity.date_deadline, time.max)
).astimezone(UTC).replace(tzinfo=None)
@api.multi
def action_notify(self):
super().action_notify()
utc_now = fields.Datetime.now().replace(tzinfo=UTC)
for activity in self:
if activity.last_reminder_local:
continue
tz = timezone(activity.user_id.sudo().tz or 'UTC')
activity.last_reminder_local = utc_now \
.astimezone(tz) \
.replace(tzinfo=None)
@api.multi
def action_remind(self):
IrModel = self.env['ir.model']
MailThread = self.env['mail.thread']
message_activity_assigned = self.env.ref(
'mail.message_activity_assigned'
)
utc_now = fields.Datetime.now().replace(tzinfo=UTC)
for activity in self:
tz = timezone(activity.user_id.sudo().tz or 'UTC')
local_now = utc_now.astimezone(tz)
model_description = IrModel._get(activity.res_model).display_name
subject = _('%s: %s assigned to you, %d day(s) remaining') % (
activity.res_name,
activity.summary or activity.activity_type_id.name,
(activity.date_deadline - local_now.date()).days
)
body = message_activity_assigned.render(
dict(activity=activity, model_description=model_description),
engine='ir.qweb',
minimal_qcontext=True,
)
MailThread.message_notify(
partner_ids=activity.user_id.partner_id.ids,
body=body,
subject=subject,
record_name=activity.res_name,
model_description=model_description,
notif_layout='mail.mail_notification_light',
)
activity.last_reminder_local = local_now.replace(tzinfo=None)