From d348c5e8801a13a153d84da651aa7b6f696f7c25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Mon, 22 Nov 2021 16:57:56 +0000 Subject: [PATCH 1/5] [IMP] crm, test_mail: flush tracking in tests involving tracking Tracking is generated using commit hooks, meaning they are really sent when the commit ends. This is done to ease values aggregation and accumulation through various record updates. In some tests we therefore have to manually flush the tracking, otherwise it is not created and posted. Notably tests about lead lost wizard were not flushing and therefore not generated the tracking messages. Those tests will be improved in future commits, cleaning them is therefore a necessary step. We also specifically add some tracking flush in mail performance tests. This is to be sure we measure impact of a write and tracking separately from previous transactions. Seems everything is working as intended as warmup and query counters already perform flushes. Here we simply flush at the end of the setup to be sure all base is clean before starting tests. Task-2671709 Part-of: odoo/odoo#78648 --- addons/crm/tests/common.py | 4 ++++ addons/crm/tests/test_crm_lead_lost.py | 7 ++++++- addons/test_mail/tests/test_performance.py | 7 +++++++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/addons/crm/tests/common.py b/addons/crm/tests/common.py index 71633308398..02b35af3a3f 100644 --- a/addons/crm/tests/common.py +++ b/addons/crm/tests/common.py @@ -242,6 +242,10 @@ class TestCrmCommon(TestSalesCommon, MailCase): 'res_id': cls.activity_type_1.id, }) + def setUp(self): + super(TestCrmCommon, self).setUp() + self.flush_tracking() + @classmethod def _activate_multi_company(cls): cls.company_2 = cls.env['res.company'].create({ diff --git a/addons/crm/tests/test_crm_lead_lost.py b/addons/crm/tests/test_crm_lead_lost.py index 7f2819f7825..a4fe7216240 100644 --- a/addons/crm/tests/test_crm_lead_lost.py +++ b/addons/crm/tests/test_crm_lead_lost.py @@ -6,7 +6,7 @@ from odoo.exceptions import AccessError from odoo.tests.common import tagged, users -@tagged('lead_manage') +@tagged('lead_manage', 'lead_lost') class TestLeadConvert(crm_common.TestCrmCommon): @classmethod @@ -22,9 +22,11 @@ class TestLeadConvert(crm_common.TestCrmCommon): 'user_id': self.user_sales_salesman.id, 'probability': 32, }) + self.flush_tracking() lead = self.lead_1.with_user(self.env.user) self.assertEqual(lead.probability, 32) + self.assertEqual(len(lead.message_ids), 2, 'Should have tracked new responsible') lost_wizard = self.env['crm.lead.lost'].with_context({ 'active_ids': lead.ids, @@ -33,11 +35,14 @@ class TestLeadConvert(crm_common.TestCrmCommon): }) lost_wizard.action_lost_reason_apply() + self.flush_tracking() self.assertEqual(lead.probability, 0) self.assertEqual(lead.automated_probability, 0) self.assertFalse(lead.active) self.assertEqual(lead.lost_reason, self.lost_reason) # TDE FIXME: should be called lost_reason_id non didjou + # check messages + self.assertEqual(len(lead.message_ids), 3, 'Should have logged a tracking message for lost lead with reason') @users('user_sales_salesman') def test_lead_lost_crm_rights(self): diff --git a/addons/test_mail/tests/test_performance.py b/addons/test_mail/tests/test_performance.py index 95df796b177..34d5bf0298d 100644 --- a/addons/test_mail/tests/test_performance.py +++ b/addons/test_mail/tests/test_performance.py @@ -47,6 +47,7 @@ class BaseMailPerformance(TransactionCaseWithUserDemo): super(BaseMailPerformance, self).setUp() # patch registry to simulate a ready environment self.patch(self.env.registry, 'ready', True) + self._flush_tracking() def _init_mail_gateway(self): # setup mail gateway @@ -59,6 +60,12 @@ class BaseMailPerformance(TransactionCaseWithUserDemo): self.env['ir.config_parameter'].set_param('mail.catchall.alias', self.alias_catchall) self.env['ir.config_parameter'].set_param('mail.default.from', self.default_from) + def _flush_tracking(self): + """ Force the creation of tracking values notably, and ensure tests are + reproducible. """ + self.env['base'].flush() + self.cr.flush() + @tagged('mail_performance') class TestBaseMailPerformance(BaseMailPerformance): From a830ceaaf9ef72002027afa25cbb5b1575a28ee3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Wed, 20 Oct 2021 07:14:08 +0000 Subject: [PATCH 2/5] [IMP] crm: allow to log a feedback when marking a lead as lost PURPOSE Allow sales reps to add a closing note to their lead while it is being marked as lost. This is currently already done by a lot of sales reps but manually with the "Log a Note" button. SPECIFICATIONS In ``Lost Reason`` model: add a new html field allowing to log a note on the lost leads. Below the m2o, add an Extra Comment field where users can add a "closing note". When the wizard is submitted, log this message as a note on selected records. Add tests, allowing to test both the wizard and this new feature. Task-2671709 Part-of: odoo/odoo#78648 --- addons/crm/tests/test_crm_lead_lost.py | 71 +++++++++++++++++++++-- addons/crm/wizard/crm_lead_lost.py | 19 +++++- addons/crm/wizard/crm_lead_lost_views.xml | 1 + addons/mail/tests/common.py | 9 ++- 4 files changed, 91 insertions(+), 9 deletions(-) diff --git a/addons/crm/tests/test_crm_lead_lost.py b/addons/crm/tests/test_crm_lead_lost.py index a4fe7216240..735d3ec2ed3 100644 --- a/addons/crm/tests/test_crm_lead_lost.py +++ b/addons/crm/tests/test_crm_lead_lost.py @@ -4,6 +4,7 @@ from odoo.addons.crm.tests import common as crm_common from odoo.exceptions import AccessError from odoo.tests.common import tagged, users +from odoo.tools import mute_logger @tagged('lead_manage', 'lead_lost') @@ -18,34 +19,96 @@ class TestLeadConvert(crm_common.TestCrmCommon): @users('user_sales_salesman') def test_lead_lost(self): + """ Test setting a lead as lost using the wizard. Also check that an + 'html editor' void content used as feedback is not logged on the lead. """ + # Initial data + self.assertEqual(len(self.lead_1.message_ids), 1, 'Should contain creation message') + creation_message = self.lead_1.message_ids[0] + self.assertEqual(creation_message.subtype_id, self.env.ref('crm.mt_lead_create')) + + # Update responsible as ACLs is "own only" for user_sales_salesman self.lead_1.with_user(self.user_sales_manager).write({ 'user_id': self.user_sales_salesman.id, 'probability': 32, }) self.flush_tracking() - lead = self.lead_1.with_user(self.env.user) + lead = self.env['crm.lead'].browse(self.lead_1.ids) + self.assertFalse(lead.lost_reason) self.assertEqual(lead.probability, 32) self.assertEqual(len(lead.message_ids), 2, 'Should have tracked new responsible') + update_message = lead.message_ids[0] + self.assertEqual(update_message.subtype_id, self.env.ref('mail.mt_note')) + # mark as lost using the wizard lost_wizard = self.env['crm.lead.lost'].with_context({ 'active_ids': lead.ids, }).create({ - 'lost_reason_id': self.lost_reason.id + 'lost_reason_id': self.lost_reason.id, + 'lost_feedback': '

', # void content }) lost_wizard.action_lost_reason_apply() self.flush_tracking() - self.assertEqual(lead.probability, 0) - self.assertEqual(lead.automated_probability, 0) + # check lead update self.assertFalse(lead.active) + self.assertEqual(lead.automated_probability, 0) self.assertEqual(lead.lost_reason, self.lost_reason) # TDE FIXME: should be called lost_reason_id non didjou + self.assertEqual(lead.probability, 0) # check messages self.assertEqual(len(lead.message_ids), 3, 'Should have logged a tracking message for lost lead with reason') + update_message = lead.message_ids[0] + self.assertEqual(update_message.subtype_id, self.env.ref('crm.mt_lead_lost')) + self.assertEqual(len(update_message.tracking_value_ids), 2, 'Tracking: active, lost reason') + self.assertTracking( + update_message, + [('active', 'boolean', True, False), + ('lost_reason', 'many2one', False, self.lost_reason) + ] + ) + + @users('user_sales_leads') + def test_lead_lost_batch_wfeedback(self): + """ Test setting leads as lost in batch using the wizard, including a log + message. """ + leads = self._create_leads_batch(lead_type='lead', count=10, probabilities=[10, 20, 30]) + self.assertEqual(len(leads), 10) + self.flush_tracking() + + lost_wizard = self.env['crm.lead.lost'].with_context({ + 'active_ids': leads.ids, + }).create({ + 'lost_reason_id': self.lost_reason.id, + 'lost_feedback': '

I cannot find it. It was in my closet and pouf, disappeared.

', + }) + lost_wizard.action_lost_reason_apply() + self.flush_tracking() + + for lead in leads: + # check content + self.assertFalse(lead.active) + self.assertEqual(lead.automated_probability, 0) + self.assertEqual(lead.probability, 0) + self.assertEqual(lead.lost_reason, self.lost_reason) + # check messages + self.assertEqual(len(lead.message_ids), 3, 'Should have 3 messages: creation, lost, and log') + lost_message = lead.message_ids.filtered(lambda msg: msg.subtype_id == self.env.ref('crm.mt_lead_lost')) + self.assertTrue(lost_message) + self.assertTracking( + lost_message, + [('active', 'boolean', True, False), + ('lost_reason', 'many2one', False, self.lost_reason) + ] + ) + note_message = lead.message_ids.filtered(lambda msg: msg.subtype_id == self.env.ref('mail.mt_note')) + self.assertTrue(note_message) + self.assertEqual(note_message.body, '

I cannot find it. It was in my closet and pouf, disappeared.

') @users('user_sales_salesman') + @mute_logger('odoo.addons.base.models') def test_lead_lost_crm_rights(self): + """ Test ACLs of lost reasons management and usage """ lead = self.lead_1.with_user(self.env.user) # nice try little salesman but only managers can create lost reason to avoid bloating the DB diff --git a/addons/crm/wizard/crm_lead_lost.py b/addons/crm/wizard/crm_lead_lost.py index 8f64a40579b..f2ca5958544 100644 --- a/addons/crm/wizard/crm_lead_lost.py +++ b/addons/crm/wizard/crm_lead_lost.py @@ -1,6 +1,8 @@ # -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. -from odoo import api, fields, models +from odoo import fields, models, _ +from odoo.tools.mail import is_html_empty class CrmLeadLost(models.TransientModel): @@ -8,7 +10,20 @@ class CrmLeadLost(models.TransientModel): _description = 'Get Lost Reason' lost_reason_id = fields.Many2one('crm.lost.reason', 'Lost Reason') + lost_feedback = fields.Html( + 'Closing Note', sanitize=True, + help="Closing note logged in leads discussion history." + ) def action_lost_reason_apply(self): + self.ensure_one() leads = self.env['crm.lead'].browse(self.env.context.get('active_ids')) - return leads.action_set_lost(lost_reason=self.lost_reason_id.id) + res = leads.action_set_lost(lost_reason=self.lost_reason_id.id) + if not is_html_empty(self.lost_feedback): + leads._message_log_batch( + bodies=dict( + (lead.id, self.lost_feedback) + for lead in leads), + subject=False, + ) + return res diff --git a/addons/crm/wizard/crm_lead_lost_views.xml b/addons/crm/wizard/crm_lead_lost_views.xml index 79611a98e7c..c6ca6b23aca 100644 --- a/addons/crm/wizard/crm_lead_lost_views.xml +++ b/addons/crm/wizard/crm_lead_lost_views.xml @@ -8,6 +8,7 @@ +