[IMP] mail_activity_reminder: black, isort, prettier

pull/1228/head
Denis Roussel 2023-04-21 18:23:02 +02:00 committed by Sébastien Alix
parent d4aa3f0c60
commit 695e683f09
6 changed files with 158 additions and 174 deletions

View File

@ -3,22 +3,15 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
{
'name': 'Mail Activity Reminder',
'version': '12.0.1.0.1',
'category': 'Discuss',
'website': 'https://github.com/OCA/social',
'author':
'CorporateHub, '
'Odoo Community Association (OCA)',
'license': 'AGPL-3',
'installable': True,
'application': False,
'summary': 'Reminder notifications about planned activities',
'depends': [
'mail',
],
'data': [
'data/mail_activity_reminder_cron.xml',
'views/mail_activity_type.xml',
],
"name": "Mail Activity Reminder",
"version": "12.0.1.0.1",
"category": "Discuss",
"website": "https://github.com/OCA/social",
"author": "CorporateHub, " "Odoo Community Association (OCA)",
"license": "AGPL-3",
"installable": True,
"application": False,
"summary": "Reminder notifications about planned activities",
"depends": ["mail",],
"data": ["data/mail_activity_reminder_cron.xml", "views/mail_activity_type.xml",],
}

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8" ?>
<!--
Copyright 2020 Brainbean Apps (https://brainbeanapps.com)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
@ -7,14 +7,14 @@
<record id="mail_activity_reminder" model="ir.cron">
<field name="name">Mail Activity: Reminders</field>
<field name="model_id" ref="model_mail_activity"/>
<field name="model_id" ref="model_mail_activity" />
<field name="state">code</field>
<field name="code">model._process_reminders()</field>
<field name="interval_number">1</field>
<field name="interval_type">hours</field>
<field name="nextcall">2020-01-01 00:01:00</field>
<field name="numbercall">-1</field>
<field name="doall" eval="True"/>
<field name="doall" eval="True" />
</record>
</odoo>

View File

@ -2,43 +2,38 @@
# 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 pytz import UTC, timezone
from odoo import _, api, fields, models
class MailActivity(models.Model):
_inherit = 'mail.activity'
_inherit = "mail.activity"
next_reminder = fields.Datetime(
string='Next reminder',
compute='_compute_next_reminder',
string="Next reminder",
compute="_compute_next_reminder",
compute_sudo=True,
store=True,
)
last_reminder_local = fields.Datetime(
string='Last reminder (local)',
)
last_reminder_local = fields.Datetime(string="Last reminder (local)",)
deadline = fields.Datetime(
string='Deadline',
compute='_compute_deadline',
compute_sudo=True,
store=True,
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()),
("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())
return self.search(self._get_activities_to_remind_domain())
@api.model
def _process_reminders(self):
@ -48,10 +43,7 @@ class MailActivity(models.Model):
@api.multi
@api.depends(
'user_id.tz',
'activity_type_id.reminders',
'deadline',
'last_reminder_local',
"user_id.tz", "activity_type_id.reminders", "deadline", "last_reminder_local",
)
def _compute_next_reminder(self):
now = fields.Datetime.now()
@ -64,37 +56,39 @@ class MailActivity(models.Model):
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,
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
)
if not last_reminder_local \
or next_reminder_local > last_reminder_local:
)
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:
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)
activity.next_reminder = next_reminder_local.astimezone(UTC).replace(
tzinfo=None
)
@api.multi
@api.depends('user_id.tz', 'date_deadline')
@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)
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):
@ -103,31 +97,27 @@ class MailActivity(models.Model):
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)
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'
)
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')
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') % (
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
(activity.date_deadline - local_now.date()).days,
)
body = message_activity_assigned.render(
dict(activity=activity, model_description=model_description),
engine='ir.qweb',
engine="ir.qweb",
minimal_qcontext=True,
)
MailThread.message_notify(
@ -136,6 +126,6 @@ class MailActivity(models.Model):
subject=subject,
record_name=activity.res_name,
model_description=model_description,
notif_layout='mail.mail_notification_light',
notif_layout="mail.mail_notification_light",
)
activity.last_reminder_local = local_now.replace(tzinfo=None)

View File

@ -7,12 +7,12 @@ from odoo import api, fields, models
class MailActivityType(models.Model):
_inherit = 'mail.activity.type'
_inherit = "mail.activity.type"
reminders = fields.Char(
string='Reminders',
string="Reminders",
help=(
'A non-digit-separated list of offsets (in days) when reminders'
"A non-digit-separated list of offsets (in days) when reminders"
' should be fired: e.g. 0 means "on the deadline day" while'
' 5 means "5 calendar days before the deadline".'
),
@ -24,4 +24,4 @@ class MailActivityType(models.Model):
self.ensure_one()
if not self.reminders:
return []
return [int(x) for x in split(r'\D+', self.reminders) if x]
return [int(x) for x in split(r"\D+", self.reminders) if x]

View File

@ -2,6 +2,7 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from datetime import datetime
from dateutil.relativedelta import relativedelta
from freezegun import freeze_time
@ -9,88 +10,85 @@ from odoo.tests import common
class TestMailActivityReminder(common.SavepointCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.env = cls.env(context=dict(
cls.env.context,
tracking_disable=True,
no_reset_password=True,
))
cls.ResUsers = cls.env['res.users']
cls.Company = cls.env['res.company']
cls.MailActivityType = cls.env['mail.activity.type']
cls.MailActivity = cls.env['mail.activity']
cls.env = cls.env(
context=dict(
cls.env.context, tracking_disable=True, no_reset_password=True,
)
)
cls.ResUsers = cls.env["res.users"]
cls.Company = cls.env["res.company"]
cls.MailActivityType = cls.env["mail.activity.type"]
cls.MailActivity = cls.env["mail.activity"]
cls.company_id = cls.Company._company_default_get()
cls.now = datetime(2020, 4, 19, 15, 00)
cls.today = cls.now.date()
cls.model_res_partner = cls.env['ir.model'].search(
[('model', '=', 'res.partner')], limit=1
cls.model_res_partner = cls.env["ir.model"].search(
[("model", "=", "res.partner")], limit=1
)
cls.partner_DecoAddict = cls.env['res.partner'].search(
[('name', 'ilike', 'Deco Addict')], limit=1
cls.partner_DecoAddict = cls.env["res.partner"].search(
[("name", "ilike", "Deco Addict")], limit=1
)
def test_none_reminders(self):
activity_type = self.MailActivityType.create({
'name': 'Activity Type',
})
activity_type = self.MailActivityType.create({"name": "Activity Type",})
self.assertEqual(activity_type._get_reminder_offsets(), [])
def test_empty_reminders(self):
activity_type = self.MailActivityType.create({
'name': 'Activity Type',
'reminders': ' -./',
})
activity_type = self.MailActivityType.create(
{"name": "Activity Type", "reminders": " -./",}
)
self.assertEqual(activity_type._get_reminder_offsets(), [])
def test_delimiters(self):
activity_type = self.MailActivityType.create({
'name': 'Activity Type',
'reminders': '0 1_2/3.4t5',
})
self.assertEqual(activity_type._get_reminder_offsets(), [
0, 1, 2, 3, 4, 5
])
activity_type = self.MailActivityType.create(
{"name": "Activity Type", "reminders": "0 1_2/3.4t5",}
)
self.assertEqual(activity_type._get_reminder_offsets(), [0, 1, 2, 3, 4, 5])
def test_first_notice_is_reminder(self):
activity_type = self.MailActivityType.create({
'name': 'Activity Type',
'reminders': '0',
})
user = self.ResUsers.sudo().create({
'name': 'User',
'login': 'user',
'email': 'user@example.com',
'company_id': self.company_id.id,
})
activity = self.MailActivity.create({
'summary': 'Activity',
'activity_type_id': activity_type.id,
'res_model_id': self.model_res_partner.id,
'res_id': self.partner_DecoAddict.id,
'date_deadline': self.today,
'user_id': user.id,
})
activity_type = self.MailActivityType.create(
{"name": "Activity Type", "reminders": "0",}
)
user = self.ResUsers.sudo().create(
{
"name": "User",
"login": "user",
"email": "user@example.com",
"company_id": self.company_id.id,
}
)
activity = self.MailActivity.create(
{
"summary": "Activity",
"activity_type_id": activity_type.id,
"res_model_id": self.model_res_partner.id,
"res_id": self.partner_DecoAddict.id,
"date_deadline": self.today,
"user_id": user.id,
}
)
self.assertTrue(activity.last_reminder_local)
def test_reminder_behaviour(self):
activity_type = self.MailActivityType.create({
'name': 'Activity Type',
'reminders': '0/2',
})
activity_type = self.MailActivityType.create(
{"name": "Activity Type", "reminders": "0/2",}
)
with freeze_time(self.now):
activity = self.MailActivity.create({
'summary': 'Activity',
'activity_type_id': activity_type.id,
'res_model_id': self.model_res_partner.id,
'res_id': self.partner_DecoAddict.id,
'date_deadline': self.today + relativedelta(days=5),
})
activity = self.MailActivity.create(
{
"summary": "Activity",
"activity_type_id": activity_type.id,
"res_model_id": self.model_res_partner.id,
"res_id": self.partner_DecoAddict.id,
"date_deadline": self.today + relativedelta(days=5),
}
)
with freeze_time(self.now):
activities = self.MailActivity._get_activities_to_remind()
@ -120,19 +118,20 @@ class TestMailActivityReminder(common.SavepointCase):
self.assertFalse(activities)
def test_reminder_flow(self):
activity_type = self.MailActivityType.create({
'name': 'Activity Type',
'reminders': '0/2',
})
activity_type = self.MailActivityType.create(
{"name": "Activity Type", "reminders": "0/2",}
)
with freeze_time(self.now):
activity = self.MailActivity.create({
'summary': 'Activity',
'activity_type_id': activity_type.id,
'res_model_id': self.model_res_partner.id,
'res_id': self.partner_DecoAddict.id,
'date_deadline': self.today + relativedelta(days=5),
})
activity = self.MailActivity.create(
{
"summary": "Activity",
"activity_type_id": activity_type.id,
"res_model_id": self.model_res_partner.id,
"res_id": self.partner_DecoAddict.id,
"date_deadline": self.today + relativedelta(days=5),
}
)
with freeze_time(self.now):
activities = self.MailActivity._process_reminders()
@ -155,19 +154,20 @@ class TestMailActivityReminder(common.SavepointCase):
self.assertEqual(activities, activity)
def test_repeated_reminder(self):
activity_type = self.MailActivityType.create({
'name': 'Activity Type',
'reminders': '0',
})
activity_type = self.MailActivityType.create(
{"name": "Activity Type", "reminders": "0",}
)
with freeze_time(self.now):
activity = self.MailActivity.create({
'summary': 'Activity',
'activity_type_id': activity_type.id,
'res_model_id': self.model_res_partner.id,
'res_id': self.partner_DecoAddict.id,
'date_deadline': self.today + relativedelta(days=1),
})
activity = self.MailActivity.create(
{
"summary": "Activity",
"activity_type_id": activity_type.id,
"res_model_id": self.model_res_partner.id,
"res_id": self.partner_DecoAddict.id,
"date_deadline": self.today + relativedelta(days=1),
}
)
with freeze_time(self.now + relativedelta(days=1)):
activities = self.MailActivity._process_reminders()
@ -177,19 +177,20 @@ class TestMailActivityReminder(common.SavepointCase):
self.assertFalse(activities)
def test_overdue_reminder(self):
activity_type = self.MailActivityType.create({
'name': 'Activity Type',
'reminders': '0',
})
activity_type = self.MailActivityType.create(
{"name": "Activity Type", "reminders": "0",}
)
with freeze_time(self.now):
self.MailActivity.create({
'summary': 'Activity',
'activity_type_id': activity_type.id,
'res_model_id': self.model_res_partner.id,
'res_id': self.partner_DecoAddict.id,
'date_deadline': self.today + relativedelta(days=1),
})
self.MailActivity.create(
{
"summary": "Activity",
"activity_type_id": activity_type.id,
"res_model_id": self.model_res_partner.id,
"res_id": self.partner_DecoAddict.id,
"date_deadline": self.today + relativedelta(days=1),
}
)
with freeze_time(self.now + relativedelta(days=2)):
activities = self.MailActivity._get_activities_to_remind()

View File

@ -1,4 +1,4 @@
<?xml version="1.0"?>
<?xml version="1.0" ?>
<!--
Copyright 2020 Brainbean Apps (https://brainbeanapps.com)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
@ -8,10 +8,10 @@
<record id="mail_activity_type_view_form" model="ir.ui.view">
<field name="name">mail.activity.type.view.form</field>
<field name="model">mail.activity.type</field>
<field name="inherit_id" ref="mail.mail_activity_type_view_form"/>
<field name="inherit_id" ref="mail.mail_activity_type_view_form" />
<field name="arch" type="xml">
<field name="summary" position="after">
<field name="reminders"/>
<field name="reminders" />
</field>
</field>
</record>