[IMP] crm: merge the followers of the leads if they are active
Purpose ======= When merging multiple leads, we want to move the followers to the destination lead if they posted a message in the last 30 days. A message will be added in the merge note to know which followers have been added. Task-2447721 PR odoo/odoo#75742
This commit is contained in:
@@ -122,7 +122,7 @@
|
||||
<div t-if="lead.state_id" t-field="lead.state_id"/>
|
||||
<div t-if="lead.country_id" t-field="lead.country_id"/>
|
||||
</div>
|
||||
<div class="mt-3 mb-3" name="marketing"
|
||||
<div class="mt-3" name="marketing"
|
||||
t-if="lead.campaign_id or lead.medium_id or lead.source_id">
|
||||
<div class="font-weight-bold">
|
||||
Marketing:
|
||||
@@ -137,6 +137,22 @@
|
||||
Source: <span t-field="lead.source_id"/>
|
||||
</div>
|
||||
</div>
|
||||
<t t-set="lead_followers" t-value="merged_followers and merged_followers.get(lead.id)"/>
|
||||
<div class="mt-3 mb-3" name="merged_followers" t-if="lead_followers">
|
||||
<div>
|
||||
The contacts below have been added as followers of this lead
|
||||
because they have been contacted less than 30 days ago on
|
||||
<span class="font-weight-bold" t-esc="lead.name"/>.
|
||||
</div>
|
||||
<ul>
|
||||
<li t-foreach="lead_followers" t-as="follower">
|
||||
<t t-esc="follower.partner_id.name"/>
|
||||
<t t-if="follower.partner_id.email">
|
||||
(<t t-esc="follower.partner_id.email"/>)
|
||||
</t>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</blockquote>
|
||||
</t>
|
||||
</div>
|
||||
|
||||
@@ -15,7 +15,7 @@ from odoo.addons.phone_validation.tools import phone_validation
|
||||
from odoo.exceptions import UserError, AccessError
|
||||
from odoo.osv import expression
|
||||
from odoo.tools.translate import _
|
||||
from odoo.tools import date_utils, email_re, email_split, is_html_empty
|
||||
from odoo.tools import date_utils, email_re, email_split, is_html_empty, groupby
|
||||
|
||||
from . import crm_stage
|
||||
|
||||
@@ -1296,10 +1296,13 @@ class Lead(models.Model):
|
||||
if team_id:
|
||||
merged_data['team_id'] = team_id
|
||||
|
||||
merged_followers = opportunities_head._merge_followers(opportunities_tail)
|
||||
|
||||
# log merge message
|
||||
opportunities_head.message_post_with_view(
|
||||
"crm.crm_lead_merge_summary",
|
||||
values={
|
||||
"merged_followers": merged_followers,
|
||||
"opportunities": opportunities_tail,
|
||||
"is_html_empty": is_html_empty
|
||||
},
|
||||
@@ -1434,6 +1437,50 @@ class Lead(models.Model):
|
||||
'opportunity_id': self.id,
|
||||
})
|
||||
|
||||
def _merge_followers(self, opportunities):
|
||||
"""Add the followers into the destination lead if they post a message in the last 30 days.
|
||||
|
||||
:param opportunities : Record<crm.lead> of opportunities to transfer
|
||||
:return: {old_lead_id: Record<mail.followers>} Followers which have been added in
|
||||
the destination lead grouped by source lead ID.
|
||||
"""
|
||||
self.ensure_one()
|
||||
|
||||
self.env['mail.message'].flush()
|
||||
self.env['mail.followers'].flush()
|
||||
|
||||
# Get the active followers (followers whose partner post a message on the
|
||||
# leads in the last 30 days) which should be moved on the destination lead
|
||||
self.env.cr.execute(
|
||||
'''
|
||||
SELECT MAX(mf.id) AS id
|
||||
FROM mail_followers AS mf
|
||||
JOIN mail_message AS mm
|
||||
ON mm.author_id = mf.partner_id
|
||||
AND mm.res_id = mf.res_id
|
||||
AND mm.model = 'crm.lead'
|
||||
AND mm.date > NOW() - INTERVAL '30 DAY'
|
||||
/* Check if the partner is already
|
||||
following the destination lead */
|
||||
LEFT JOIN mail_followers AS destf
|
||||
ON destf.res_model = 'crm.lead'
|
||||
AND destf.res_id = %(lead_id)s
|
||||
AND destf.partner_id = mf.partner_id
|
||||
/* Select only once each partner
|
||||
to not create duplicated followers */
|
||||
WHERE mf.res_model = 'crm.lead'
|
||||
AND mf.res_id IN %(lead_ids)s
|
||||
AND destf IS NULL
|
||||
GROUP BY mf.partner_id
|
||||
''',
|
||||
{'lead_ids': tuple(opportunities.ids), 'lead_id': self.id},
|
||||
)
|
||||
followers_to_update = [r[0] for r in self.env.cr.fetchall()]
|
||||
followers_to_update = self.env['mail.followers'].browse(followers_to_update).sudo()
|
||||
followers_by_old_lead = dict(groupby(followers_to_update, lambda f: f.res_id))
|
||||
followers_to_update.write({'res_id': self.id})
|
||||
return followers_by_old_lead
|
||||
|
||||
# CONVERT
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import base64
|
||||
from datetime import timedelta
|
||||
|
||||
from odoo.addons.crm.tests.common import TestLeadConvertMassCommon
|
||||
from odoo.fields import Datetime
|
||||
@@ -391,3 +392,97 @@ class TestLeadMerge(TestLeadMergeCommon):
|
||||
# 2many accessors updated
|
||||
self.assertEqual(master_lead.activity_ids, activity)
|
||||
self.assertEqual(master_lead.calendar_event_ids, calendar_event)
|
||||
|
||||
@users('user_sales_manager')
|
||||
@mute_logger('odoo.models.unlink')
|
||||
def test_merge_method_followers(self):
|
||||
""" Test that the followers of the leads are added in the destination lead.
|
||||
|
||||
They should be added if:
|
||||
- The related partner was active on the lead (posted a message in the last 30 days)
|
||||
- The related partner is not already following the destination lead
|
||||
|
||||
Leads Followers Info
|
||||
---------------------------------------------------------------------------------
|
||||
lead_w_contact contact_1 OK (destination lead)
|
||||
lead_w_email contact_1 KO (already following the destination lead)
|
||||
contact_2 OK (active on lead_w_email)
|
||||
contact_company KO (most recent message on lead_w_email is 35 days ago, message
|
||||
on lead_w_partner is not counted as he doesn't follow it)
|
||||
lead_w_partner contact_2 KO (already added with lead_w_email)
|
||||
lead_w_partner_company
|
||||
"""
|
||||
self.leads.message_follower_ids.unlink()
|
||||
self.leads.message_ids.unlink()
|
||||
|
||||
self.lead_w_contact.message_subscribe([self.contact_1.id])
|
||||
self.lead_w_email.message_subscribe([self.contact_1.id, self.contact_2.id, self.contact_company.id])
|
||||
self.lead_w_partner.message_subscribe([self.contact_2.id])
|
||||
|
||||
self.env['mail.message'].create([{
|
||||
'author_id': self.contact_1.id,
|
||||
'model': 'crm.lead',
|
||||
'res_id': self.lead_w_contact.id,
|
||||
'date': Datetime.now() - timedelta(days=1),
|
||||
'subtype_id': self.ref('mail.mt_comment'),
|
||||
'reply_to': False,
|
||||
'body': 'Test follower',
|
||||
}, {
|
||||
'author_id': self.contact_1.id,
|
||||
'model': 'crm.lead',
|
||||
'res_id': self.lead_w_email.id,
|
||||
'date': Datetime.now() - timedelta(days=20),
|
||||
'subtype_id': self.ref('mail.mt_comment'),
|
||||
'reply_to': False,
|
||||
'body': 'Test follower',
|
||||
}, {
|
||||
'author_id': self.contact_2.id,
|
||||
'model': 'crm.lead',
|
||||
'res_id': self.lead_w_email.id,
|
||||
'date': Datetime.now() - timedelta(days=15),
|
||||
'subtype_id': self.ref('mail.mt_comment'),
|
||||
'reply_to': False,
|
||||
'body': 'Test follower',
|
||||
}, {
|
||||
'author_id': self.contact_2.id,
|
||||
'model': 'crm.lead',
|
||||
'res_id': self.lead_w_partner.id,
|
||||
'date': Datetime.now() - timedelta(days=29),
|
||||
'subtype_id': self.ref('mail.mt_comment'),
|
||||
'reply_to': False,
|
||||
'body': 'Test follower',
|
||||
}, {
|
||||
'author_id': self.contact_company.id,
|
||||
'model': 'crm.lead',
|
||||
'res_id': self.lead_w_email.id,
|
||||
'date': Datetime.now() - timedelta(days=35),
|
||||
'subtype_id': self.ref('mail.mt_comment'),
|
||||
'reply_to': False,
|
||||
'body': 'Test follower',
|
||||
}, {
|
||||
'author_id': self.contact_company.id,
|
||||
'model': 'crm.lead',
|
||||
'res_id': self.lead_w_partner.id,
|
||||
'date': Datetime.now(),
|
||||
'subtype_id': self.ref('mail.mt_comment'),
|
||||
'reply_to': False,
|
||||
'body': 'Test follower',
|
||||
}])
|
||||
initial_followers = self.lead_w_contact.message_follower_ids
|
||||
|
||||
leads = self.env['crm.lead'].browse(self.leads.ids)._sort_by_confidence_level(reverse=True)
|
||||
master_lead = leads._merge_opportunity(max_length=None)
|
||||
|
||||
self.assertEqual(master_lead, self.lead_w_contact)
|
||||
|
||||
# Check followers of the destination lead
|
||||
new_partner_followers = (master_lead.message_follower_ids - initial_followers).partner_id
|
||||
self.assertIn(self.contact_2, new_partner_followers,
|
||||
'The partner must follow the destination lead')
|
||||
# "contact_company" posted a message 35 days ago on lead_2, so it's considered as inactive
|
||||
# "contact_company" posted a message now on lead_3, but he doesn't follow lead_3
|
||||
# so this message is just ignored
|
||||
self.assertNotIn(self.contact_company, new_partner_followers,
|
||||
'The partner was not active on the lead')
|
||||
self.assertIn(self.contact_1, master_lead.message_follower_ids.partner_id,
|
||||
'Should not have removed follower of the destination lead')
|
||||
|
||||
Reference in New Issue
Block a user