It looks like in enterprise, the value of has_group is already in cache
This will lead to an additional query when checking mail.message
creation access rights in community.
This commit warmup the user _has_group ormcache to avoid an
inconsistency between community and enterprise
Stack of the additional query:
```
sql('SELECT 1 FROM res_groups_users_rel WHERE uid=%s AND gid IN\n ... (SELECT res_id FROM ir_model_data WHERE module=%s AND name=%s)') (SELECT 1 FROM res_groups_users_rel WHERE uid=29 AND gid IN (SELECT res_id FROM ir_model_data WHERE module='base' AND name='group_user'))
execute (odoo/addons/base/models/res_users.py (self._cr.execute("""SELECT 1 FROM res_groups_users_rel WHERE uid=%s AND gid IN):847)
_has_group (odoo/tools/cache.py (value = d[key] = self.method(*args, **kwargs)):90)
lookup (called at <decorator-gen-111> ():2)
_has_group (odoo/addons/base/models/res_users.py (return self.with_user(uid)._has_group(group_ext_id)):832)
has_group (addons/mail/models/mail_message.py (if not self.env['res.users'].has_group('base.group_user'):):380)
check_access_rule (odoo/models.py (records.check_access_rule('create')):4321)
_create (odoo/models.py (records = self._create(data_list)):4087)
create (odoo/api.py (return create(self, arg)):410)
_model_create_multi (called at <decorator-gen-16> ():2)
create (odoo/addons/base/models/ir_fields.py (recs = super().create(vals_list)):613)
create (odoo/api.py (return create(self, arg)):410)
_model_create_multi (called at <decorator-gen-68> ():2)
create (addons/mail/models/mail_message.py (messages = super(Message, self).create(values_list)):599)
create (odoo/api.py (return create(self, arg)):410)
_model_create_multi (called at <decorator-gen-193> ():2)
create (addons/mail/models/mail_thread.py (return self.env['mail.message'].create(create_values_list)):2132)
_message_create (addons/mail/models/mail_thread.py (new_message = self._message_create(msg_values)):1874)
message_post (addons/rating/models/mail_thread.py (message = super(MailThread, self).message_post(**kwargs)):14)
message_post (addons/mail/wizard/mail_compose_message.py (ActiveModel.browse(res_id).message_post(**post_params)):321)
_action_send_mail (addons/mail/models/mail_thread.py (return composer._action_send_mail(auto_commit=auto_commit)):1964)
message_post_with_template (addons/mail/models/mail_thread.py (return record.message_post_with_template(False, **kwargs)):1929)
_message_compose_with_view (addons/mail/models/mail_thread.py (self._message_compose_with_view(views_or_xmlid, **kwargs)):1933)
message_post_with_view (addons/crm/models/crm_lead.py (opportunities_head.message_post_with_view():1336)
_merge_opportunity (addons/crm/models/crm_team.py (merged = lead_duplicates._merge_opportunity(user_id=False, team_id=False, auto_unlink=False, max_length=0)):578)
_allocate_leads_deduplicate (addons/crm/models/crm_team.py (assign_res = team._allocate_leads_deduplicate(candidate_lead, duplicates_cache=duplicates_lead_cache)):507)
_allocate_leads (addons/crm/models/crm_team.py (teams_data = self._allocate_leads(work_days=work_days)):304)
_action_assign_leads
test_assign_perf_duplicates (odoo/tools/misc.py (return func(*args, **kwargs)):792)
```
task-2796579
Part-of: odoo/odoo#85525
196 lines
9.4 KiB
Python
196 lines
9.4 KiB
Python
# -*- coding: utf-8 -*-
|
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
|
|
import random
|
|
|
|
from odoo.addons.crm.tests.test_crm_lead_assignment import TestLeadAssignCommon
|
|
from odoo.tests.common import tagged
|
|
from odoo.tools import mute_logger
|
|
|
|
|
|
@tagged('lead_assign', 'crm_performance')
|
|
class TestLeadAssignPerf(TestLeadAssignCommon):
|
|
""" Test performances of lead assignment feature added in saas-14.2
|
|
|
|
Assign process is a random process: randomizing teams leads to searching,
|
|
assigning and de-duplicating leads in various order. As a lot of search
|
|
are implied during assign process query counters may vary from run to run.
|
|
"Heavy" performance test included here ranged from 6K to 6.3K queries. Either
|
|
we set high counters maximum which makes those tests less useful. Either we
|
|
avoid random if possible which is what we decided to do by setting the seed
|
|
of random in tests.
|
|
"""
|
|
|
|
@mute_logger('odoo.models.unlink', 'odoo.addons.crm.models.crm_team', 'odoo.addons.crm.models.crm_team_member')
|
|
def test_assign_perf_duplicates(self):
|
|
""" Test assign process with duplicates on partner. Allow to ensure notably
|
|
that de duplication is effectively performed. """
|
|
# fix the seed and avoid randomness
|
|
random.seed(1940)
|
|
|
|
leads = self._create_leads_batch(
|
|
lead_type='lead',
|
|
user_ids=[False],
|
|
partner_ids=[self.contact_1.id, self.contact_2.id, False, False, False],
|
|
count=200
|
|
)
|
|
# commit probability and related fields
|
|
leads.flush()
|
|
self.assertInitialData()
|
|
|
|
# assign probability to leads (bypass auto probability as purpose is not to test pls)
|
|
leads = self.env['crm.lead'].search([('id', 'in', leads.ids)]) # ensure order
|
|
for idx in range(0, 5):
|
|
sliced_leads = leads[idx:len(leads):5]
|
|
for lead in sliced_leads:
|
|
lead.probability = (idx + 1) * 10 * ((int(lead.priority) + 1) / 2)
|
|
# commit probability and related fields
|
|
leads.flush()
|
|
|
|
with self.with_user('user_sales_manager'):
|
|
self.env['res.users'].has_group('base.group_user') # warmup the cache to avoid inconsistency between community an enterprise
|
|
with self.assertQueryCount(user_sales_manager=1279):
|
|
self.env['crm.team'].browse(self.sales_teams.ids)._action_assign_leads(work_days=2)
|
|
|
|
# teams assign
|
|
leads = self.env['crm.lead'].search([('id', 'in', leads.ids)]) # ensure order
|
|
leads_st1 = leads.filtered_domain([('team_id', '=', self.sales_team_1.id)])
|
|
leads_stc = leads.filtered_domain([('team_id', '=', self.sales_team_convert.id)])
|
|
self.assertLessEqual(len(leads_st1), 128)
|
|
self.assertLessEqual(len(leads_stc), 96)
|
|
self.assertEqual(len(leads_st1) + len(leads_stc), len(leads)) # Make sure all lead are assigned
|
|
|
|
# salespersons assign
|
|
self.members.invalidate_cache(fnames=['lead_month_count'])
|
|
self.assertMemberAssign(self.sales_team_1_m1, 11) # 45 max on 2 days (3) + compensation (8.4)
|
|
self.assertMemberAssign(self.sales_team_1_m2, 4) # 15 max on 2 days (1) + compensation (2.8)
|
|
self.assertMemberAssign(self.sales_team_1_m3, 4) # 15 max on 2 days (1) + compensation (2.8)
|
|
self.assertMemberAssign(self.sales_team_convert_m1, 8) # 30 max on 15 (2) + compensation (5.6)
|
|
self.assertMemberAssign(self.sales_team_convert_m2, 15) # 60 max on 15 (4) + compsantion (11.2)
|
|
|
|
@mute_logger('odoo.models.unlink', 'odoo.addons.crm.models.crm_team', 'odoo.addons.crm.models.crm_team_member')
|
|
def test_assign_perf_no_duplicates(self):
|
|
# fix the seed and avoid randomness
|
|
random.seed(1945)
|
|
|
|
leads = self._create_leads_batch(
|
|
lead_type='lead',
|
|
user_ids=[False],
|
|
partner_ids=[False],
|
|
count=100
|
|
)
|
|
# commit probability and related fields
|
|
leads.flush()
|
|
self.assertInitialData()
|
|
|
|
# assign probability to leads (bypass auto probability as purpose is not to test pls)
|
|
leads = self.env['crm.lead'].search([('id', 'in', leads.ids)]) # ensure order
|
|
for idx in range(0, 5):
|
|
sliced_leads = leads[idx:len(leads):5]
|
|
for lead in sliced_leads:
|
|
lead.probability = (idx + 1) * 10 * ((int(lead.priority) + 1) / 2)
|
|
# commit probability and related fields
|
|
leads.flush()
|
|
|
|
with self.with_user('user_sales_manager'):
|
|
with self.assertQueryCount(user_sales_manager=584):
|
|
self.env['crm.team'].browse(self.sales_teams.ids)._action_assign_leads(work_days=2)
|
|
|
|
# teams assign
|
|
leads = self.env['crm.lead'].search([('id', 'in', leads.ids)]) # ensure order
|
|
leads_st1 = leads.filtered_domain([('team_id', '=', self.sales_team_1.id)])
|
|
leads_stc = leads.filtered_domain([('team_id', '=', self.sales_team_convert.id)])
|
|
self.assertEqual(len(leads_st1) + len(leads_stc), 100)
|
|
|
|
# salespersons assign
|
|
self.members.invalidate_cache(fnames=['lead_month_count'])
|
|
self.assertMemberAssign(self.sales_team_1_m1, 11) # 45 max on 2 days (3) + compensation (8.4)
|
|
self.assertMemberAssign(self.sales_team_1_m2, 4) # 15 max on 2 days (1) + compensation (2.8)
|
|
self.assertMemberAssign(self.sales_team_1_m3, 4) # 15 max on 2 days (1) + compensation (2.8)
|
|
self.assertMemberAssign(self.sales_team_convert_m1, 8) # 30 max on 15 (2) + compensation (5.6)
|
|
self.assertMemberAssign(self.sales_team_convert_m2, 15) # 60 max on 15 (4) + compensation (11.2)
|
|
|
|
@mute_logger('odoo.models.unlink', 'odoo.addons.crm.models.crm_team', 'odoo.addons.crm.models.crm_team_member')
|
|
def test_assign_perf_populated(self):
|
|
""" Test assignment on a more high volume oriented test set in order to
|
|
have more insights on query counts. """
|
|
# fix the seed and avoid randomness
|
|
random.seed(1871)
|
|
|
|
# create leads enough to have interesting counters
|
|
_lead_count, _email_dup_count, _partner_count = 600, 50, 150
|
|
leads = self._create_leads_batch(
|
|
lead_type='lead',
|
|
user_ids=[False],
|
|
partner_count=_partner_count,
|
|
country_ids=[self.env.ref('base.be').id, self.env.ref('base.fr').id, False],
|
|
count=_lead_count,
|
|
email_dup_count=_email_dup_count)
|
|
# commit probability and related fields
|
|
leads.flush()
|
|
self.assertInitialData()
|
|
|
|
# assign for one month, aka a lot
|
|
self.env.ref('crm.ir_cron_crm_lead_assign').write({'interval_type': 'days', 'interval_number': 30})
|
|
# create a third team
|
|
sales_team_3 = self.env['crm.team'].create({
|
|
'name': 'Sales Team 3',
|
|
'sequence': 15,
|
|
'alias_name': False,
|
|
'use_leads': True,
|
|
'use_opportunities': True,
|
|
'company_id': False,
|
|
'user_id': False,
|
|
'assignment_domain': [('country_id', '!=', False)],
|
|
})
|
|
sales_team_3_m1 = self.env['crm.team.member'].create({
|
|
'user_id': self.user_sales_manager.id,
|
|
'crm_team_id': sales_team_3.id,
|
|
'assignment_max': 60,
|
|
'assignment_domain': False,
|
|
})
|
|
sales_team_3_m2 = self.env['crm.team.member'].create({
|
|
'user_id': self.user_sales_leads.id,
|
|
'crm_team_id': sales_team_3.id,
|
|
'assignment_max': 60,
|
|
'assignment_domain': False,
|
|
})
|
|
sales_team_3_m3 = self.env['crm.team.member'].create({
|
|
'user_id': self.user_sales_salesman.id,
|
|
'crm_team_id': sales_team_3.id,
|
|
'assignment_max': 15,
|
|
'assignment_domain': [('probability', '>=', 10)],
|
|
})
|
|
sales_teams = self.sales_teams | sales_team_3
|
|
self.assertEqual(sum(team.assignment_max for team in sales_teams), 300)
|
|
self.assertEqual(len(leads), 650)
|
|
|
|
# assign probability to leads (bypass auto probability as purpose is not to test pls)
|
|
leads = self.env['crm.lead'].search([('id', 'in', leads.ids)]) # ensure order
|
|
for idx in range(0, 5):
|
|
sliced_leads = leads[idx:len(leads):5]
|
|
for lead in sliced_leads:
|
|
lead.probability = (idx + 1) * 10 * ((int(lead.priority) + 1) / 2)
|
|
# commit probability and related fields
|
|
leads.flush()
|
|
|
|
with self.with_user('user_sales_manager'):
|
|
with self.assertQueryCount(user_sales_manager=6487):
|
|
self.env['crm.team'].browse(sales_teams.ids)._action_assign_leads(work_days=30)
|
|
|
|
# teams assign
|
|
leads = self.env['crm.lead'].search([('id', 'in', leads.ids)])
|
|
self.assertEqual(leads.team_id, sales_teams)
|
|
self.assertEqual(leads.user_id, sales_teams.member_ids)
|
|
|
|
# salespersons assign
|
|
self.members.invalidate_cache(fnames=['lead_month_count'])
|
|
self.assertMemberAssign(self.sales_team_1_m1, 45) # 45 max on one month
|
|
self.assertMemberAssign(self.sales_team_1_m2, 15) # 15 max on one month
|
|
self.assertMemberAssign(self.sales_team_1_m3, 15) # 15 max on one month
|
|
self.assertMemberAssign(self.sales_team_convert_m1, 30) # 30 max on one month
|
|
self.assertMemberAssign(self.sales_team_convert_m2, 60) # 60 max on one month
|
|
self.assertMemberAssign(sales_team_3_m1, 60) # 60 max on one month
|
|
self.assertMemberAssign(sales_team_3_m2, 60) # 60 max on one month
|
|
self.assertMemberAssign(sales_team_3_m3, 15) # 15 max on one month
|