[MIG] 13.0 mail_activity_board

This commit is contained in:
Pedro Gonzalez 2019-10-23 12:19:26 +02:00 committed by augusto-weiss
parent 1f6b3d4c3f
commit 2d241f37e4
8 changed files with 219 additions and 176 deletions

View File

@ -1,24 +1,16 @@
# Copyright 2018 David Juaneda - <djuaneda@sdi.es> # Copyright 2018 David Juaneda - <djuaneda@sdi.es>
# 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).
{ {
'name': 'Activities board', "name": "Activities board",
'summary': 'Add Activity Boards', "summary": "Add Activity Boards",
'version': '12.0.1.0.0', "version": "13.0.1.0.0",
'development_status': 'Beta', "development_status": "Beta",
'category': 'Social Network', "category": "Social Network",
'website': 'https://github.com/OCA/social', "website": "https://github.com/OCA/social",
'author': 'SDi, David Juaneda, Odoo Community Association (OCA)', "author": "SDi, David Juaneda, Odoo Community Association (OCA)",
'license': 'AGPL-3', "license": "AGPL-3",
'installable': True, "installable": True,
'depends': [ "depends": ["calendar", "board"],
'calendar', "data": ["views/templates.xml", "views/mail_activity_view.xml"],
'board', "qweb": ["static/src/xml/inherit_chatter.xml"],
],
'data': [
'views/templates.xml',
'views/mail_activity_view.xml',
],
'qweb': [
'static/src/xml/inherit_chatter.xml',
]
} }

View File

@ -1,99 +1,119 @@
# Copyright 2018 David Juaneda - <djuaneda@sdi.es> # Copyright 2018 David Juaneda - <djuaneda@sdi.es>
# Copyright 2018 Eficent Business and IT Consulting Services, S.L. # Copyright 2018 Eficent Business and IT Consulting Services, 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 api, models, fields, SUPERUSER_ID from odoo import SUPERUSER_ID, api, fields, models
class MailActivity(models.Model): class MailActivity(models.Model):
_inherit = "mail.activity" _inherit = "mail.activity"
res_model_id_name = fields.Char( res_model_id_name = fields.Char(
related='res_model_id.name', string="Origin", related="res_model_id.name", string="Origin", readonly=True
readonly=True) )
duration = fields.Float( duration = fields.Float(related="calendar_event_id.duration", readonly=True)
related='calendar_event_id.duration', readonly=True)
calendar_event_id_start = fields.Datetime( calendar_event_id_start = fields.Datetime(
related='calendar_event_id.start', readonly=True) related="calendar_event_id.start", readonly=True
)
calendar_event_id_partner_ids = fields.Many2many( calendar_event_id_partner_ids = fields.Many2many(
related='calendar_event_id.partner_ids', related="calendar_event_id.partner_ids", readonly=True
readonly=True) )
@api.multi
def open_origin(self): def open_origin(self):
self.ensure_one() self.ensure_one()
vid = self.env[self.res_model].browse(self.res_id).get_formview_id() vid = self.env[self.res_model].browse(self.res_id).get_formview_id()
response = { response = {
'type': 'ir.actions.act_window', "type": "ir.actions.act_window",
'res_model': self.res_model, "res_model": self.res_model,
'view_mode': 'form', "view_mode": "form",
'res_id': self.res_id, "res_id": self.res_id,
'target': 'current', "target": "current",
'flags': { "flags": {"form": {"action_buttons": False}},
'form': { "views": [(vid, "form")],
'action_buttons': False
}
},
'views': [
(vid, "form")
]
} }
return response return response
@api.model @api.model
def action_activities_board(self): def action_activities_board(self):
action = self.env.ref( action = self.env.ref("mail_activity_board.open_boards_activities").read()[0]
'mail_activity_board.open_boards_activities').read()[0]
return action return action
@api.model @api.model
def _find_allowed_model_wise(self, doc_model, doc_dict): def _find_allowed_model_wise(self, doc_model, doc_dict):
doc_ids = list(doc_dict) doc_ids = list(doc_dict)
allowed_doc_ids = self.env[doc_model].with_context( allowed_doc_ids = (
active_test=False).search([('id', 'in', doc_ids)]).ids self.env[doc_model]
return set([message_id for allowed_doc_id in allowed_doc_ids .with_context(active_test=False)
for message_id in doc_dict[allowed_doc_id]]) .search([("id", "in", doc_ids)])
.ids
)
return {
message_id
for allowed_doc_id in allowed_doc_ids
for message_id in doc_dict[allowed_doc_id]
}
@api.model @api.model
def _find_allowed_doc_ids(self, model_ids): def _find_allowed_doc_ids(self, model_ids):
ir_model_access_model = self.env['ir.model.access'] ir_model_access_model = self.env["ir.model.access"]
allowed_ids = set() allowed_ids = set()
for doc_model, doc_dict in model_ids.items(): for doc_model, doc_dict in model_ids.items():
if not ir_model_access_model.check(doc_model, 'read', False): if not ir_model_access_model.check(doc_model, "read", False):
continue continue
allowed_ids |= self._find_allowed_model_wise(doc_model, doc_dict) allowed_ids |= self._find_allowed_model_wise(doc_model, doc_dict)
return allowed_ids return allowed_ids
@api.model @api.model
def _search(self, args, offset=0, limit=None, order=None, count=False, def _search(
access_rights_uid=None): self,
args,
offset=0,
limit=None,
order=None,
count=False,
access_rights_uid=None,
):
# Rules do not apply to administrator # Rules do not apply to administrator
if self._uid == SUPERUSER_ID: if self._uid == SUPERUSER_ID:
return super(MailActivity, self)._search( return super(MailActivity, self)._search(
args, offset=offset, limit=limit, order=order, args,
count=count, access_rights_uid=access_rights_uid) offset=offset,
limit=limit,
order=order,
count=count,
access_rights_uid=access_rights_uid,
)
ids = super(MailActivity, self)._search( ids = super(MailActivity, self)._search(
args, offset=offset, limit=limit, order=order, args,
count=False, access_rights_uid=access_rights_uid) offset=offset,
limit=limit,
order=order,
count=False,
access_rights_uid=access_rights_uid,
)
if not ids and count: if not ids and count:
return 0 return 0
elif not ids: elif not ids:
return ids return ids
# check read access rights before checking the actual rules # check read access rights before checking the actual rules
super(MailActivity, self.sudo(access_rights_uid or self._uid)).\ super(
check_access_rights('read') MailActivity, self.with_user(access_rights_uid or self._uid)
).check_access_rights("read")
model_ids = {} model_ids = {}
self._cr.execute(""" self._cr.execute(
"""
SELECT DISTINCT a.id, im.id, im.model, a.res_id SELECT DISTINCT a.id, im.id, im.model, a.res_id
FROM "%s" a FROM "%s" a
LEFT JOIN ir_model im ON im.id = a.res_model_id LEFT JOIN ir_model im ON im.id = a.res_model_id
WHERE a.id = ANY (%%(ids)s)""" % self._table, dict(ids=ids)) WHERE a.id = ANY (%%(ids)s)"""
for a_id, ir_model_id, model, model_id in self._cr.fetchall(): % self._table,
model_ids.setdefault(model, {}).setdefault( dict(ids=ids),
model_id, set()).add(a_id) )
for a_id, _ir_model_id, model, model_id in self._cr.fetchall():
model_ids.setdefault(model, {}).setdefault(model_id, set()).add(a_id)
allowed_ids = self._find_allowed_doc_ids(model_ids) allowed_ids = self._find_allowed_doc_ids(model_ids)

View File

@ -4,7 +4,7 @@ from odoo import models
class MailActivityMixin(models.AbstractModel): class MailActivityMixin(models.AbstractModel):
_inherit = 'mail.activity.mixin' _inherit = "mail.activity.mixin"
def redirect_to_activities(self, **kwargs): def redirect_to_activities(self, **kwargs):
"""Redirects to the list of activities of the object shown. """Redirects to the list of activities of the object shown.
@ -21,12 +21,12 @@ class MailActivityMixin(models.AbstractModel):
:return: action. :return: action.
""" """
_id = kwargs.get("id") _id = kwargs.get("id")
action = self.env['mail.activity'].action_activities_board() action = self.env["mail.activity"].action_activities_board()
views = [] views = []
for v in action['views']: for v in action["views"]:
if v[1] == 'tree': if v[1] == "tree":
v = (v[0], 'list') v = (v[0], "list")
views.append(v) views.append(v)
action['views'] = views action["views"] = views
action['domain'] = [('res_id', '=', _id)] action["domain"] = [("res_id", "=", _id)]
return action return action

View File

@ -5,3 +5,7 @@
* `Eficent <https://www.eficent.com>`_: * `Eficent <https://www.eficent.com>`_:
* Miquel Raïch (miquel.raich@eficent.com) * Miquel Raïch (miquel.raich@eficent.com)
* `Pesol <https://www.pesol.es>`_:
* Pedro Gonzalez (pedro.gonzalez@pesol.es)

View File

@ -1,2 +1 @@
This module adds an activity board with form, tree, kanban, calendar, pivot, graph and search views. This module adds an activity board with form, tree, kanban, calendar, pivot, graph and search views.

View File

@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve"> <templates id="template" xml:space="preserve">
<t t-extend="mail.Chatter.Buttons"> <t t-extend="mail.chatter.Buttons">
<t t-jquery="button.o_chatter_button_schedule_activity" t-operation="after"> <t t-jquery="button.o_chatter_button_schedule_activity" t-operation="after">
<button t-if="schedule_activity_btn" class="btn btn-sm btn-link o_chatter_button_list_activity" <button t-if="scheduleActivityButton" class="btn btn-link o_chatter_button_list_activity"
title="See activities list" type="button"> title="See activities list" type="button" disabled="disabled">
<i class="fa fa-list"/> Activities <i class="fa fa-list"/> Activities
</button> </button>
</t> </t>

View File

@ -4,104 +4,138 @@ from odoo.tests.common import TransactionCase
class TestMailActivityBoardMethods(TransactionCase): class TestMailActivityBoardMethods(TransactionCase):
def setUp(self): def setUp(self):
super(TestMailActivityBoardMethods, self).setUp() super(TestMailActivityBoardMethods, self).setUp()
# Set up activities # Set up activities
# Create a user as 'Crm Salesman' and added few groups # Create a user as 'Crm Salesman' and added few groups
self.employee = self.env['res.users'].create({ self.employee = self.env["res.users"].create(
'company_id': self.env.ref("base.main_company").id, {
'name': "Employee", "company_id": self.env.ref("base.main_company").id,
'login': "csu", "name": "Employee",
'email': "crmuser@yourcompany.com", "login": "csu",
'groups_id': [(6, 0, [self.env.ref('base.group_user').id])] "email": "crmuser@yourcompany.com",
}) "groups_id": [(6, 0, [self.env.ref("base.group_user").id])],
}
)
# Create a user who doesn't have access to anything except activities # Create a user who doesn't have access to anything except activities
mail_activity_group = self.create_mail_activity_group() mail_activity_group = self.create_mail_activity_group()
self.employee2 = self.env['res.users'].create({ self.employee2 = self.env["res.users"].create(
'company_id': self.env.ref("base.main_company").id, {
'name': "Employee2", "company_id": self.env.ref("base.main_company").id,
'login': "alien", "name": "Employee2",
'email': "alien@yourcompany.com", "login": "alien",
'groups_id': [(6, 0, [mail_activity_group.id])], "email": "alien@yourcompany.com",
}) "groups_id": [(6, 0, [mail_activity_group.id])],
}
)
# lead_model_id = self.env['ir.model']._get('crm.lead').id # lead_model_id = self.env['ir.model']._get('crm.lead').id
partner_model_id = self.env['ir.model']._get('res.partner').id partner_model_id = self.env["ir.model"]._get("res.partner").id
ActivityType = self.env['mail.activity.type'] ActivityType = self.env["mail.activity.type"]
self.activity1 = ActivityType.create({ self.activity1 = ActivityType.create(
'name': 'Initial Contact', {
'days': 5, "name": "Initial Contact",
'summary': 'ACT 1 : Presentation, barbecue, ... ', "delay_count": 5,
'res_model_id': partner_model_id, "delay_unit": "days",
}) "summary": "ACT 1 : Presentation, barbecue, ... ",
self.activity2 = ActivityType.create({ "res_model_id": partner_model_id,
'name': 'Call for Demo', }
'days': 6, )
'summary': 'ACT 2 : I want to show you my ERP !', self.activity2 = ActivityType.create(
'res_model_id': partner_model_id, {
}) "name": "Call for Demo",
self.activity3 = ActivityType.create({ "delay_count": 6,
'name': 'Celebrate the sale', "delay_unit": "days",
'days': 3, "summary": "ACT 2 : I want to show you my ERP !",
'summary': 'ACT 3 : ' "res_model_id": partner_model_id,
'Beers for everyone because I am a good salesman !', }
'res_model_id': partner_model_id, )
}) self.activity3 = ActivityType.create(
{
"name": "Celebrate the sale",
"delay_count": 3,
"delay_unit": "days",
"summary": "ACT 3 : "
"Beers for everyone because I am a good salesman !",
"res_model_id": partner_model_id,
}
)
# I create an opportunity, as employee # I create an opportunity, as employee
self.partner_client = self.env.ref("base.res_partner_1") self.partner_client = self.env.ref("base.res_partner_1")
# assure there isn't any mail activity yet # assure there isn't any mail activity yet
self.env['mail.activity'].sudo().search([]).unlink() self.env["mail.activity"].sudo().search([]).unlink()
self.act1 = self.env['mail.activity'].sudo().create({ self.act1 = (
'activity_type_id': self.activity3.id, self.env["mail.activity"]
'note': 'Partner activity 1.', .sudo()
'res_id': self.partner_client.id, .create(
'res_model_id': partner_model_id, {
'user_id': self.employee.id "activity_type_id": self.activity3.id,
}) "note": "Partner activity 1.",
self.act2 = self.env['mail.activity'].sudo().create({ "res_id": self.partner_client.id,
'activity_type_id': self.activity2.id, "res_model_id": partner_model_id,
'note': 'Partner activity 2.', "user_id": self.employee.id,
'res_id': self.partner_client.id, }
'res_model_id': partner_model_id, )
'user_id': self.employee.id )
}) self.act2 = (
self.act3 = self.env['mail.activity'].sudo().create({ self.env["mail.activity"]
'activity_type_id': self.activity3.id, .sudo()
'note': 'Partner activity 3.', .create(
'res_id': self.partner_client.id, {
'res_model_id': partner_model_id, "activity_type_id": self.activity2.id,
'user_id': self.employee.id "note": "Partner activity 2.",
}) "res_id": self.partner_client.id,
"res_model_id": partner_model_id,
"user_id": self.employee.id,
}
)
)
self.act3 = (
self.env["mail.activity"]
.sudo()
.create(
{
"activity_type_id": self.activity3.id,
"note": "Partner activity 3.",
"res_id": self.partner_client.id,
"res_model_id": partner_model_id,
"user_id": self.employee.id,
}
)
)
def create_mail_activity_group(self): def create_mail_activity_group(self):
manager_mail_activity_test_group = self.env['res.groups'].create({ manager_mail_activity_test_group = self.env["res.groups"].create(
'name': 'group_manager_mail_activity_test', {"name": "group_manager_mail_activity_test"}
}) )
mail_activity_model_id = self.env['ir.model'].sudo().search( mail_activity_model_id = (
[('model', '=', 'mail.activity')], limit=1) self.env["ir.model"]
access = self.env['ir.model.access'].create({ .sudo()
'name': 'full_access_mail_activity', .search([("model", "=", "mail.activity")], limit=1)
'model_id': mail_activity_model_id.id, )
'perm_read': True, access = self.env["ir.model.access"].create(
'perm_write': True, {
'perm_create': True, "name": "full_access_mail_activity",
'perm_unlink': True, "model_id": mail_activity_model_id.id,
}) "perm_read": True,
"perm_write": True,
"perm_create": True,
"perm_unlink": True,
}
)
access.group_id = manager_mail_activity_test_group access.group_id = manager_mail_activity_test_group
return manager_mail_activity_test_group return manager_mail_activity_test_group
def get_view(self, activity): def get_view(self, activity):
action = activity.open_origin() action = activity.open_origin()
result = self.env[action.get('res_model')]\ result = self.env[action.get("res_model")].load_views(action.get("views"))
.load_views(action.get('views')) return result.get("fields_views").get(action.get("view_mode"))
return result.get('fields_views').get(action.get('view_mode'))
def test_open_origin_res_partner(self): def test_open_origin_res_partner(self):
""" This test case checks """ This test case checks
@ -110,63 +144,58 @@ class TestMailActivityBoardMethods(TransactionCase):
belongs. belongs.
""" """
# Id of the form view for the class 'crm.lead', type 'lead' # Id of the form view for the class 'crm.lead', type 'lead'
form_view_partner_id = self.env.ref('base.view_partner_form').id form_view_partner_id = self.env.ref("base.view_partner_form").id
# Id of the form view return open_origin() # Id of the form view return open_origin()
view = self.get_view(self.act1) view = self.get_view(self.act1)
# Check the next view is correct # Check the next view is correct
self.assertEqual(form_view_partner_id, view.get('view_id')) self.assertEqual(form_view_partner_id, view.get("view_id"))
# Id of the form view return open_origin() # Id of the form view return open_origin()
view = self.get_view(self.act2) view = self.get_view(self.act2)
# Check the next view is correct # Check the next view is correct
self.assertEqual(form_view_partner_id, view.get('view_id')) self.assertEqual(form_view_partner_id, view.get("view_id"))
# Id of the form view return open_origin() # Id of the form view return open_origin()
view = self.get_view(self.act3) view = self.get_view(self.act3)
# Check the next view is correct # Check the next view is correct
self.assertEqual(form_view_partner_id, view.get('view_id')) self.assertEqual(form_view_partner_id, view.get("view_id"))
def test_redirect_to_activities(self): def test_redirect_to_activities(self):
""" This test case checks """ This test case checks
- if the method returns the correct action, - if the method returns the correct action,
- if the correct activities are shown. - if the correct activities are shown.
""" """
action_id = self.env.ref( action_id = self.env.ref("mail_activity_board.open_boards_activities").id
'mail_activity_board.open_boards_activities').id action = self.partner_client.redirect_to_activities(
action = self.partner_client\ **{"id": self.partner_client.id}
.redirect_to_activities(**{'id': self.partner_client.id}) )
self.assertEqual(action.get('id'), action_id) self.assertEqual(action.get("id"), action_id)
kwargs = { kwargs = {"groupby": ["activity_type_id"]}
'groupby': [ kwargs["domain"] = action.get("domain")
"activity_type_id"
],
}
kwargs['domain'] = action.get('domain')
result = self.env[action.get('res_model')]\ result = self.env[action.get("res_model")].load_views(action.get("views"))
.load_views(action.get('views')) fields = result.get("fields_views").get("kanban").get("fields")
fields = result.get('fields_views').get('kanban').get('fields') kwargs["fields"] = list(fields.keys())
kwargs['fields'] = list(fields.keys())
result = self.env['mail.activity'].read_group(**kwargs) result = self.env["mail.activity"].read_group(**kwargs)
acts = [] acts = []
for group in result: for group in result:
records = self.env['mail.activity'].search_read( records = self.env["mail.activity"].search_read(
domain=group.get('__domain'), fields=kwargs['fields'] domain=group.get("__domain"), fields=kwargs["fields"]
) )
acts += [record_id.get('id') for record_id in records] acts += [record_id.get("id") for record_id in records]
for act in acts: for act in acts:
self.assertIn(act, self.partner_client.activity_ids.ids) self.assertIn(act, self.partner_client.activity_ids.ids)
def test_read_permissions(self): def test_read_permissions(self):
search1 = self.env['mail.activity'].sudo(self.employee).search([]) search1 = self.env["mail.activity"].with_user(self.employee).search([])
self.assertEqual(len(search1), 3) self.assertEqual(len(search1), 3)
search2 = self.env['mail.activity'].sudo(self.employee2).search([]) search2 = self.env["mail.activity"].with_user(self.employee2).search([])
self.assertEqual(len(search2), 0) self.assertEqual(len(search2), 0)

View File

@ -156,7 +156,7 @@
<field name="res_name" string="Origin"/> <field name="res_name" string="Origin"/>
</xpath> </xpath>
<xpath expr='//filter[@name="activities_my"]' position='after'> <xpath expr='//filter[@name="activities_overdue"]' position='before'>
<filter string="Act. next month" name="activities_month" <filter string="Act. next month" name="activities_month"
domain="[('date_deadline', '&lt;', (context_today()+datetime.timedelta(days=30)).strftime('%Y-%m-%d'))]" domain="[('date_deadline', '&lt;', (context_today()+datetime.timedelta(days=30)).strftime('%Y-%m-%d'))]"
help="Show activities scheduled for next month."/> help="Show activities scheduled for next month."/>
@ -181,7 +181,6 @@
<record model="ir.actions.act_window" id="open_boards_activities"> <record model="ir.actions.act_window" id="open_boards_activities">
<field name="name">Activities</field> <field name="name">Activities</field>
<field name="res_model">mail.activity</field> <field name="res_model">mail.activity</field>
<field name="view_type">form</field>
<field name="view_mode">kanban,form</field> <field name="view_mode">kanban,form</field>
<field name="domain">[]</field> <field name="domain">[]</field>
<field name="context">{}</field> <field name="context">{}</field>