diff --git a/mail_activity_team/__manifest__.py b/mail_activity_team/__manifest__.py index af7632cda..9125afcac 100644 --- a/mail_activity_team/__manifest__.py +++ b/mail_activity_team/__manifest__.py @@ -12,10 +12,12 @@ "installable": True, "depends": ["mail_activity_board"], "data": [ + "views/assets_backend.xml", "security/ir.model.access.csv", "security/mail_activity_team_security.xml", "views/mail_activity_team_views.xml", "views/mail_activity_views.xml", "views/res_users_views.xml", ], + "qweb": ["static/src/xml/systray.xml"], } diff --git a/mail_activity_team/models/mail_activity.py b/mail_activity_team/models/mail_activity.py index 7dc7e86ca..a37a64251 100644 --- a/mail_activity_team/models/mail_activity.py +++ b/mail_activity_team/models/mail_activity.py @@ -19,6 +19,8 @@ class MailActivity(models.Model): ) return self.env["mail.activity.team"].search(domain, limit=1) + user_id = fields.Many2one(required=False) + team_id = fields.Many2one( comodel_name="mail.activity.team", default=lambda s: s._get_default_team_id() ) diff --git a/mail_activity_team/models/mail_activity_mixin.py b/mail_activity_team/models/mail_activity_mixin.py index f8840ee53..d9215cebd 100644 --- a/mail_activity_team/models/mail_activity_mixin.py +++ b/mail_activity_team/models/mail_activity_mixin.py @@ -1,11 +1,27 @@ # Copyright 2021 Tecnativa - David Vidal # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -from odoo import models +from odoo import api, fields, models class MailActivityMixin(models.AbstractModel): _inherit = "mail.activity.mixin" + activity_team_user_ids = fields.Many2many( + comodel_name="res.users", + string="test field", + compute="_compute_activity_team_user_ids", + search="_search_activity_team_user_ids", + ) + + @api.depends("activity_ids") + def _compute_activity_team_user_ids(self): + for rec in self: + rec.activity_team_user_ids = rec.activity_ids.mapped("team_id.member_ids") + + @api.model + def _search_activity_team_user_ids(self, operator, operand): + return [("activity_ids.team_id.member_ids", operator, operand)] + def activity_schedule( self, act_type_xmlid="", date_deadline=None, summary="", note="", **act_values ): diff --git a/mail_activity_team/models/res_users.py b/mail_activity_team/models/res_users.py index b30bfa1fc..6d881cc18 100644 --- a/mail_activity_team/models/res_users.py +++ b/mail_activity_team/models/res_users.py @@ -1,6 +1,6 @@ # Copyright 2018 ForgeFlow, S.L. # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -from odoo import fields, models +from odoo import api, fields, models, modules class ResUsers(models.Model): @@ -11,3 +11,64 @@ class ResUsers(models.Model): relation="mail_activity_team_users_rel", string="Activity Teams", ) + + @api.model + def systray_get_activities(self): + if not self._context.get("team_activities", False): + return super().systray_get_activities() + 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, act.user_id as user_id + FROM mail_activity AS act + JOIN ir_model AS m ON act.res_model_id = m.id + WHERE team_id in ( + SELECT mail_activity_team_id + FROM mail_activity_team_users_rel + WHERE res_users_id = + %(user_id)s + ) + GROUP BY m.id, states, act.res_model, act.user_id; + """ + user = self.env.uid + self.env.cr.execute( + query, {"today": fields.Date.context_today(self), "user_id": user} + ) + 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"].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"], + "type": "activity", + "icon": modules.module.get_module_icon( + self.env[activity["model"]]._original_module + ), + "total_count": 0, + "today_count": 0, + "overdue_count": 0, + "planned_count": 0, + } + user_activities[activity["model"]][ + "%s_count" % activity["states"] + ] += activity["count"] + if activity["states"] in ("today", "overdue"): + user_activities[activity["model"]]["total_count"] += activity["count"] + if activity["user_id"] == user and activity["states"] in ( + "today", + "overdue", + ): + user_activities[activity["model"]]["total_count"] -= activity["count"] + + return list(user_activities.values()) diff --git a/mail_activity_team/static/src/js/systray.js b/mail_activity_team/static/src/js/systray.js new file mode 100644 index 000000000..331b06e83 --- /dev/null +++ b/mail_activity_team/static/src/js/systray.js @@ -0,0 +1,108 @@ +odoo.define("mail_activity_team.systray.ActivityMenu", function(require) { + "use strict"; + + var ActivityMenu = require("mail.systray.ActivityMenu"); + var session = require("web.session"); + + ActivityMenu.include({ + events: _.extend({}, ActivityMenu.prototype.events, { + "click .o_filter_button": "_onClickFilterButton", + }), + start: function() { + this._super.apply(this, arguments); + this.$filter_buttons = this.$(".o_filter_button"); + this.$my_activities = this.$filter_buttons.first(); + this.filter = "my"; + session.user_context = _.extend({}, session.user_context, { + team_activities: false, + }); + }, + + _updateCounter: function(data) { + this._super.apply(this, data); + this.$(".o_notification_counter").text(this.activityCounter); + }, + + _onClickFilterButton: function(event) { + var self = this; + event.stopPropagation(); + self.$filter_buttons.removeClass("active"); + var $target = $(event.currentTarget); + $target.addClass("active"); + self.filter = $target.data("filter"); + + session.user_context = _.extend({}, session.user_context, { + team_activities: self.filter === "team", + }); + + self._updateActivityPreview(); + }, + _onActivityFilterClick: function(event) { + if (this.filter === "my") { + this._super.apply(this, arguments); + } + if (this.filter === "team") { + var data = _.extend( + {}, + $(event.currentTarget).data(), + $(event.target).data() + ); + var context = {}; + if (data.filter === "my") { + context.search_default_activities_overdue = 1; + context.search_default_activities_today = 1; + } else { + context["search_default_activities_" + data.filter] = 1; + } + this.do_action({ + type: "ir.actions.act_window", + name: data.model_name, + res_model: data.res_model, + views: [ + [false, "kanban"], + [false, "form"], + ], + search_view_id: [false], + domain: [["activity_team_user_ids", "in", session.uid]], + context: context, + }); + } + }, + _open_boards_activities_domain: function() { + if (this.filter === "team") { + return {additional_context: {search_default_my_team_activities: 1}}; + } + return this._super.apply(this, arguments); + }, + _getActivityData: function() { + var self = this; + return self._super.apply(self, arguments).then(function() { + session.user_context = _.extend({}, session.user_context, { + team_activities: !session.user_context.team_activities, + }); + + self._rpc({ + model: "res.users", + method: "systray_get_activities", + args: [], + kwargs: { + context: session.user_context, + }, + }).then(function(data) { + self.activityCounter += _.reduce( + data, + function(total_count, p_data) { + return total_count + p_data.total_count || 0; + }, + 0 + ); + self.$(".o_notification_counter").text(self.activityCounter); + self.$el.toggleClass("o_no_notification", !self.activityCounter); + session.user_context = _.extend({}, session.user_context, { + team_activities: !session.user_context.team_activities, + }); + }); + }); + }, + }); +}); diff --git a/mail_activity_team/static/src/xml/systray.xml b/mail_activity_team/static/src/xml/systray.xml new file mode 100644 index 000000000..1f96514f5 --- /dev/null +++ b/mail_activity_team/static/src/xml/systray.xml @@ -0,0 +1,23 @@ + + + + + +
+ + +
+
+
+ +
diff --git a/mail_activity_team/tests/test_mail_activity_team.py b/mail_activity_team/tests/test_mail_activity_team.py index 82faedd72..e8f248e07 100644 --- a/mail_activity_team/tests/test_mail_activity_team.py +++ b/mail_activity_team/tests/test_mail_activity_team.py @@ -189,3 +189,12 @@ class TestMailActivityTeam(TransactionCase): activity_type_id=self.env.ref("mail.mail_activity_data_call").id, ) self.assertEqual(activity.team_id, self.team2) + + def test_activity_count(self): + res = ( + self.env["res.users"] + .sudo(self.employee.id) + .with_context({"team_activities": True}) + .systray_get_activities() + ) + self.assertEqual(res[0]["total_count"], 0) diff --git a/mail_activity_team/views/assets_backend.xml b/mail_activity_team/views/assets_backend.xml new file mode 100644 index 000000000..f5f3eeee0 --- /dev/null +++ b/mail_activity_team/views/assets_backend.xml @@ -0,0 +1,11 @@ + + +