[IMP] calendar, crm, hr_holidays: move meeting stat button to calendar
Move the meeting stat button and kanban pill from CRM to Calendar, purpose is to allow its usage even if CRM is not installed as this makes more sense since this field is usually related to Calendar. Increase query number limit in company leave test, in order to take into account the newly introduced query in Calendar. UPG-PR: https://github.com/odoo/upgrade/pull/2423 Task-2514473 closes odoo/odoo#69846 Related: odoo/upgrade#2423 Signed-off-by: Thibault Delavallee (tde) <tde@openerp.com>
This commit is contained in:
@@ -32,6 +32,7 @@ If you need to manage your meetings, you should install the CRM module.
|
||||
'views/mail_activity_views.xml',
|
||||
'views/calendar_templates.xml',
|
||||
'views/calendar_views.xml',
|
||||
'views/res_partner_views.xml',
|
||||
],
|
||||
'installable': True,
|
||||
'application': True,
|
||||
|
||||
@@ -9,9 +9,50 @@ from odoo import api, fields, models
|
||||
class Partner(models.Model):
|
||||
_inherit = 'res.partner'
|
||||
|
||||
meeting_count = fields.Integer("# Meetings", compute='_compute_meeting_count')
|
||||
meeting_ids = fields.Many2many('calendar.event', 'calendar_event_res_partner_rel', 'res_partner_id',
|
||||
'calendar_event_id', string='Meetings', copy=False)
|
||||
|
||||
calendar_last_notif_ack = fields.Datetime(
|
||||
'Last notification marked as read from base Calendar', default=fields.Datetime.now)
|
||||
|
||||
def _compute_meeting_count(self):
|
||||
result = self._compute_meeting()
|
||||
for p in self:
|
||||
p.meeting_count = len(result.get(p.id, []))
|
||||
|
||||
def _compute_meeting(self):
|
||||
if self.ids:
|
||||
all_partners = self.with_context(active_test=False).search([('id', 'child_of', self.ids)])
|
||||
self.env.cr.execute("""
|
||||
SELECT res_partner_id, calendar_event_id, count(1)
|
||||
FROM calendar_event_res_partner_rel
|
||||
WHERE res_partner_id IN %s
|
||||
GROUP BY res_partner_id, calendar_event_id
|
||||
""", [tuple(all_partners.ids)])
|
||||
meeting_data = self.env.cr.fetchall()
|
||||
|
||||
# Keep only valid meeting data based on record rules of events
|
||||
events = [row[1] for row in meeting_data]
|
||||
events = self.env['calendar.event'].search([('id', 'in', events)]).ids
|
||||
meeting_data = [m for m in meeting_data if m[1] in events]
|
||||
|
||||
# Create a dict {partner_id: event_ids} and fill with events linked to the partner
|
||||
meetings = {p.id: set() for p in all_partners}
|
||||
for m in meeting_data:
|
||||
meetings[m[0]].add(m[1])
|
||||
|
||||
# Add the events linked to the children of the partner
|
||||
all_partners.read(['parent_id'])
|
||||
for p in all_partners:
|
||||
partner = p
|
||||
while partner:
|
||||
if partner in self:
|
||||
meetings[partner.id] |= meetings[p.id]
|
||||
partner = partner.parent_id
|
||||
return {p.id: list(meetings[p.id]) for p in self}
|
||||
return {}
|
||||
|
||||
def get_attendee_detail(self, meeting_ids):
|
||||
""" Return a list of dict of the given meetings with the attendees details
|
||||
Used by:
|
||||
@@ -40,3 +81,14 @@ class Partner(models.Model):
|
||||
def _set_calendar_last_notif_ack(self):
|
||||
partner = self.env['res.users'].browse(self.env.context.get('uid', self.env.uid)).partner_id
|
||||
partner.write({'calendar_last_notif_ack': datetime.now()})
|
||||
|
||||
def schedule_meeting(self):
|
||||
self.ensure_one()
|
||||
partner_ids = self.ids
|
||||
partner_ids.append(self.env.user.partner_id.id)
|
||||
action = self.env["ir.actions.actions"]._for_xml_id("calendar.action_calendar_event")
|
||||
action['context'] = {
|
||||
'default_partner_ids': partner_ids,
|
||||
}
|
||||
action['domain'] = ['|', ('id', 'in', self._compute_meeting()[self.id]), ('partner_ids', 'in', self.ids)]
|
||||
return action
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
<?xml version="1.0"?>
|
||||
<odoo>
|
||||
|
||||
<!-- Partner kanban view inherit -->
|
||||
<record id="res_partner_kanban_view" model="ir.ui.view">
|
||||
<field name="name">res.partner.view.kanban.calendar</field>
|
||||
<field name="model">res.partner</field>
|
||||
<field name="inherit_id" ref="base.res_partner_kanban_view"/>
|
||||
<field name="priority" eval="10"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="mobile" position="after">
|
||||
<field name="meeting_count"/>
|
||||
</field>
|
||||
<xpath expr="//span[hasclass('oe_kanban_partner_links')]" position="inside">
|
||||
<span class="badge badge-pill" t-if="record.meeting_count.value>0">
|
||||
<i class="fa fa-fw fa-calendar" aria-label="Meetings" role="img" title="Meetings"/>
|
||||
<t t-esc="record.meeting_count.value"/>
|
||||
</span>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Add contextual button on partner form view -->
|
||||
<record id="view_partners_form" model="ir.ui.view">
|
||||
<field name="name">res_partner.view.form.calendar</field>
|
||||
<field name="model">res.partner</field>
|
||||
<field name="inherit_id" ref="base.view_partner_form"/>
|
||||
<field eval="1" name="priority"/>
|
||||
<field name="arch" type="xml">
|
||||
<data>
|
||||
<div name="button_box" position="inside">
|
||||
<button class="oe_stat_button" type="object"
|
||||
name="schedule_meeting"
|
||||
icon="fa-calendar"
|
||||
context="{'partner_id': active_id, 'partner_name': name}">
|
||||
<field string="Meetings" name="meeting_count" widget="statinfo"/>
|
||||
</button>
|
||||
</div>
|
||||
</data>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
@@ -10,9 +10,7 @@ class Partner(models.Model):
|
||||
|
||||
team_id = fields.Many2one('crm.team', string='Sales Team')
|
||||
opportunity_ids = fields.One2many('crm.lead', 'partner_id', string='Opportunities', domain=[('type', '=', 'opportunity')])
|
||||
meeting_ids = fields.Many2many('calendar.event', 'calendar_event_res_partner_rel', 'res_partner_id', 'calendar_event_id', string='Meetings', copy=False)
|
||||
opportunity_count = fields.Integer("Opportunity", compute='_compute_opportunity_count')
|
||||
meeting_count = fields.Integer("# Meetings", compute='_compute_meeting_count')
|
||||
|
||||
@api.model
|
||||
def default_get(self, fields):
|
||||
@@ -54,55 +52,6 @@ class Partner(models.Model):
|
||||
partner.opportunity_count += group['partner_id_count']
|
||||
partner = partner.parent_id
|
||||
|
||||
def _compute_meeting_count(self):
|
||||
result = self._compute_meeting()
|
||||
for p in self:
|
||||
p.meeting_count = len(result.get(p.id, []))
|
||||
|
||||
def _compute_meeting(self):
|
||||
if self.ids:
|
||||
all_partners = self.with_context(active_test=False).search([('id', 'child_of', self.ids)])
|
||||
self.env.cr.execute("""
|
||||
SELECT res_partner_id, calendar_event_id, count(1)
|
||||
FROM calendar_event_res_partner_rel
|
||||
WHERE res_partner_id IN %s
|
||||
GROUP BY res_partner_id, calendar_event_id
|
||||
""", [tuple(all_partners.ids)])
|
||||
meeting_data = self.env.cr.fetchall()
|
||||
|
||||
# Keep only valid meeting data based on record rules of events
|
||||
events = [row[1] for row in meeting_data]
|
||||
events = self.env['calendar.event'].search([('id', 'in', events)]).ids
|
||||
meeting_data = [m for m in meeting_data if m[1] in events]
|
||||
|
||||
# Create a dict {partner_id: event_ids} and fill with events linked to the partner
|
||||
meetings = {p.id: set() for p in all_partners}
|
||||
for m in meeting_data:
|
||||
meetings[m[0]].add(m[1])
|
||||
|
||||
# Add the events linked to the children of the partner
|
||||
all_partners.read(['parent_id'])
|
||||
for p in all_partners:
|
||||
partner = p
|
||||
while partner:
|
||||
if partner in self:
|
||||
meetings[partner.id] |= meetings[p.id]
|
||||
partner = partner.parent_id
|
||||
return {p.id: list(meetings[p.id]) for p in self}
|
||||
return {}
|
||||
|
||||
|
||||
def schedule_meeting(self):
|
||||
self.ensure_one()
|
||||
partner_ids = self.ids
|
||||
partner_ids.append(self.env.user.partner_id.id)
|
||||
action = self.env["ir.actions.actions"]._for_xml_id("calendar.action_calendar_event")
|
||||
action['context'] = {
|
||||
'default_partner_ids': partner_ids,
|
||||
}
|
||||
action['domain'] = ['|', ('id', 'in', self._compute_meeting()[self.id]), ('partner_ids', 'in', self.ids)]
|
||||
return action
|
||||
|
||||
def action_view_opportunity(self):
|
||||
'''
|
||||
This function returns an action that displays the opportunities from partner.
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
</field>
|
||||
<xpath expr="//span[hasclass('oe_kanban_partner_links')]" position="inside">
|
||||
<span class="badge badge-pill" t-if="record.opportunity_count.value>0"><i class="fa fa-fw fa-star" aria-label="Favorites" role="img" title="Favorites"/><t t-esc="record.opportunity_count.value"/></span>
|
||||
<span class="badge badge-pill" t-if="record.meeting_count.value>0"><i class="fa fa-fw fa-calendar" aria-label="Meetings" role="img" title="Meetings"/><t t-esc="record.meeting_count.value"/></span>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
@@ -37,13 +36,6 @@
|
||||
context="{'default_partner_id': active_id}">
|
||||
<field string="Opportunities" name="opportunity_count" widget="statinfo"/>
|
||||
</button>
|
||||
<button class="oe_stat_button" type="object"
|
||||
name="schedule_meeting"
|
||||
icon="fa-calendar"
|
||||
groups="sales_team.group_sale_salesman"
|
||||
context="{'partner_id': active_id, 'partner_name': name}">
|
||||
<field string="Meetings" name="meeting_count" widget="statinfo"/>
|
||||
</button>
|
||||
</div>
|
||||
</data>
|
||||
</field>
|
||||
|
||||
@@ -313,7 +313,7 @@ class TestCompanyLeave(TransactionCase):
|
||||
})
|
||||
company_leave._compute_date_from_to()
|
||||
|
||||
with self.assertQueryCount(__system__=842, admin=865):
|
||||
with self.assertQueryCount(__system__=843, admin=865):
|
||||
# Original query count: 1987
|
||||
# Without tracking/activity context keys: 5154
|
||||
company_leave.action_validate()
|
||||
|
||||
Reference in New Issue
Block a user