[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:
Hitesh Trivedi
2015-08-11 10:56:09 +02:00
committed by Thibault Delavallée
parent d86406e8af
commit 30a7ef804a
24 changed files with 306 additions and 146 deletions
+1
View File
@@ -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',
+12 -17
View File
@@ -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
View File
@@ -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)
# ----------------------------------------
+30 -1
View File
@@ -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>
+82 -53
View File
@@ -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', '&gt;', 0), ('active', '=', True)]}">Lost</span>
<span class="label label-success"
attrs="{'invisible': [('probability', '&lt;', 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', '&gt;', 0), ('active', '=', True)]}">Lost</span>
<span class="label label-success"
attrs="{'invisible': [('probability', '&lt;', 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', '&lt;', 2)]}"> Meetings</span>
<span class="o_stat_text" attrs="{'invisible': [('meeting_count', '&gt;', 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', '&gt;', 0), ('active', '=', True)]}">Lost</span>
<span class="label label-success"
attrs="{'invisible': [('probability', '&lt;', 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', '&gt;', 0), ('active', '=', True)]}">Lost</span>
<span class="label label-success"
attrs="{'invisible': [('probability', '&lt;', 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 &lt; 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
-->
+22
View File
@@ -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>
+5 -1
View File
@@ -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>
+3
View File
@@ -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 = {
+7
View File
@@ -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>
+31 -6
View File
@@ -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')
+2 -2
View File
@@ -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>
+8 -6
View File
@@ -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>
+5
View File
@@ -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
View File
@@ -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
+18
View File
@@ -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
+29
View File
@@ -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">
+4 -1
View File
@@ -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"
+11 -22
View File
@@ -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:
+3
View File
@@ -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,
})
+2 -2
View File
@@ -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"