[REF] sales_team, various: improve default team computation
GLOBAl PURPOSE Ability to have salesmen belonging to several sales team is a core requirement of CRM. It is therefore moved from website_crm_score to crm along with cleaning and behavior improvement. Automatic lead assignment is also moved and cleaned. SPECIFICATIONS Compute default team id for sales related documents. Note that this method is not called by default_get as it takes some additional parameters and is meant to be called by other default methods. Heuristic (when multiple match: take first sequence ordered) 1- any of my teams (member OR responsible) matching domain 2- any of my teams (member OR responsible) 3- default from context 4- any team matching my company and domain 5- any team matching my company Note: ResPartner.team_id field is explicitly not taken into account. We think this field causes a lot of noises compared to its added value. Think notably: team not in responsible teams, team company not matching responsible or lead company, asked domain not matching, ... We also improve various places where sale team is computed on sales documents. Purpose is to try to use same heuristic as much as possible in various team_id fields. LINKS Task ID-2086889 (main task) Task ID-2357969 (scoring migration task) Community PR odoo/odoo#48422 Enterprise PR odoo/enterprise#499 Upgrade PR odoo/upgrade#996
This commit is contained in:
@@ -166,7 +166,7 @@ class TestLeadConvertMass(crm_common.TestLeadConvertMassCommon):
|
||||
test_leads = self._create_leads_batch(count=50, user_ids=[False])
|
||||
user_ids = self.assign_users.ids
|
||||
|
||||
with self.assertQueryCount(user_sales_manager=1363): # crm only: 1352
|
||||
with self.assertQueryCount(user_sales_manager=1364): # crm only: 1353
|
||||
mass_convert = self.env['crm.lead2opportunity.partner.mass'].with_context({
|
||||
'active_model': 'crm.lead',
|
||||
'active_ids': test_leads.ids,
|
||||
|
||||
@@ -101,8 +101,7 @@ class Lead2OpportunityPartner(models.TransientModel):
|
||||
user = convert.user_id
|
||||
if convert.team_id and user in convert.team_id.member_ids | convert.team_id.user_id:
|
||||
continue
|
||||
team_domain = []
|
||||
team = self.env['crm.team']._get_default_team_id(user_id=user.id, domain=team_domain)
|
||||
team = self.env['crm.team']._get_default_team_id(user_id=user.id, domain=None)
|
||||
convert.team_id = team.id
|
||||
|
||||
@api.model
|
||||
|
||||
@@ -50,8 +50,7 @@ class Lead2OpportunityMassConvert(models.TransientModel):
|
||||
user = convert.user_id or convert.user_ids and convert.user_ids[0] or self.env.user
|
||||
if convert.team_id and user in convert.team_id.member_ids | convert.team_id.user_id:
|
||||
continue
|
||||
team_domain = []
|
||||
team = self.env['crm.team']._get_default_team_id(user_id=user.id, domain=team_domain)
|
||||
team = self.env['crm.team']._get_default_team_id(user_id=user.id, domain=None)
|
||||
convert.team_id = team.id
|
||||
|
||||
@api.depends('lead_tomerge_ids')
|
||||
|
||||
@@ -104,10 +104,20 @@ class CRMLeadMiningRequest(models.Model):
|
||||
for request in self:
|
||||
request.lead_count = mapped_data.get(request.id, 0)
|
||||
|
||||
@api.depends('user_id')
|
||||
@api.depends('user_id', 'lead_type')
|
||||
def _compute_team_id(self):
|
||||
for record in self:
|
||||
record.team_id = record.user_id.sale_team_id
|
||||
""" When changing the user, also set a team_id or restrict team id
|
||||
to the ones user_id is member of. """
|
||||
for mining in self:
|
||||
# setting user as void should not trigger a new team computation
|
||||
if not mining.user_id:
|
||||
continue
|
||||
user = mining.user_id
|
||||
if mining.team_id and user in mining.team_id.member_ids | mining.team_id.user_id:
|
||||
continue
|
||||
team_domain = [('use_leads', '=', True)] if mining.lead_type == 'lead' else [('use_opportunities', '=', True)]
|
||||
team = self.env['crm.team']._get_default_team_id(user_id=user.id, domain=team_domain)
|
||||
mining.team_id = team.id
|
||||
|
||||
@api.onchange('lead_number')
|
||||
def _onchange_lead_number(self):
|
||||
|
||||
@@ -407,7 +407,7 @@ class SaleOrder(models.Model):
|
||||
if self.user_id:
|
||||
self.team_id = self.env['crm.team'].with_context(
|
||||
default_team_id=self.team_id.id
|
||||
)._get_default_team_id(user_id=self.user_id.id)
|
||||
)._get_default_team_id(user_id=self.user_id.id, domain=None)
|
||||
|
||||
@api.onchange('partner_id')
|
||||
def onchange_partner_id_warning(self):
|
||||
|
||||
@@ -20,17 +20,57 @@ class CrmTeam(models.Model):
|
||||
_check_company_auto = True
|
||||
|
||||
def _get_default_team_id(self, user_id=None, domain=None):
|
||||
if user_id is None:
|
||||
user_id = self.env.user.id
|
||||
""" Compute default team id for sales related documents. Note that this
|
||||
method is not called by default_get as it takes some additional
|
||||
parameters and is meant to be called by other default methods.
|
||||
|
||||
team = self.env['crm.team'].search([
|
||||
('company_id', 'in', [False, self.env.company.id]),
|
||||
'|', ('user_id', '=', user_id), ('member_ids', 'in', [user_id]),
|
||||
], limit=1)
|
||||
Heuristic (when multiple match: take first sequence ordered)
|
||||
|
||||
1- any of my teams (member OR responsible) matching domain
|
||||
2- any of my teams (member OR responsible)
|
||||
3- default from context
|
||||
4- any team matching my company and domain
|
||||
5- any team matching my company
|
||||
|
||||
Note: ResPartner.team_id field is explicitly not taken into account. We
|
||||
think this field causes a lot of noises compared to its added value.
|
||||
Think notably: team not in responsible teams, team company not matching
|
||||
responsible or lead company, asked domain not matching, ...
|
||||
|
||||
:param user_id: salesperson to target, fallback on env.uid;
|
||||
:domain: optional domain to filter teams (like use_lead = True);
|
||||
"""
|
||||
if user_id is None:
|
||||
user = self.env.user
|
||||
else:
|
||||
user = self.env['res.users'].sudo().browse(user_id)
|
||||
valid_cids = [False] + user.company_ids.ids
|
||||
|
||||
# 1- find in user memberships - note that if current user in C1 searches
|
||||
# for team belonging to a user in C1/C2 -> only results for C1 will be returned
|
||||
team = self.env['crm.team']
|
||||
teams = self.env['crm.team'].search([
|
||||
('company_id', 'in', valid_cids),
|
||||
'|', ('user_id', '=', user.id), ('member_ids', 'in', [user.id]),
|
||||
])
|
||||
if teams and domain:
|
||||
team = teams.filtered_domain(domain)[:1]
|
||||
# 2- any of my teams
|
||||
if not team:
|
||||
team = teams[:1]
|
||||
|
||||
# 3- default: context
|
||||
if not team and 'default_team_id' in self.env.context:
|
||||
team = self.env['crm.team'].browse(self.env.context.get('default_team_id'))
|
||||
|
||||
# 4- default: first one matching domain, then first one
|
||||
if not team:
|
||||
team = self.env['crm.team'].search(domain or [], limit=1)
|
||||
teams = self.env['crm.team'].search([('company_id', 'in', valid_cids)])
|
||||
if teams and domain:
|
||||
team = teams.filtered_domain(domain)[:1]
|
||||
if not team:
|
||||
team = teams[:1]
|
||||
|
||||
return team
|
||||
|
||||
def _get_default_favorite_user_ids(self):
|
||||
|
||||
Reference in New Issue
Block a user