social/mail_activity_reminder/models/mail_activity.py

132 lines
4.8 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 UTC, timezone
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)