diff --git a/addons/crm/crm_lead.py b/addons/crm/crm_lead.py index d9124ad00fe..52e9e4ed942 100644 --- a/addons/crm/crm_lead.py +++ b/addons/crm/crm_lead.py @@ -36,7 +36,6 @@ CRM_LEAD_FIELDS_TO_MERGE = ['name', 'company_id', 'country_id', 'section_id', - 'stage_id', 'state_id', 'type_id', 'user_id', @@ -472,6 +471,15 @@ class crm_lead(base_stage, format_address, osv.osv): return 'lead' + def _merge_get_result_stage(self, cr, uid, opps, context=None): + stage = None + for opp in opps: + if not stage: + stage = opp.stage_id.id + if opp.type == 'opportunity': + return opp.stage_id.id + return stage + def _merge_data(self, cr, uid, ids, oldest, fields, context=None): """ Prepare lead/opp data into a dictionary for merging. Different types @@ -488,10 +496,8 @@ class crm_lead(base_stage, format_address, osv.osv): opportunities = self.browse(cr, uid, ids, context=context) def _get_first_not_null(attr): - if hasattr(oldest, attr): - return getattr(oldest, attr) for opp in opportunities: - if hasattr(opp, attr): + if hasattr(opp, attr) and bool(getattr(opp, attr)): return getattr(opp, attr) return False @@ -520,7 +526,7 @@ class crm_lead(base_stage, format_address, osv.osv): # Define the resulting type ('lead' or 'opportunity') data['type'] = self._merge_get_result_type(cr, uid, opportunities, context) - + data['stage_id'] = self._merge_get_result_stage(cr, uid, opportunities, context) return data def _merge_find_oldest(self, cr, uid, ids, context=None): @@ -533,9 +539,6 @@ class crm_lead(base_stage, format_address, osv.osv): if context is None: context = {} - if context.get('convert'): - ids = list(set(ids) - set(context.get('lead_ids', []))) - # Search opportunities order by create date opportunity_ids = self.search(cr, uid, [('id', 'in', ids)], order='create_date', context=context) oldest_opp_id = opportunity_ids[0] @@ -643,19 +646,11 @@ class crm_lead(base_stage, format_address, osv.osv): if len(ids) <= 1: raise osv.except_osv(_('Warning!'),_('Please select more than one element (lead or opportunity) from the list view.')) - - lead_ids = context.get('lead_ids', []) - - ctx_opportunities = self.browse(cr, uid, lead_ids, context=context) - opportunities = self.browse(cr, uid, ids, context=context) - opportunities_list = list(set(opportunities) - set(ctx_opportunities)) + ids.sort() oldest = self._merge_find_oldest(cr, uid, ids, context=context) - if ctx_opportunities: - first_opportunity = ctx_opportunities[0] - tail_opportunities = opportunities_list + ctx_opportunities[1:] - else: - first_opportunity = opportunities_list[0] - tail_opportunities = opportunities_list[1:] + opportunities_rest = self.browse(cr, uid, list(set(ids) - set([oldest.id])), context=context) + first_opportunity = oldest + tail_opportunities = opportunities_rest merged_data = self._merge_data(cr, uid, ids, oldest, CRM_LEAD_FIELDS_TO_MERGE, context=context) @@ -664,14 +659,14 @@ class crm_lead(base_stage, format_address, osv.osv): self._merge_opportunity_attachments(cr, uid, first_opportunity.id, tail_opportunities, context=context) # Merge notifications about loss of information + opportunities = [oldest] + opportunities.extend(opportunities_rest) self._merge_notify(cr, uid, first_opportunity, opportunities, context=context) # Write merged data into first opportunity self.write(cr, uid, [first_opportunity.id], merged_data, context=context) # Delete tail opportunities self.unlink(cr, uid, [x.id for x in tail_opportunities], context=context) - # Open first opportunity - self.case_open(cr, uid, [first_opportunity.id]) return first_opportunity.id def _convert_opportunity_data(self, cr, uid, lead, customer, section_id=False, context=None): @@ -769,7 +764,7 @@ class crm_lead(base_stage, format_address, osv.osv): res = False res_partner = self.pool.get('res.partner') if partner_id: - res_partner.write(cr, uid, partner_id, {'section_id': lead.section_id.id or False}) + res_partner.write(cr, uid, partner_id, {'section_id': lead.section_id and lead.section_id.id or False}) contact_id = res_partner.address_get(cr, uid, [partner_id])['default'] res = lead.write({'partner_id': partner_id}, context=context) message = _("Partner set to %s." % (lead.partner_id.name)) @@ -878,8 +873,8 @@ class crm_lead(base_stage, format_address, osv.osv): 'res_id': int(opportunity_id), 'view_id': False, 'views': [(form_view or False, 'form'), - (tree_view or False, 'tree'), - (False, 'calendar'), (False, 'graph')], + (tree_view or False, 'tree'), + (False, 'calendar'), (False, 'graph')], 'type': 'ir.actions.act_window', } diff --git a/addons/crm/crm_lead_view.xml b/addons/crm/crm_lead_view.xml index 3006de86a3d..3e9249aa6fa 100644 --- a/addons/crm/crm_lead_view.xml +++ b/addons/crm/crm_lead_view.xml @@ -219,6 +219,7 @@ + diff --git a/addons/crm/wizard/crm_lead_to_opportunity.py b/addons/crm/wizard/crm_lead_to_opportunity.py index e7129c98d6c..32396b95f4e 100644 --- a/addons/crm/wizard/crm_lead_to_opportunity.py +++ b/addons/crm/wizard/crm_lead_to_opportunity.py @@ -34,7 +34,7 @@ class crm_lead2opportunity_partner(osv.osv_memory): ('convert', 'Convert to opportunity'), ('merge', 'Merge with existing opportunities') ], 'Conversion Action', required=True), - 'opportunity_ids': fields.many2many('crm.lead', string='Opportunities', domain=[('type', '=', 'opportunity')]), + 'opportunity_ids': fields.many2many('crm.lead', string='Opportunities'), } def default_get(self, cr, uid, fields, context=None): @@ -46,42 +46,34 @@ class crm_lead2opportunity_partner(osv.osv_memory): lead_obj = self.pool.get('crm.lead') res = super(crm_lead2opportunity_partner, self).default_get(cr, uid, fields, context=context) - opportunities = res.get('opportunity_ids') or [] - partner_id = False - email = False - for lead in lead_obj.browse(cr, uid, opportunities, context=context): - partner_id = lead.partner_id and lead.partner_id.id or False + if context.get('active_id'): + tomerge = set([int(context['active_id'])]) + + email = False + partner_id = res.get('partner_id') + lead = lead_obj.browse(cr, uid, int(context['active_id']), context=context) #TOFIX: use mail.mail_message.to_mail email = re.findall(r'([^ ,<@]+@[^> ,]+)', lead.email_from or '') - email = map(lambda x: "'" + x + "'", email) - if not partner_id and res.get('partner_id'): - partner_id = res.get('partner_id') - - ids = [] - if partner_id: - # Search for opportunities that have the same partner and that arent done or cancelled - ids = lead_obj.search(cr, uid, [('partner_id', '=', partner_id), ('type', '=', 'opportunity'), '!', ('state', 'in', ['done', 'cancel'])]) - if ids: - opportunities.append(ids[0]) - if not partner_id: + if partner_id: + # Search for opportunities that have the same partner and that arent done or cancelled + ids = lead_obj.search(cr, uid, [('partner_id', '=', partner_id)]) + for id in ids: + tomerge.add(id) if email: - # Find email of existing opportunity matching the email_from of the lead - cr.execute("""select id from crm_lead where type='opportunity' and - substring(email_from from '([^ ,<@]+@[^> ,]+)') in (%s)""" % (','.join(email))) - ids = map(lambda x:x[0], cr.fetchall()) - if ids: - opportunities.append(ids[0]) + ids = lead_obj.search(cr, uid, [('email_from', 'ilike', email[0])]) + for id in ids: + tomerge.add(id) - if 'action' in fields: - res.update({'action' : partner_id and 'exist' or 'create'}) - if 'partner_id' in fields: - res.update({'partner_id' : partner_id}) - if 'name' in fields: - res.update({'name' : ids and 'merge' or 'convert'}) - if 'opportunity_ids' in fields: - res.update({'opportunity_ids': opportunities}) + if 'action' in fields: + res.update({'action' : partner_id and 'exist' or 'create'}) + if 'partner_id' in fields: + res.update({'partner_id' : partner_id}) + if 'name' in fields: + res.update({'name' : len(tomerge) >= 2 and 'merge' or 'convert'}) + if 'opportunity_ids' in fields and len(tomerge) >= 2: + res.update({'opportunity_ids': list(tomerge)}) return res @@ -115,38 +107,44 @@ class crm_lead2opportunity_partner(osv.osv_memory): lead.allocate_salesman(cr, uid, lead_ids, user_ids, team_id=team_id, context=context) return res - def _merge_opportunity(self, cr, uid, ids, opportunity_ids, action='merge', context=None): - if context is None: - context = {} - res = False - # Expected: all newly-converted leads (active_ids) will be merged with the opportunity(ies) - # that have been selected in the 'opportunity_ids' m2m, with all these records - # merged into the first opportunity (and the rest deleted) - opportunity_ids = [o.id for o in opportunity_ids] - lead_ids = context.get('active_ids', []) - if action == 'merge' and lead_ids and opportunity_ids: - # Add the leads in the to-merge list, next to other opps - # (the fact that they're passed in context['lead_ids'] means that - # they cannot be selected to contain the result of the merge. - opportunity_ids.extend(lead_ids) - context.update({'lead_ids': lead_ids, "convert" : True}) - res = self.pool.get('crm.lead').merge_opportunity(cr, uid, opportunity_ids, context=context) - return res - def action_apply(self, cr, uid, ids, context=None): """ Convert lead to opportunity or merge lead and opportunity and open the freshly created opportunity view. """ + if context is None: + context = {} + + w = self.browse(cr, uid, ids, context=context)[0] + opp_ids = [o.id for o in w.opportunity_ids] + if w.name == 'merge': + lead_id = self.pool.get('crm.lead').merge_opportunity(cr, uid, opp_ids, context=context) + lead_ids = [lead_id] + lead = self.pool.get('crm.lead').read(cr, uid, lead_id, ['type'], context=context) + if lead['type'] == "lead": + context.update({'active_ids': lead_ids}) + self._convert_opportunity(cr, uid, ids, {'lead_ids': lead_ids}, context=context) + else: + lead_ids = context.get('active_ids', []) + self._convert_opportunity(cr, uid, ids, {'lead_ids': lead_ids}, context=context) + + return self.pool.get('crm.lead').redirect_opportunity_view(cr, uid, lead_ids[0], context=context) + + def _create_partner(self, cr, uid, ids, context=None): + """ + Create partner based on action. + :return dict: dictionary organized as followed: {lead_id: partner_assigned_id} + """ + #TODO this method in only called by crm_lead2opportunity_partner + #wizard and would probably diserve to be refactored or at least + #moved to a better place if context is None: context = {} lead = self.pool.get('crm.lead') lead_ids = context.get('active_ids', []) data = self.browse(cr, uid, ids, context=context)[0] - self._convert_opportunity(cr, uid, ids, {'lead_ids': lead_ids}, context=context) - self._merge_opportunity(cr, uid, ids, data.opportunity_ids, data.name, context=context) - return lead.redirect_opportunity_view(cr, uid, lead_ids[0], context=context) - + partner_id = data.partner_id and data.partner_id.id or False + return lead.handle_partner_assignation(cr, uid, lead_ids, data.action, partner_id, context=context) class crm_lead2opportunity_mass_convert(osv.osv_memory): _name = 'crm.lead2opportunity.partner.mass' diff --git a/addons/crm/wizard/crm_lead_to_opportunity_view.xml b/addons/crm/wizard/crm_lead_to_opportunity_view.xml index 1a7bd687a94..8bfd60fccec 100644 --- a/addons/crm/wizard/crm_lead_to_opportunity_view.xml +++ b/addons/crm/wizard/crm_lead_to_opportunity_view.xml @@ -9,11 +9,19 @@
- + + + + - - + + + + + + + @@ -51,9 +59,15 @@ + - - + + + + + + + diff --git a/addons/crm/wizard/crm_merge_opportunities_view.xml b/addons/crm/wizard/crm_merge_opportunities_view.xml index 4b035200737..1dc98b6b68f 100644 --- a/addons/crm/wizard/crm_merge_opportunities_view.xml +++ b/addons/crm/wizard/crm_merge_opportunities_view.xml @@ -11,9 +11,14 @@ + - - + + + + + + diff --git a/addons/crm/wizard/crm_partner_binding.py b/addons/crm/wizard/crm_partner_binding.py index efef0fa2611..cb2184dca2a 100644 --- a/addons/crm/wizard/crm_partner_binding.py +++ b/addons/crm/wizard/crm_partner_binding.py @@ -96,20 +96,4 @@ class crm_partner_binding(osv.osv_memory): return res - def _create_partner(self, cr, uid, ids, context=None): - """ - Create partner based on action. - :return dict: dictionary organized as followed: {lead_id: partner_assigned_id} - """ - #TODO this method in only called by crm_lead2opportunity_partner - #wizard and would probably diserve to be refactored or at least - #moved to a better place - if context is None: - context = {} - lead = self.pool.get('crm.lead') - lead_ids = context.get('active_ids', []) - data = self.browse(cr, uid, ids, context=context)[0] - partner_id = data.partner_id and data.partner_id.id or False - return lead.handle_partner_assignation(cr, uid, lead_ids, data.action, partner_id, context=context) - # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: