[IMP] crm: stage management
Stages are now sales team dependant, and not shared anymore. This comes with a sales-team way of working : - sales team is the entrance point, click on the big Pipeline button to see the opportunities pipeline of this specific sales team - no more opportunities menu entry, as you should come from a sales team - leads are still sales-team agnostic The stage management has been updated : - Won is still a stage (probability=100, onchange=1). - Lost is not a stage anymore. Lost is equivalent to archiving. Archiving uses the active field. Setting a lead or an opportunity as lost set them as unactive. Downside of the no more share policy: multi sales team opportunities management can quickly become complicated. Indeed you may have stages with the same name, not being the same stage, therefore not displayed in the same column. Grouping on the stage name leads to other issues (sequencing incoherence, impossible to drag n drop), so this is not an option.
This commit is contained in:
committed by
Thibault Delavallée
parent
a056a5d890
commit
f255aa7b36
@@ -46,6 +46,7 @@ Dashboard for CRM will include:
|
||||
'data': [
|
||||
'data/crm_action_data.xml',
|
||||
'crm_data.xml',
|
||||
'data/crm_stage_data.xml',
|
||||
'crm_lead_data.xml',
|
||||
'crm_tip_data.xml',
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data noupdate="1">
|
||||
|
||||
<record id="base.user_demo" model="res.users">
|
||||
<field name="groups_id" eval="[(4,ref('base.group_sale_salesman'))]"/>
|
||||
</record>
|
||||
@@ -9,10 +8,5 @@
|
||||
<record id="sales_team.team_sales_department" model="crm.team">
|
||||
<field name="member_ids" eval="[(4, ref('base.user_demo'))]"/>
|
||||
</record>
|
||||
|
||||
<record model="crm.team" id="sales_team.crm_team_1">
|
||||
<field name="name">Indirect Sales</field>
|
||||
<field name="member_ids" eval="[(4, ref('base.user_root')),(4, ref('base.user_demo'))]"/>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
+25
-37
@@ -249,6 +249,7 @@ class crm_lead(format_address, osv.osv):
|
||||
'team_id': lambda s, cr, uid, c: s.pool['crm.team']._get_default_team_id(cr, uid, context=c),
|
||||
'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_stage.AVAILABLE_PRIORITIES[0][0],
|
||||
'probability': 10,
|
||||
'color': 0,
|
||||
'date_last_stage_update': fields.datetime.now,
|
||||
}
|
||||
@@ -260,13 +261,10 @@ class crm_lead(format_address, osv.osv):
|
||||
def onchange_stage_id(self, cr, uid, ids, stage_id, context=None):
|
||||
if not stage_id:
|
||||
return {'value': {}}
|
||||
stage = self.pool.get('crm.stage').browse(cr, uid, stage_id, context=context)
|
||||
stage = self.pool['crm.stage'].browse(cr, uid, stage_id, context=context)
|
||||
if not stage.on_change:
|
||||
return {'value': {}}
|
||||
vals = {'probability': stage.probability}
|
||||
if stage.on_change and (stage.probability >= 100 or (stage.probability == 0 and stage.sequence > 1)):
|
||||
vals['date_closed'] = fields.datetime.now()
|
||||
return {'value': vals}
|
||||
return {'value': {'probability': stage.probability}}
|
||||
|
||||
def on_change_partner_id(self, cr, uid, ids, partner_id, context=None):
|
||||
values = {}
|
||||
@@ -345,28 +343,20 @@ class crm_lead(format_address, osv.osv):
|
||||
return stage_ids[0]
|
||||
return False
|
||||
|
||||
def case_mark_lost(self, cr, uid, ids, context=None):
|
||||
""" Mark the case as lost: state=cancel and probability=0
|
||||
"""
|
||||
stages_leads = {}
|
||||
for lead in self.browse(cr, uid, ids, context=context):
|
||||
stage_id = self.stage_find(cr, uid, [lead], lead.team_id.id or False, [('probability', '=', 0.0), ('on_change', '=', True), ('sequence', '>', 1)], context=context)
|
||||
if stage_id:
|
||||
if stages_leads.get(stage_id):
|
||||
stages_leads[stage_id].append(lead.id)
|
||||
else:
|
||||
stages_leads[stage_id] = [lead.id]
|
||||
else:
|
||||
raise UserError(_('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 action_set_lost(self, cr, uid, ids, context=None):
|
||||
""" Lost semantic: probability = 0, active = False """
|
||||
return self.write(cr, uid, ids, {'probability': 0, 'active': False}, context=context)
|
||||
# Backward compatibility
|
||||
case_mark_lost = action_set_lost
|
||||
|
||||
def case_mark_won(self, cr, uid, ids, context=None):
|
||||
""" Mark the case as won: state=done and probability=100
|
||||
"""
|
||||
def action_set_active(self, cr, uid, ids, context=None):
|
||||
return self.write(cr, uid, ids, {'active': True}, context=context)
|
||||
|
||||
def action_set_unactive(self, cr, uid, ids, context=None):
|
||||
return self.write(cr, uid, ids, {'active': False}, context=context)
|
||||
|
||||
def action_set_won(self, cr, uid, ids, context=None):
|
||||
""" Won semantic: probability = 100 (active untouched) """
|
||||
stages_leads = {}
|
||||
for lead in self.browse(cr, uid, ids, context=context):
|
||||
stage_id = self.stage_find(cr, uid, [lead], lead.team_id.id or False, [('probability', '=', 100.0), ('on_change', '=', True)], context=context)
|
||||
@@ -375,13 +365,11 @@ class crm_lead(format_address, osv.osv):
|
||||
stages_leads[stage_id].append(lead.id)
|
||||
else:
|
||||
stages_leads[stage_id] = [lead.id]
|
||||
else:
|
||||
raise UserError(_('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
|
||||
return self.write(cr, uid, ids, {'probability': 100}, context=context)
|
||||
# Backward compatibility
|
||||
case_mark_won = action_set_won
|
||||
|
||||
def log_next_activity_1(self, cr, uid, ids, context=None):
|
||||
return self.log_next_activity_done(cr, uid, ids, next_activity_name='activity_1_id', context=context)
|
||||
@@ -615,7 +603,6 @@ class crm_lead(format_address, osv.osv):
|
||||
"""
|
||||
Search for opportunities that have the same partner and that arent done or cancelled
|
||||
"""
|
||||
final_stage_domain = ['|', '|', ('stage_id.on_change', '=', False), ('stage_id.probability', 'not in', [0, 100]), ('stage_id.sequence', '<=', 1)]
|
||||
partner_match_domain = []
|
||||
for email in set(email_split(email) + [email]):
|
||||
partner_match_domain.append(('email_from', '=ilike', email))
|
||||
@@ -626,7 +613,7 @@ class crm_lead(format_address, osv.osv):
|
||||
return []
|
||||
domain = partner_match_domain
|
||||
if not include_lost:
|
||||
domain += final_stage_domain
|
||||
domain += ['&', ('active', '=', True), ('probability', '<', 100)]
|
||||
return self.search(cr, uid, domain, context=context)
|
||||
|
||||
def merge_dependences(self, cr, uid, highest, opportunities, context=None):
|
||||
@@ -723,8 +710,7 @@ class crm_lead(format_address, osv.osv):
|
||||
partner = self.pool.get('res.partner')
|
||||
customer = partner.browse(cr, uid, partner_id, context=context)
|
||||
for lead in self.browse(cr, uid, ids, context=context):
|
||||
# TDE: was if lead.state in ('done', 'cancel'):
|
||||
if (lead.probability == 100 or lead.probability == 0) and lead.stage_id.on_change and lead.stage_id.sequence > 1:
|
||||
if not lead.active or lead.probability == 100:
|
||||
continue
|
||||
vals = self._convert_opportunity_data(cr, uid, lead, customer, team_id, context=context)
|
||||
self.write(cr, uid, [lead.id], vals, context=context)
|
||||
@@ -907,9 +893,11 @@ class crm_lead(format_address, osv.osv):
|
||||
if vals.get('user_id') and 'date_open' not in vals:
|
||||
vals['date_open'] = fields.datetime.now()
|
||||
# stage change with new stage: update probability and date_closed
|
||||
if vals.get('stage_id') and not vals.get('probability'):
|
||||
if vals.get('stage_id') and 'probability' not in vals:
|
||||
onchange_stage_values = self.onchange_stage_id(cr, uid, ids, vals.get('stage_id'), context=context)['value']
|
||||
vals.update(onchange_stage_values)
|
||||
if vals.get('probability') >= 100 or not vals.get('active', True):
|
||||
vals['date_closed'] = fields.datetime.now()
|
||||
return super(crm_lead, self).write(cr, uid, ids, vals, context=context)
|
||||
|
||||
def copy(self, cr, uid, id, default=None, context=None):
|
||||
@@ -944,7 +932,7 @@ class crm_lead(format_address, osv.osv):
|
||||
record = self.browse(cr, uid, ids[0], context=context)
|
||||
if 'stage_id' in init_values and record.probability == 100 and record.stage_id and record.stage_id.on_change:
|
||||
return 'crm.mt_lead_won'
|
||||
elif 'stage_id' in init_values and record.probability == 0 and record.stage_id and record.stage_id.on_change and record.stage_id.sequence > 1:
|
||||
elif 'active' in init_values and record.probability == 0 and not record.active:
|
||||
return 'crm.mt_lead_lost'
|
||||
elif 'stage_id' in init_values and record.probability == 0 and record.stage_id and record.stage_id.sequence <= 1:
|
||||
return 'crm.mt_lead_create'
|
||||
|
||||
@@ -5,12 +5,13 @@
|
||||
<record model="ir.actions.act_window" id="crm_lead_all_leads">
|
||||
<field name="name">Leads</field>
|
||||
<field name="res_model">crm.lead</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="view_mode">tree,kanban,graph,pivot,calendar,form</field>
|
||||
<field name="domain">['|', ('type','=','lead'), ('type','=',False)]</field>
|
||||
<field name="view_id" ref="crm_case_tree_view_leads"/>
|
||||
<field name="search_view_id" ref="crm.view_crm_case_leads_filter"/>
|
||||
<field name="context">{
|
||||
'default_type':'lead',
|
||||
'search_default_type': 'lead',
|
||||
'stage_type':'lead',
|
||||
'needaction_menu_ref': 'crm.menu_crm_opportunities',
|
||||
'search_default_to_process':1,
|
||||
@@ -77,9 +78,6 @@
|
||||
<menuitem id="base.menu_sales" name="Sales" parent="base.menu_base_partner" sequence="5"/>
|
||||
<menuitem name="Leads" id="menu_crm_leads" parent="base.menu_sales" sequence="1"
|
||||
action="crm_lead_all_leads"/>
|
||||
<menuitem name="Opportunities" id="menu_crm_opportunities" parent="base.menu_sales" sequence="2"
|
||||
action="crm_lead_opportunities"
|
||||
groups="base.group_sale_salesman,base.group_sale_manager"/>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
@@ -106,6 +106,18 @@
|
||||
<header>
|
||||
<button name="%(crm.action_crm_lead2opportunity_partner)d" string="Convert to Opportunity" type="action"
|
||||
help="Convert to Opportunity" class="oe_highlight"/>
|
||||
<button name="action_set_unactive" string="Archive"
|
||||
type="object" class="oe_highlight"
|
||||
attrs="{'invisible': ['|', ('active','=',False), ('probability', '<', 100)]}"/>
|
||||
<button name="action_set_won" string="Mark Won"
|
||||
type="object" class="oe_highlight"
|
||||
attrs="{'invisible': ['|', ('active','=',False), ('probability', '=', 100)]}"/>
|
||||
<button name="action_set_lost" string="Mark Lost"
|
||||
type="object" class="oe_highlight"
|
||||
attrs="{'invisible': [('active', '=', False)]}"/>
|
||||
<button name="action_set_active" string="Unarchive"
|
||||
type="object" class="oe_highlight"
|
||||
attrs="{'invisible': [('active', '=', True)]}"/>
|
||||
<field name="stage_id" widget="statusbar" clickable="True"
|
||||
domain="['&', ('team_ids', '=', team_id), '|', ('type', '=', type), ('type', '=', 'both')]"
|
||||
options="{'fold_field': 'fold'}"
|
||||
@@ -116,6 +128,10 @@
|
||||
<div class="oe_title">
|
||||
<label for="name" class="oe_edit_only"/>
|
||||
<h1><field name="name" placeholder="Describe the lead..."/></h1>
|
||||
<span class="label label-danger"
|
||||
attrs="{'invisible': ['|', ('probability', '>', 0), ('active', '=', True)]}">Lost</span>
|
||||
<span class="label label-success"
|
||||
attrs="{'invisible': [('probability', '<', 100)]}">Won</span>
|
||||
</div>
|
||||
<group>
|
||||
<group>
|
||||
@@ -280,6 +296,7 @@
|
||||
<field name="message_unread_counter"/>
|
||||
<field name="tag_ids"/>
|
||||
<field name="partner_id"/>
|
||||
<field name="active"/>
|
||||
<templates>
|
||||
<field name="date_deadline"/>
|
||||
<t t-name="kanban-box">
|
||||
@@ -290,10 +307,10 @@
|
||||
<span class="fa fa-bars fa-lg"/>
|
||||
</a>
|
||||
<ul class="dropdown-menu" role="menu" aria-labelledby="dLabel">
|
||||
<t t-if="widget.editable"><li><a type="edit">Edit Opportunity</a></li></t>
|
||||
<t t-if="widget.editable"><li><a type="edit">Edit</a></li></t>
|
||||
<t t-if="widget.deletable"><li><a type="delete">Delete</a></li></t>
|
||||
<li><a name="%(mail.action_email_compose_message_wizard)d" type="action" >Send Email</a></li>
|
||||
<li><a name="action_schedule_meeting" type="object">Schedule Meeting</a></li>
|
||||
<li t-if="! record.active.value"><a name="action_set_active" type="object">Unarchive</a></li>
|
||||
<li t-if="record.active.value"><a name="action_set_unactive" type="object">Archive</a></li>
|
||||
<li><ul class="oe_kanban_colorpicker" data-field="color"/></li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -337,15 +354,22 @@
|
||||
<field name="create_date"/>
|
||||
<field name="country_id"/>
|
||||
<separator/>
|
||||
<filter string="Archived"
|
||||
domain="[('active', '=', False)]"/>
|
||||
<separator />
|
||||
<filter string="Leads"
|
||||
name="type_lead"
|
||||
domain="[('type', '=', 'lead')]"/>
|
||||
<filter string="Opportunities"
|
||||
name="type_opportunity"
|
||||
domain="[('type', '=', 'opportunity')]"/>
|
||||
<separator/>
|
||||
<filter string="My Leads"
|
||||
domain="[('user_id','=',uid)]"
|
||||
help="Leads that are assigned to me"/>
|
||||
<filter string="Unassigned" name="unassigned"
|
||||
domain="[('user_id','=', False)]"
|
||||
help="No salesperson"/>
|
||||
<filter string="To Process" name="to_process"
|
||||
domain="['|',('stage_id.probability','>', 0),('stage_id.fold','=', False)]"
|
||||
help="Not marked as Dead"/>
|
||||
<separator />
|
||||
<filter string="New Mail" name="message_unread" domain="[('message_unread','=',True)]"/>
|
||||
<separator />
|
||||
@@ -380,11 +404,22 @@
|
||||
<field name="arch" type="xml">
|
||||
<form string="Opportunities">
|
||||
<header>
|
||||
<button name="case_mark_won" string="Mark Won" attrs="{'invisible': [('probability', '=', 100)]}" type="object" class="oe_highlight"/>
|
||||
<button name="case_mark_lost" string="Mark Lost" attrs="{'invisible': [('probability', '=', 100)]}" type="object" class="oe_highlight"/>
|
||||
<button name="action_set_unactive" string="Archive"
|
||||
type="object" class="oe_highlight"
|
||||
attrs="{'invisible': ['|', ('active','=',False), ('probability', '<', 100)]}"/>
|
||||
<button name="action_set_won" string="Mark Won"
|
||||
type="object" class="oe_highlight"
|
||||
attrs="{'invisible': ['|', ('active','=',False), ('probability', '=', 100)]}"/>
|
||||
<button name="action_set_lost" string="Mark Lost"
|
||||
type="object" class="oe_highlight"
|
||||
attrs="{'invisible': [('active', '=', False)]}"/>
|
||||
<button name="action_set_active" string="Unarchive"
|
||||
type="object" class="oe_highlight"
|
||||
attrs="{'invisible': [('active', '=', True)]}"/>
|
||||
<field name="stage_id" widget="statusbar" clickable="True"
|
||||
options="{'fold_field': 'fold'}"
|
||||
domain="['&', ('team_ids', '=', team_id), '|', ('type', '=', type), ('type', '=', 'both')]"/>
|
||||
domain="['&', ('team_ids', '=', team_id), '|', ('type', '=', type), ('type', '=', 'both')]"
|
||||
attrs="{'invisible': [('active', '=', False)]}"/>
|
||||
</header>
|
||||
<sheet>
|
||||
<div class="oe_button_box" name="button_box">
|
||||
@@ -397,6 +432,10 @@
|
||||
<div class="oe_title">
|
||||
<label for="name" class="oe_edit_only"/>
|
||||
<h1><field name="name" placeholder="e.g. Product Pricing"/></h1>
|
||||
<span class="label label-danger"
|
||||
attrs="{'invisible': ['|', ('probability', '>', 0), ('active', '=', True)]}">Lost</span>
|
||||
<span class="label label-success"
|
||||
attrs="{'invisible': [('probability', '<', 100)]}">Won</span>
|
||||
<div class="o_row">
|
||||
<label for="planned_revenue" class="oe_edit_only"/>
|
||||
<label for="probability" class="oe_edit_only"/>
|
||||
@@ -577,8 +616,9 @@
|
||||
<field name="probability"/>
|
||||
<field name="lost_reason"/>
|
||||
<separator/>
|
||||
<filter string="New" name="new"
|
||||
domain="['&', ('stage_id.probability', '=', 0), ('stage_id.sequence', '<=', 1)]"/>
|
||||
<filter string="Archived"
|
||||
domain="[('active', '=', False)]"/>
|
||||
<separator/>
|
||||
<filter string="Won" name="won"
|
||||
domain="['&', ('stage_id.probability', '=', 100), ('stage_id.fold', '=', True)]"/>
|
||||
<filter string="Lost" name="lost"
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from openerp.osv import osv, fields
|
||||
from openerp.http import request
|
||||
|
||||
AVAILABLE_PRIORITIES = [
|
||||
('0', 'Normal'),
|
||||
@@ -11,6 +10,7 @@ AVAILABLE_PRIORITIES = [
|
||||
('3', 'Very High'),
|
||||
]
|
||||
|
||||
|
||||
class crm_stage(osv.Model):
|
||||
""" Model for case stages. This models the main stages of a document
|
||||
management flow. Main CRM objects (leads, opportunities, project
|
||||
@@ -22,6 +22,9 @@ class crm_stage(osv.Model):
|
||||
_rec_name = 'name'
|
||||
_order = "sequence"
|
||||
|
||||
def _default_team_ids(self, cr, uid, context=None):
|
||||
return context.get('default_team_id') and [(6, 0, [context['default_team_id']])] or False
|
||||
|
||||
_columns = {
|
||||
'name': fields.char('Stage Name', required=True, translate=True),
|
||||
'sequence': fields.integer('Sequence', help="Used to order stages. Lower is better."),
|
||||
@@ -43,7 +46,8 @@ class crm_stage(osv.Model):
|
||||
|
||||
_defaults = {
|
||||
'sequence': 1,
|
||||
'probability': 1.0,
|
||||
'probability': 10.0,
|
||||
'team_ids': _default_team_ids,
|
||||
'fold': False,
|
||||
'type': 'both',
|
||||
}
|
||||
|
||||
@@ -23,18 +23,11 @@
|
||||
<group>
|
||||
<field name="name"/>
|
||||
<field name="type"/>
|
||||
<field name="on_change"/>
|
||||
<label for="probability" attrs="{'invisible': [('on_change', '=', False)]}"/>
|
||||
<div attrs="{'invisible': [('on_change', '=', False)]}">
|
||||
<field name="probability"/>
|
||||
<p class="text-muted">
|
||||
A stage will be considered as 'Won' if the probability is 100% and if 'Change Probability Automatically' is true.<br/>
|
||||
A stage will be considered as 'Lost' or 'Dead' if the probability is 0% and if 'Change Probability Automatically' is true.
|
||||
</p>
|
||||
</div>
|
||||
<field name="fold"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="fold"/>
|
||||
<field name="on_change"/>
|
||||
<field name="probability" attrs="{'invisible': [('on_change', '=', False)]}"/>
|
||||
</group>
|
||||
</group>
|
||||
<separator string="Requirements"/>
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo noupdate="1">
|
||||
<record model="crm.stage" id="stage_lead1">
|
||||
<field name="name">New</field>
|
||||
<field name="probability">10</field>
|
||||
<field name="on_change">1</field>
|
||||
<field name="sequence">1</field>
|
||||
<field name="type">both</field>
|
||||
</record>
|
||||
<record model="crm.stage" id="stage_lead5">
|
||||
<field name="name">Won</field>
|
||||
<field name="fold" eval="True"/>
|
||||
<field name="probability">100</field>
|
||||
<field name="on_change">1</field>
|
||||
<field name="sequence">70</field>
|
||||
<field name="type">opportunity</field>
|
||||
</record>
|
||||
<!-- Update data sales team with default stages -->
|
||||
<record model="crm.team" id="sales_team.team_sales_department">
|
||||
<field name="stage_ids" eval="[(4, ref('stage_lead1')), (4, ref('stage_lead5'))]"/>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
@@ -3,64 +3,68 @@
|
||||
<data>
|
||||
|
||||
<!-- Crm stages -->
|
||||
<record model="crm.stage" id="stage_lead1">
|
||||
<field name="name">New</field>
|
||||
<field name="probability">0</field>
|
||||
<field name="on_change">1</field>
|
||||
<field name="sequence">1</field>
|
||||
<field name="type">both</field>
|
||||
</record>
|
||||
<record model="crm.stage" id="stage_lead2">
|
||||
<field name="name">Dead</field>
|
||||
<field name="fold">1</field>
|
||||
<field name="probability">0</field>
|
||||
<field name="on_change">1</field>
|
||||
<field name="sequence">30</field>
|
||||
<field name="type">lead</field>
|
||||
</record>
|
||||
<record model="crm.stage" id="stage_lead3">
|
||||
<field name="name">Qualification</field>
|
||||
<field name="probability">20</field>
|
||||
<field name="on_change">1</field>
|
||||
<field name="sequence">40</field>
|
||||
<field name="type">opportunity</field>
|
||||
</record>
|
||||
<record model="crm.stage" id="stage_lead4">
|
||||
<record model="crm.stage" id="stage_lead3">
|
||||
<field name="name">Proposition</field>
|
||||
<field name="probability">40</field>
|
||||
<field name="on_change">1</field>
|
||||
<field name="sequence">50</field>
|
||||
<field name="type">opportunity</field>
|
||||
</record>
|
||||
<record model="crm.stage" id="stage_lead5">
|
||||
<record model="crm.stage" id="stage_lead4">
|
||||
<field name="name">Negotiation</field>
|
||||
<field name="probability">60</field>
|
||||
<field name="on_change">1</field>
|
||||
<field name="sequence">60</field>
|
||||
<field name="type">opportunity</field>
|
||||
</record>
|
||||
<record model="crm.stage" id="stage_lead6">
|
||||
|
||||
<record model="crm.stage" id="crm_stage_2_1">
|
||||
<field name="name">New</field>
|
||||
<field name="probability">10</field>
|
||||
<field name="on_change">1</field>
|
||||
<field name="sequence">1</field>
|
||||
<field name="type">both</field>
|
||||
</record>
|
||||
<record model="crm.stage" id="crm_stage_2_2">
|
||||
<field name="name">Qualification</field>
|
||||
<field name="probability">20</field>
|
||||
<field name="on_change">1</field>
|
||||
<field name="sequence">40</field>
|
||||
<field name="type">opportunity</field>
|
||||
</record>
|
||||
<record model="crm.stage" id="crm_stage_2_3">
|
||||
<field name="name">Negotiation</field>
|
||||
<field name="probability">60</field>
|
||||
<field name="on_change">1</field>
|
||||
<field name="sequence">60</field>
|
||||
<field name="type">opportunity</field>
|
||||
</record>
|
||||
<record model="crm.stage" id="crm_stage_2_4">
|
||||
<field name="name">Won</field>
|
||||
<field name="fold">1</field>
|
||||
<field name="fold" eval="True"/>
|
||||
<field name="probability">100</field>
|
||||
<field name="on_change">1</field>
|
||||
<field name="sequence">70</field>
|
||||
<field name="type">opportunity</field>
|
||||
</record>
|
||||
<record model="crm.stage" id="stage_lead7">
|
||||
<field name="name">Lost</field>
|
||||
<field name="fold">1</field>
|
||||
<field name="probability">0</field>
|
||||
<field name="on_change">1</field>
|
||||
<field name="sequence">80</field>
|
||||
<field name="type">opportunity</field>
|
||||
</record>
|
||||
|
||||
<record model="crm.team" id="sales_team.team_sales_department">
|
||||
<field name="stage_ids" eval="[ (4, ref('stage_lead1')), (4, ref('stage_lead2')),
|
||||
(4, ref('stage_lead3')), (4, ref('stage_lead4')),
|
||||
(4, ref('stage_lead5')), (4, ref('stage_lead6')),
|
||||
(4, ref('stage_lead7'))]"/>
|
||||
<field name="stage_ids" eval="[(4, ref('stage_lead2')), (4, ref('stage_lead3')),
|
||||
(4, ref('stage_lead4'))]"/>
|
||||
</record>
|
||||
<record model="crm.team" id="sales_team.crm_team_1">
|
||||
<field name="member_ids" eval="[(4, ref('base.user_root')),(4, ref('base.user_demo'))]"/>
|
||||
<field name="stage_ids" eval="[(4, ref('crm_stage_2_1')),
|
||||
(4, ref('crm_stage_2_2')),
|
||||
(4, ref('crm_stage_2_3')),
|
||||
(4, ref('crm_stage_2_4'))]"/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
|
||||
@@ -1,12 +1,32 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from openerp.osv import fields, osv
|
||||
from openerp.tools.translate import _
|
||||
|
||||
|
||||
class crm_team(osv.Model):
|
||||
_inherit = 'crm.team'
|
||||
_inherits = {'mail.alias': 'alias_id'}
|
||||
|
||||
def _get_default_stage_ids(self, cr, uid, context=None):
|
||||
return [
|
||||
(0, 0, {
|
||||
'name': _('New'),
|
||||
'sequence': 1,
|
||||
'probability': 10.0,
|
||||
'on_change': True,
|
||||
'fold': False,
|
||||
'type': 'both',
|
||||
}),
|
||||
(0, 0, {
|
||||
'name': _('Won'),
|
||||
'sequence': 50,
|
||||
'probability': 100.0,
|
||||
'on_change': True,
|
||||
'fold': True,
|
||||
'type': 'both',
|
||||
})]
|
||||
|
||||
_columns = {
|
||||
'resource_calendar_id': fields.many2one('resource.calendar', "Working Time", help="Used to compute open days"),
|
||||
'stage_ids': fields.many2many('crm.stage', 'crm_team_stage_rel', 'team_id', 'stage_id', 'Stages'),
|
||||
@@ -22,6 +42,7 @@ class crm_team(osv.Model):
|
||||
'crm.lead', self._columns['alias_id'], 'name', alias_prefix='Lead+', alias_defaults={}, context=context)
|
||||
|
||||
_defaults = {
|
||||
'stage_ids': _get_default_stage_ids,
|
||||
'use_leads': True,
|
||||
'use_opportunities': True,
|
||||
}
|
||||
|
||||
@@ -11,28 +11,19 @@
|
||||
I check default stage of lead.
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
stage = self.pool.get('crm.stage').search_read(cr,uid,[('sequence','=',1)],['id'],context)[0]
|
||||
stage = self.pool.get('crm.stage').search_read(cr, uid, [], ['id'], context)[0]
|
||||
lead = self.browse(cr, uid, ref('test_crm_lead_new'))
|
||||
stage_id = self.stage_find(cr, uid , [lead], lead.team_id.id or False,[], context)
|
||||
assert stage_id == stage['id'], "Default stage of lead is incorrect!"
|
||||
assert lead.stage_id.id == stage['id'], "Default stage of lead is incorrect!"
|
||||
-
|
||||
I change type from lead to opportunity.
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
self.convert_opportunity(cr, uid ,[ref("test_crm_lead_new")], ref("base.res_partner_2"))
|
||||
-
|
||||
Now I check default stage after change type.
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
stage = self.pool.get('crm.stage').search_read(cr,uid,[('sequence','=',1)],['id'],context)[0]
|
||||
opp = self.browse(cr, uid, ref('test_crm_lead_new'))
|
||||
stage_id = self.stage_find(cr, uid , [opp], opp.team_id.id or False,[], context)
|
||||
assert stage_id == stage['id'], "Default stage of opportunity is incorrect!"
|
||||
-
|
||||
Now I change the stage of opportunity to won.
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
self.case_mark_won(cr, uid, [ref("test_crm_lead_new")])
|
||||
self.action_set_won(cr, uid, [ref("test_crm_lead_new")])
|
||||
-
|
||||
I check statge of opp should won, after change stage.
|
||||
-
|
||||
|
||||
@@ -73,8 +73,6 @@
|
||||
-
|
||||
!python {model: crm.lead}: |
|
||||
lead = self.browse(cr, uid, ref('crm_case_2'))
|
||||
assert lead.stage_id.id == ref('crm.stage_lead7'), "Opportunity stage should be 'Lost'."
|
||||
assert lead.stage_id.sequence != 1 and lead.stage_id.probability == 0.0, "Lost opportunity is not in 'cancel' state!"
|
||||
assert lead.probability == 0.0, "Revenue probability should be 0.0!"
|
||||
-
|
||||
I confirm review needs meeting.
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from openerp.osv import fields,osv
|
||||
from openerp.osv import fields, osv
|
||||
from openerp import tools
|
||||
from openerp.addons.crm import crm
|
||||
from openerp.addons.crm import crm_stage
|
||||
|
||||
|
||||
class crm_lead_report_assign(osv.osv):
|
||||
@@ -33,7 +33,7 @@ class crm_lead_report_assign(osv.osv):
|
||||
'date_closed': fields.datetime('Close Date', readonly=True),
|
||||
'nbr': fields.integer('# of Cases', readonly=True), # TDE FIXME master: rename into nbr_cases
|
||||
'company_id': fields.many2one('res.company', 'Company', readonly=True),
|
||||
'priority': fields.selection(crm.AVAILABLE_PRIORITIES, 'Priority'),
|
||||
'priority': fields.selection(crm_stage.AVAILABLE_PRIORITIES, 'Priority'),
|
||||
'type':fields.selection([
|
||||
('lead','Lead'),
|
||||
('opportunity','Opportunity')
|
||||
|
||||
Reference in New Issue
Block a user