[FIX] crm, claim : crm stage button behavior

bzr revid: tfr@openerp.com-20101220090936-8vts5qdi45kmph8q
This commit is contained in:
Thibault Francois
2010-12-20 10:09:36 +01:00
10 changed files with 217 additions and 75 deletions
+91 -12
View File
@@ -47,7 +47,68 @@ AVAILABLE_PRIORITIES = [
class crm_case(object):
"""A simple python class to be used for common functions """
def _find_lost_stage(self, cr, uid, type, section_id):
return self._find_percent_stage(cr, uid, 0.0, type, section_id)
def _find_won_stage(self, cr, uid, type, section_id):
return self._find_percent_stage(cr, uid, 100.0, type, section_id)
def _find_percent_stage(self, cr, uid, percent, type, section_id):
"""
Return the first stage with a probability == percent
"""
stage_pool = self.pool.get('crm.case.stage')
if section_id :
ids = stage_pool.search(cr, uid, [("probability", '=', percent), ("type", 'like', type), ("section_ids", 'in', [section_id])])
else :
ids = stage_pool.search(cr, uid, [("probability", '=', percent), ("type", 'like', type)])
if ids:
return ids[0]
return False
def _find_first_stage(self, cr, uid, type, section_id):
"""
return the first stage that has a sequence number equal or higher than sequence
"""
stage_pool = self.pool.get('crm.case.stage')
if section_id :
ids = stage_pool.search(cr, uid, [("sequence", '>', 0), ("type", 'like', type), ("section_ids", 'in', [section_id])])
else :
ids = stage_pool.search(cr, uid, [("sequence", '>', 0), ("type", 'like', type)])
if ids:
stages = stage_pool.browse(cr, uid, ids)
stage_min = stages[0]
for stage in stages:
if stage_min.sequence > stage.sequence:
stage_min = stage
return stage_min.id
else :
return False
def onchange_stage_id(self, cr, uid, ids, stage_id, context={}):
""" @param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current user’s ID for security checks,
@param ids: List of stage’s IDs
@stage_id: change state id on run time """
if not stage_id:
return {'value':{}}
stage = self.pool.get('crm.case.stage').browse(cr, uid, stage_id, context)
if not stage.on_change:
return {'value':{}}
return {'value':{'probability': stage.probability}}
def _get_default_partner_address(self, cr, uid, context=None):
"""Gives id of default address for current user
@param self: The object pointer
@param cr: the current row, from the database cursor,
@@ -149,6 +210,9 @@ class crm_case(object):
return False
next_seq = next_stage.sequence
if not current_seq :
current_seq = 0
if (abs(next_seq - current_seq)) >= 1:
return next_stage
else :
@@ -157,17 +221,21 @@ class crm_case(object):
def stage_change(self, cr, uid, ids, context=None, order='sequence'):
if context is None:
context = {}
stage_pool = self.pool.get('crm.case.stage')
stage_type = context and context.get('stage_type','')
current_seq = False
next_stage_id = False
for case in self.browse(cr, uid, ids, context=context):
next_stage = False
data = {}
value = {}
if case.section_id.id :
domain = [('type', '=', stage_type),('section_ids', '=', case.section_id.id)]
else :
domain = [('type', '=', stage_type)]
domain = [('type', '=', stage_type),('section_ids', '=', case.section_id.id)]
if case.section_id and case.section_id.stage_ids:
domain.append(('id', 'in', map(lambda x: x.id, case.section_id.stage_ids)))
stages = stage_pool.search(cr, uid, domain, order=order)
current_seq = case.stage_id.sequence
@@ -176,14 +244,16 @@ class crm_case(object):
index = stages.index(case.stage_id.id)
next_stage = self._find_next_stage(cr, uid, stages, index, current_seq, stage_pool, context=context)
if next_stage:
next_stage_id = next_stage.id
data = {'stage_id': next_stage.id}
value.update({'stage_id': next_stage.id})
if next_stage.on_change:
data.update({'probability': next_stage.probability})
self.write(cr, uid, [case.id], data, context=context)
value.update({'probability': next_stage.probability})
self.write(cr, uid, [case.id], value, context=context)
return next_stage_id
return next_stage_id #FIXME should return a list of all id
def stage_next(self, cr, uid, ids, context=None):
@@ -194,7 +264,6 @@ class crm_case(object):
@param uid: the current user’s ID for security checks,
@param ids: List of case IDs
@param context: A standard dictionary for contextual values"""
return self.stage_change(cr, uid, ids, context=context, order='sequence')
@@ -257,6 +326,7 @@ class crm_case(object):
@param ids: List of case Ids
@param *args: Tuple Value for additional Params
"""
cases = self.browse(cr, uid, ids)
self._history(cr, uid, cases, _('Open'))
for case in cases:
@@ -264,7 +334,9 @@ class crm_case(object):
if not case.user_id:
data['user_id'] = uid
self.write(cr, uid, case.id, data)
self._action(cr, uid, cases, 'open')
self._action(cr, uid, cases, 'open')
return True
def case_close(self, cr, uid, ids, *args):
@@ -483,6 +555,12 @@ class crm_case_stage(osv.osv):
_description = "Stage of case"
_rec_name = 'name'
_order = "sequence"
def _get_type_value(self, cr, user, context):
return [('lead','Lead'),('opportunity','Opportunity')]
_columns = {
'name': fields.char('Stage Name', size=64, required=True, translate=True),
@@ -491,9 +569,10 @@ class crm_case_stage(osv.osv):
'on_change': fields.boolean('Change Probability Automatically', \
help="Change Probability on next and previous stages."),
'requirements': fields.text('Requirements'),
'type': fields.selection([('lead','Lead'),('opportunity','Opportunity'),('claim','Claim'), ('fundraising','Fundraising')], 'Type'),
'type': fields.selection(_get_type_value, 'Type'),
}
def _find_stage_type(self, cr, uid, context=None):
"""Finds type of stage according to object.
@param self: The object pointer
+26 -34
View File
@@ -151,18 +151,6 @@ class crm_lead(crm_case, osv.osv):
'message_ids': fields.one2many('mailgate.message', 'res_id', 'Messages', domain=[('model','=',_name)]),
}
def _get_stage_id(self, cr, uid, context=None):
"""Finds type of stage according to object.
@param self: The object pointer
@param cr: the current row, from the database cursor,
@param uid: the current user’s ID for security checks,
@param context: A standard dictionary for contextual values
"""
if context is None:
context = {}
type = context and context.get('stage_type', '')
stage_ids = self.pool.get('crm.case.stage').search(cr, uid, [('type','=',type),('sequence','>=',1)])
return stage_ids and stage_ids[0] or False
_defaults = {
'active': lambda *a: 1,
@@ -173,8 +161,10 @@ class crm_lead(crm_case, osv.osv):
'section_id': crm_case._get_section,
'company_id': lambda s, cr, uid, c: s.pool.get('res.company')._company_default_get(cr, uid, 'crm.lead', context=c),
'priority': lambda *a: crm.AVAILABLE_PRIORITIES[2][0],
'stage_id': _get_stage_id,
#'stage_id': _get_stage_id,
}
def onchange_partner_address_id(self, cr, uid, ids, add, email=False):
"""This function returns value of partner email based on Partner Address
@@ -198,27 +188,30 @@ class crm_lead(crm_case, osv.osv):
@param ids: List of case's Ids
@param *args: Give Tuple Value
"""
old_state = self.read(cr, uid, ids, ['state'])[0]['state']
old_stage_id = self.read(cr, uid, ids, ['stage_id'])[0]['stage_id']
leads = self.browse(cr, uid, ids)
for i in xrange(0, len(ids)):
if leads[i].state == 'draft':
value = {}
if not leads[i].stage_id :
stage_id = self._find_first_stage(cr, uid, leads[i].type, leads[i].section_id.id or False)
value.update({'stage_id' : stage_id})
value.update({'date_open': time.strftime('%Y-%m-%d %H:%M:%S')})
self.write(cr, uid, [ids[i]], value)
self.log_open( cr, uid, leads[i])
res = super(crm_lead, self).case_open(cr, uid, ids, *args)
if old_state == 'draft':
value = {}
if not old_stage_id:
stage_id = super(crm_lead, self).stage_next(cr, uid, ids, *args)
if stage_id:
value.update(self.onchange_stage_id(cr, uid, ids, stage_id, context={})['value'])
value.update({'date_open': time.strftime('%Y-%m-%d %H:%M:%S')})
self.write(cr, uid, ids, value)
for case in self.browse(cr, uid, ids):
if case.type == 'lead':
message = _("The lead '%s' has been opened.") % case.name
elif case.type == 'opportunity':
message = _("The opportunity '%s' has been opened.") % case.name
else:
message = _("The case '%s' has been opened.") % case.name
self.log(cr, uid, case.id, message)
return res
def log_open(self, cr, uid, case):
if case.type == 'lead':
message = _("The lead '%s' has been opened.") % case.name
elif case.type == 'opportunity':
message = _("The opportunity '%s' has been opened.") % case.name
else:
message = _("The case '%s' has been opened.") % case.name
self.log(cr, uid, case.id, message)
def case_close(self, cr, uid, ids, *args):
"""Overrides close for crm_case for setting close date
@@ -228,7 +221,7 @@ class crm_lead(crm_case, osv.osv):
@param ids: List of case Ids
@param *args: Tuple Value for additional Params
"""
res = super(crm_lead, self).case_close(cr, uid, ids, args)
res = super(crm_lead, self).case_close(cr, uid, ids, *args)
self.write(cr, uid, ids, {'date_closed': time.strftime('%Y-%m-%d %H:%M:%S')})
for case in self.browse(cr, uid, ids):
if case.type == 'lead':
@@ -399,7 +392,6 @@ class crm_lead(crm_case, osv.osv):
if case.state in CRM_LEAD_PENDING_STATES:
values.update(state=crm.AVAILABLE_STATES[1][0]) #re-open
res = self.write(cr, uid, [case.id], values, context=context)
return res
def msg_send(self, cr, uid, id, *args, **argv):
+2
View File
@@ -13,6 +13,8 @@
<field name="context">{'type':'lead'}</field>
<field name="help">Create specific stages that will help your sales better organise their sales pipeline by maintaining them to their leads and sales opportunities. It will allow them to easily track how is positioned a specific lead or opportunity in the sales cycle.</field>
</record>
<menuitem action="crm_lead_stage_act" id="menu_crm_lead_stage_act" name="Stages"
groups="base.group_extended" sequence="0"
+27 -21
View File
@@ -53,6 +53,28 @@ class crm_opportunity(osv.osv):
'stage_id': fields.many2one('crm.case.stage', 'Stage', domain="[('type','=','opportunity')]"),
}
def _case_close_generic(self, cr, uid, ids, find_stage, *args):
res = super(crm_opportunity, self).case_close(cr, uid, ids, *args)
for case in self.browse(cr, uid, ids):
#if the case is not an opportunity close won't change the stage
if not case.type == 'opportunity':
return res
value = {}
stage_id = find_stage(cr, uid, 'opportunity', case.section_id.id or False)
if stage_id:
stage_obj = self.pool.get('crm.case.stage').browse(cr, uid, stage_id)
value.update({'stage_id': stage_id})
if stage_obj.on_change:
value.update({'probability': stage_obj.probability})
#Done un crm.case
#value.update({'date_closed': time.strftime('%Y-%m-%d %H:%M:%S')})
self.write(cr, uid, ids, value)
return res
def case_close(self, cr, uid, ids, *args):
"""Overrides close for crm_case for setting probability and close date
@param self: The object pointer
@@ -61,16 +83,8 @@ class crm_opportunity(osv.osv):
@param ids: List of case Ids
@param *args: Tuple Value for additional Params
"""
res = super(crm_opportunity, self).case_close(cr, uid, ids, args)
data_obj = self.pool.get('ir.model.data')
data_id = data_obj._get_id(cr, uid, 'crm', 'stage_lead5')
stage_id = data_obj.browse(cr, uid, data_id).res_id
stage_obj = self.pool.get('crm.case.stage').browse(cr, uid, stage_id)
value = {'date_closed': time.strftime('%Y-%m-%d %H:%M:%S'), 'stage_id': stage_id}
if stage_obj.on_change:
value.update({'probability': stage_obj.probability})
self.write(cr, uid, ids, value)
res = self._case_close_generic(cr, uid, ids, self._find_won_stage, *args)
for (id, name) in self.name_get(cr, uid, ids):
opp = self.browse(cr, uid, id)
if opp.type == 'opportunity':
@@ -86,16 +100,8 @@ class crm_opportunity(osv.osv):
@param ids: List of case Ids
@param *args: Tuple Value for additional Params
"""
res = super(crm_opportunity, self).case_close(cr, uid, ids, args)
data_obj = self.pool.get('ir.model.data')
data_id = data_obj._get_id(cr, uid, 'crm', 'stage_lead6')
stage_id = data_obj.browse(cr, uid, data_id).res_id
stage_obj = self.pool.get('crm.case.stage').browse(cr, uid, stage_id)
value = {'date_closed': time.strftime('%Y-%m-%d %H:%M:%S'), 'stage_id': stage_id}
if stage_obj.on_change:
value.update({'probability': stage_obj.probability})
self.write(cr, uid, ids, value)
res = self._case_close_generic(cr, uid, ids, self._find_lost_stage, *args)
for (id, name) in self.name_get(cr, uid, ids):
opp = self.browse(cr, uid, id)
if opp.type == 'opportunity':
@@ -137,7 +143,7 @@ class crm_opportunity(osv.osv):
@param *args: Give Tuple Value
"""
res = super(crm_opportunity, self).case_open(cr, uid, ids, *args)
self.write(cr, uid, ids, {'date_open': time.strftime('%Y-%m-%d %H:%M:%S')})
return res
def onchange_stage_id(self, cr, uid, ids, stage_id, context=None):
+2
View File
@@ -11,6 +11,8 @@
<field name="context">{'type':'opportunity'}</field>
<field name="help">Create specific stages that will help your sales better organise their sales pipeline by maintaining them to their sales opportunities. It will allow them to easily track how is positioned a specific opportunity in the sales cycle.</field>
</record>
<menuitem action="crm_opportunity_stage_act" id="menu_crm_opportunity_stage_act" name="Stages"
groups="base.group_extended" sequence="0"
+5 -1
View File
@@ -108,6 +108,7 @@
<field name="sequence"/>
<field name="name"/>
<field name="probability"/>
<field name="type" />
</tree>
</field>
</record>
@@ -118,17 +119,19 @@
<field name="name">crm.case.stage.form</field>
<field name="model">crm.case.stage</field>
<field name="type">form</field>
<field name="priority" eval="1"/>
<field name="arch" type="xml">
<form string="Stage">
<separator string="Stage Definition" colspan="4"/>
<field name="name" select="1"/>
<field name="type" invisible="1" />
<field name="section_ids" invisible="1" />
<field name="sequence"/>
<field name="probability"/>
<field name="on_change"/>
<separator string="Requirements" colspan="4"/>
<field name="requirements" nolabel="1" colspan="4"/>
<field name="section_ids" invisible="1" />
</form>
</field>
</record>
@@ -141,6 +144,7 @@
<field name="view_type">form</field>
<field name="view_id" ref="crm_case_stage_tree"/>
</record>
<!-- Case Categories Form View -->
+32 -1
View File
@@ -96,7 +96,7 @@ class crm_claim(crm.crm_case, osv.osv):
'date': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'),
'company_id': lambda s, cr, uid, c: s.pool.get('res.company')._company_default_get(cr, uid, 'crm.case', context=c),
'priority': lambda *a: crm.AVAILABLE_PRIORITIES[2][0],
'stage_id': _get_stage_id,
#'stage_id': _get_stage_id,
}
def onchange_partner_id(self, cr, uid, ids, part, email=False):
@@ -132,7 +132,38 @@ class crm_claim(crm.crm_case, osv.osv):
return {'value': {'email_from': False}}
address = self.pool.get('res.partner.address').browse(cr, uid, add)
return {'value': {'email_from': address.email, 'partner_phone': address.phone, 'partner_mobile': address.mobile}}
def case_open(self, cr, uid, ids, *args):
"""
Opens Claim
"""
res = super(crm_claim, self).case_open(cr, uid, ids, *args)
claims = self.browse(cr, uid, ids)
for i in xrange(0, len(ids)):
if not claims[i].stage_id :
stage_id = self._find_first_stage(cr, uid, 'claim', claims[i].section_id.id or False)
self.write(cr, uid, [ids[i]], {'stage_id' : stage_id})
return res
crm_claim()
class crm_stage_claim(osv.osv):
def _get_type_value(self, cr, user, context):
list = super(crm_stage_claim, self)._get_type_value(cr, user, context)
list.append(('claim','Claim'))
return list
_inherit = "crm.case.stage"
_columns = {
'type': fields.selection(_get_type_value, 'Type'),
}
crm_stage_claim()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
+14 -6
View File
@@ -33,7 +33,7 @@
<field name="context">{'type':'claim'}</field>
<field name="help">You can create claim stages to categorize the status of every claim entered in the system. The stages define all the steps required for the resolution of a claim.</field>
</record>
<menuitem action="crm_claim_stage_act" name="Stages"
id="menu_crm_claim_stage_act" parent="menu_config_claim" />
@@ -70,18 +70,26 @@
<field name="type">form</field>
<field name="arch" type="xml">
<form string="Claims">
<group colspan="4" col="6">
<group>
<field name="name" />
<field name="date"/>
<field name="date_deadline"/>
<newline/>
</group>
<group colspan="4" col="6">
<field name="user_id"/>
<field name="priority"/>
<field name="section_id" widget="selection" />
<group colspan="2" col="4">
<field name="stage_id" domain="[('type','=','claim')]"/>
<field name="stage_id" domain="[('type','=','claim'),('section_ids', '=', section_id)]"/>
<button name="stage_previous" string="" type="object" icon="gtk-go-back" />
<button icon="gtk-go-forward" string="" name="stage_next" type="object"/>
</group>
<newline />
<field name="priority"/>
<field name="date_deadline"/>
</group>
<group colspan="4" col="4">
<notebook>
+16
View File
@@ -94,3 +94,19 @@ class crm_fundraising(crm.crm_case, osv.osv):
}
crm_fundraising()
class crm_stage_fundraising(osv.osv):
def _get_type_value(self, cr, user, context):
list = super(crm_stage_fundraising, self)._get_type_value(cr, user, context)
list.append(('fundraising','Fundraising'))
return list
_inherit = "crm.case.stage"
_columns = {
'type': fields.selection(_get_type_value, 'Type'),
}
crm_stage_fundraising()
@@ -33,6 +33,8 @@
<field name="context">{'type':'fundraising'}</field>
<field name="help">Create and manage fund raising activity categories you want to be maintained in the system.</field>
</record>
<menuitem action="crm_fundraising_stage_act"
groups="base.group_extended" name="Stages"