diff --git a/addons/crm/models/crm_lead.py b/addons/crm/models/crm_lead.py index 0e20b7226a3..e84b4a3cc43 100644 --- a/addons/crm/models/crm_lead.py +++ b/addons/crm/models/crm_lead.py @@ -664,15 +664,8 @@ class Lead(models.Model): def _merge_get_result_type(self): """ Define the type of the result of the merge. If at least one of the - element to merge is an opp, the resulting new element will be an opp. - Otherwise it will be a lead. - We'll directly use a list of browse records instead of a list of ids - for performances' sake: it will spare a second browse of the - leads/opps. - - :param list opps: list of browse records containing the leads/opps to process - :return string type: the type of the final element - """ + element to merge is an opp, the resulting new element will be an opp. + Otherwise it will be a lead. """ if any(record.type == 'opportunity' for record in self): return 'opportunity' return 'lead' @@ -719,19 +712,20 @@ class Lead(models.Model): data['type'] = self._merge_get_result_type() return data - def _mail_body(self, fields): - """ generate the message body with the changed values - :param fields : list of fields to track - :returns a list of message bodies for the corresponding leads + def _merge_notify_get_merged_fields_message(self, fields): + """ Generate the message body with the changed values + + :param fields : list of fields to track + :returns a list of message bodies for the corresponding leads """ bodies = [] for lead in self: title = "%s : %s\n" % (_('Merged opportunity') if lead.type == 'opportunity' else _('Merged lead'), lead.name) body = [title] _fields = self.env['ir.model.fields'].search([ - ('name', 'in', fields or []), - ('model_id.model', '=', lead._name), - ]) + ('name', 'in', fields or []), + ('model_id.model', '=', lead._name), + ]) for field in _fields: value = getattr(lead, field.name, False) if field.ttype == 'selection': @@ -751,11 +745,11 @@ class Lead(models.Model): return bodies def _merge_notify(self, opportunities): - """ Create a message gathering merged leads/opps informations. Using message_post, send a - message explaining which fields has been merged and their new value. `self` is the - resulting merge crm.lead record. - :param opportunities : recordset of merged crm.lead - :returns mail.message posted on resulting crm.lead + """ Post a message gathering merged leads/opps informations. It explains + which fields has been merged and their new value. `self` is the resulting + merge crm.lead record. + + :param opportunities: see ``merge_dependences`` """ # TODO JEM: mail template should be used instead of fix body, subject text self.ensure_one() @@ -764,14 +758,15 @@ class Lead(models.Model): merge_message = _('Merged leads') if result_type == 'lead' else _('Merged opportunities') subject = merge_message + ": " + ", ".join(opportunities.mapped('name')) # message bodies - message_bodies = opportunities._mail_body(list(CRM_LEAD_FIELDS_TO_MERGE)) + message_bodies = opportunities._merge_notify_get_merged_fields_message(list(CRM_LEAD_FIELDS_TO_MERGE)) message_body = "\n\n".join(message_bodies) return self.message_post(body=message_body, subject=subject) def _merge_opportunity_history(self, opportunities): """ Move mail.message from the given opportunities to the current one. `self` is the crm.lead record destination for message of `opportunities`. - :param opportunities : recordset of crm.lead to move the messages + + :param opportunities: see ``merge_dependences`` """ self.ensure_one() for opportunity in opportunities: @@ -785,7 +780,8 @@ class Lead(models.Model): def _merge_opportunity_attachments(self, opportunities): """ Move attachments of given opportunities to the current one `self`, and rename the attachments having same name than native ones. - :param opportunities : recordset of merged crm.lead + + :param opportunities: see ``merge_dependences`` """ self.ensure_one() @@ -810,8 +806,9 @@ class Lead(models.Model): def merge_dependences(self, opportunities): """ Merge dependences (messages, attachments, ...). These dependences will be transfered to `self`, the most important lead. - :param opportunities : recordset of opportunities to transfert. Does - not include `self`. + + :param opportunities : recordset of opportunities to transfer. Does not + include `self` which is the target crm.lead being the result of the merge. """ self.ensure_one() self._merge_notify(opportunities) @@ -940,16 +937,18 @@ class Lead(models.Model): return True - def _create_lead_partner_data(self, name, is_company, parent_id=False): - """ extract data from lead to create a partner - :param name : furtur name of the partner - :param is_company : True if the partner is a company - :param parent_id : id of the parent partner (False if no parent) - :returns res.partner record + def _create_lead_partner_data(self, partner_name, is_company=False, parent_id=False): + """ Extract data from lead to create a partner. + + :param name : furtur name of the partner + :param is_company : True if the partner is a company + :param parent_id : id of the parent partner (False if no parent) + + :return: dictionary of values to give at res_partner.create() """ email_split = tools.email_split(self.email_from) return { - 'name': name, + 'name': partner_name, 'user_id': self.env.context.get('default_user_id') or self.user_id.id, 'comment': self.description, 'team_id': self.team_id.id, @@ -980,28 +979,30 @@ class Lead(models.Model): contact_name = Partner._parse_partner_name(self.email_from)[0] if self.email_from else False if self.partner_name: - partner_company = Partner.create(self._create_lead_partner_data(self.partner_name, True)) + partner_company = Partner.create(self._create_lead_partner_data(self.partner_name, is_company=True)) elif self.partner_id: partner_company = self.partner_id else: partner_company = None if contact_name: - return Partner.create(self._create_lead_partner_data(contact_name, False, partner_company.id if partner_company else False)) + return Partner.create(self._create_lead_partner_data(contact_name, is_company=False, parent_id=partner_company.id if partner_company else False)) if partner_company: return partner_company - return Partner.create(self._create_lead_partner_data(self.name, False)) + return Partner.create(self._create_lead_partner_data(self.name, is_company=False)) - def handle_partner_assignation(self, action='create', partner_id=False): + def handle_partner_assignation(self, action='create', partner_id=False): """ Handle partner assignation during a lead conversion. - if action is 'create', create new partner with contact and assign lead to new partner_id. - otherwise assign lead to the specified partner_id - :param list ids: leads/opportunities ids to process - :param string action: what has to be done regarding partners (create it, assign an existing one, or nothing) - :param int partner_id: partner to assign if any - :return dict: dictionary organized as followed: {lead_id: partner_assigned_id} + If action is 'create', create new partner with contact and assign lead to + new partner_id. Otherwise assign lead to the specified partner_id + + TDE FIXME: docstring does not match code... code seems a bit random. + + :param string action: what has to be done regarding partners (create it, assign an existing one, or nothing) + :param int partner_id: partner to assign if any + :return: dict(lead_id: partner_id) """ partner_ids = {} for lead in self: @@ -1042,6 +1043,10 @@ class Lead(models.Model): lead.write(value) return True + # ------------------------------------------------------------ + # TOOLS + # ------------------------------------------------------------ + def redirect_lead_opportunity_view(self): self.ensure_one() return { diff --git a/addons/crm/tests/test_crm_lead.py b/addons/crm/tests/test_crm_lead.py index c8eaa84e198..80b32bea315 100644 --- a/addons/crm/tests/test_crm_lead.py +++ b/addons/crm/tests/test_crm_lead.py @@ -78,7 +78,7 @@ class TestCRMLead(TestCrmCommon): subtype_xmlid='mail.mt_comment') self.assertEqual(message.author_id, self.user_sales_manager.partner_id) - new_partner_id = new_lead.handle_partner_assignation()[new_lead.id] + new_partner_id = new_lead.handle_partner_assignation(action='create')[new_lead.id] 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) diff --git a/addons/crm/wizard/crm_lead_to_opportunity.py b/addons/crm/wizard/crm_lead_to_opportunity.py index 3a94ba69111..ff81fc1db81 100644 --- a/addons/crm/wizard/crm_lead_to_opportunity.py +++ b/addons/crm/wizard/crm_lead_to_opportunity.py @@ -7,7 +7,6 @@ from odoo.tools.translate import _ class Lead2OpportunityPartner(models.TransientModel): - _name = 'crm.lead2opportunity.partner' _description = 'Convert Lead to Opportunity (not in mass)' _inherit = 'crm.partner.binding' @@ -26,7 +25,7 @@ class Lead2OpportunityPartner(models.TransientModel): lead = self.env['crm.lead'].browse(self._context['active_id']) email = lead.partner_id.email if lead.partner_id else lead.email_from - tomerge.update(self._get_duplicated_leads(partner_id, email, include_lost=True).ids) + tomerge.update(self.env['crm.lead']._get_duplicated_leads_by_emails(partner_id, email, include_lost=True).ids) if 'action' in fields and not result.get('action'): result['action'] = 'exist' if partner_id else 'create' @@ -73,11 +72,6 @@ class Lead2OpportunityPartner(models.TransientModel): values = self.env['crm.lead']._onchange_user_values(self.user_id.id if self.user_id else False) self.team_id = values.get('team_id', False) - @api.model - def _get_duplicated_leads(self, partner_id, email, include_lost=False): - """ Search for opportunities that have the same partner and that arent done or cancelled """ - return self.env['crm.lead']._get_duplicated_leads_by_emails(partner_id, email, include_lost=include_lost) - # NOTE JEM : is it the good place to test this ? @api.model def view_init(self, fields): diff --git a/addons/crm/wizard/crm_lead_to_opportunity_mass.py b/addons/crm/wizard/crm_lead_to_opportunity_mass.py index 910b9ae6dac..723142cabc9 100644 --- a/addons/crm/wizard/crm_lead_to_opportunity_mass.py +++ b/addons/crm/wizard/crm_lead_to_opportunity_mass.py @@ -43,7 +43,7 @@ class Lead2OpportunityMassConvert(models.TransientModel): partner_ids = [(lead.partner_id.id, lead.partner_id and lead.partner_id.email or lead.email_from) for lead in active_leads] partners_duplicated_leads = {} for partner_id, email in partner_ids: - duplicated_leads = self._get_duplicated_leads(partner_id, email) + duplicated_leads = self.env['crm.lead']._get_duplicated_leads_by_emails(partner_id, email, include_lost=False) if len(duplicated_leads) > 1: partners_duplicated_leads.setdefault((partner_id, email), []).extend(duplicated_leads) @@ -77,7 +77,7 @@ class Lead2OpportunityMassConvert(models.TransientModel): for lead_id in lead_selected: if lead_id not in merged_lead_ids: lead = self.env['crm.lead'].browse(lead_id) - duplicated_leads = self._get_duplicated_leads(lead.partner_id.id, lead.partner_id.email if lead.partner_id else lead.email_from) + duplicated_leads = self.env['crm.lead']._get_duplicated_leads_by_emails(lead.partner_id.id, lead.partner_id.email if lead.partner_id else lead.email_from, include_lost=False) if len(duplicated_leads) > 1: lead = duplicated_leads.merge_opportunity() merged_lead_ids.update(duplicated_leads.ids) diff --git a/addons/website_crm/models/website_visitor.py b/addons/website_crm/models/website_visitor.py index 38f9cab2616..616ea37c563 100644 --- a/addons/website_crm/models/website_visitor.py +++ b/addons/website_crm/models/website_visitor.py @@ -50,7 +50,7 @@ class WebsiteVisitor(models.Model): lead = self.lead_ids._sort_by_confidence_level(reverse=True)[0] partner_id = self.partner_id.id if not self.partner_id: - partner_id = lead.handle_partner_assignation()[lead.id] + partner_id = lead.handle_partner_assignation(action='create')[lead.id] if not lead.partner_id: lead.partner_id = partner_id self.partner_id = partner_id