diff options
| author | Thibault Delavallée <tde@odoo.com> | 2020-10-05 14:17:28 +0000 |
|---|---|---|
| committer | Thibault Delavallée <tde@odoo.com> | 2020-10-06 14:47:39 +0000 |
| commit | 950dd491bc4b680e0bcfab83815313e909a3c282 (patch) | |
| tree | e4fd4941f2dc8c8475b5a1c179aed55de5a0abb2 | |
| parent | f21b3c5cff74f935f0f221d1b690f4a4fb44e003 (diff) | |
[IMP] crm: move and add some test for lead user assign
Purpose of this commit is to
* move tests about mass management of leads (mass assignment + mass convert
wizards) in its own file to ease writing of tests;
* add some performance tests :
* performance for assignment;
* performance for convert wizard in mass mode;
Task ID-2351604
PR #59084
| -rw-r--r-- | addons/crm/tests/__init__.py | 1 | ||||
| -rw-r--r-- | addons/crm/tests/common.py | 22 | ||||
| -rw-r--r-- | addons/crm/tests/test_crm_activity.py | 3 | ||||
| -rw-r--r-- | addons/crm/tests/test_crm_lead_convert.py | 144 | ||||
| -rw-r--r-- | addons/crm/tests/test_crm_lead_convert_mass.py | 212 | ||||
| -rw-r--r-- | addons/sales_team/tests/common.py | 18 |
6 files changed, 250 insertions, 150 deletions
diff --git a/addons/crm/tests/__init__.py b/addons/crm/tests/__init__.py index e8c18d42468..793d217c703 100644 --- a/addons/crm/tests/__init__.py +++ b/addons/crm/tests/__init__.py @@ -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_convert_mass from . import test_crm_lead_lost from . import test_crm_lead_merge from . import test_crm_activity diff --git a/addons/crm/tests/common.py b/addons/crm/tests/common.py index b94acd89b03..f46e1fd265f 100644 --- a/addons/crm/tests/common.py +++ b/addons/crm/tests/common.py @@ -6,6 +6,7 @@ from unittest.mock import patch from odoo.addons.mail.tests.common import MailCase, mail_new_test_user from odoo.addons.sales_team.tests.common import TestSalesCommon from odoo.fields import Datetime +from odoo import tools INCOMING_EMAIL = """Return-Path: {return_path} X-Original-To: {to} @@ -150,7 +151,7 @@ class TestCrmCommon(TestSalesCommon, MailCase): 'zip': '97648', }) - def _create_leads_batch(self, lead_type='lead', count=10): + def _create_leads_batch(self, lead_type='lead', count=10, partner_ids=None, user_ids=None): """ Helper tool method creating a batch of leads, useful when dealing with batch processes. Please update me. @@ -158,14 +159,28 @@ class TestCrmCommon(TestSalesCommon, MailCase): None (depends on configuration); """ types = ['lead', 'opportunity'] - partners = [self.contact_1.id, self.contact_2.id, False] leads_data = [{ 'name': 'TestLead_%02d' % (x), 'type': lead_type if lead_type else types[x % 2], - 'partner_id': partners[x % 3], 'priority': '%s' % (x % 3), } for x in range(count)] + # customer information + if partner_ids: + for idx, lead_data in enumerate(leads_data): + lead_data['partner_id'] = partner_ids[idx % len(partner_ids)] + else: + for idx, lead_data in enumerate(leads_data): + lead_data['email_from'] = tools.formataddr(( + 'TestCustomer_%02d' % (idx), + 'customer_email_%02d@example.com' % (idx) + )) + + # salesteam information + if user_ids: + for idx, lead_data in enumerate(leads_data): + lead_data['user_id'] = user_ids[idx % len(user_ids)] + return self.env['crm.lead'].create(leads_data) def _create_duplicates(self, lead, create_opp=True): @@ -247,6 +262,7 @@ class TestLeadConvertCommon(TestCrmCommon): cls.sales_team_convert = cls.env['crm.team'].create({ 'name': 'Convert Sales Team', + 'sequence': 10, 'alias_name': False, 'use_leads': True, 'use_opportunities': True, diff --git a/addons/crm/tests/test_crm_activity.py b/addons/crm/tests/test_crm_activity.py index 6f57b5dbd19..44eb0310492 100644 --- a/addons/crm/tests/test_crm_activity.py +++ b/addons/crm/tests/test_crm_activity.py @@ -42,7 +42,7 @@ class TestCrmMailActivity(TestCrmCommon): # Initialize some batch data default_order = self.env['crm.lead']._order self.assertEqual(default_order, "priority desc, id desc") # force updating this test is order changes - test_leads = self._create_leads_batch(count=10).sorted('id') + test_leads = self._create_leads_batch(count=10, partner_ids=[self.contact_1.id, self.contact_2.id, False]).sorted('id') # assert initial data, ensure we did not break base behavior for lead in test_leads: @@ -108,7 +108,6 @@ class TestCrmMailActivity(TestCrmCommon): search_res = self.env['crm.lead'].search(_domain, limit=None, offset=3, order=_order) self.assertEqual(expected_leads_desc[3:].ids, search_res.ids) - def test_crm_activity_recipients(self): """ This test case checks - no internal subtype followed by client diff --git a/addons/crm/tests/test_crm_lead_convert.py b/addons/crm/tests/test_crm_lead_convert.py index e830e0888d1..71532306629 100644 --- a/addons/crm/tests/test_crm_lead_convert.py +++ b/addons/crm/tests/test_crm_lead_convert.py @@ -406,147 +406,3 @@ class TestLeadConvertBatch(crm_common.TestLeadConvertMassCommon): self.assertEqual(opp.stage_id, self.stage_gen_1) # did not change else: self.assertFalse(True) - - -@tagged('lead_manage') -class TestLeadConvertMass(crm_common.TestLeadConvertMassCommon): - - @classmethod - def setUpClass(cls): - super(TestLeadConvertMass, cls).setUpClass() - - cls.leads = cls.lead_1 + cls.lead_w_partner + cls.lead_w_email_lost - cls.assign_users = cls.user_sales_manager + cls.user_sales_leads_convert + cls.user_sales_salesman - - @users('user_sales_manager') - def test_mass_convert_internals(self): - """ Test internals mass converted in convert mode, without duplicate management """ - # reset some assigned users to test salesmen assign - (self.lead_w_partner | self.lead_w_email_lost).write({ - 'user_id': False - }) - - mass_convert = self.env['crm.lead2opportunity.partner.mass'].with_context({ - 'active_model': 'crm.lead', - 'active_ids': self.leads.ids, - 'active_id': self.leads.ids[0] - }).create({ - 'deduplicate': False, - 'user_id': self.user_sales_salesman.id, - 'force_assignment': False, - }) - - # default values - self.assertEqual(mass_convert.name, 'convert') - self.assertEqual(mass_convert.action, 'each_exist_or_create') - # depending on options - self.assertEqual(mass_convert.partner_id, self.env['res.partner']) - self.assertEqual(mass_convert.deduplicate, False) - self.assertEqual(mass_convert.user_id, self.user_sales_salesman) - self.assertEqual(mass_convert.team_id, self.sales_team_convert) - - mass_convert.action_mass_convert() - for lead in self.lead_1 | self.lead_w_partner: - self.assertEqual(lead.type, 'opportunity') - if lead == self.lead_w_partner: - self.assertEqual(lead.user_id, self.env['res.users']) # user_id is bypassed - self.assertEqual(lead.partner_id, self.contact_1) - elif lead == self.lead_1: - self.assertEqual(lead.user_id, self.user_sales_leads) # existing value not forced - new_partner = lead.partner_id - self.assertEqual(new_partner.name, 'Amy Wong') - self.assertEqual(new_partner.email, 'amy.wong@test.example.com') - - # test unforced assignation - mass_convert.write({ - 'user_ids': self.user_sales_salesman.ids, - }) - mass_convert.action_mass_convert() - self.assertEqual(self.lead_w_partner.user_id, self.user_sales_salesman) - self.assertEqual(self.lead_1.user_id, self.user_sales_leads) # existing value not forced - - # lost leads are untouched - self.assertEqual(self.lead_w_email_lost.type, 'lead') - self.assertFalse(self.lead_w_email_lost.active) - self.assertFalse(self.lead_w_email_lost.date_conversion) - # TDE FIXME: partner creation is done even on lost leads because not checked in wizard - # self.assertEqual(self.lead_w_email_lost.partner_id, self.env['res.partner']) - - def test_mass_convert_deduplicate(self): - """ Test duplicated_lead_ids fields having another behavior in mass convert - because why not. Its use is: among leads under convert, store those with - duplicates if deduplicate is set to True. """ - lead_1_dups = self._create_duplicates(self.lead_1, create_opp=False) - lead_1_final = self.lead_1 # after merge: same but with lower ID - - lead_w_partner_dups = self._create_duplicates(self.lead_w_partner, create_opp=False) - lead_w_partner_final = lead_w_partner_dups[0] # lead_w_partner has no stage -> lower in sort by confidence - lead_w_partner_dups_partner = lead_w_partner_dups[1] # copy with a partner_id (with the same email) - - mass_convert = self.env['crm.lead2opportunity.partner.mass'].with_context({ - 'active_model': 'crm.lead', - 'active_ids': self.leads.ids, - }).create({ - 'deduplicate': True, - }) - self.assertEqual(mass_convert.action, 'each_exist_or_create') - self.assertEqual(mass_convert.name, 'convert') - self.assertEqual(mass_convert.lead_tomerge_ids, self.leads) - self.assertEqual(mass_convert.duplicated_lead_ids, self.lead_1 | self.lead_w_partner) - - mass_convert.action_mass_convert() - - self.assertEqual( - (lead_1_dups | lead_w_partner_dups | lead_w_partner_dups_partner).exists(), - lead_w_partner_final - ) - for lead in lead_1_final | lead_w_partner_final: - self.assertTrue(lead.active) - self.assertEqual(lead.type, 'opportunity') - - def test_mass_convert_find_existing(self): - """ Check that we don't find a wrong partner - that have similar name during mass conversion - """ - wrong_partner = self.env['res.partner'].create({ - 'name': 'casa depapel', - 'street': "wrong street" - }) - - lead = self.env['crm.lead'].create({'name': 'Asa Depape'}) - mass_convert = self.env['crm.lead2opportunity.partner.mass'].with_context({ - 'active_model': 'crm.lead', - 'active_ids': lead.ids, - 'active_id': lead.ids[0] - }).create({ - 'deduplicate': False, - 'action': 'each_exist_or_create', - 'name': 'convert', - }) - mass_convert.action_mass_convert() - - self.assertNotEqual(lead.partner_id, wrong_partner, "Partner Id should not match the wrong contact") - - def test_mass_convert_w_salesmen(self): - # reset some assigned users to test salesmen assign - (self.lead_w_partner | self.lead_w_email_lost).write({ - 'user_id': False - }) - - mass_convert = self.env['crm.lead2opportunity.partner.mass'].with_context({ - 'active_model': 'crm.lead', - 'active_ids': self.leads.ids, - 'active_id': self.leads.ids[0] - }).create({ - 'deduplicate': False, - 'user_ids': self.assign_users.ids, - 'force_assignment': True, - }) - - # TDE FIXME: what happens if we mix people from different sales team ? currently nothing, to check - mass_convert.action_mass_convert() - - for idx, lead in enumerate(self.leads - self.lead_w_email_lost): - self.assertEqual(lead.type, 'opportunity') - assigned_user = self.assign_users[idx % len(self.assign_users)] - self.assertEqual(lead.user_id, assigned_user) diff --git a/addons/crm/tests/test_crm_lead_convert_mass.py b/addons/crm/tests/test_crm_lead_convert_mass.py new file mode 100644 index 00000000000..05c347301a6 --- /dev/null +++ b/addons/crm/tests/test_crm_lead_convert_mass.py @@ -0,0 +1,212 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo.addons.crm.tests import common as crm_common +from odoo.tests.common import tagged, users + + +@tagged('lead_manage') +class TestLeadConvertMass(crm_common.TestLeadConvertMassCommon): + + @classmethod + def setUpClass(cls): + super(TestLeadConvertMass, cls).setUpClass() + + cls.leads = cls.lead_1 + cls.lead_w_partner + cls.lead_w_email_lost + cls.assign_users = cls.user_sales_manager + cls.user_sales_leads_convert + cls.user_sales_salesman + + @users('user_sales_manager') + def test_assignment_salesmen(self): + test_leads = self._create_leads_batch(count=50, user_ids=[False]) + user_ids = self.assign_users.ids + self.assertEqual(test_leads.user_id, self.env['res.users']) + + with self.assertQueryCount(user_sales_manager=0): + test_leads = self.env['crm.lead'].browse(test_leads.ids) + + with self.assertQueryCount(user_sales_manager=330): + test_leads.handle_salesmen_assignment(user_ids=user_ids, team_id=False) + + self.assertEqual(test_leads.team_id, self.sales_team_convert | self.sales_team_1) + self.assertEqual(test_leads[0::3].user_id, self.user_sales_manager) + self.assertEqual(test_leads[1::3].user_id, self.user_sales_leads_convert) + self.assertEqual(test_leads[2::3].user_id, self.user_sales_salesman) + + @users('user_sales_manager') + def test_assignment_salesmen_wteam(self): + test_leads = self._create_leads_batch(count=50, user_ids=[False]) + user_ids = self.assign_users.ids + team_id = self.sales_team_convert.id + self.assertEqual(test_leads.user_id, self.env['res.users']) + + with self.assertQueryCount(user_sales_manager=0): + test_leads = self.env['crm.lead'].browse(test_leads.ids) + + with self.assertQueryCount(user_sales_manager=342): + test_leads.handle_salesmen_assignment(user_ids=user_ids, team_id=team_id) + + self.assertEqual(test_leads.team_id, self.sales_team_convert) + self.assertEqual(test_leads[0::3].user_id, self.user_sales_manager) + self.assertEqual(test_leads[1::3].user_id, self.user_sales_leads_convert) + self.assertEqual(test_leads[2::3].user_id, self.user_sales_salesman) + + @users('user_sales_manager') + def test_mass_convert_internals(self): + """ Test internals mass converted in convert mode, without duplicate management """ + # reset some assigned users to test salesmen assign + (self.lead_w_partner | self.lead_w_email_lost).write({ + 'user_id': False + }) + + mass_convert = self.env['crm.lead2opportunity.partner.mass'].with_context({ + 'active_model': 'crm.lead', + 'active_ids': self.leads.ids, + 'active_id': self.leads.ids[0] + }).create({ + 'deduplicate': False, + 'user_id': self.user_sales_salesman.id, + 'force_assignment': False, + }) + + # default values + self.assertEqual(mass_convert.name, 'convert') + self.assertEqual(mass_convert.action, 'each_exist_or_create') + # depending on options + self.assertEqual(mass_convert.partner_id, self.env['res.partner']) + self.assertEqual(mass_convert.deduplicate, False) + self.assertEqual(mass_convert.user_id, self.user_sales_salesman) + self.assertEqual(mass_convert.team_id, self.sales_team_convert) + + mass_convert.action_mass_convert() + for lead in self.lead_1 | self.lead_w_partner: + self.assertEqual(lead.type, 'opportunity') + if lead == self.lead_w_partner: + self.assertEqual(lead.user_id, self.env['res.users']) # user_id is bypassed + self.assertEqual(lead.partner_id, self.contact_1) + elif lead == self.lead_1: + self.assertEqual(lead.user_id, self.user_sales_leads) # existing value not forced + new_partner = lead.partner_id + self.assertEqual(new_partner.name, 'Amy Wong') + self.assertEqual(new_partner.email, 'amy.wong@test.example.com') + + # test unforced assignation + mass_convert.write({ + 'user_ids': self.user_sales_salesman.ids, + }) + mass_convert.action_mass_convert() + self.assertEqual(self.lead_w_partner.user_id, self.user_sales_salesman) + self.assertEqual(self.lead_1.user_id, self.user_sales_leads) # existing value not forced + + # lost leads are untouched + self.assertEqual(self.lead_w_email_lost.type, 'lead') + self.assertFalse(self.lead_w_email_lost.active) + self.assertFalse(self.lead_w_email_lost.date_conversion) + # TDE FIXME: partner creation is done even on lost leads because not checked in wizard + # self.assertEqual(self.lead_w_email_lost.partner_id, self.env['res.partner']) + + @users('user_sales_manager') + def test_mass_convert_deduplicate(self): + """ Test duplicated_lead_ids fields having another behavior in mass convert + because why not. Its use is: among leads under convert, store those with + duplicates if deduplicate is set to True. """ + lead_1_dups = self._create_duplicates(self.lead_1, create_opp=False) + lead_1_final = self.lead_1 # after merge: same but with lower ID + + lead_w_partner_dups = self._create_duplicates(self.lead_w_partner, create_opp=False) + lead_w_partner_final = lead_w_partner_dups[0] # lead_w_partner has no stage -> lower in sort by confidence + lead_w_partner_dups_partner = lead_w_partner_dups[1] # copy with a partner_id (with the same email) + + mass_convert = self.env['crm.lead2opportunity.partner.mass'].with_context({ + 'active_model': 'crm.lead', + 'active_ids': self.leads.ids, + }).create({ + 'deduplicate': True, + }) + self.assertEqual(mass_convert.action, 'each_exist_or_create') + self.assertEqual(mass_convert.name, 'convert') + self.assertEqual(mass_convert.lead_tomerge_ids, self.leads) + self.assertEqual(mass_convert.duplicated_lead_ids, self.lead_1 | self.lead_w_partner) + + mass_convert.action_mass_convert() + + self.assertEqual( + (lead_1_dups | lead_w_partner_dups | lead_w_partner_dups_partner).exists(), + lead_w_partner_final + ) + for lead in lead_1_final | lead_w_partner_final: + self.assertTrue(lead.active) + self.assertEqual(lead.type, 'opportunity') + + @users('user_sales_manager') + def test_mass_convert_find_existing(self): + """ Check that we don't find a wrong partner + that have similar name during mass conversion + """ + wrong_partner = self.env['res.partner'].create({ + 'name': 'casa depapel', + 'street': "wrong street" + }) + + lead = self.env['crm.lead'].create({'name': 'Asa Depape'}) + mass_convert = self.env['crm.lead2opportunity.partner.mass'].with_context({ + 'active_model': 'crm.lead', + 'active_ids': lead.ids, + 'active_id': lead.ids[0] + }).create({ + 'deduplicate': False, + 'action': 'each_exist_or_create', + 'name': 'convert', + }) + mass_convert.action_mass_convert() + + self.assertNotEqual(lead.partner_id, wrong_partner, "Partner Id should not match the wrong contact") + + @users('user_sales_manager') + def test_mass_convert_performances(self): + test_leads = self._create_leads_batch(count=50, user_ids=[False]) + user_ids = self.assign_users.ids + + with self.assertQueryCount(user_sales_manager=1472): + mass_convert = self.env['crm.lead2opportunity.partner.mass'].with_context({ + 'active_model': 'crm.lead', + 'active_ids': test_leads.ids, + }).create({ + 'deduplicate': True, + 'user_ids': user_ids, + 'force_assignment': True, + }) + mass_convert.action_mass_convert() + + self.assertEqual(set(test_leads.mapped('type')), set(['opportunity'])) + self.assertEqual(len(test_leads.partner_id), len(test_leads)) + # TDE FIXME: strange + # self.assertEqual(test_leads.team_id, self.sales_team_convert | self.sales_team_1) + self.assertEqual(test_leads.team_id, self.sales_team_1) + self.assertEqual(test_leads[0::3].user_id, self.user_sales_manager) + self.assertEqual(test_leads[1::3].user_id, self.user_sales_leads_convert) + self.assertEqual(test_leads[2::3].user_id, self.user_sales_salesman) + + @users('user_sales_manager') + def test_mass_convert_w_salesmen(self): + # reset some assigned users to test salesmen assign + (self.lead_w_partner | self.lead_w_email_lost).write({ + 'user_id': False + }) + + mass_convert = self.env['crm.lead2opportunity.partner.mass'].with_context({ + 'active_model': 'crm.lead', + 'active_ids': self.leads.ids, + 'active_id': self.leads.ids[0] + }).create({ + 'deduplicate': False, + 'user_ids': self.assign_users.ids, + 'force_assignment': True, + }) + + # TDE FIXME: what happens if we mix people from different sales team ? currently nothing, to check + mass_convert.action_mass_convert() + + for idx, lead in enumerate(self.leads - self.lead_w_email_lost): + self.assertEqual(lead.type, 'opportunity') + assigned_user = self.assign_users[idx % len(self.assign_users)] + self.assertEqual(lead.user_id, assigned_user) diff --git a/addons/sales_team/tests/common.py b/addons/sales_team/tests/common.py index a06f97c02c2..665245d1396 100644 --- a/addons/sales_team/tests/common.py +++ b/addons/sales_team/tests/common.py @@ -11,6 +11,21 @@ class TestSalesCommon(SavepointCase): def setUpClass(cls): super(TestSalesCommon, cls).setUpClass() + # Salesmen organization + # ------------------------------------------------------------ + # Role: M (team member) R (team manager) + # SALESMAN---------------sales_team_1 + # admin------------------M----------- + # user_sales_manager-----R----------- + # user_sales_leads-------M----------- + # user_sales_salesman----/----------- + + # Sales teams organization + # ------------------------------------------------------------ + # SALESTEAM-----------SEQU-----COMPANY + # sales_team_1--------5--------False + # data----------------9999-----?? + cls.company_main = cls.env.user.company_id cls.user_sales_manager = mail_new_test_user( cls.env, login='user_sales_manager', @@ -33,6 +48,7 @@ class TestSalesCommon(SavepointCase): notification_type='inbox', groups='sales_team.group_sale_salesman', ) + cls.user_admin = cls.env.ref('base.user_admin') cls.env['crm.team'].search([]).write({'sequence': 9999}) cls.sales_team_1 = cls.env['crm.team'].create({ @@ -40,7 +56,7 @@ class TestSalesCommon(SavepointCase): 'sequence': 5, 'company_id': False, 'user_id': cls.user_sales_manager.id, - 'member_ids': [(4, cls.user_sales_leads.id), (4, cls.env.ref('base.user_admin').id)], + 'member_ids': [(4, cls.user_sales_leads.id), (4, cls.user_admin.id)], }) |
