[IMP] crm: move and improve tests about merge and merge wizard
PURPOSE
As crm will soon evolve (onchange -> compute, code improvements, better
management of sales teams) cleaning and improving tests is necessary to avoid
regressions.
SPECIFICATIONS
Improve and clean tests about leads and opportunities merge.
Some strange behaviors spotted :
* user_id / team_id interaction is somehow unclear;
* probability is not taken into account in confidence level, which is very
very strange;
LINKS
Task ID 2180521 (add tests for crm wizards)
Task ID 2056759 (remove crm.partner.binding mixin)
Task ID 2088565 (crm onchange -> compute)
Community PR odoo/odoo#43473
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
from . import test_crm_lead
|
||||
from . import test_crm_lead_notification
|
||||
from . import test_crm_lead_convert
|
||||
from . import test_crm_lead_merge
|
||||
from . import test_crm_activity
|
||||
from . import test_crm_ui
|
||||
from . import test_crm_pls
|
||||
|
||||
@@ -82,110 +82,3 @@ class TestCRMLead(TestCrmCommon):
|
||||
new_partner = self.env['res.partner'].with_user(self.user_sales_manager).browse(new_partner_id)
|
||||
self.assertEqual(new_partner.email, 'unknown.sender@test.example.com')
|
||||
self.assertEqual(new_partner.team_id, self.sales_team_1)
|
||||
|
||||
def test_crm_lead_merge(self):
|
||||
# During a mixed merge (involving leads and opps), data should be handled a certain way following their type
|
||||
# (m2o, m2m, text, ...) Start by creating two leads and an opp and giving the rights of Sales manager.
|
||||
default_stage_id = self.stage_team1_1.id
|
||||
LeadSalesmanager = self.env['crm.lead'].with_user(self.user_sales_manager)
|
||||
|
||||
# TEST CASE 1
|
||||
test_crm_opp_01 = LeadSalesmanager.create({
|
||||
'type': 'opportunity',
|
||||
'name': 'Test opportunity 1',
|
||||
'partner_id': self.contact_2.id,
|
||||
'stage_id': default_stage_id,
|
||||
'description': 'This is the description of the test opp 1.'
|
||||
})
|
||||
|
||||
test_crm_lead_01 = LeadSalesmanager.create({
|
||||
'type': 'lead',
|
||||
'name': 'Test lead first',
|
||||
'partner_id': self.contact_1.id,
|
||||
'stage_id': default_stage_id,
|
||||
'description': 'This is the description of the test lead first.'
|
||||
})
|
||||
|
||||
test_crm_lead_02 = LeadSalesmanager.create({
|
||||
'type': 'lead',
|
||||
'name': 'Test lead second',
|
||||
'partner_id': self.contact_1.id,
|
||||
'stage_id': default_stage_id,
|
||||
'description': 'This is the description of the test lead second.'
|
||||
})
|
||||
|
||||
lead_ids = [test_crm_opp_01.id, test_crm_lead_01.id, test_crm_lead_02.id]
|
||||
additionnal_context = {'active_model': 'crm.lead', 'active_ids': lead_ids, 'active_id': lead_ids[0]}
|
||||
|
||||
# I create a merge wizard and merge the leads and opp together in the first item of the list.
|
||||
merge_opp_wizard_01 = self.env['crm.merge.opportunity'].with_user(self.user_sales_manager).with_context(**additionnal_context).create({})
|
||||
merge_opp_wizard_01.action_merge()
|
||||
|
||||
# I check for the resulting merged opp (based on name and partner)
|
||||
merged_lead = self.env['crm.lead'].search([('name', '=', 'Test opportunity 1'), ('partner_id', '=', self.contact_2.id)], limit=1)
|
||||
self.assertTrue(merged_lead, 'Fail to create merge opportunity wizard')
|
||||
self.assertEqual(merged_lead.description, 'This is the description of the test opp 1.\n\nThis is the description of the test lead first.\n\nThis is the description of the test lead second.', 'Description mismatch: when merging leads/opps with different text values, these values should get concatenated and separated with line returns')
|
||||
self.assertEqual(merged_lead.type, 'opportunity', 'Type mismatch: when at least one opp in involved in the merge, the result should be a new opp (instead of %s)' % merged_lead.type)
|
||||
|
||||
# The other (tailing) leads/opps shouldn't exist anymore
|
||||
self.assertFalse(test_crm_lead_01.exists(), 'This tailing lead (id %s) should not exist anymore' % test_crm_lead_02.id)
|
||||
self.assertFalse(test_crm_lead_02.exists(), 'This tailing opp (id %s) should not exist anymore' % test_crm_opp_01.id)
|
||||
|
||||
# TEST CASE 2
|
||||
# I want to test leads merge. Start by creating two leads (with the same partner)
|
||||
test_crm_lead_03 = LeadSalesmanager.create({
|
||||
'type': 'lead',
|
||||
'name': 'Test lead 3',
|
||||
'partner_id': self.contact_1.id,
|
||||
'stage_id': default_stage_id
|
||||
})
|
||||
|
||||
test_crm_lead_04 = LeadSalesmanager.create({
|
||||
'type': 'lead',
|
||||
'name': 'Test lead 4',
|
||||
'partner_id': self.contact_1.id,
|
||||
'stage_id': default_stage_id
|
||||
})
|
||||
|
||||
lead_ids = [test_crm_lead_03.id, test_crm_lead_04.id]
|
||||
additionnal_context = {'active_model': 'crm.lead', 'active_ids': lead_ids, 'active_id': lead_ids[0]}
|
||||
|
||||
# I create a merge wizard and merge the leads together.
|
||||
merge_opp_wizard_02 = self.env['crm.merge.opportunity'].with_user(self.user_sales_manager).with_context(**additionnal_context).create({})
|
||||
merge_opp_wizard_02.action_merge()
|
||||
|
||||
# I check for the resulting merged lead (based on name and partner)
|
||||
merged_lead = self.env['crm.lead'].search([('name', '=', 'Test lead 3'), ('partner_id', '=', self.contact_1.id)], limit=1)
|
||||
self.assertTrue(merged_lead, 'Fail to create merge opportunity wizard')
|
||||
self.assertEqual(merged_lead.partner_id.id, self.contact_1.id, 'Partner mismatch')
|
||||
self.assertEqual(merged_lead.type, 'lead', 'Type mismatch: when leads get merged together, the result should be a new lead (instead of %s)' % merged_lead.type)
|
||||
self.assertFalse(test_crm_lead_04.exists(), 'This tailing lead (id %s) should not exist anymore' % test_crm_lead_04.id)
|
||||
|
||||
# TEST CASE 3
|
||||
# I want to test opps merge. Start by creating two opportunities (with the same partner).
|
||||
test_crm_opp_02 = LeadSalesmanager.create({
|
||||
'type': 'opportunity',
|
||||
'name': 'Test opportunity 2',
|
||||
'partner_id': self.contact_2.id,
|
||||
'stage_id': default_stage_id
|
||||
})
|
||||
|
||||
test_crm_opp_03 = LeadSalesmanager.create({
|
||||
'type': 'opportunity',
|
||||
'name': 'Test opportunity 3',
|
||||
'partner_id': self.contact_2.id,
|
||||
'stage_id': default_stage_id
|
||||
})
|
||||
|
||||
opportunity_ids = [test_crm_opp_02.id, test_crm_opp_03.id]
|
||||
additionnal_context = {'active_model': 'crm.lead', 'active_ids': opportunity_ids, 'active_id': opportunity_ids[0]}
|
||||
|
||||
# I create a merge wizard and merge the opps together.
|
||||
merge_opp_wizard_03 = self.env['crm.merge.opportunity'].with_user(self.user_sales_manager).with_context(**additionnal_context).create({})
|
||||
merge_opp_wizard_03.action_merge()
|
||||
|
||||
merged_opportunity = self.env['crm.lead'].search([('name', '=', 'Test opportunity 2'), ('partner_id', '=', self.contact_2.id)], limit=1)
|
||||
self.assertTrue(merged_opportunity, 'Fail to create merge opportunity wizard')
|
||||
self.assertEqual(merged_opportunity.partner_id.id, self.contact_2.id, 'Partner mismatch')
|
||||
self.assertEqual(merged_opportunity.type, 'opportunity', 'Type mismatch: when opps get merged together, the result should be a new opp (instead of %s)' % merged_opportunity.type)
|
||||
self.assertFalse(test_crm_opp_03.exists(), 'This tailing opp (id %s) should not exist anymore' % test_crm_opp_03.id)
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo.addons.crm.tests.common import TestLeadConvertMassCommon
|
||||
from odoo.tests.common import tagged, users
|
||||
|
||||
|
||||
@tagged('lead_manage')
|
||||
class TestLeadMerge(TestLeadConvertMassCommon):
|
||||
""" During a mixed merge (involving leads and opps), data should be handled a certain way following their type
|
||||
(m2o, m2m, text, ...). """
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(TestLeadMerge, cls).setUpClass()
|
||||
|
||||
cls.leads = cls.lead_1 + cls.lead_w_partner + cls.lead_w_contact + cls.lead_w_email + cls.lead_w_partner_company + cls.lead_w_email_lost
|
||||
# reset some assigned users to test salesmen assign
|
||||
(cls.lead_w_partner | cls.lead_w_email_lost).write({
|
||||
'user_id': False
|
||||
})
|
||||
|
||||
cls.lead_w_contact.write({'description': 'lead_w_contact'})
|
||||
cls.lead_w_email.write({'description': 'lead_w_email'})
|
||||
cls.lead_1.write({'description': 'lead_1'})
|
||||
cls.lead_w_partner.write({'description': 'lead_w_partner'})
|
||||
|
||||
cls.assign_users = cls.user_sales_manager + cls.user_sales_leads_convert + cls.user_sales_salesman
|
||||
|
||||
@users('user_sales_manager')
|
||||
def test_lead_merge_internals(self):
|
||||
""" Test internals of merge wizard. In this test leads are ordered as
|
||||
|
||||
lead_w_contact --lead---seq=30
|
||||
lead_w_email ----lead---seq=3
|
||||
lead_1 ----------lead---seq=1
|
||||
lead_w_partner --lead---seq=False
|
||||
"""
|
||||
# ensure initial data
|
||||
self.assertEqual(self.lead_1.user_id, self.user_sales_leads)
|
||||
self.assertEqual(self.lead_1.team_id, self.sales_team_1)
|
||||
self.assertEqual(self.lead_1.stage_id, self.stage_team1_1)
|
||||
self.lead_w_partner_company.action_set_won() # won opps should be excluded
|
||||
|
||||
merge = self.env['crm.merge.opportunity'].with_context({
|
||||
'active_model': 'crm.lead',
|
||||
'active_ids': self.leads.ids,
|
||||
'active_id': False,
|
||||
}).create({
|
||||
'user_id': self.user_sales_leads_convert.id,
|
||||
})
|
||||
# check user correctly triggered its sales team
|
||||
merge._onchange_user()
|
||||
self.assertEqual(merge.team_id, self.sales_team_convert)
|
||||
|
||||
# TDE FIXME: not sure the browse in default get of wizard intended to exlude lost, as it browse ids
|
||||
# and exclude inactive leads, but that's not written anywhere ... intended ??
|
||||
self.assertEqual(merge.opportunity_ids, self.leads - self.lead_w_partner_company - self.lead_w_email_lost)
|
||||
ordered_merge = self.lead_w_contact + self.lead_w_email + self.lead_1 + self.lead_w_partner
|
||||
ordered_merge_description = '\n\n'.join(l.description for l in ordered_merge)
|
||||
|
||||
# merged opportunity: in this test, all input are leads. Confidence is based on stage
|
||||
# sequence -> lead_w_contact has a stage sequence of 30
|
||||
result = merge.action_merge()
|
||||
merge_opportunity = self.env['crm.lead'].browse(result['res_id'])
|
||||
self.assertFalse((ordered_merge - merge_opportunity).exists())
|
||||
self.assertEqual(merge_opportunity, self.lead_w_contact)
|
||||
self.assertEqual(merge_opportunity.type, 'lead')
|
||||
self.assertEqual(merge_opportunity.description, ordered_merge_description)
|
||||
# merged opportunity has updated salesman / team / stage is ok as generic
|
||||
self.assertEqual(merge_opportunity.user_id, self.user_sales_leads_convert)
|
||||
self.assertEqual(merge_opportunity.team_id, self.sales_team_convert)
|
||||
self.assertEqual(merge_opportunity.stage_id, self.stage_gen_1)
|
||||
|
||||
@users('user_sales_manager')
|
||||
def test_lead_merge_mixed(self):
|
||||
""" In case of mix, opportunities are on top, and result is an opportunity
|
||||
|
||||
lead_1 -------------------opp----seq=1
|
||||
lead_w_partner_company ---opp----seq=1 (ID greater)
|
||||
lead_w_contact -----------lead---seq=30
|
||||
lead_w_email -------------lead---seq=3
|
||||
lead_w_partner -----------lead---seq=False
|
||||
"""
|
||||
# ensure initial data
|
||||
(self.lead_w_partner_company | self.lead_1).write({'type': 'opportunity'})
|
||||
self.assertEqual(self.lead_w_partner_company.stage_id.sequence, 1)
|
||||
self.assertEqual(self.lead_1.stage_id.sequence, 1)
|
||||
|
||||
merge = self.env['crm.merge.opportunity'].with_context({
|
||||
'active_model': 'crm.lead',
|
||||
'active_ids': self.leads.ids,
|
||||
'active_id': False,
|
||||
}).create({
|
||||
'team_id': self.sales_team_convert.id,
|
||||
'user_id': False,
|
||||
})
|
||||
# TDE FIXME: see aa44700dccdc2618e0b8bc94252789264104047c -> no user, no team -> strange
|
||||
merge._onchange_user()
|
||||
merge.write({'team_id': self.sales_team_convert.id})
|
||||
|
||||
# TDE FIXME: not sure the browse in default get of wizard intended to exlude lost, as it browse ids
|
||||
# and exclude inactive leads, but that's not written anywhere ... intended ??
|
||||
self.assertEqual(merge.opportunity_ids, self.leads - self.lead_w_email_lost)
|
||||
ordered_merge = self.lead_w_partner_company + self.lead_w_contact + self.lead_w_email + self.lead_w_partner
|
||||
|
||||
result = merge.action_merge()
|
||||
merge_opportunity = self.env['crm.lead'].browse(result['res_id'])
|
||||
self.assertFalse((ordered_merge - merge_opportunity).exists())
|
||||
self.assertEqual(merge_opportunity, self.lead_1)
|
||||
self.assertEqual(merge_opportunity.type, 'opportunity')
|
||||
|
||||
# merged opportunity has same salesman (not updated in wizard)
|
||||
self.assertEqual(merge_opportunity.user_id, self.user_sales_leads)
|
||||
# TDE FIXME: as same uer_id is enforced, team is updated through onchange and therefore stage
|
||||
# self.assertEqual(merge_opportunity.team_id, self.sales_team_convert)
|
||||
self.assertEqual(merge_opportunity.team_id, self.sales_team_1)
|
||||
# TDE FIXME: BUT team_id is computed after checking stage, based on wizard's team_id
|
||||
self.assertEqual(merge_opportunity.stage_id, self.stage_team_convert_1)
|
||||
Reference in New Issue
Block a user