[FIX] crm: fix date_{last_stage_update/open} update issues

Before this commit:
  * when a user changes 'user_id' to set the same previous 'user_id', the
    assign date 'date_open' is updated but it should not as the responsible
    did not change;
  * when a user changes the salesperson 'user_id' of a crm lead, it triggers
    a recompute of 'team_id' that triggers a recompute of 'stage_id' that
    updates  'date_last_stage_update' even if the stage does not change, which
    happens frequently when changing leads within a given team (new assign,
    salesperson on holidays, ...)
  * when merging opportunities, 'user_id' can be set on the main opportunity
    which triggers a recomputation of both 'date_last_stage_update' and
    'date_open' as explained in above points;

Reason:
The 'date_last_stage_update' field depends on 'stage_id' which depends on
'team_id' which depends on 'user_id'. As a result, when 'user_id' changes,
'date_last_stage_update' also updates.

Moreover those fields are implemented using editable stored computed fields
which are triggered everytime a value is given to those fields, even when
the same value is given.

After this commit:
'date_last_stage_update' and 'date_open' will only update when there are
real changes.

Task-3515225

X-original-commit: 8dc18806847e5240dba6f05bdd80d313bf466ebf
Part-of: odoo/odoo#161918
This commit is contained in:
Jay Savaliya
2024-04-16 07:02:57 +00:00
committed by Thibault Delavallée
parent 7eeeb52f44
commit 1e45ec7b36
2 changed files with 43 additions and 21 deletions
+33 -11
View File
@@ -297,7 +297,8 @@ class Lead(models.Model):
continue
team_domain = [('use_leads', '=', True)] if lead.type == 'lead' else [('use_opportunities', '=', True)]
team = self.env['crm.team']._get_default_team_id(user_id=user.id, domain=team_domain)
lead.team_id = team.id
if lead.team_id != team:
lead.team_id = team.id
@api.depends('user_id', 'team_id', 'partner_id')
def _compute_company_id(self):
@@ -345,12 +346,14 @@ class Lead(models.Model):
@api.depends('user_id')
def _compute_date_open(self):
for lead in self:
lead.date_open = self.env.cr.now() if lead.user_id else False
if not lead.date_open and lead.user_id:
lead.date_open = self.env.cr.now()
@api.depends('stage_id')
def _compute_date_last_stage_update(self):
for lead in self:
lead.date_last_stage_update = self.env.cr.now()
if not lead.date_last_stage_update:
lead.date_last_stage_update = self.env.cr.now()
@api.depends('create_date', 'date_open')
def _compute_day_open(self):
@@ -767,13 +770,27 @@ class Lead(models.Model):
if vals.get('website'):
vals['website'] = self.env['res.partner']._clean_website(vals['website'])
stage_updated, stage_is_won = vals.get('stage_id'), False
# stage change: update date_last_stage_update
if stage_updated:
stage = self.env['crm.stage'].browse(vals['stage_id'])
if stage.is_won:
vals.update({'probability': 100, 'automated_probability': 100})
stage_is_won = True
now = self.env.cr.now()
stage_updated, stage_is_won = False, False
# stage change (or reset): update date_last_stage_update if at least one
# lead does not have the same stage
if 'stage_id' in vals:
stage_updated = any(lead.stage_id.id != vals['stage_id'] for lead in self)
if stage_updated:
vals['date_last_stage_update'] = now
if stage_updated and vals.get('stage_id'):
stage = self.env['crm.stage'].browse(vals['stage_id'])
if stage.is_won:
vals.update({'probability': 100, 'automated_probability': 100})
stage_is_won = True
# user change; update date_open if at least one lead does not
# have the same user
if 'user_id' in vals and not vals.get('user_id'):
vals['date_open'] = False
elif vals.get('user_id'):
user_updated = any(lead.user_id.id != vals['user_id'] for lead in self)
if user_updated:
vals['date_open'] = now
# stage change with new stage: update probability and date_closed
if vals.get('probability', 0) >= 100 or not vals.get('active', True):
@@ -1432,7 +1449,12 @@ class Lead(models.Model):
if merged_data.get('stage_id') not in team_stage_ids.ids:
merged_data['stage_id'] = team_stage_ids[0].id if team_stage_ids else False
# write merged data into first opportunity
# write merged data into first opportunity; remove some keys if already
# set on opp to avoid useless recomputes
if 'user_id' in merged_data and opportunities_head.user_id.id == merged_data['user_id']:
merged_data.pop('user_id')
if 'team_id' in merged_data and opportunities_head.team_id.id == merged_data['team_id']:
merged_data.pop('team_id')
opportunities_head.write(merged_data)
# delete tail opportunities
+10 -10
View File
@@ -680,17 +680,17 @@ class TestCRMLead(TestCrmCommon):
self.assertEqual(lead.stage_id, self.stage_team1_1)
self.assertEqual(lead.team_id, self.sales_team_1)
self.assertEqual(
leads[0].date_last_stage_update, updated_time,
'FIXME: set same stage when changing user_id, should not update')
leads[0].date_last_stage_update, first_now,
'Setting same stage when changing user_id, should not update')
self.assertEqual(
leads[0].date_open, updated_time,
'User assigned -> assign date updated')
self.assertEqual(
leads[1].date_last_stage_update, updated_time,
'FIXME: set same stage when changing user_id, should not update')
leads[1].date_last_stage_update, first_now,
'Setting same stage when changing user_id, should not update')
self.assertEqual(
leads[1].date_open, updated_time,
'FIXME: Should not update date_open, was already the same user_id')
'Should not update date_open, was already the same user_id, but done in batch so ...')
# set won changes stage -> update date_last_stage_update
newer_time = datetime(2023, 11, 26, 8, 0, 0)
@@ -713,16 +713,16 @@ class TestCRMLead(TestCrmCommon):
auto_unlink=False,
)
leads.flush_recordset()
self.assertEqual(leads[0].date_last_stage_update, updated_time)
self.assertEqual(leads[0].date_last_stage_update, first_now)
self.assertEqual(leads[0].date_open, updated_time)
self.assertEqual(leads[0].stage_id, self.stage_team1_1)
self.assertEqual(leads[0].team_id, self.sales_team_1)
self.assertEqual(
leads[1].date_last_stage_update, last_time,
'FIXME: should not rewrite when setting same stage')
leads[1].date_last_stage_update, newer_time,
'Should not rewrite when setting same stage')
self.assertEqual(
leads[1].date_open, last_time,
'FIXME: should not rewrite when setting same user_id')
leads[1].date_open, updated_time,
'Should not rewrite when setting same user_id')
self.assertEqual(leads[1].stage_id, self.stage_gen_won)
self.assertEqual(leads[1].team_id, self.sales_team_1)
self.assertEqual(leads[1].user_id, self.user_sales_salesman)