[FIX]Merge Lead/Opp on convert to opportunity

bzr revid: dle@openerp.com-20130204175106-q2r6xmox16co4n35
This commit is contained in:
dle@openerp.com 2013-02-04 18:51:06 +01:00
parent 91954d029f
commit 1b9503923c
5 changed files with 62 additions and 72 deletions

View File

@ -36,7 +36,6 @@ CRM_LEAD_FIELDS_TO_MERGE = ['name',
'company_id', 'company_id',
'country_id', 'country_id',
'section_id', 'section_id',
'stage_id',
'state_id', 'state_id',
'type_id', 'type_id',
'user_id', 'user_id',
@ -472,6 +471,15 @@ class crm_lead(base_stage, format_address, osv.osv):
return 'lead' 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): def _merge_data(self, cr, uid, ids, oldest, fields, context=None):
""" """
Prepare lead/opp data into a dictionary for merging. Different types Prepare lead/opp data into a dictionary for merging. Different types
@ -520,7 +528,7 @@ class crm_lead(base_stage, format_address, osv.osv):
# Define the resulting type ('lead' or 'opportunity') # Define the resulting type ('lead' or 'opportunity')
data['type'] = self._merge_get_result_type(cr, uid, opportunities, context) 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 return data
def _merge_find_oldest(self, cr, uid, ids, context=None): def _merge_find_oldest(self, cr, uid, ids, context=None):
@ -533,9 +541,6 @@ class crm_lead(base_stage, format_address, osv.osv):
if context is None: if context is None:
context = {} context = {}
if context.get('convert'):
ids = list(set(ids) - set(context.get('lead_ids', [])))
# Search opportunities order by create date # Search opportunities order by create date
opportunity_ids = self.search(cr, uid, [('id', 'in', ids)], order='create_date', context=context) opportunity_ids = self.search(cr, uid, [('id', 'in', ids)], order='create_date', context=context)
oldest_opp_id = opportunity_ids[0] oldest_opp_id = opportunity_ids[0]
@ -643,19 +648,11 @@ class crm_lead(base_stage, format_address, osv.osv):
if len(ids) <= 1: if len(ids) <= 1:
raise osv.except_osv(_('Warning!'),_('Please select more than one element (lead or opportunity) from the list view.')) raise osv.except_osv(_('Warning!'),_('Please select more than one element (lead or opportunity) from the list view.'))
ids.sort()
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))
oldest = self._merge_find_oldest(cr, uid, ids, context=context) oldest = self._merge_find_oldest(cr, uid, ids, context=context)
if ctx_opportunities: opportunities_rest = self.browse(cr, uid, list(set(ids) - set([oldest.id])), context=context)
first_opportunity = ctx_opportunities[0] first_opportunity = oldest
tail_opportunities = opportunities_list + ctx_opportunities[1:] tail_opportunities = opportunities_rest
else:
first_opportunity = opportunities_list[0]
tail_opportunities = opportunities_list[1:]
merged_data = self._merge_data(cr, uid, ids, oldest, CRM_LEAD_FIELDS_TO_MERGE, context=context) merged_data = self._merge_data(cr, uid, ids, oldest, CRM_LEAD_FIELDS_TO_MERGE, context=context)
@ -664,7 +661,7 @@ class crm_lead(base_stage, format_address, osv.osv):
self._merge_opportunity_attachments(cr, uid, first_opportunity.id, tail_opportunities, context=context) self._merge_opportunity_attachments(cr, uid, first_opportunity.id, tail_opportunities, context=context)
# Merge notifications about loss of information # Merge notifications about loss of information
self._merge_notify(cr, uid, first_opportunity, opportunities, context=context) self._merge_notify(cr, uid, first_opportunity, tail_opportunities, context=context)
# Write merged data into first opportunity # Write merged data into first opportunity
self.write(cr, uid, [first_opportunity.id], merged_data, context=context) self.write(cr, uid, [first_opportunity.id], merged_data, context=context)
# Delete tail opportunities # Delete tail opportunities
@ -763,7 +760,9 @@ class crm_lead(base_stage, format_address, osv.osv):
res = False res = False
res_partner = self.pool.get('res.partner') res_partner = self.pool.get('res.partner')
if partner_id: if partner_id:
res_partner.write(cr, uid, partner_id, {'section_id': lead.section_id.id or False}) if lead.section_id:
print '---TESTTRUE---'
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'] contact_id = res_partner.address_get(cr, uid, [partner_id])['default']
res = lead.write({'partner_id': partner_id}, context=context) res = lead.write({'partner_id': partner_id}, context=context)
message = _("<b>Partner</b> set to <em>%s</em>." % (lead.partner_id.name)) message = _("<b>Partner</b> set to <em>%s</em>." % (lead.partner_id.name))
@ -870,10 +869,6 @@ class crm_lead(base_stage, format_address, osv.osv):
'res_model': 'crm.lead', 'res_model': 'crm.lead',
'domain': [('type', '=', 'opportunity')], 'domain': [('type', '=', 'opportunity')],
'res_id': int(opportunity_id), 'res_id': int(opportunity_id),
'view_id': False,
'views': [(form_view or False, 'form'),
(tree_view or False, 'tree'),
(False, 'calendar'), (False, 'graph')],
'type': 'ir.actions.act_window', 'type': 'ir.actions.act_window',
} }

View File

@ -34,7 +34,8 @@ class crm_lead2opportunity_partner(osv.osv_memory):
('convert', 'Convert to opportunity'), ('convert', 'Convert to opportunity'),
('merge', 'Merge with existing opportunities') ('merge', 'Merge with existing opportunities')
], 'Conversion Action', required=True), ], 'Conversion Action', required=True),
'opportunity_ids': fields.many2many('crm.lead', string='Opportunities', domain=[('type', '=', 'opportunity')]), 'opportunity_ids': fields.many2many('crm.lead', string='Opportunities'),
'partner_id': fields.many2one('res.partner', 'Customer'),
} }
def default_get(self, cr, uid, fields, context=None): def default_get(self, cr, uid, fields, context=None):
@ -55,15 +56,14 @@ class crm_lead2opportunity_partner(osv.osv_memory):
#TOFIX: use mail.mail_message.to_mail #TOFIX: use mail.mail_message.to_mail
email = re.findall(r'([^ ,<@]+@[^> ,]+)', lead.email_from or '') email = re.findall(r'([^ ,<@]+@[^> ,]+)', lead.email_from or '')
email = email[0]
if partner_id: if partner_id:
# Search for opportunities that have the same partner and that arent done or cancelled # 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')]) ids = lead_obj.search(cr, uid, [('partner_id', '=', partner_id)])
for id in ids: for id in ids:
tomerge.add(id) tomerge.add(id)
if email: if email:
ids = lead_obj.search(cr, uid, [('email_from', 'ilike', email), ('type', '=', 'opportunity')]) ids = lead_obj.search(cr, uid, [('email_from', 'ilike', email[0])])
for id in ids: for id in ids:
tomerge.add(id) tomerge.add(id)
@ -72,7 +72,7 @@ class crm_lead2opportunity_partner(osv.osv_memory):
if 'partner_id' in fields: if 'partner_id' in fields:
res.update({'partner_id' : partner_id}) res.update({'partner_id' : partner_id})
if 'name' in fields: if 'name' in fields:
res.update({'name' : ids and 'merge' or 'convert'}) res.update({'name' : len(tomerge) >= 2 and 'merge' or 'convert'})
if 'opportunity_ids' in fields and len(tomerge) >= 2: if 'opportunity_ids' in fields and len(tomerge) >= 2:
res.update({'opportunity_ids': list(tomerge)}) res.update({'opportunity_ids': list(tomerge)})
@ -108,39 +108,44 @@ class crm_lead2opportunity_partner(osv.osv_memory):
lead.allocate_salesman(cr, uid, lead_ids, user_ids, team_id=team_id, context=context) lead.allocate_salesman(cr, uid, lead_ids, user_ids, team_id=team_id, context=context)
return res return res
def _merge_opportunity(self, cr, uid, ids, opportunity_ids, 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 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): def action_apply(self, cr, uid, ids, context=None):
""" """
Convert lead to opportunity or merge lead and opportunity and open Convert lead to opportunity or merge lead and opportunity and open
the freshly created opportunity view. 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":
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: if context is None:
context = {} context = {}
lead = self.pool.get('crm.lead') lead = self.pool.get('crm.lead')
lead_ids = context.get('active_ids', []) lead_ids = context.get('active_ids', [])
data = self.browse(cr, uid, ids, context=context)[0] data = self.browse(cr, uid, ids, context=context)[0]
self._convert_opportunity(cr, uid, ids, {'lead_ids': lead_ids}, context=context) print repr(data._table._columns)
if data.name == 'merge': partner_id = data.partner_id and data.partner_id.id or False
self._merge_opportunity(cr, uid, ids, data.opportunity_ids, context=context) return lead.handle_partner_assignation(cr, uid, lead_ids, data.action, partner_id, context=context)
return lead.redirect_opportunity_view(cr, uid, lead_ids[0], context=context)
class crm_lead2opportunity_mass_convert(osv.osv_memory): class crm_lead2opportunity_mass_convert(osv.osv_memory):
_name = 'crm.lead2opportunity.partner.mass' _name = 'crm.lead2opportunity.partner.mass'

View File

@ -13,7 +13,7 @@
<group string="Opportunities"> <group string="Opportunities">
<field name="opportunity_ids" attrs="{'invisible': [('name', '!=', 'merge')]}" nolabel="1"> <field name="opportunity_ids" attrs="{'invisible': [('name', '!=', 'merge')]}" nolabel="1">
<tree> <tree>
<field name="create_date" groups="base.group_no_one"/> <field name="create_date"/>
<field name="name"/> <field name="name"/>
<field name="type"/> <field name="type"/>
<field name="contact_name"/> <field name="contact_name"/>
@ -59,10 +59,16 @@
<group string="Select Opportunities" attrs="{'invisible': [('name', '!=', 'merge')]}"> <group string="Select Opportunities" attrs="{'invisible': [('name', '!=', 'merge')]}">
<field name="opportunity_ids" colspan="4" nolabel="1" attrs="{'invisible': [('name', '=', 'convert')]}"> <field name="opportunity_ids" colspan="4" nolabel="1" attrs="{'invisible': [('name', '=', 'convert')]}">
<tree> <tree>
<field name="create_date"/>
<field name="name"/> <field name="name"/>
<field name="partner_id"/> <field name="type"/>
<field name="user_id"/> <field name="contact_name"/>
<field name="section_id"/> <field name="country_id" invisible="context.get('invisible_country', True)"/>
<field name="email_from"/>
<field name="phone"/>
<field name="stage_id"/>
<field name="user_id" invisible="1"/>
<field name="section_id" invisible="context.get('invisible_section', True)"/>
</tree> </tree>
</field> </field>
</group> </group>

View File

@ -11,7 +11,7 @@
<separator string="Select Leads/Opportunities"/> <separator string="Select Leads/Opportunities"/>
<field name="opportunity_ids"> <field name="opportunity_ids">
<tree> <tree>
<field name="create_date" groups="base.group_no_one"/> <field name="create_date"/>
<field name="name"/> <field name="name"/>
<field name="type"/> <field name="type"/>
<field name="contact_name"/> <field name="contact_name"/>

View File

@ -96,20 +96,4 @@ class crm_partner_binding(osv.osv_memory):
return res 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: # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: