mirror of https://github.com/OCA/social.git
[IMP] mail_activity_team
parent
6d586fa3f3
commit
a04207cb8e
|
@ -19,8 +19,5 @@
|
||||||
"views/mail_activity_views.xml",
|
"views/mail_activity_views.xml",
|
||||||
"views/res_users_views.xml",
|
"views/res_users_views.xml",
|
||||||
],
|
],
|
||||||
|
"qweb": ["static/src/xml/systray.xml"],
|
||||||
'qweb': [
|
|
||||||
'static/src/xml/systray.xml',
|
|
||||||
],
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,4 +2,3 @@ from . import mail_activity_team
|
||||||
from . import mail_activity
|
from . import mail_activity
|
||||||
from . import mail_activity_mixin
|
from . import mail_activity_mixin
|
||||||
from . import res_users
|
from . import res_users
|
||||||
from . import mail_activity_mixin
|
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
# Copyright 2021 Tecnativa - David Vidal
|
# Copyright 2021 Tecnativa - David Vidal
|
||||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||||
from odoo import api, models, fields
|
from odoo import api, fields, models
|
||||||
|
|
||||||
|
|
||||||
class MailActivityMixin(models.AbstractModel):
|
class MailActivityMixin(models.AbstractModel):
|
||||||
_inherit = "mail.activity.mixin"
|
_inherit = "mail.activity.mixin"
|
||||||
|
|
||||||
activity_team_user_ids = fields.Many2many(
|
activity_team_user_ids = fields.Many2many(
|
||||||
comodel_name='res.users', string='test field',
|
comodel_name="res.users",
|
||||||
|
string="test field",
|
||||||
compute="_compute_activity_team_user_ids",
|
compute="_compute_activity_team_user_ids",
|
||||||
search="_search_activity_team_user_ids",
|
search="_search_activity_team_user_ids",
|
||||||
)
|
)
|
||||||
|
@ -15,12 +16,11 @@ class MailActivityMixin(models.AbstractModel):
|
||||||
@api.depends("activity_ids")
|
@api.depends("activity_ids")
|
||||||
def _compute_activity_team_user_ids(self):
|
def _compute_activity_team_user_ids(self):
|
||||||
for rec in self:
|
for rec in self:
|
||||||
rec.activity_team_user_ids = rec.activity_ids.mapped(
|
rec.activity_team_user_ids = rec.activity_ids.mapped("team_id.member_ids")
|
||||||
"team_id.member_ids")
|
|
||||||
|
|
||||||
@api.model
|
@api.model
|
||||||
def _search_activity_team_user_ids(self, operator, operand):
|
def _search_activity_team_user_ids(self, operator, operand):
|
||||||
return [('activity_ids.team_id.member_ids', operator, operand)]
|
return [("activity_ids.team_id.member_ids", operator, operand)]
|
||||||
|
|
||||||
def activity_schedule(
|
def activity_schedule(
|
||||||
self, act_type_xmlid="", date_deadline=None, summary="", note="", **act_values
|
self, act_type_xmlid="", date_deadline=None, summary="", note="", **act_values
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Copyright 2018 ForgeFlow, S.L.
|
# Copyright 2018 ForgeFlow, S.L.
|
||||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||||
from odoo import models, fields, api, modules
|
from odoo import api, fields, models, modules
|
||||||
|
|
||||||
|
|
||||||
class ResUsers(models.Model):
|
class ResUsers(models.Model):
|
||||||
|
@ -13,9 +13,9 @@ class ResUsers(models.Model):
|
||||||
)
|
)
|
||||||
|
|
||||||
@api.model
|
@api.model
|
||||||
def activity_user_count(self, user_id=False):
|
def systray_get_activities(self):
|
||||||
if not self._context.get('team_activities', False):
|
if not self._context.get("team_activities", False):
|
||||||
return super().activity_user_count()
|
return super().systray_get_activities()
|
||||||
query = """SELECT m.id, count(*), act.res_model as model,
|
query = """SELECT m.id, count(*), act.res_model as model,
|
||||||
CASE
|
CASE
|
||||||
WHEN %(today)s::date -
|
WHEN %(today)s::date -
|
||||||
|
@ -35,35 +35,40 @@ class ResUsers(models.Model):
|
||||||
)
|
)
|
||||||
GROUP BY m.id, states, act.res_model, act.user_id;
|
GROUP BY m.id, states, act.res_model, act.user_id;
|
||||||
"""
|
"""
|
||||||
user = user_id if user_id else self.env.uid
|
user = self.env.uid
|
||||||
self.env.cr.execute(query, {
|
self.env.cr.execute(
|
||||||
'today': fields.Date.context_today(self),
|
query, {"today": fields.Date.context_today(self), "user_id": user}
|
||||||
'user_id': user,
|
)
|
||||||
})
|
|
||||||
activity_data = self.env.cr.dictfetchall()
|
activity_data = self.env.cr.dictfetchall()
|
||||||
model_ids = [a['id'] for a in activity_data]
|
model_ids = [a["id"] for a in activity_data]
|
||||||
model_names = {n[0]: n[1] for n in
|
model_names = {
|
||||||
self.env['ir.model'].browse(model_ids).name_get()}
|
n[0]: n[1] for n in self.env["ir.model"].browse(model_ids).name_get()
|
||||||
|
}
|
||||||
|
|
||||||
user_activities = {}
|
user_activities = {}
|
||||||
for activity in activity_data:
|
for activity in activity_data:
|
||||||
if not user_activities.get(activity['model']):
|
if not user_activities.get(activity["model"]):
|
||||||
user_activities[activity['model']] = {
|
user_activities[activity["model"]] = {
|
||||||
'name': model_names[activity['id']],
|
"name": model_names[activity["id"]],
|
||||||
'model': activity['model'],
|
"model": activity["model"],
|
||||||
'icon': modules.module.get_module_icon(
|
"type": "activity",
|
||||||
self.env[activity['model']]._original_module),
|
"icon": modules.module.get_module_icon(
|
||||||
'total_count': 0, 'today_count': 0, 'overdue_count': 0,
|
self.env[activity["model"]]._original_module
|
||||||
'planned_count': 0,
|
),
|
||||||
|
"total_count": 0,
|
||||||
|
"today_count": 0,
|
||||||
|
"overdue_count": 0,
|
||||||
|
"planned_count": 0,
|
||||||
}
|
}
|
||||||
user_activities[activity['model']][
|
user_activities[activity["model"]][
|
||||||
'%s_count' % activity['states']] += activity['count']
|
"%s_count" % activity["states"]
|
||||||
if activity['states'] in ('today', 'overdue'):
|
] += activity["count"]
|
||||||
user_activities[activity['model']]['total_count'] += activity[
|
if activity["states"] in ("today", "overdue"):
|
||||||
'count']
|
user_activities[activity["model"]]["total_count"] += activity["count"]
|
||||||
if activity['user_id'] == user:
|
if activity["user_id"] == user and activity["states"] in (
|
||||||
user_activities[
|
"today",
|
||||||
activity['model']
|
"overdue",
|
||||||
]['total_count'] -= activity['count']
|
):
|
||||||
|
user_activities[activity["model"]]["total_count"] -= activity["count"]
|
||||||
|
|
||||||
return list(user_activities.values())
|
return list(user_activities.values())
|
||||||
|
|
|
@ -1,99 +1,108 @@
|
||||||
odoo.define('mail_activity_team.systray', function (require) {
|
odoo.define("mail_activity_team.systray.ActivityMenu", function(require) {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var systray = require('mail.systray');
|
var ActivityMenu = require("mail.systray.ActivityMenu");
|
||||||
var session = require("web.session");
|
var session = require("web.session");
|
||||||
|
|
||||||
systray.ActivityMenu.include({
|
ActivityMenu.include({
|
||||||
events: _.extend({}, systray.ActivityMenu.prototype.events, {
|
events: _.extend({}, ActivityMenu.prototype.events, {
|
||||||
'click .o_filter_button': 'on_click_filter_button',
|
"click .o_filter_button": "_onClickFilterButton",
|
||||||
}),
|
}),
|
||||||
start: function () {
|
start: function() {
|
||||||
this._super.apply(this, arguments);
|
this._super.apply(this, arguments);
|
||||||
this.$filter_buttons = this.$('.o_filter_button');
|
this.$filter_buttons = this.$(".o_filter_button");
|
||||||
this.$my_activities = this.$filter_buttons.first();
|
this.$my_activities = this.$filter_buttons.first();
|
||||||
this.filter = 'my';
|
this.filter = "my";
|
||||||
session.user_context = _.extend({}, session.user_context, {
|
session.user_context = _.extend({}, session.user_context, {
|
||||||
'team_activities': false
|
team_activities: false,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
_updateCounter: function (data) {
|
_updateCounter: function(data) {
|
||||||
this._super.apply(this, arguments);
|
this._super.apply(this, data);
|
||||||
this.$('.o_new_notification_counter').text(this.activityCounter);
|
this.$(".o_notification_counter").text(this.activityCounter);
|
||||||
},
|
},
|
||||||
|
|
||||||
on_click_filter_button: function (event) {
|
_onClickFilterButton: function(event) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
self.$filter_buttons.removeClass('active');
|
self.$filter_buttons.removeClass("active");
|
||||||
var $target = $(event.currentTarget);
|
var $target = $(event.currentTarget);
|
||||||
$target.addClass('active');
|
$target.addClass("active");
|
||||||
self.filter = $target.data('filter');
|
self.filter = $target.data("filter");
|
||||||
|
|
||||||
session.user_context = _.extend({}, session.user_context, {
|
session.user_context = _.extend({}, session.user_context, {
|
||||||
'team_activities': self.filter === 'team'
|
team_activities: self.filter === "team",
|
||||||
});
|
});
|
||||||
|
|
||||||
self._updateActivityPreview();
|
self._updateActivityPreview();
|
||||||
|
|
||||||
},
|
},
|
||||||
_onActivityFilterClick: function (event) {
|
_onActivityFilterClick: function(event) {
|
||||||
if (this.filter === 'my') {
|
if (this.filter === "my") {
|
||||||
this._super.apply(this, arguments);
|
this._super.apply(this, arguments);
|
||||||
}
|
}
|
||||||
if (this.filter === 'team') {
|
if (this.filter === "team") {
|
||||||
var data = _.extend(
|
var data = _.extend(
|
||||||
{},
|
{},
|
||||||
$(event.currentTarget).data(),
|
$(event.currentTarget).data(),
|
||||||
$(event.target).data()
|
$(event.target).data()
|
||||||
);
|
);
|
||||||
var context = {};
|
var context = {};
|
||||||
if (data.filter === 'my') {
|
if (data.filter === "my") {
|
||||||
context.search_default_activities_overdue = 1;
|
context.search_default_activities_overdue = 1;
|
||||||
context.search_default_activities_today = 1;
|
context.search_default_activities_today = 1;
|
||||||
} else {
|
} else {
|
||||||
context['search_default_activities_' + data.filter] = 1;
|
context["search_default_activities_" + data.filter] = 1;
|
||||||
}
|
}
|
||||||
this.do_action({
|
this.do_action({
|
||||||
type: 'ir.actions.act_window',
|
type: "ir.actions.act_window",
|
||||||
name: data.model_name,
|
name: data.model_name,
|
||||||
res_model: data.res_model,
|
res_model: data.res_model,
|
||||||
views: [[false, 'kanban'], [false, 'form']],
|
views: [
|
||||||
|
[false, "kanban"],
|
||||||
|
[false, "form"],
|
||||||
|
],
|
||||||
search_view_id: [false],
|
search_view_id: [false],
|
||||||
domain: [
|
domain: [["activity_team_user_ids", "in", session.uid]],
|
||||||
['activity_team_user_ids', 'in', session.uid]
|
context: context,
|
||||||
],
|
|
||||||
context:context,
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_getActivityData: function(){
|
_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;
|
var self = this;
|
||||||
return self._super.apply(self, arguments).then(function (data) {
|
return self._super.apply(self, arguments).then(function() {
|
||||||
session.user_context = _.extend({}, session.user_context, {
|
session.user_context = _.extend({}, session.user_context, {
|
||||||
'team_activities': !session.user_context['team_activities'],
|
team_activities: !session.user_context.team_activities,
|
||||||
});
|
});
|
||||||
|
|
||||||
self._rpc({
|
self._rpc({
|
||||||
model: 'res.users',
|
model: "res.users",
|
||||||
method: 'activity_user_count',
|
method: "systray_get_activities",
|
||||||
|
args: [],
|
||||||
kwargs: {
|
kwargs: {
|
||||||
context: session.user_context,
|
context: session.user_context,
|
||||||
},
|
},
|
||||||
}).then(function (data) {
|
}).then(function(data) {
|
||||||
self.activityCounter += _.reduce(data, function(
|
self.activityCounter += _.reduce(
|
||||||
total_count, p_data
|
data,
|
||||||
){ return total_count + p_data.total_count; }, 0);
|
function(total_count, p_data) {
|
||||||
self.$('.o_new_notification_counter').text(self.activityCounter);
|
return total_count + p_data.total_count || 0;
|
||||||
self.$el.toggleClass('o_no_notification', !self.activityCounter);
|
},
|
||||||
|
0
|
||||||
|
);
|
||||||
|
self.$(".o_notification_counter").text(self.activityCounter);
|
||||||
|
self.$el.toggleClass("o_no_notification", !self.activityCounter);
|
||||||
session.user_context = _.extend({}, session.user_context, {
|
session.user_context = _.extend({}, session.user_context, {
|
||||||
'team_activities': !session.user_context['team_activities'],
|
team_activities: !session.user_context.team_activities,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
.o_new_notification_counter {
|
|
||||||
.o-position-absolute(@top: 20%, @right: 1px);
|
|
||||||
background: @odoo-brand-optional;
|
|
||||||
color: white;
|
|
||||||
padding: 0em 0.3em;
|
|
||||||
font-size: 0.7em;
|
|
||||||
}
|
|
|
@ -1,11 +1,21 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
<templates>
|
<templates>
|
||||||
|
|
||||||
<t t-extend="mail.systray.ActivityMenu">
|
<t t-extend="mail.systray.ActivityMenu">
|
||||||
<t t-jquery=".o_mail_systray_dropdown_items" t-operation="before">
|
<t t-jquery=".o_mail_systray_dropdown_items" t-operation="before">
|
||||||
<div>
|
<div>
|
||||||
<button type="button" class="btn btn-link o_filter_button active" data-filter='my' role="tab"> My Activities </button>
|
<button
|
||||||
<button type="button" class="btn btn-link o_filter_button" data-filter='team' role="tab"> Team Activities </button>
|
type="button"
|
||||||
|
class="btn btn-link o_filter_button active"
|
||||||
|
data-filter='my'
|
||||||
|
role="tab"
|
||||||
|
> My Activities </button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="btn btn-link o_filter_button"
|
||||||
|
data-filter='team'
|
||||||
|
role="tab"
|
||||||
|
> Team Activities </button>
|
||||||
</div>
|
</div>
|
||||||
</t>
|
</t>
|
||||||
</t>
|
</t>
|
||||||
|
|
|
@ -191,9 +191,10 @@ class TestMailActivityTeam(TransactionCase):
|
||||||
self.assertEqual(activity.team_id, self.team2)
|
self.assertEqual(activity.team_id, self.team2)
|
||||||
|
|
||||||
def test_activity_count(self):
|
def test_activity_count(self):
|
||||||
res = self.env['res.users'].with_context(
|
res = (
|
||||||
{'team_activities': True}
|
self.env["res.users"]
|
||||||
).activity_user_count(
|
.sudo(self.employee.id)
|
||||||
user_id=self.employee.id
|
.with_context({"team_activities": True})
|
||||||
|
.systray_get_activities()
|
||||||
)
|
)
|
||||||
self.assertEqual(res[0]['total_count'], 0)
|
self.assertEqual(res[0]["total_count"], 0)
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
<odoo>
|
<odoo>
|
||||||
<template id="assets_backend" name="mail assets"
|
<template id="assets_backend" name="mail assets" inherit_id="web.assets_backend">
|
||||||
inherit_id="web.assets_backend">
|
|
||||||
<xpath expr="." position="inside">
|
<xpath expr="." position="inside">
|
||||||
<script type="text/javascript" src="/mail_activity_team/static/src/js/systray.js"/>
|
<script
|
||||||
<link rel="stylesheet" href="/mail_activity_team/static/src/less/systray.less" type="text/less"/>
|
type="text/javascript"
|
||||||
|
src="/mail_activity_team/static/src/js/systray.js"
|
||||||
|
/>
|
||||||
</xpath>
|
</xpath>
|
||||||
</template>
|
</template>
|
||||||
</odoo>
|
</odoo>
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<record id="mail_activity_view_form_popup" model="ir.ui.view">
|
<record id="mail_activity_view_form_popup" model="ir.ui.view">
|
||||||
<field name="name">mail.activity.view.form.popup</field>
|
<field name="name">mail.activity.view.form.popup</field>
|
||||||
<field name="model">mail.activity</field>
|
<field name="model">mail.activity</field>
|
||||||
<field name="inherit_id" ref="mail.mail_activity_view_form_popup"/>
|
<field name="inherit_id" ref="mail.mail_activity_view_form_popup" />
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<field name="user_id" position="after">
|
<field name="user_id" position="after">
|
||||||
<field name="team_id" options="{'no_create': True, 'no_open': True}" />
|
<field name="team_id" options="{'no_create': True, 'no_open': True}" />
|
||||||
|
|
Loading…
Reference in New Issue