[IMP] crm: usability improvements
Among various small fixes, some changes : - correct computation of default sales team, located in sales_team with a small code cleaning. Rely on this method everywhere it is necessary. - add a configuration option to enable the use of leads in sales team; otherwise it is hidden - better display of alias in empty list help; - add a menu for next activities, that are the opportunities with an action whose deadline is near assigned to the current user; - automatic update of aliases configuration on sales team, based on whether they use leads and/or opportunities; - add a wizard to log the lost reasong when deactivating a lead or an opportunity
This commit is contained in:
committed by
Thibault Delavallée
parent
d86406e8af
commit
30a7ef804a
@@ -54,6 +54,7 @@ Dashboard for CRM will include:
|
||||
'security/crm_security.xml',
|
||||
'security/ir.model.access.csv',
|
||||
|
||||
'wizard/crm_lead_lost_view.xml',
|
||||
'wizard/crm_lead_to_opportunity_view.xml',
|
||||
'wizard/crm_merge_opportunities_view.xml',
|
||||
|
||||
|
||||
@@ -1,22 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<!-- the sequence of the configuration sub menu is 30 -->
|
||||
|
||||
<record model="ir.actions.act_window" id="base_partner_merge_automatic_act">
|
||||
<field name="name">Deduplicate Contacts</field>
|
||||
<field name="res_model">base.partner.merge.automatic.wizard</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="target">new</field>
|
||||
<field name="context">{'active_test': False}</field>
|
||||
</record>
|
||||
|
||||
<menuitem id='partner_merge_automatic_menu'
|
||||
action='base_partner_merge_automatic_act'
|
||||
groups='base.group_system'
|
||||
parent='base.menu_config_address_book'
|
||||
sequence='4'/>
|
||||
<act_window id="action_partner_deduplicate"
|
||||
res_model="base.partner.merge.automatic.wizard"
|
||||
src_model="res.partner"
|
||||
target="new"
|
||||
multi="True"
|
||||
key2="client_action_multi"
|
||||
view_mode="form"
|
||||
name="Deduplicate Contact"
|
||||
context="{'default_state': 'option'}"
|
||||
/>
|
||||
|
||||
<record model='ir.ui.view' id='base_partner_merge_automatic_wizard_form'>
|
||||
<field name='name'>base.partner.merge.automatic.wizard.form</field>
|
||||
@@ -26,7 +21,7 @@
|
||||
<sheet>
|
||||
<group attrs="{'invisible': [('state', '!=', 'finished')]}" col="1">
|
||||
<h2>There is no more contacts to merge for this request...</h2>
|
||||
<button name="%(base_partner_merge_automatic_act)d" string="Deduplicate the other Contacts" class="oe_highlight"
|
||||
<button name="%(action_partner_deduplicate)d" string="Deduplicate the other Contacts" class="oe_highlight"
|
||||
type="action"/>
|
||||
</group>
|
||||
<p class="oe_grey" attrs="{'invisible': [('state', '!=', ('option'))]}">
|
||||
@@ -118,7 +113,7 @@
|
||||
</record>
|
||||
|
||||
<act_window id="action_partner_merge" res_model="base.partner.merge.automatic.wizard" src_model="res.partner"
|
||||
target="new" multi="True" key2="client_action_multi" view_mode="form" name="Automatic Merge"/>
|
||||
target="new" multi="True" key2="client_action_multi" view_mode="form" name="Merge Selected Contacts"/>
|
||||
|
||||
</data>
|
||||
|
||||
|
||||
+18
-23
@@ -58,14 +58,6 @@ class crm_lead(format_address, osv.osv):
|
||||
_inherit = ['mail.thread', 'ir.needaction_mixin', 'utm.mixin']
|
||||
_mail_mass_mailing = _('Leads / Opportunities')
|
||||
|
||||
def get_empty_list_help(self, cr, uid, help, context=None):
|
||||
context = dict(context or {})
|
||||
if context.get('default_type') == 'lead':
|
||||
context['empty_list_help_model'] = 'crm.team'
|
||||
context['empty_list_help_id'] = context.get('default_team_id')
|
||||
context['empty_list_help_document_name'] = _("leads")
|
||||
return super(crm_lead, self).get_empty_list_help(cr, uid, help, context=context)
|
||||
|
||||
def _get_default_stage_id(self, cr, uid, context=None):
|
||||
""" Gives default stage_id """
|
||||
team_id = self.pool['crm.team']._get_default_team_id(cr, uid, context=context)
|
||||
@@ -91,7 +83,7 @@ class crm_lead(format_address, osv.osv):
|
||||
# - OR ('fold', '=', False): add default columns that are not folded
|
||||
# - OR ('team_ids', '=', team_id), ('fold', '=', False) if team_id: add team columns that are not folded
|
||||
search_domain = []
|
||||
team_id = self.pool['crm.team']._resolve_team_id_from_context(cr, uid, context=context)
|
||||
team_id = context and context.get('default_team_id') or False
|
||||
if team_id:
|
||||
search_domain += ['|', ('team_ids', '=', team_id)]
|
||||
search_domain += [('id', 'in', ids)]
|
||||
@@ -183,7 +175,7 @@ class crm_lead(format_address, osv.osv):
|
||||
[('lead', 'Lead'), ('opportunity', 'Opportunity')],
|
||||
string='Type', select=True, required=True,
|
||||
help="Type is used to separate Leads and Opportunities"),
|
||||
'priority': fields.selection(crm_stage.AVAILABLE_PRIORITIES, 'Priority', select=True),
|
||||
'priority': fields.selection(crm_stage.AVAILABLE_PRIORITIES, 'Rating', select=True),
|
||||
'date_closed': fields.datetime('Closed', readonly=True, copy=False),
|
||||
'stage_id': fields.many2one('crm.stage', 'Stage', track_visibility='onchange', select=True,
|
||||
domain="['&', ('team_ids', '=', team_id), '|', ('type', '=', type), ('type', '=', 'both')]"),
|
||||
@@ -204,8 +196,6 @@ class crm_lead(format_address, osv.osv):
|
||||
# Only used for type opportunity
|
||||
'probability': fields.float('Probability', group_operator="avg"),
|
||||
'planned_revenue': fields.float('Expected Revenue', track_visibility='always'),
|
||||
'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."),
|
||||
# CRM Actions
|
||||
@@ -213,8 +203,8 @@ class crm_lead(format_address, osv.osv):
|
||||
'next_activity_1': fields.related("next_activity_id", "activity_1_id", "name", type="char", string="Next Activity 1"),
|
||||
'next_activity_2': fields.related("next_activity_id", "activity_2_id", "name", type="char", string="Next Activity 2"),
|
||||
'next_activity_3': fields.related("next_activity_id", "activity_3_id", "name", type="char", string="Next Activity 3"),
|
||||
'date_action': fields.date('Next Action Date', select=True),
|
||||
'title_action': fields.char('Next Action Summary'),
|
||||
'date_action': fields.date('Next Activity Date', select=True),
|
||||
'title_action': fields.char('Next Activity Summary'),
|
||||
|
||||
'color': fields.integer('Color Index'),
|
||||
'partner_address_name': fields.related('partner_id', 'name', type='char', string='Partner Contact Name', readonly=True),
|
||||
@@ -242,7 +232,7 @@ class crm_lead(format_address, osv.osv):
|
||||
|
||||
_defaults = {
|
||||
'active': 1,
|
||||
'type': 'lead',
|
||||
'type': lambda s, cr, uid, c: 'lead' if s.pool['res.users'].has_group(cr, uid, 'crm.group_use_lead') else 'opportunity',
|
||||
'user_id': lambda s, cr, uid, c: uid,
|
||||
'stage_id': lambda s, cr, uid, c: s._get_default_stage_id(cr, uid, c),
|
||||
'team_id': lambda s, cr, uid, c: s.pool['crm.team']._get_default_team_id(cr, uid, context=c),
|
||||
@@ -291,11 +281,7 @@ class crm_lead(format_address, osv.osv):
|
||||
def on_change_user(self, cr, uid, ids, user_id, context=None):
|
||||
""" When changing the user, also set a team_id or restrict team id
|
||||
to the ones user_id is member of. """
|
||||
team_id = self.pool['crm.team']._get_default_team_id(cr, uid, user_id=user_id, context=context)
|
||||
if user_id and not team_id:
|
||||
team_ids = self.pool.get('crm.team').search(cr, uid, ['|', ('user_id', '=', user_id), ('member_ids', '=', user_id)], context=context)
|
||||
if team_ids:
|
||||
team_id = team_ids[0]
|
||||
team_id = self.pool['crm.team']._get_default_team_id(cr, uid, context=context, user_id=user_id)
|
||||
return {'value': {'team_id': team_id}}
|
||||
|
||||
def stage_find(self, cr, uid, cases, team_id, domain=None, order='sequence', context=None):
|
||||
@@ -918,9 +904,18 @@ class crm_lead(format_address, osv.osv):
|
||||
context = dict(context or {})
|
||||
context['empty_list_help_model'] = 'crm.team'
|
||||
context['empty_list_help_id'] = context.get('default_team_id', None)
|
||||
context['empty_list_help_document_name'] = _("opportunity")
|
||||
if context.get('default_type') == 'lead':
|
||||
context['empty_list_help_document_name'] = _("lead")
|
||||
context['empty_list_help_document_name'] = _("opportunities")
|
||||
if help:
|
||||
alias_record = self.pool['ir.model.data'].xmlid_to_object(cr, uid, "crm.mail_alias_lead_info")
|
||||
if alias_record and alias_record.alias_domain and alias_record.alias_name:
|
||||
dynamic_help = '<p>%s</p>' % _("""All email incoming to %(link)s will automatically create new opportunity.
|
||||
Update your business card, phone book, social media,... Send an email right now and see it here.""") % {
|
||||
'link': "<a href='mailto:%s'>%s</a>" % (alias_record.alias_name, alias_record.alias_domain)
|
||||
}
|
||||
return '<p class="oe_view_nocontent_create">%s</p>%s%s' % (
|
||||
_('Click to add a new opportunity'),
|
||||
help,
|
||||
dynamic_help)
|
||||
return super(crm_lead, self).get_empty_list_help(cr, uid, help, context=context)
|
||||
|
||||
# ----------------------------------------
|
||||
|
||||
@@ -77,7 +77,36 @@
|
||||
|
||||
<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"/>
|
||||
action="crm_lead_all_leads" groups="crm.group_use_lead"/>
|
||||
|
||||
<record id="crm_lead_action_activities" model="ir.actions.act_window">
|
||||
<field name="name">Next Activities</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">crm.lead</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="search_view_id" ref="crm.view_crm_case_opportunities_filter"/>
|
||||
<field name="view_ids"
|
||||
eval="[(5, 0, 0),
|
||||
(0, 0, {'view_mode': 'tree', 'view_id': ref('crm_lead_view_tree_activity')}),
|
||||
(0, 0, {'view_mode': 'form', 'view_id': ref('crm_case_form_view_oppor')}),
|
||||
(0, 0, {'view_mode': 'kanban'})]"/>
|
||||
<field name="domain">[('type','=','opportunity'), ('date_action','!=',False)]</field>
|
||||
<field name="context">{
|
||||
'default_type': 'opportunity',
|
||||
'default_user_id': uid,
|
||||
'search_default_assigned_to_me': 1
|
||||
}
|
||||
</field>
|
||||
<field name="help" type="html">
|
||||
<p>
|
||||
Here is the list of your next activities. Those are linked to your opportunities.
|
||||
To set a next activity, go on an opportunity and add one. It will then appear in this list.
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<menuitem id="crm_lead_menu_activities" name="Next Activities" sequence="5"
|
||||
parent="base.menu_sales" action="crm_lead_action_activities" />
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
@@ -126,20 +126,24 @@
|
||||
<sheet>
|
||||
<div class="oe_button_box" name="button_box"/>
|
||||
<div class="oe_title">
|
||||
<label for="name" class="oe_edit_only"/>
|
||||
<label for="name" class="oe_edit_only" string="Lead"/>
|
||||
<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>
|
||||
<label for="tag_ids" class="oe_edit_only"/>
|
||||
<field name="tag_ids" widget="many2many_tags"/>
|
||||
<div class="mt4">
|
||||
<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>
|
||||
</div>
|
||||
<group>
|
||||
<group>
|
||||
<field name="partner_name" string="Company Name"/>
|
||||
<!-- Preload all the partner's information -->
|
||||
<field name="partner_id" string="Customer"
|
||||
options='{"create_name_field": "name"}'
|
||||
context="{'default_name': contact_name, 'default_street': street, 'default_city': city, 'default_state_id': state_id, 'default_zip': zip, 'default_country_id': country_id, 'default_function': function, 'default_phone': phone, 'default_mobile': mobile, 'default_fax': fax, 'default_email': email_from, 'default_user_id': user_id, 'default_team_id': team_id}"/>
|
||||
context="{'default_name': contact_name, 'default_street': street, 'default_city': city, 'default_state_id': state_id, 'default_zip': zip, 'default_country_id': country_id, 'default_function': function, 'default_phone': phone, 'default_mobile': mobile, 'default_fax': fax, 'default_email': email_from, 'default_user_id': user_id, 'default_team_id': team_id}" groups="base.group_no_one"/>
|
||||
<field name="partner_name" string="Company Name"/>
|
||||
<label for="street" string="Address"/>
|
||||
<div class="o_address_format">
|
||||
<field name="street" placeholder="Street..." class="o_address_street"/>
|
||||
@@ -153,7 +157,7 @@
|
||||
<group>
|
||||
<label for="contact_name"/>
|
||||
<div class="o_row">
|
||||
<field name="contact_name"/><span attrs="{'invisible': [('title', '=', '')]}">, </span>
|
||||
<field name="contact_name"/>
|
||||
<field name="title" placeholder="Title" domain="[('domain', '=', 'contact')]" options='{"no_open": True}'/>
|
||||
</div>
|
||||
<field name="email_from" widget="email"/>
|
||||
@@ -164,15 +168,11 @@
|
||||
</group>
|
||||
<group>
|
||||
<field name="user_id" on_change="on_change_user(user_id, context)"
|
||||
context="{'default_groups_ref': ['base.group_user', 'base.group_partner_manager', 'base.group_sale_salesman_all_leads'] }"/>
|
||||
<label for="team_id"/>
|
||||
<div class="o_row">
|
||||
<field name="team_id"/>
|
||||
</div>
|
||||
context="{'default_groups_ref': ['base.group_user', 'base.group_partner_manager', 'base.group_sale_salesman_all_leads'] }" widget="selection"/>
|
||||
<field name="team_id" widget="selection" domain="[('use_leads','=',True)]"/>
|
||||
<field name="type" invisible="1"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="tag_ids" widget="many2many_tags"/>
|
||||
<field name="priority" widget="priority"/>
|
||||
</group>
|
||||
</group>
|
||||
@@ -182,9 +182,9 @@
|
||||
</page>
|
||||
<page name="extra" string="Extra Info">
|
||||
<group>
|
||||
<group string="Mailings">
|
||||
<group>
|
||||
<field name="opt_out"/>
|
||||
<field name="message_bounce" readonly="1"/>
|
||||
<field name="message_bounce" readonly="1" groups="base.group_no_one"/>
|
||||
</group>
|
||||
<group string="Categorization" groups="base.group_multi_company,base.group_no_one" name="categorization">
|
||||
<field name="company_id"
|
||||
@@ -194,7 +194,7 @@
|
||||
<field name="medium_id"/>
|
||||
<field name="source_id" />
|
||||
</group>
|
||||
<group name="misc" string="Misc">
|
||||
<group name="misc">
|
||||
<field name="probability" groups="base.group_no_one"/>
|
||||
<field name="active"/>
|
||||
<field name="referred"/>
|
||||
@@ -247,7 +247,7 @@
|
||||
<tree string="Leads" decoration-bf="message_unread==True" decoration-muted="probability == 100">
|
||||
<field name="date_deadline" invisible="1"/>
|
||||
<field name="create_date"/>
|
||||
<field name="name"/>
|
||||
<field name="name" string="Lead"/>
|
||||
<field name="contact_name"/>
|
||||
<field name="country_id"/>
|
||||
<field name="email_from"/>
|
||||
@@ -324,6 +324,14 @@
|
||||
<div class="text-muted">
|
||||
<span t-if="record.planned_revenue.raw_value"><t t-esc="record.planned_revenue.value"/><field name="company_currency"/></span> <span t-if="record.partner_id.value"> - <t t-esc="record.partner_id.value"/></span>
|
||||
</div>
|
||||
<div class="text-muted">
|
||||
<t t-if="record.date_deadline.raw_value and record.date_deadline.raw_value lt (new Date())" t-set="red">oe_kanban_text_red</t>
|
||||
<span t-attf-class="#{red || ''}">
|
||||
<field name="date_action"/>
|
||||
<t t-if="record.date_action.raw_value"> : </t>
|
||||
<field name="next_activity_id"/>
|
||||
</span>
|
||||
</div>
|
||||
<div class="o_kanban_footer">
|
||||
<field name="priority" widget="priority" groups="base.group_user"/>
|
||||
<t t-if="record.message_unread_counter.raw_value">
|
||||
@@ -410,8 +418,9 @@
|
||||
<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"
|
||||
<button name="%(crm.crm_lead_lost_action)d" string="Mark Lost"
|
||||
type="action" class="oe_highlight"
|
||||
context="{'default_lead_id': active_id}"
|
||||
attrs="{'invisible': [('active', '=', False)]}"/>
|
||||
<button name="action_set_active" string="Unarchive"
|
||||
type="object" class="oe_highlight"
|
||||
@@ -426,27 +435,41 @@
|
||||
<button class="oe_stat_button" type="object"
|
||||
context="{'partner_id': partner_id}"
|
||||
name="action_schedule_meeting" icon="fa-calendar">
|
||||
<field string="Meetings" name="meeting_count" widget="statinfo"/>
|
||||
<div class="o_stat_info">
|
||||
<field name="meeting_count" class="o_stat_value"/>
|
||||
<span class="o_stat_text" attrs="{'invisible': [('meeting_count', '<', 2)]}"> Meetings</span>
|
||||
<span class="o_stat_text" attrs="{'invisible': [('meeting_count', '>', 1)]}"> Meeting</span>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
<div class="oe_title">
|
||||
<div>
|
||||
<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"/>
|
||||
<label for="tag_ids" class="oe_edit_only"/>
|
||||
<field name="tag_ids" widget="many2many_tags"/>
|
||||
<div class="mt4">
|
||||
<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>
|
||||
<div class="o_row">
|
||||
<div class="oe_left">
|
||||
<label for="planned_revenue" class="oe_edit_only"/>
|
||||
<h2 class="o_row">
|
||||
<field name="company_currency" invisible="1"/>
|
||||
<field name="planned_revenue" widget='monetary' options="{'currency_field': 'company_currency'}"/>
|
||||
<span class="oe_grey"> at </span>
|
||||
</h2>
|
||||
</div>
|
||||
<div>
|
||||
<label for="probability" class="oe_edit_only"/>
|
||||
<h2 class="o_row">
|
||||
<field name="probability" widget="integer"/>
|
||||
<span>%%</span>
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
<h2 class="o_row">
|
||||
<field name="company_currency" invisible="1"/>
|
||||
<field name="planned_revenue" widget='monetary' options="{'currency_field': 'company_currency'}"/>
|
||||
<span class="oe_grey"> at </span>
|
||||
<field name="probability" widget="integer"/>
|
||||
<span>%%</span>
|
||||
</h2>
|
||||
</div>
|
||||
<group>
|
||||
<group>
|
||||
@@ -489,19 +512,15 @@
|
||||
</div>
|
||||
</div>
|
||||
<field name="date_deadline"/>
|
||||
<field name="priority" widget="priority"/>
|
||||
</group>
|
||||
|
||||
<group>
|
||||
<field name="user_id" on_change="on_change_user(user_id, context)" context="{'default_groups_ref': ['base.group_user', 'base.group_partner_manager', 'base.group_sale_salesman_all_leads']}"/>
|
||||
<label for="team_id"/>
|
||||
<div class="o_row">
|
||||
<field name="team_id" widget="selection"/>
|
||||
</div>
|
||||
<field name="user_id" on_change="on_change_user(user_id, context)" context="{'default_groups_ref': ['base.group_user', 'base.group_partner_manager', 'base.group_sale_salesman_all_leads']}" widget="selection"/>
|
||||
<field name="team_id" widget="selection"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="tag_ids" widget="many2many_tags"/>
|
||||
<field name="lost_reason"/>
|
||||
<field name="priority" widget="priority"/>
|
||||
<field name="lost_reason" attrs="{'invisible': [('active', '=', True)]}"/>
|
||||
<field name="date_conversion" invisible="1"/>
|
||||
</group>
|
||||
</group>
|
||||
@@ -510,7 +529,7 @@
|
||||
<page string="Internal Notes">
|
||||
<field name="description"/>
|
||||
</page>
|
||||
<page name="lead" string="Lead">
|
||||
<page name="lead" string="Lead" groups="crm.group_use_lead">
|
||||
<group>
|
||||
<group>
|
||||
<field name="partner_name"/>
|
||||
@@ -534,26 +553,20 @@
|
||||
<field name="function"/>
|
||||
<field name="mobile"/>
|
||||
<field name="fax"/>
|
||||
<field name="opt_out"/>
|
||||
</group>
|
||||
<group string="Marketing">
|
||||
<field name="campaign_id" />
|
||||
<field name="medium_id" />
|
||||
<field name="source_id" />
|
||||
</group>
|
||||
<group string="Mailings" name="mailings">
|
||||
<field name="opt_out"/>
|
||||
</group>
|
||||
<group string="Misc">
|
||||
<group string="Misc" name="Misc">
|
||||
<field name="active"/>
|
||||
<field name="day_open" groups="base.group_no_one"/>
|
||||
<field name="day_close" groups="base.group_no_one"/>
|
||||
<field name="referred"/>
|
||||
<field name="type" invisible="1"/>
|
||||
</group>
|
||||
<group name="references" string="References">
|
||||
<field name="ref"/>
|
||||
<field name="ref2"/>
|
||||
</group>
|
||||
</group>
|
||||
</page>
|
||||
</notebook>
|
||||
@@ -608,6 +621,8 @@
|
||||
<field name="user_id"/>
|
||||
<field name="partner_id" operator="child_of" string="Customer"/>
|
||||
<field name="stage_id" domain="[]"/>
|
||||
<field name="next_activity_id"/>
|
||||
<field name="title_action"/>
|
||||
<field name="probability"/>
|
||||
<field name="lost_reason"/>
|
||||
<separator/>
|
||||
@@ -648,6 +663,20 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="crm_lead_view_tree_activity" model="ir.ui.view">
|
||||
<field name="name">crm.lead.next.activity.tree</field>
|
||||
<field name="model">crm.lead</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Next Activity" create="false" colors="red:date_action and (date_action < current_date)" default_order="date_action">
|
||||
<field name="name"/>
|
||||
<field name="date_action"/>
|
||||
<field name="next_activity_id"/>
|
||||
<field name="title_action"/>
|
||||
<field name="date_deadline"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!--
|
||||
MASS MAILING
|
||||
-->
|
||||
|
||||
@@ -34,5 +34,27 @@
|
||||
<field name="placement">auto top</field>
|
||||
</record>
|
||||
|
||||
<record model="web.tip" id="crm_tip_5">
|
||||
<field name="title"></field>
|
||||
<field name="description"><![CDATA[Use the graph view to have a clear reporting of your opportunity pipeline.]]></field>
|
||||
<field name="model">crm.lead</field>
|
||||
<field name="mode">kanban</field>
|
||||
<field name="trigger_selector">.o_kanban_record:eq(20):visible</field>
|
||||
<field name="highlight_selector">button[data-view-type=graph]</field>
|
||||
<field name="end_event">mousedown</field>
|
||||
<field name="placement">left</field>
|
||||
</record>
|
||||
|
||||
<record model="web.tip" id="crm_tip_6">
|
||||
<field name="title"></field>
|
||||
<field name="description"><![CDATA[Gain some time and change the stage of your opportunity right here, no need to go back to your pipeline.]]></field>
|
||||
<field name="model">crm.lead</field>
|
||||
<field name="mode">form</field>
|
||||
<field name="trigger_selector">.oe_form_field_status.oe_form_status_clickable:visible</field>
|
||||
<field name="highlight_selector">.oe_form_field_status.oe_form_status_clickable</field>
|
||||
<field name="end_event">mousedown</field>
|
||||
<field name="placement">bottom</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
@@ -16,7 +16,7 @@ class crm_activity_report(models.Model):
|
||||
author_id = fields.Many2one('res.partner', 'Author', readonly=True)
|
||||
user_id = fields.Many2one('res.users', 'Responsible', readonly=True)
|
||||
team_id = fields.Many2one('crm.team', 'Sales Team', readonly=True)
|
||||
subtype_id = fields.Many2one('mail.message.subtype', 'Action', readonly=True)
|
||||
subtype_id = fields.Many2one('mail.message.subtype', 'Activity', readonly=True)
|
||||
country_id = fields.Many2one('res.country', 'Country', readonly=True)
|
||||
company_id = fields.Many2one('res.company', 'Company', readonly=True)
|
||||
stage_id = fields.Many2one('crm.stage', 'Stage', readonly=True)
|
||||
@@ -48,6 +48,10 @@ class crm_activity_report(models.Model):
|
||||
"crm_lead" l
|
||||
on
|
||||
(m.res_id = l.id)
|
||||
inner join
|
||||
"crm_activity" a
|
||||
on
|
||||
(m.subtype_id = a.subtype_id)
|
||||
WHERE
|
||||
(m.model = 'crm.lead')
|
||||
)""")
|
||||
|
||||
@@ -179,7 +179,7 @@ teams of the sales pipeline.</field>
|
||||
(including those converted into opportunities).</field>
|
||||
</record>
|
||||
<menuitem id="crm_opportunity_report_menu_lead" name="Leads Analysis"
|
||||
parent="base.menu_sale_report" action="crm_opportunity_report_action_lead" sequence="6"/>
|
||||
parent="base.menu_sale_report" groups="crm.group_use_lead" action="crm_opportunity_report_action_lead" sequence="6"/>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
@@ -15,6 +15,9 @@ class crm_configuration(osv.TransientModel):
|
||||
help="Odoo will generate an email alias based on the sales team name"),
|
||||
'alias_prefix': fields.char('Default Alias Name for Leads'),
|
||||
'alias_domain' : fields.char('Alias Domain'),
|
||||
'group_use_lead': fields.boolean(
|
||||
"Use leads if you need a qualification step before creating an opportunity or a customer",
|
||||
implied_group='crm.group_use_lead')
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
|
||||
@@ -32,6 +32,13 @@
|
||||
</div>
|
||||
|
||||
</group>
|
||||
<group>
|
||||
<label for="id" string="Manage Leads"/>
|
||||
<div>
|
||||
<field name="group_use_lead" class="oe_inline"/>
|
||||
<label for="group_use_lead"/>
|
||||
</div>
|
||||
</group>
|
||||
</div>
|
||||
</data>
|
||||
</field>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from openerp.osv import fields, osv
|
||||
from openerp.tools.safe_eval import safe_eval as eval
|
||||
from openerp.tools.translate import _
|
||||
|
||||
|
||||
@@ -46,10 +47,25 @@ class crm_team(osv.Model):
|
||||
'use_opportunities': True,
|
||||
}
|
||||
|
||||
def onchange_use_leads(self, cr, uid, ids, use_leads, context=None):
|
||||
if not use_leads:
|
||||
return {'value': {'alias_name': False}}
|
||||
return {'value': {}}
|
||||
def onchange_use_leads_opportunities(self, cr, uid, ids, use_leads, use_opportunities, context=None):
|
||||
if use_leads or use_opportunities:
|
||||
return {'value': {}}
|
||||
return {'value': {'alias_name': False}}
|
||||
|
||||
def _get_alias_defaults_values(self, cr, uid, ids, context=None):
|
||||
res = dict.fromkeys(ids, False)
|
||||
is_group_use_lead = self.pool['res.users'].has_group(cr, uid, 'crm.group_use_lead')
|
||||
for team in self.browse(cr, uid, ids, context=context):
|
||||
alias_defaults = eval(team.alias_defaults)
|
||||
alias_defaults.update({
|
||||
'type': 'lead' if is_group_use_lead and team.use_leads else 'opportunity',
|
||||
'team_id': team.id,
|
||||
})
|
||||
res[team.id] = {
|
||||
'alias_defaults': alias_defaults,
|
||||
'alias_parent_thread_id': team.id,
|
||||
}
|
||||
return res
|
||||
|
||||
def create(self, cr, uid, vals, context=None):
|
||||
if context is None:
|
||||
@@ -59,10 +75,19 @@ class crm_team(osv.Model):
|
||||
if generate_alias_name and not vals.get('alias_name'):
|
||||
vals['alias_name'] = vals.get('name')
|
||||
team_id = super(crm_team, self).create(cr, uid, vals, context=create_context)
|
||||
team = self.browse(cr, uid, team_id, context=context)
|
||||
self.pool.get('mail.alias').write(cr, uid, [team.alias_id.id], {'alias_parent_thread_id': team_id, 'alias_defaults': {'team_id': team_id, 'type': 'lead'}}, context=context)
|
||||
self.write(cr, uid, [team_id],
|
||||
self._get_alias_defaults_values(cr, uid, [team_id], context=context)[team_id],
|
||||
context=context)
|
||||
return team_id
|
||||
|
||||
def write(self, cr, uid, ids, vals, context=None):
|
||||
res = super(crm_team, self).write(cr, uid, ids, vals, context=context)
|
||||
if vals.get('use_leads') or vals.get('alias_defaults'):
|
||||
alias_res = self._get_alias_defaults_values(cr, uid, ids, context=context)
|
||||
for team_id, values in alias_res.iteritems():
|
||||
super(crm_team, self).write(cr, uid, [team_id], values, context=context)
|
||||
return res
|
||||
|
||||
def unlink(self, cr, uid, ids, context=None):
|
||||
# Cascade-delete mail aliases as well, as they should not exist without the sales team.
|
||||
mail_alias = self.pool.get('mail.alias')
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
</xpath>
|
||||
|
||||
<xpath expr="//div[contains(@class, 'o_kanban_manage_view')]" position="inside">
|
||||
<div t-if="record.use_leads.raw_value">
|
||||
<div t-if="record.use_leads.raw_value" groups="crm.group_use_lead">
|
||||
<a name="%(crm_case_form_view_salesteams_lead)d" type="action">
|
||||
Leads
|
||||
</a>
|
||||
@@ -63,7 +63,7 @@
|
||||
</xpath>
|
||||
|
||||
<xpath expr="//div[contains(@class, 'o_kanban_manage_reports')]" position="inside">
|
||||
<div>
|
||||
<div t-if="record.use_leads.raw_value" groups="crm.group_use_lead">
|
||||
<a name="%(action_report_crm_lead_salesteam)d" type="action">
|
||||
Leads
|
||||
</a>
|
||||
|
||||
@@ -87,9 +87,11 @@
|
||||
<field name="inherit_id" ref="sales_team.crm_team_view_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//div[@name='options_active']" position="inside">
|
||||
<field name="use_leads" on_change="onchange_use_leads(use_leads)"/>
|
||||
<label for="use_leads" string="Leads"/>
|
||||
<field name="use_opportunities" class="oe_inline"/>
|
||||
<div groups="crm.group_use_lead">
|
||||
<field name="use_leads" on_change="onchange_use_leads_opportunities(use_leads, use_opportunities)"/>
|
||||
<label for="use_leads" string="Leads"/>
|
||||
</div>
|
||||
<field name="use_opportunities" class="oe_inline" on_change="onchange_use_leads_opportunities(use_leads, use_opportunities)"/>
|
||||
<label for="use_opportunities"/>
|
||||
</xpath>
|
||||
<xpath expr="//page[@name='members']" position="after">
|
||||
@@ -101,10 +103,10 @@
|
||||
<xpath expr="//field[@name='code']" position="after">
|
||||
<label for="alias_name" string="Email Alias"
|
||||
groups="base.group_no_one"
|
||||
attrs="{'invisible': [('use_leads', '=', False)]}"/>
|
||||
attrs="{'invisible': [('use_leads', '=', False), ('use_opportunities', '=', False)]}"/>
|
||||
<div name="alias_def"
|
||||
groups="base.group_no_one"
|
||||
attrs="{'invisible': [('use_leads', '=', False)]}">
|
||||
attrs="{'invisible': [('use_leads', '=', False), ('use_opportunities', '=', False)]}">
|
||||
<field name="alias_id" class="oe_read_only oe_inline"
|
||||
string="Email Alias" required="0"/>
|
||||
<div class="oe_edit_only oe_inline" name="edit_alias" style="display: inline;" >
|
||||
@@ -113,7 +115,7 @@
|
||||
</div>
|
||||
<field name="alias_contact" class="oe_inline"
|
||||
string="Accept Emails From"
|
||||
attrs="{'invisible': [('use_leads', '=', False)]}"/>
|
||||
attrs="{'invisible': [('use_leads', '=', False), ('use_opportunities', '=', False)]}"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
@@ -24,6 +24,11 @@
|
||||
<field name="users" eval="[(4, ref('base.user_root'))]"/>
|
||||
</record>
|
||||
|
||||
<record id="group_use_lead" model="res.groups">
|
||||
<field name="name">Show Lead Menu</field>
|
||||
<field name="category_id" ref="base.module_category_hidden"/>
|
||||
</record>
|
||||
|
||||
<record model="res.users" id="base.user_root">
|
||||
<field eval="[(4,ref('base.group_partner_manager'))]" name="groups_id"/>
|
||||
</record>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import crm_lead_lost
|
||||
import crm_partner_binding
|
||||
import crm_lead_to_opportunity
|
||||
import crm_merge_opportunities
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from openerp import api, fields, models
|
||||
|
||||
|
||||
class CrmLeadLost(models.TransientModel):
|
||||
_name = 'crm.lead.lost'
|
||||
_description = 'Get Lost Reason'
|
||||
|
||||
lead_id = fields.Many2one('crm.lead', 'Lead', required=True)
|
||||
lost_reason_id = fields.Many2one('crm.lost.reason', 'Lost Reason')
|
||||
|
||||
@api.multi
|
||||
def action_lost_reason_apply(self):
|
||||
res = False
|
||||
for wizard in self:
|
||||
self.lead_id.lost_reason_id = self.lost_reason_id.id
|
||||
res = self.lead_id.action_set_lost()
|
||||
return res
|
||||
@@ -0,0 +1,29 @@
|
||||
<?xml version="1.0"?>
|
||||
<odoo>
|
||||
<record id="crm_lead_lost_view_form" model="ir.ui.view">
|
||||
<field name="name">crm.lead.lost.form</field>
|
||||
<field name="model">crm.lead.lost</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Lost Reason">
|
||||
<group class="oe_title">
|
||||
<field name="lead_id" invisible="1"/>
|
||||
<field name="lost_reason_id"/>
|
||||
</group>
|
||||
<footer>
|
||||
<button name="action_lost_reason_apply" string="Submit" type="object" class="oe_highlight"/>
|
||||
or
|
||||
<button string="Cancel" class="oe_link" special="cancel"/>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="crm_lead_lost_action" model="ir.actions.act_window">
|
||||
<field name="name">Lost Reason</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">crm.lead.lost</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="view_id" ref="crm_lead_lost_view_form"/>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -11,8 +11,8 @@
|
||||
<field name="name" widget="radio"/>
|
||||
</group>
|
||||
<group string="Assign these opportunities to">
|
||||
<field name="user_id" on_change="on_change_user(user_id, team_id, context)"/>
|
||||
<field name="team_id"/>
|
||||
<field name="user_id" on_change="on_change_user(user_id, team_id, context)" widget="selection"/>
|
||||
<field name="team_id" widget="selection"/>
|
||||
</group>
|
||||
<group string="Opportunities" attrs="{'invisible': [('name', '!=', 'merge')]}">
|
||||
<field name="opportunity_ids" nolabel="1">
|
||||
|
||||
@@ -33,7 +33,10 @@
|
||||
<button class="oe_stat_button" type="action"
|
||||
name="%(sale_action_quotations)d" icon="fa-usd"
|
||||
context="{'search_default_partner_id': partner_id, 'default_partner_id': partner_id}">
|
||||
<field name="sale_number" widget="statinfo" string="Quotes"/>
|
||||
<div class="o_stat_info">
|
||||
<field name="sale_number" class="o_stat_value"/>
|
||||
<span class="o_stat_text"> Quote(s) </span>
|
||||
</div>
|
||||
</button>
|
||||
<button class="oe_stat_button" type="action" attrs="{'invisible': [('sale_amount_total', '=', 0)]}"
|
||||
name="%(sale_action_quotations)d" icon="fa-usd"
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
from datetime import date, datetime
|
||||
from dateutil import relativedelta
|
||||
from openerp import tools
|
||||
|
||||
from openerp.osv import fields, osv
|
||||
|
||||
|
||||
@@ -16,27 +14,18 @@ class crm_team(osv.Model):
|
||||
def get_full_name(self, cr, uid, ids, field_name, arg, context=None):
|
||||
return dict(self.name_get(cr, uid, ids, context=context))
|
||||
|
||||
def _get_default_team_id(self, cr, uid, user_id=None, context=None):
|
||||
team_id = self._resolve_team_id_from_context(cr, uid, context=context) or False
|
||||
if not team_id:
|
||||
team_ids = self.search(cr, uid, [('member_ids', '=', user_id or uid)], limit=1, context=context)
|
||||
team_id = team_ids[0] if team_ids else False
|
||||
return team_id
|
||||
|
||||
def _resolve_team_id_from_context(self, cr, uid, context=None):
|
||||
""" Returns ID of team based on the value of 'default_team_id'
|
||||
context key, or None if it cannot be resolved to a single
|
||||
Sales Team.
|
||||
"""
|
||||
def _get_default_team_id(self, cr, uid, context=None, user_id=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
if type(context.get('default_team_id')) in (int, long):
|
||||
return context.get('default_team_id')
|
||||
if isinstance(context.get('default_team_id'), basestring):
|
||||
team_ids = self.name_search(cr, uid, name=context['default_team_id'], context=context)
|
||||
if len(team_ids) == 1:
|
||||
return int(team_ids[0][0])
|
||||
return None
|
||||
if user_id is None:
|
||||
user_id = uid
|
||||
team_id = context.get('default_team_id')
|
||||
if not team_id:
|
||||
team_ids = self.search(cr, uid, ['|', ('user_id', '=', user_id), ('member_ids', 'in', user_id)], limit=1, context=context)
|
||||
team_id = team_ids[0] if team_ids else False
|
||||
if not team_id:
|
||||
team_id = self.pool['ir.model.data'].xmlid_to_res_id(cr, uid, 'sales_team.team_sales_department')
|
||||
return team_id
|
||||
|
||||
_columns = {
|
||||
'name': fields.char('Sales Team', size=64, required=True, translate=True),
|
||||
|
||||
@@ -88,12 +88,3 @@ class Lead(models.Model):
|
||||
if 'user_id' in vals:
|
||||
vals['assign_date'] = vals.get('user_id') and fields.datetime.now() or False
|
||||
return super(Lead, self).write(vals)
|
||||
|
||||
@api.multi
|
||||
@api.onchange('user_id')
|
||||
def on_change_user(self, user_id):
|
||||
ret = super(Lead, self).on_change_user(user_id)
|
||||
if user_id:
|
||||
team_ids = self.env['crm.team'].search([('team_user_ids.user_id', '=', user_id)])
|
||||
ret['value']['team_id'] = team_ids and team_ids[0] or False
|
||||
return ret
|
||||
|
||||
@@ -75,6 +75,15 @@ class team_user(models.Model):
|
||||
class crm_team(osv.osv):
|
||||
_inherit = "crm.team"
|
||||
|
||||
@api.model
|
||||
def _get_default_team_id(self, user_id=None):
|
||||
team_id = super(crm_team, self)._get_default_team_id(user_id=user_id)
|
||||
if user_id is None:
|
||||
user_id = self.env.user.id
|
||||
if not team_id:
|
||||
team_id = self.search([('team_user_ids.user_id', '=', user_id)], limit=1).id
|
||||
return team_id
|
||||
|
||||
@api.one
|
||||
def _count_leads(self):
|
||||
if self.id:
|
||||
|
||||
@@ -60,6 +60,7 @@ class TestScoring(common.TransactionCase):
|
||||
'country_id': self.belgium,
|
||||
'email_from': 'lead0@test.com',
|
||||
'user_id': None,
|
||||
'team_id': False,
|
||||
'stage_id': self.stage,
|
||||
|
||||
})
|
||||
@@ -68,12 +69,14 @@ class TestScoring(common.TransactionCase):
|
||||
'country_id': self.france,
|
||||
'email_from': 'lead1@test.com',
|
||||
'user_id': None,
|
||||
'team_id': False,
|
||||
'stage_id': self.stage,
|
||||
})
|
||||
self.lead2 = self.crm_lead.create(cr, uid, {
|
||||
'name': 'lead2',
|
||||
'email_from': 'lead2@test.com',
|
||||
'user_id': None,
|
||||
'team_id': False,
|
||||
'stage_id': self.stage,
|
||||
})
|
||||
|
||||
|
||||
@@ -81,10 +81,10 @@
|
||||
<field name="model">crm.lead</field>
|
||||
<field name="inherit_id" ref="crm.crm_case_form_view_oppor" />
|
||||
<field name="arch" type="xml">
|
||||
<field name="user_id" position="after">
|
||||
<field name="priority" position="after">
|
||||
<field name="score" />
|
||||
</field>
|
||||
<xpath expr="//group[@name='references']" position="after">
|
||||
<xpath expr="//group[@name='Misc']" position="after">
|
||||
<group string="Scoring">
|
||||
<field name="score_ids"
|
||||
widget="many2many_tags"
|
||||
|
||||
Reference in New Issue
Block a user