From 473b07e34cb7d626ec33386ea302b2ec38e85452 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thibault=20Delavall=C3=A9e?= Date: Thu, 19 Nov 2020 11:24:58 +0000 Subject: [PATCH] [FIX] crm_livechat: do not set public user partner as lead customer usign /lead command When chatting with visitors, operator may use /lead command to directly create a lead from discussion. That way commercial discussion can follow visitors inquiries. Anonymous (public) users may be part of channels, notably since f5fe11cf1e74216afea7976d8515d4448f054dd2. In that case we don't want new leads to be associated with those users. Indeed * they are not real users, just technical users for website / frontend; * merge processes may think all leads having public users as customer are duplicates and should be merged, which means loosing information and leads; We therefore set the following heuristics * if a public user is member of a channel -> consider this is a livechat with an anonymous and set customer_id to False; * otherwise try to find a share partner in channel members and link the lead to that partner; Task ID-2389564 closes odoo/odoo#62192 X-original-commit: 7fbeda3f7d92fa501c2752c873be2255697f5d97 Signed-off-by: Thibault Delavallee (tde) --- addons/crm_livechat/models/mail_channel.py | 22 ++++++- addons/crm_livechat/tests/__init__.py | 4 ++ addons/crm_livechat/tests/test_crm_lead.py | 77 ++++++++++++++++++++++ 3 files changed, 100 insertions(+), 3 deletions(-) create mode 100644 addons/crm_livechat/tests/__init__.py create mode 100644 addons/crm_livechat/tests/test_crm_lead.py diff --git a/addons/crm_livechat/models/mail_channel.py b/addons/crm_livechat/models/mail_channel.py index f608bd1a0dd..b7650342d5a 100644 --- a/addons/crm_livechat/models/mail_channel.py +++ b/addons/crm_livechat/models/mail_channel.py @@ -26,16 +26,32 @@ class MailChannel(models.Model): self._send_transient_message(partner, msg) def _convert_visitor_to_lead(self, partner, channel_partners, key): + """ Create a lead from channel /lead command + :param partner: internal user partner (operator) that created the lead; + :param channel_partners: channel members; + :param key: operator input in chat ('/lead Lead about Product') + """ description = ''.join( '%s: %s\n' % (message.author_id.name or self.anonymous_name, message.body) for message in self.channel_message_ids.sorted('id') ) + # if public user is part of the chat: consider lead to be linked to an + # anonymous user whatever the participants. Otherwise keep only share + # partners (no user or portal user) to link to the lead. + customers = self.env['res.partner'] + for customer in channel_partners.partner_id.filtered('partner_share'): + if customer.user_ids and all(user._is_public() for user in customer.user_ids): + customers = self.env['res.partner'] + break + else: + customers |= customer + utm_source = self.env.ref('crm_livechat.utm_source_livechat', raise_if_not_found=False) return self.env['crm.lead'].create({ 'name': html2plaintext(key[5:]), - 'partner_id': channel_partners.partner_id.id, - 'user_id': None, - 'team_id': None, + 'partner_id': customers[0].id if customers else False, + 'user_id': False, + 'team_id': False, 'description': html2plaintext(description), 'referred': partner.name, 'source_id': utm_source and utm_source.id, diff --git a/addons/crm_livechat/tests/__init__.py b/addons/crm_livechat/tests/__init__.py new file mode 100644 index 00000000000..3721104aa97 --- /dev/null +++ b/addons/crm_livechat/tests/__init__.py @@ -0,0 +1,4 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from . import test_crm_lead diff --git a/addons/crm_livechat/tests/test_crm_lead.py b/addons/crm_livechat/tests/test_crm_lead.py new file mode 100644 index 00000000000..c3d6364e385 --- /dev/null +++ b/addons/crm_livechat/tests/test_crm_lead.py @@ -0,0 +1,77 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo.addons.crm.tests.common import TestCrmCommon +from odoo.addons.mail.tests.common import mail_new_test_user +from odoo.tests.common import users + + +class TestLivechatLead(TestCrmCommon): + + @classmethod + def setUpClass(cls): + super(TestLivechatLead, cls).setUpClass() + + cls.user_anonymous = mail_new_test_user( + cls.env, login='user_anonymous', + name='Anonymous Website', email=False, + company_id=cls.company_main.id, + notification_type='inbox', + groups='base.group_public', + ) + cls.user_portal = mail_new_test_user( + cls.env, login='user_portal', + name='Paulette Portal', email='user_portal@test.example.com', + company_id=cls.company_main.id, + notification_type='inbox', + groups='base.group_portal', + ) + + @users('user_sales_leads') + def test_crm_lead_creation_guest(self): + """ Test customer set on lead: not if public, guest if not public """ + # public: should not be set as customer + channel = self.env['mail.channel'].create({ + 'name': 'Chat with Visitor', + 'channel_partner_ids': [(4, self.user_anonymous.partner_id.id)] + }) + lead = channel._convert_visitor_to_lead(self.env.user.partner_id, channel.channel_last_seen_partner_ids, '/lead TestLead command') + + self.assertEqual( + channel.channel_last_seen_partner_ids.partner_id, + self.user_sales_leads.partner_id | self.user_anonymous.partner_id + ) + self.assertEqual(lead.name, 'TestLead command') + self.assertEqual(lead.partner_id, self.env['res.partner']) + + # public + someone else: no customer (as he was anonymous) + channel.write({ + 'channel_partner_ids': [(4, self.user_sales_manager.partner_id.id)] + }) + lead = channel._convert_visitor_to_lead(self.env.user.partner_id, channel.channel_last_seen_partner_ids, '/lead TestLead command') + self.assertEqual(lead.partner_id, self.env['res.partner']) + + # portal: should be set as customer + channel = self.env['mail.channel'].create({ + 'name': 'Chat with Visitor', + 'channel_partner_ids': [(4, self.user_portal.partner_id.id)] + }) + lead = channel._convert_visitor_to_lead(self.env.user.partner_id, channel.channel_last_seen_partner_ids, '/lead TestLead command') + + self.assertEqual( + channel.channel_last_seen_partner_ids.partner_id, + self.user_sales_leads.partner_id | self.user_portal.partner_id + ) + self.assertEqual(lead.partner_id, self.user_portal.partner_id) + + # another operator invited: internal user should not be customer if portal is present + channel.write({ + 'channel_partner_ids': [(4, self.user_sales_manager.partner_id.id)] + }) + lead = channel._convert_visitor_to_lead(self.env.user.partner_id, channel.channel_last_seen_partner_ids, '/lead TestLead command') + + self.assertEqual( + channel.channel_last_seen_partner_ids.partner_id, + self.user_sales_leads.partner_id | self.user_portal.partner_id | self.user_sales_manager.partner_id + ) + self.assertEqual(lead.partner_id, self.user_portal.partner_id)