[IMP] calendar: Forward port of Saas 14.3 calendar perf yti
Forward port of https://github.com/odoo/odoo/pull/71808 closes odoo/odoo#72043 X-original-commit: 4f13a2214aed380c8aea984d3414caca506401bf Signed-off-by: Yannick Tivisse (yti) <yti@odoo.com> Signed-off-by: Arnaud Joset <arj-odoo@users.noreply.github.com>
This commit is contained in:
@@ -4,6 +4,7 @@ import uuid
|
||||
import base64
|
||||
import logging
|
||||
|
||||
from collections import defaultdict
|
||||
from odoo import api, fields, models, _
|
||||
from odoo.addons.base.models.res_partner import _tz_get
|
||||
from odoo.exceptions import UserError
|
||||
@@ -76,11 +77,14 @@ class Attendee(models.Model):
|
||||
raise UserError(_('You cannot duplicate a calendar attendee.'))
|
||||
|
||||
def _subscribe_partner(self):
|
||||
mapped_followers = defaultdict(lambda: self.env['calendar.event'])
|
||||
for event in self.event_id:
|
||||
partners = (event.attendee_ids & self).partner_id - event.message_partner_ids
|
||||
# current user is automatically added as followers, don't add it twice.
|
||||
partners -= self.env.user.partner_id
|
||||
event.message_subscribe(partner_ids=partners.ids)
|
||||
mapped_followers[partners] |= event
|
||||
for partners, events in mapped_followers.items():
|
||||
events.message_subscribe(partner_ids=partners.ids)
|
||||
|
||||
def _unsubscribe_partner(self):
|
||||
for event in self.event_id:
|
||||
|
||||
@@ -68,6 +68,7 @@ class Meeting(models.Model):
|
||||
if 'res_model_id' not in defaults and 'res_model_id' in fields and \
|
||||
self.env.context.get('active_model') and self.env.context['active_model'] != 'calendar.event':
|
||||
defaults['res_model_id'] = self.env['ir.model'].sudo().search([('model', '=', self.env.context['active_model'])], limit=1).id
|
||||
defaults['res_model'] = self.env.context.get('active_model')
|
||||
if 'res_id' not in defaults and 'res_id' in fields and \
|
||||
defaults.get('res_model_id') and self.env.context.get('active_id'):
|
||||
defaults['res_id'] = self.env.context['active_id']
|
||||
@@ -354,25 +355,32 @@ class Meeting(models.Model):
|
||||
for vals in vals_list
|
||||
]
|
||||
|
||||
for values in vals_list:
|
||||
# created from calendar: try to create an activity on the related record
|
||||
if not values.get('activity_ids'):
|
||||
defaults = self.default_get(['activity_ids', 'res_model_id', 'res_id', 'user_id'])
|
||||
defaults = self.default_get(['activity_ids', 'res_model_id', 'res_id', 'user_id', 'res_model'])
|
||||
meeting_activity_type = self.env['mail.activity.type'].search([('category', '=', 'meeting')], limit=1)
|
||||
# get list of models ids and filter out None values directly
|
||||
model_ids = list(filter(bool, {values.get('res_model_id', defaults.get('res_model_id')) for values in vals_list}))
|
||||
model_name = defaults.get('res_model')
|
||||
valid_activity_model_ids = model_name and self.env[model_name].sudo().browse(model_ids).filtered(lambda m: 'activity_ids' in m).ids or []
|
||||
if meeting_activity_type and not defaults.get('activity_ids'):
|
||||
for values in vals_list:
|
||||
# created from calendar: try to create an activity on the related record
|
||||
if values.get('activity_ids'):
|
||||
continue
|
||||
res_model_id = values.get('res_model_id', defaults.get('res_model_id'))
|
||||
res_id = values.get('res_id', defaults.get('res_id'))
|
||||
user_id = values.get('user_id', defaults.get('user_id'))
|
||||
if not defaults.get('activity_ids') and res_model_id and res_id:
|
||||
if hasattr(self.env[self.env['ir.model'].sudo().browse(res_model_id).model], 'activity_ids'):
|
||||
meeting_activity_type = self.env['mail.activity.type'].search([('category', '=', 'meeting')], limit=1)
|
||||
if meeting_activity_type:
|
||||
activity_vals = {
|
||||
'res_model_id': res_model_id,
|
||||
'res_id': res_id,
|
||||
'activity_type_id': meeting_activity_type.id,
|
||||
}
|
||||
if user_id:
|
||||
activity_vals['user_id'] = user_id
|
||||
values['activity_ids'] = [(0, 0, activity_vals)]
|
||||
if not res_model_id or not res_id:
|
||||
continue
|
||||
if res_model_id not in valid_activity_model_ids:
|
||||
continue
|
||||
activity_vals = {
|
||||
'res_model_id': res_model_id,
|
||||
'res_id': res_id,
|
||||
'activity_type_id': meeting_activity_type.id,
|
||||
}
|
||||
if user_id:
|
||||
activity_vals['user_id'] = user_id
|
||||
values['activity_ids'] = [(0, 0, activity_vals)]
|
||||
|
||||
# Automatically add the current partner when creating an event if there is none (happens when we quickcreate an event)
|
||||
self_partner_id = [(4, self.env.user.partner_id.id)]
|
||||
@@ -556,10 +564,13 @@ class Meeting(models.Model):
|
||||
added_partner_ids += [command[1]] if command[1] not in self.partner_ids.ids else []
|
||||
# commands 0 and 1 not supported
|
||||
|
||||
attendees_to_unlink = self.env['calendar.attendee'].search([
|
||||
('event_id', 'in', self.ids),
|
||||
('partner_id', 'in', removed_partner_ids),
|
||||
])
|
||||
if not self:
|
||||
attendees_to_unlink = self.env['calendar.attendee']
|
||||
else:
|
||||
attendees_to_unlink = self.env['calendar.attendee'].search([
|
||||
('event_id', 'in', self.ids),
|
||||
('partner_id', 'in', removed_partner_ids),
|
||||
])
|
||||
attendee_commands += [[2, attendee.id] for attendee in attendees_to_unlink] # Removes and delete
|
||||
|
||||
attendee_commands += [
|
||||
@@ -650,8 +661,8 @@ class Meeting(models.Model):
|
||||
def _setup_alarms(self):
|
||||
""" Schedule cron triggers for future events """
|
||||
cron = self.env.ref('calendar.ir_cron_scheduler_alarm').sudo()
|
||||
alarm_manager = self.env['calendar.alarm_manager']
|
||||
alarm_types = self._get_trigger_alarm_types()
|
||||
events_to_notify = self.env['calendar.event']
|
||||
|
||||
for event in self:
|
||||
for alarm in (alarm for alarm in event.alarm_ids if alarm.alarm_type in alarm_types):
|
||||
@@ -661,8 +672,9 @@ class Meeting(models.Model):
|
||||
cron._trigger(at=at)
|
||||
if any(alarm.alarm_type == 'notification' for alarm in event.alarm_ids):
|
||||
# filter events before notifying attendees through calendar_alarm_manager
|
||||
need_notifs = event.filtered(lambda ev: ev.alarm_ids and ev.stop >= fields.Datetime.now())
|
||||
alarm_manager._notify_next_alarm(need_notifs.partner_ids.ids)
|
||||
events_to_notify |= event.filtered(lambda ev: ev.alarm_ids and ev.stop >= fields.Datetime.now())
|
||||
if events_to_notify:
|
||||
self.env['calendar.alarm_manager']._notify_next_alarm(events_to_notify.partner_ids.ids)
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# RECURRENCY
|
||||
|
||||
@@ -8,8 +8,10 @@ from unittest.mock import patch
|
||||
from odoo.addons.google_calendar.utils.google_calendar import GoogleCalendarService
|
||||
from odoo.addons.google_calendar.models.res_users import User
|
||||
from odoo.addons.google_calendar.tests.test_sync_common import TestSyncGoogle, patch_api
|
||||
from odoo.tests.common import users, warmup
|
||||
from odoo.tests import tagged
|
||||
|
||||
|
||||
@tagged('odoo2google')
|
||||
@patch.object(User, '_get_google_calendar_token', lambda user: 'dummy-token')
|
||||
class TestSyncOdoo2Google(TestSyncGoogle):
|
||||
|
||||
@@ -53,6 +55,73 @@ class TestSyncOdoo2Google(TestSyncGoogle):
|
||||
'extendedProperties': {'shared': {'%s_odoo_id' % self.env.cr.dbname: event.id}}
|
||||
})
|
||||
|
||||
@patch_api
|
||||
@users('__system__')
|
||||
@warmup
|
||||
def test_event_creation_perf(self):
|
||||
EVENT_COUNT = 100
|
||||
partners = self.env['res.partner'].create([
|
||||
{'name': 'Jean-Luc %s' % (i), 'email': 'jean-luc-%s@opoo.com' % (i)} for i in range(EVENT_COUNT)])
|
||||
alarm = self.env['calendar.alarm'].create({
|
||||
'name': 'Notif',
|
||||
'alarm_type': 'notification',
|
||||
'interval': 'minutes',
|
||||
'duration': 18,
|
||||
})
|
||||
partner_model = self.env.ref('base.model_res_partner')
|
||||
partner = self.env['res.partner'].search([], limit=1)
|
||||
with self.assertQueryCount(__system__=1211):
|
||||
events = self.env['calendar.event'].create([{
|
||||
'name': "Event %s" % (i),
|
||||
'start': datetime(2020, 1, 15, 8, 0),
|
||||
'stop': datetime(2020, 1, 15, 18, 0),
|
||||
'partner_ids': [(4, partners[i].id), (4, self.env.user.partner_id.id)],
|
||||
'alarm_ids': [(4, alarm.id)],
|
||||
'privacy': 'private',
|
||||
'need_sync': False,
|
||||
'res_model_id': partner_model.id,
|
||||
'res_id': partner.id,
|
||||
} for i in range(EVENT_COUNT)])
|
||||
|
||||
events._sync_odoo2google(self.google_service)
|
||||
|
||||
with self.assertQueryCount(__system__=129):
|
||||
events.unlink()
|
||||
|
||||
|
||||
@patch_api
|
||||
@users('__system__')
|
||||
@warmup
|
||||
def test_recurring_event_creation_perf(self):
|
||||
partner = self.env['res.partner'].create({'name': 'Jean-Luc', 'email': 'jean-luc@opoo.com'})
|
||||
alarm = self.env['calendar.alarm'].create({
|
||||
'name': 'Notif',
|
||||
'alarm_type': 'notification',
|
||||
'interval': 'minutes',
|
||||
'duration': 18,
|
||||
})
|
||||
partner_model = self.env.ref('base.model_res_partner')
|
||||
partner = self.env['res.partner'].search([], limit=1)
|
||||
with self.assertQueryCount(__system__=3637):
|
||||
event = self.env['calendar.event'].create({
|
||||
'name': "Event",
|
||||
'start': datetime(2020, 1, 15, 8, 0),
|
||||
'stop': datetime(2020, 1, 15, 18, 0),
|
||||
'partner_ids': [(4, partner.id)],
|
||||
'alarm_ids': [(4, alarm.id)],
|
||||
'privacy': 'private',
|
||||
'need_sync': False,
|
||||
'interval': 1,
|
||||
'recurrency': True,
|
||||
'rrule_type': 'daily',
|
||||
'end_type': 'forever',
|
||||
'res_model_id': partner_model.id,
|
||||
'res_id': partner.id,
|
||||
})
|
||||
|
||||
with self.assertQueryCount(__system__=2191):
|
||||
event.unlink()
|
||||
|
||||
def test_event_without_user(self):
|
||||
event = self.env['calendar.event'].create({
|
||||
'name': "Event",
|
||||
|
||||
@@ -313,7 +313,7 @@ class TestCompanyLeave(TransactionCase):
|
||||
})
|
||||
company_leave._compute_date_from_to()
|
||||
|
||||
with self.assertQueryCount(__system__=843, admin=865):
|
||||
with self.assertQueryCount(__system__=845, admin=865):
|
||||
# Original query count: 1987
|
||||
# Without tracking/activity context keys: 5154
|
||||
company_leave.action_validate()
|
||||
|
||||
@@ -31,7 +31,7 @@ class TestWorkEntryHolidaysPerformance(TestWorkEntryHolidaysBase):
|
||||
self.richard_emp.generate_work_entries(date(2018, 1, 1), date(2018, 1, 2))
|
||||
leave = self.create_leave(datetime(2018, 1, 1, 7, 0), datetime(2018, 1, 1, 18, 0))
|
||||
|
||||
with self.assertQueryCount(__system__=94, admin=95):
|
||||
with self.assertQueryCount(__system__=96, admin=97):
|
||||
leave.action_validate()
|
||||
leave.action_refuse()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user