From 60ad2fd7045cede66ba26bf9789a80cef033e868 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Mart=C3=ADnez?= Date: Thu, 28 Sep 2023 16:39:02 +0200 Subject: [PATCH 1/4] [IMP-FIX] mail_activity_done: Re-do systray_get_activities() method + improve tests --- mail_activity_done/models/res_users.py | 103 ++++++++++-------- .../tests/test_mail_activity_done.py | 15 ++- 2 files changed, 68 insertions(+), 50 deletions(-) diff --git a/mail_activity_done/models/res_users.py b/mail_activity_done/models/res_users.py index 9696f53a2a..05a3c4edba 100644 --- a/mail_activity_done/models/res_users.py +++ b/mail_activity_done/models/res_users.py @@ -1,6 +1,9 @@ # Copyright 2018-22 ForgeFlow +# Copyright 2023 Tecnativa - Víctor Martínez # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). -from odoo import api, fields, models, modules +from collections import defaultdict + +from odoo import api, fields, models class ResUsers(models.Model): @@ -8,51 +11,61 @@ class ResUsers(models.Model): @api.model def systray_get_activities(self): - # Here we totally override the method. Not very nice, but - # we should perhaps ask Odoo to add a hook here. - query = """SELECT m.id, count(*), act.res_model as model, - CASE - WHEN %(today)s::date - - act.date_deadline::date = 0 Then 'today' - WHEN %(today)s::date - - act.date_deadline::date > 0 Then 'overdue' - WHEN %(today)s::date - - act.date_deadline::date < 0 Then 'planned' - END AS states - FROM mail_activity AS act - JOIN ir_model AS m ON act.res_model_id = m.id - WHERE user_id = %(user_id)s - AND act.done = False - GROUP BY m.id, states, act.res_model; - """ + # TODO: Simplify if Odoo allows to modify query + res = super().systray_get_activities() + # Convert list to dict + user_activities = {} + for item in res: + user_activities[item["model"]] = item + # Redo the method only with the archived records and subtract them. + query = """SELECT array_agg(res_id) as res_ids, m.id, count(*), + CASE + WHEN %(today)s::date - act.date_deadline::date = 0 Then 'today' + WHEN %(today)s::date - act.date_deadline::date > 0 Then 'overdue' + WHEN %(today)s::date - act.date_deadline::date < 0 Then 'planned' + END AS states + FROM mail_activity AS act + JOIN ir_model AS m ON act.res_model_id = m.id + WHERE user_id = %(user_id)s + AND act.active = False + GROUP BY m.id, states; + """ self.env.cr.execute( - query, {"today": fields.Date.context_today(self), "user_id": self.env.uid} + query, + { + "today": fields.Date.context_today(self), + "user_id": self.env.uid, + }, ) activity_data = self.env.cr.dictfetchall() - model_ids = [a["id"] for a in activity_data] - model_names = { - n[0]: n[1] for n in self.env["ir.model"].sudo().browse(model_ids).name_get() - } - - user_activities = {} - for activity in activity_data: - if not user_activities.get(activity["model"]): - user_activities[activity["model"]] = { - "name": model_names[activity["id"]], - "model": activity["model"], - "icon": modules.module.get_module_icon( - self.env[activity["model"]]._original_module - ), - "total_count": 0, - "today_count": 0, - "overdue_count": 0, - "planned_count": 0, - "type": "activity", - } - user_activities[activity["model"]][ - "%s_count" % activity["states"] - ] += activity["count"] - if activity["states"] in ("today", "overdue"): - user_activities[activity["model"]]["total_count"] += activity["count"] - + records_by_state_by_model = defaultdict( + lambda: {"today": set(), "overdue": set(), "planned": set(), "all": set()} + ) + for data in activity_data: + records_by_state_by_model[data["id"]][data["states"]] = set(data["res_ids"]) + records_by_state_by_model[data["id"]]["all"] = records_by_state_by_model[ + data["id"] + ]["all"] | set(data["res_ids"]) + for model_id in records_by_state_by_model: + model_dic = records_by_state_by_model[model_id] + model = ( + self.env["ir.model"] + .sudo() + .browse(model_id) + .with_prefetch(tuple(records_by_state_by_model.keys())) + ) + allowed_records = self.env[model.model].search( + [("id", "in", tuple(model_dic["all"]))] + ) + if not allowed_records: + continue + today = len(model_dic["today"] & set(allowed_records.ids)) + overdue = len(model_dic["overdue"] & set(allowed_records.ids)) + # Decrease total + user_activities[model.model]["total_count"] -= today + overdue + user_activities[model.model]["today_count"] -= today + user_activities[model.model]["overdue_count"] -= overdue + user_activities[model.model]["planned_count"] -= len( + model_dic["planned"] & set(allowed_records.ids) + ) return list(user_activities.values()) diff --git a/mail_activity_done/tests/test_mail_activity_done.py b/mail_activity_done/tests/test_mail_activity_done.py index 1b4c8c86d8..b76d00f63a 100644 --- a/mail_activity_done/tests/test_mail_activity_done.py +++ b/mail_activity_done/tests/test_mail_activity_done.py @@ -1,5 +1,5 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). - +# Copyright 2023 Tecnativa - Víctor Martínez from datetime import date from odoo.tests.common import TransactionCase @@ -35,7 +35,12 @@ def test_mail_activity_done(self): self.assertEqual(self.act1.state, "done") def test_systray_get_activities(self): - act_count = self.employee.with_user(self.employee).systray_get_activities() - self.assertEqual( - len(act_count), 1, "Number of activities should be equal to one" - ) + res = self.employee.with_user(self.employee).systray_get_activities() + self.assertEqual(res[0]["total_count"], 1) + self.act1.action_feedback() + self.assertFalse(self.act1.active) + self.assertEqual(self.act1.state, "done") + self.assertTrue(self.act1.done) + self.act1.flush() + res = self.employee.with_user(self.employee).systray_get_activities() + self.assertEqual(res[0]["total_count"], 0) From b60d91089e7a68a8b3173b2d41ce9babaa8d6dc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Mart=C3=ADnez?= Date: Thu, 28 Sep 2023 16:44:29 +0200 Subject: [PATCH 2/4] [IMP] mail_activity_done: Speed up tests --- .../tests/test_mail_activity_done.py | 40 +++++++++++-------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/mail_activity_done/tests/test_mail_activity_done.py b/mail_activity_done/tests/test_mail_activity_done.py index b76d00f63a..b80f37b4cb 100644 --- a/mail_activity_done/tests/test_mail_activity_done.py +++ b/mail_activity_done/tests/test_mail_activity_done.py @@ -2,30 +2,38 @@ # Copyright 2023 Tecnativa - Víctor Martínez from datetime import date -from odoo.tests.common import TransactionCase +from odoo.tests.common import TransactionCase, new_test_user class TestMailActivityDoneMethods(TransactionCase): - def setUp(self): - super(TestMailActivityDoneMethods, self).setUp() - - self.employee = self.env["res.users"].create( - { - "company_id": self.env.ref("base.main_company").id, - "name": "Test User", - "login": "testuser", - "groups_id": [(6, 0, [self.env.ref("base.group_user").id])], - } + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.env = cls.env( + context=dict( + cls.env.context, + mail_activity_quick_update=True, + mail_create_nolog=True, + mail_create_nosubscribe=True, + mail_notrack=True, + no_reset_password=True, + tracking_disable=True, + ) + ) + cls.employee = new_test_user( + cls.env, + name="Test User", + login="testuser", ) - activity_type = self.env["mail.activity.type"].search( + activity_type = cls.env["mail.activity.type"].search( [("name", "=", "Meeting")], limit=1 ) - self.act1 = self.env["mail.activity"].create( + cls.act1 = cls.env["mail.activity"].create( { "activity_type_id": activity_type.id, - "res_id": self.env.ref("base.res_partner_1").id, - "res_model_id": self.env["ir.model"]._get("res.partner").id, - "user_id": self.employee.id, + "res_id": cls.env.ref("base.res_partner_1").id, + "res_model_id": cls.env["ir.model"]._get("res.partner").id, + "user_id": cls.employee.id, "date_deadline": date.today(), } ) From 0e9d8013e576700b785e41aaacad0de412ed3ed5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Mart=C3=ADnez?= Date: Thu, 28 Sep 2023 14:33:15 +0200 Subject: [PATCH 3/4] [IMP] mail_activity_team: Speed up tests --- .../tests/test_mail_activity_team.py | 63 +++++++++---------- 1 file changed, 28 insertions(+), 35 deletions(-) diff --git a/mail_activity_team/tests/test_mail_activity_team.py b/mail_activity_team/tests/test_mail_activity_team.py index 8618115813..18bf7175c2 100644 --- a/mail_activity_team/tests/test_mail_activity_team.py +++ b/mail_activity_team/tests/test_mail_activity_team.py @@ -2,52 +2,45 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). from odoo.exceptions import ValidationError -from odoo.tests.common import Form, TransactionCase +from odoo.tests.common import Form, TransactionCase, new_test_user class TestMailActivityTeam(TransactionCase): @classmethod def setUpClass(cls): super().setUpClass() - cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True)) + cls.env = cls.env( + context=dict( + cls.env.context, + mail_activity_quick_update=True, + mail_create_nolog=True, + mail_create_nosubscribe=True, + mail_notrack=True, + no_reset_password=True, + tracking_disable=True, + ) + ) # Start from a clean slate cls.env["mail.activity.team"].search([]).unlink() # Create Users - cls.employee = cls.env["res.users"].create( - { - "company_id": cls.env.ref("base.main_company").id, - "name": "Employee", - "login": "csu", - "email": "crmuser@yourcompany.com", - "groups_id": [ - ( - 6, - 0, - [ - cls.env.ref("base.group_user").id, - cls.env.ref("base.group_partner_manager").id, - ], - ) - ], - } + cls.employee = new_test_user( + cls.env, + name="Employee", + login="csu", + email="crmuser@yourcompany.com", + groups="base.group_user,base.group_partner_manager", ) - cls.employee2 = cls.env["res.users"].create( - { - "company_id": cls.env.ref("base.main_company").id, - "name": "Employee 2", - "login": "csu2", - "email": "crmuser2@yourcompany.com", - "groups_id": [(6, 0, [cls.env.ref("base.group_user").id])], - } + cls.employee2 = new_test_user( + cls.env, + name="Employee 2", + login="csu2", + email="crmuser2@yourcompany.com", ) - cls.employee3 = cls.env["res.users"].create( - { - "company_id": cls.env.ref("base.main_company").id, - "name": "Employee 3", - "login": "csu3", - "email": "crmuser3@yourcompany.com", - "groups_id": [(6, 0, [cls.env.ref("base.group_user").id])], - } + cls.employee3 = new_test_user( + cls.env, + name="Employee 3", + login="csu3", + email="crmuser3@yourcompany.com", ) # Create Activity Types cls.activity1 = cls.env["mail.activity.type"].create( From 7944d6609127bc0254c678ecfc46946aa51c4b6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Mart=C3=ADnez?= Date: Thu, 28 Sep 2023 14:34:22 +0200 Subject: [PATCH 4/4] [FIX] mail_activity_team: Fix tests from https://github.com/odoo/odoo/commit/d64fff459b745d247cc19d58994b9da4bd50292a --- mail_activity_team/tests/test_mail_activity_team.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mail_activity_team/tests/test_mail_activity_team.py b/mail_activity_team/tests/test_mail_activity_team.py index 18bf7175c2..ad9cb6f6c9 100644 --- a/mail_activity_team/tests/test_mail_activity_team.py +++ b/mail_activity_team/tests/test_mail_activity_team.py @@ -272,7 +272,7 @@ def test_activity_count(self): self.assertEqual(res[0]["total_count"], 1) self.assertEqual(res[0]["today_count"], 2) res = self.env["res.users"].with_user(self.employee.id).systray_get_activities() - self.assertEqual(res[0]["total_count"], 2) + self.assertEqual(res[0]["total_count"], 1) def test_activity_schedule_next(self): self.activity1.write(