from datetime import datetime
from operator import itemgetter
+import openerp
from openerp import SUPERUSER_ID
from openerp import tools
from openerp.addons.base.res.res_partner import format_address
# this is only an heuristics; depending on your particular stage configuration it may not match all 'new' stages
'crm.mt_lead_create': lambda self, cr, uid, obj, ctx=None: obj.probability == 0 and obj.stage_id and obj.stage_id.sequence <= 1,
'crm.mt_lead_stage': lambda self, cr, uid, obj, ctx=None: (obj.stage_id and obj.stage_id.sequence > 1) and obj.probability < 100,
- 'crm.mt_lead_won': lambda self, cr, uid, obj, ctx=None: obj.probability == 100 and obj.stage_id and obj.stage_id.on_change,
- 'crm.mt_lead_lost': lambda self, cr, uid, obj, ctx=None: obj.probability == 0 and obj.stage_id and obj.stage_id.sequence > 1,
+ 'crm.mt_lead_won': lambda self, cr, uid, obj, ctx=None: obj.probability == 100 and obj.stage_id and obj.stage_id.fold,
+ 'crm.mt_lead_lost': lambda self, cr, uid, obj, ctx=None: obj.probability == 0 and obj.stage_id and obj.stage_id.fold and obj.stage_id.sequence > 1,
},
}
return result, fold
def fields_view_get(self, cr, user, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
+ if view_type == 'form' and context and context.get('opportunity_id'):
+ # TODO: replace by get_formview_action call
+ lead_type = self.browse(cr, user, context['opportunity_id'], context=context).type
+ view_lead_xml_id = 'crm_case_form_view_oppor' if lead_type == 'opportunity' else 'crm_case_form_view_leads'
+ _, view_id = self.pool['ir.model.data'].get_object_reference(cr, user, 'crm', view_lead_xml_id)
res = super(crm_lead, self).fields_view_get(cr, user, view_id, view_type, context, toolbar=toolbar, submenu=submenu)
if view_type == 'form':
res['arch'] = self.fields_view_get_address(cr, user, res['arch'], context=context)
'opt_out': fields.boolean('Opt-Out', oldname='optout',
help="If opt-out is checked, this contact has refused to receive emails for mass mailing and marketing campaign. "
"Filter 'Available for Mass Mailing' allows users to filter the leads when performing mass mailing."),
- 'type':fields.selection([ ('lead','Lead'), ('opportunity','Opportunity'), ],'Type', help="Type is used to separate Leads and Opportunities"),
+ 'type': fields.selection([ ('lead','Lead'), ('opportunity','Opportunity'), ],'Type', select=True, help="Type is used to separate Leads and Opportunities"),
'priority': fields.selection(crm.AVAILABLE_PRIORITIES, 'Priority', select=True),
'date_closed': fields.datetime('Closed', readonly=True),
- 'stage_id': fields.many2one('crm.case.stage', 'Stage', track_visibility='onchange',
+ 'stage_id': fields.many2one('crm.case.stage', 'Stage', track_visibility='onchange', select=True,
domain="['&', ('section_ids', '=', section_id), '|', ('type', '=', type), ('type', '=', 'both')]"),
'user_id': fields.many2one('res.users', 'Salesperson', select=True, track_visibility='onchange'),
'referred': fields.char('Referred By', size=64),
# Only used for type opportunity
'probability': fields.float('Success Rate (%)', group_operator="avg"),
'planned_revenue': fields.float('Expected Revenue', track_visibility='always'),
- 'ref': fields.reference('Reference', selection=crm._links_get, size=128),
- 'ref2': fields.reference('Reference 2', selection=crm._links_get, size=128),
+ 'ref': fields.reference('Reference', selection=openerp.addons.base.res.res_request.referencable_models),
+ 'ref2': fields.reference('Reference 2', selection=openerp.addons.base.res.res_request.referencable_models),
'phone': fields.char("Phone", size=64),
'date_deadline': fields.date('Expected Closing', help="Estimate of the date on which the opportunity will be won."),
'date_action': fields.date('Next Action Date', select=True),
stage = self.pool.get('crm.case.stage').browse(cr, uid, stage_id, context=context)
if not stage.on_change:
return {'value': {}}
- return {'value': {'probability': stage.probability}}
+ vals = {'probability': stage.probability}
+ if stage.probability >= 100 or (stage.probability == 0 and stage.sequence > 1):
+ vals['date_closed'] = fields.datetime.now()
+ return {'value': vals}
def on_change_partner_id(self, cr, uid, ids, partner_id, context=None):
values = {}
'phone': partner.phone,
'mobile': partner.mobile,
'fax': partner.fax,
+ 'zip': partner.zip,
}
return {'value': values}
""" Mark the case as lost: state=cancel and probability=0
:deprecated: this method will be removed in OpenERP v8.
"""
- for lead in self.browse(cr, uid, ids):
+ stages_leads = {}
+ for lead in self.browse(cr, uid, ids, context=context):
stage_id = self.stage_find(cr, uid, [lead], lead.section_id.id or False, [('probability', '=', 0.0), ('fold', '=', True), ('sequence', '>', 1)], context=context)
if stage_id:
- return self.write(cr, uid, [lead.id], {'stage_id': stage_id}, context=context)
+ if stages_leads.get(stage_id):
+ stages_leads[stage_id].append(lead.id)
+ else:
+ stages_leads[stage_id] = [lead.id]
else:
raise osv.except_osv(_('Warning!'),
_('To relieve your sales pipe and group all Lost opportunities, configure one of your sales stage as follow:\n'
'probability = 0 %, select "Change Probability Automatically".\n'
'Create a specific stage or edit an existing one by editing columns of your opportunity pipe.'))
+ for stage_id, lead_ids in stages_leads.items():
+ self.write(cr, uid, lead_ids, {'stage_id': stage_id}, context=context)
+ return True
def case_mark_won(self, cr, uid, ids, context=None):
""" Mark the case as won: state=done and probability=100
:deprecated: this method will be removed in OpenERP v8.
"""
- for lead in self.browse(cr, uid, ids):
- stage_id = self.stage_find(cr, uid, [lead], lead.section_id.id or False, [('probability', '=', 100.0), ('fold', '=', True), ('sequence', '>', 1)], context=context)
+ stages_leads = {}
+ for lead in self.browse(cr, uid, ids, context=context):
+ stage_id = self.stage_find(cr, uid, [lead], lead.section_id.id or False, [('probability', '=', 100.0), ('fold', '=', True)], context=context)
if stage_id:
- return self.write(cr, uid, [lead.id], {'stage_id': stage_id}, context=context)
+ if stages_leads.get(stage_id):
+ stages_leads[stage_id].append(lead.id)
+ else:
+ stages_leads[stage_id] = [lead.id]
else:
raise osv.except_osv(_('Warning!'),
_('To relieve your sales pipe and group all Won opportunities, configure one of your sales stage as follow:\n'
'probability = 100 % and select "Change Probability Automatically".\n'
'Create a specific stage or edit an existing one by editing columns of your opportunity pipe.'))
+ for stage_id, lead_ids in stages_leads.items():
+ self.write(cr, uid, lead_ids, {'stage_id': stage_id}, context=context)
+ return True
def case_escalate(self, cr, uid, ids, context=None):
""" Escalates case to parent level """
)
return partner_id
- def _lead_set_partner(self, cr, uid, lead, partner_id, context=None):
- """
- Assign a partner to a lead.
-
- :param object lead: browse record of the lead to process
- :param int partner_id: identifier of the partner to assign
- :return bool: True if the partner has properly been assigned
- """
- res = False
- res_partner = self.pool.get('res.partner')
- if partner_id:
- 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 = _("<b>Partner</b> set to <em>%s</em>." % (lead.partner_id.name))
- self.message_post(cr, uid, [lead.id], body=message, context=context)
- return res
-
def handle_partner_assignation(self, cr, uid, ids, action='create', partner_id=False, context=None):
"""
Handle partner assignation during a lead conversion.
"""
#TODO this is a duplication of the handle_partner_assignation method of crm_phonecall
partner_ids = {}
- # If a partner_id is given, force this partner for all elements
- force_partner_id = partner_id
for lead in self.browse(cr, uid, ids, context=context):
# If the action is set to 'create' and no partner_id is set, create a new one
- if action == 'create':
- partner_id = force_partner_id or self._create_lead_partner(cr, uid, lead, context)
- self._lead_set_partner(cr, uid, lead, partner_id, context=context)
+ if lead.partner_id:
+ partner_ids[lead.id] = lead.partner_id.id
+ continue
+ if not partner_id and action == 'create':
+ partner_id = self._create_lead_partner(cr, uid, lead, context)
+ self.pool['res.partner'].write(cr, uid, partner_id, {'section_id': lead.section_id and lead.section_id.id or False})
+ if partner_id:
+ lead.write({'partner_id': partner_id}, context=context)
partner_ids[lead.id] = partner_id
return partner_ids
model_data = self.pool.get('ir.model.data')
phonecall_dict = {}
if not categ_id:
- res_id = model_data._get_id(cr, uid, 'crm', 'categ_phone2')
- if res_id:
+ try:
+ res_id = model_data._get_id(cr, uid, 'crm', 'categ_phone2')
categ_id = model_data.browse(cr, uid, res_id, context=context).res_id
+ except ValueError:
+ pass
for lead in self.browse(cr, uid, ids, context=context):
if not section_id:
section_id = lead.section_id and lead.section_id.id or False
:return dict: dictionary value for created Meeting view
"""
opportunity = self.browse(cr, uid, ids[0], context)
- res = self.pool.get('ir.actions.act_window').for_xml_id(cr, uid, 'base_calendar', 'action_crm_meeting', context)
+ res = self.pool.get('ir.actions.act_window').for_xml_id(cr, uid, 'calendar', 'action_calendar_event', context)
res['context'] = {
'default_opportunity_id': opportunity.id,
'default_partner_id': opportunity.partner_id and opportunity.partner_id.id or False,
vals.update(onchange_stage_values)
return super(crm_lead, self).write(cr, uid, ids, vals, context=context)
+ def copy(self, cr, uid, id, default=None, context=None):
+ if not default:
+ default = {}
+ if not context:
+ context = {}
+ lead = self.browse(cr, uid, id, context=context)
+ local_context = dict(context)
+ local_context.setdefault('default_type', lead.type)
+ local_context.setdefault('default_section_id', lead.section_id)
+ if lead.type == 'opportunity':
+ default['date_open'] = fields.datetime.now()
+ else:
+ default['date_open'] = False
+ default['date_closed'] = False
+ default['stage_id'] = self._get_default_stage_id(cr, uid, local_context)
+ return super(crm_lead, self).copy(cr, uid, id, default, context=context)
+
# ----------------------------------------
# Mail Gateway
# ----------------------------------------
def schedule_phonecall_send_note(self, cr, uid, ids, phonecall_id, action, context=None):
phonecall = self.pool.get('crm.phonecall').browse(cr, uid, [phonecall_id], context=context)[0]
if action == 'log':
- prefix = 'Logged'
+ message = _('Logged a call for %(date)s. %(description)s')
else:
- prefix = 'Scheduled'
- suffix = ' %s' % phonecall.description
- message = _("%s a call for %s.%s") % (prefix, phonecall.date, suffix)
+ message = _('Scheduled a call for %(date)s. %(description)s')
+ phonecall_date = datetime.strptime(phonecall.date, tools.DEFAULT_SERVER_DATETIME_FORMAT)
+ phonecall_usertime = fields.datetime.context_timestamp(cr, uid, phonecall_date, context=context).strftime(tools.DEFAULT_SERVER_DATETIME_FORMAT)
+ html_time = "<time datetime='%s+00:00'>%s</time>" % (phonecall.date, phonecall_usertime)
+ message = message % dict(date=html_time, description=phonecall.description)
return self.message_post(cr, uid, ids, body=message, context=context)
def log_meeting(self, cr, uid, ids, meeting_subject, meeting_date, duration, context=None):