Merge PR #1507 into 16.0

Signed-off-by StefanRijnhart
pull/1517/head
OCA-git-bot 2025-03-04 14:12:22 +00:00
commit 9e97aff514
5 changed files with 127 additions and 89 deletions

View File

@ -1,2 +1 @@
from . import mail_activity
from . import res_users

View File

@ -1,7 +1,6 @@
# Copyright 2018-22 ForgeFlow <http://www.forgeflow.com>
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
from odoo import api, fields, models
from odoo.osv import expression
delete_sentinel = object()
@ -88,7 +87,44 @@ class MailActivityMixin(models.AbstractModel):
def _read_progress_bar(self, domain, group_by, progress_bar):
"""
Exclude completed activities from progress bar result.
Pass an extra domain to super to filter out records with only done activities.
"""
domain = expression.AND([domain, [("activity_ids.done", "=", False)]])
return super()._read_progress_bar(domain, group_by, progress_bar)
execute_org = self._cr.execute
def execute(query, params=None, log_exceptions=True):
original_where = "WHERE res_model = '{}'".format(self._name)
replace_where = (
"WHERE res_model = '{}' AND mail_activity.done = FALSE".format(
self._name
)
)
return execute_org(
query.replace(original_where, replace_where),
params=params,
log_exceptions=log_exceptions,
)
self._cr.execute = execute
try:
return super()._read_progress_bar(domain, group_by, progress_bar)
finally:
self._cr.execute = execute_org
def _search_activity_state(self, operator, value):
execute_org = self._cr.execute
def execute(query, params=None, log_exceptions=True):
return execute_org(
query.replace(
"WHERE mail_activity.res_model = %(res_model_table)s",
"WHERE mail_activity.res_model = %(res_model_table)s AND "
"mail_activity.done = FALSE",
),
params=params,
log_exceptions=log_exceptions,
)
self._cr.execute = execute
try:
return super()._search_activity_state(operator, value)
finally:
self._cr.execute = execute_org

View File

@ -1,59 +0,0 @@
# Copyright 2018-22 ForgeFlow <http://www.forgeflow.com>
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html).
from odoo import api, fields, models, modules
class ResUsers(models.Model):
_inherit = "res.users"
@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;
"""
self.env.cr.execute(
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"]):
module = self.env[activity["model"]]._original_module
icon = module and modules.module.get_module_icon(module)
user_activities[activity["model"]] = {
"id": activity["id"],
"name": model_names[activity["id"]],
"model": activity["model"],
"icon": icon,
"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"]
return list(user_activities.values())

View File

@ -8,10 +8,11 @@
/*
:Author: David Goodger (goodger@python.org)
:Id: $Id: html4css1.css 8954 2022-01-20 10:10:25Z milde $
:Id: $Id: html4css1.css 9511 2024-01-13 09:50:07Z milde $
:Copyright: This stylesheet has been placed in the public domain.
Default cascading style sheet for the HTML output of Docutils.
Despite the name, some widely supported CSS2 features are used.
See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to
customize this style sheet.
@ -274,7 +275,7 @@ pre.literal-block, pre.doctest-block, pre.math, pre.code {
margin-left: 2em ;
margin-right: 2em }
pre.code .ln { color: grey; } /* line numbers */
pre.code .ln { color: gray; } /* line numbers */
pre.code, code { background-color: #eeeeee }
pre.code .comment, code .comment { color: #5C6576 }
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold }
@ -300,7 +301,7 @@ span.option {
span.pre {
white-space: pre }
span.problematic {
span.problematic, pre.problematic {
color: red }
span.section-subtitle {
@ -426,7 +427,9 @@ If you spotted it first, help us to smash it by providing a detailed and welcome
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#toc-entry-6">Maintainers</a></h2>
<p>This module is maintained by the OCA.</p>
<a class="reference external image-reference" href="https://odoo-community.org"><img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" /></a>
<a class="reference external image-reference" href="https://odoo-community.org">
<img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" />
</a>
<p>OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.</p>

View File

@ -8,28 +8,66 @@ from odoo.tests.common import TransactionCase
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])],
"login": "testuser@testuser.local",
"email": "testuser@testuser.local",
"tz": "Europe/Brussels",
"groups_id": [
(
6,
0,
[
self.env.ref("base.group_user").id,
self.env.ref("base.group_partner_manager").id,
],
)
],
}
)
activity_type = self.env["mail.activity.type"].search(
[("name", "=", "Meeting")], limit=1
self.partner = (
self.env["res.partner"]
.with_user(self.employee)
.create({"name": "test partner"})
)
self.act1 = self.env["mail.activity"].create(
{
"activity_type_id": activity_type.id,
"res_id": self.env.ref("base.res_partner_1").id,
"res_model": "res.partner",
"res_model_id": self.env["ir.model"]._get("res.partner").id,
"user_id": self.employee.id,
"date_deadline": date.today(),
}
activity_type = self.env["mail.activity.type"].create(
{"name": "test activity type"}
)
self.act1 = (
self.env["mail.activity"]
.with_user(self.employee)
.create(
{
"activity_type_id": activity_type.id,
"res_id": self.partner.id,
"res_model": "res.partner",
"res_model_id": self.env["ir.model"]._get("res.partner").id,
"user_id": self.employee.id,
"date_deadline": date.today(),
}
)
)
self.act2 = (
self.env["mail.activity"]
.with_user(self.employee)
.create(
{
"activity_type_id": activity_type.id,
"res_id": self.partner.id,
"res_model": "res.partner",
"res_model_id": self.env["ir.model"]._get("res.partner").id,
"user_id": self.employee.id,
"date_deadline": date.today(),
}
)
)
self.activities = self.act1 + self.act2
def _set_activities_done(self):
self.activities._action_done()
self.activities.flush_recordset()
def test_mail_activity_done(self):
self.act1._action_done()
@ -39,20 +77,41 @@ class TestMailActivityDoneMethods(TransactionCase):
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"
act_count[0]["total_count"],
2,
"Number of activities should be equal to two",
)
self.act1._action_done()
act_count = self.employee.with_user(self.employee).systray_get_activities()
self.assertEqual(
act_count[0]["total_count"],
1,
"Number of activities should be equal to one",
)
def test_read_progress_bar(self):
res_partner = self.env["res.partner"].browse(self.act1.res_model_id)
params = {
"domain": [],
"group_by": "id",
"progress_bar": {"field": "activity_state"},
}
result = res_partner._read_progress_bar(**params)
result = self.partner._read_progress_bar(**params)
self.assertEqual(result[0]["__count"], 1)
self.act1._action_done()
self.assertEqual(self.act1.state, "done")
result = res_partner._read_progress_bar(**params)
self._set_activities_done()
result = self.partner._read_progress_bar(**params)
self.assertEqual(len(result), 0)
def test_activity_state_search(self):
today_activities = (
self.env["res.partner"]
.with_user(self.employee)
.search([("activity_state", "=", "today")])
)
self.assertEqual(len(today_activities), 1)
self._set_activities_done()
today_activities = (
self.env["res.partner"]
.with_user(self.employee)
.search([("activity_state", "=", "today")])
)
self.assertEqual(len(today_activities), 0)