[IMP] crm_iap_lead: improve onboarding tour of module crm_iap_lead

- Improve crm onboarding tour text messages and display

- Modify CRMLeadMiningRequest to improve the Lead Generation Process
Default value for lead_number changes from 10 to 3;
Computed value for team_id : per default add the
current user sale_team_id;
Default value for user_id : per default add the current user;
Default values for country_ids : Per default, add the country
of the active company because it avoids a click and is usually correct;

- Improve crm_iap_lead_mining_request_form
Group fields by sections for more readability;
Change string attribute of some fields;
Change the position of the alert messages to the top of the form
(as a ribbon);
Change button string from Submit to Generate Leads to be more explicit;

Task ID 2226563
Community PR #51587

Signed-off-by: Thibault Delavallee (tde) <tde@openerp.com>
This commit is contained in:
Pierre Collinet (pic)
2020-06-11 12:26:51 +00:00
parent f1c99a60fa
commit 4c2db92aec
4 changed files with 100 additions and 61 deletions
@@ -12,6 +12,7 @@ _logger = logging.getLogger(__name__)
DEFAULT_ENDPOINT = 'https://iap-services.odoo.com'
MAX_LEAD = 200
MAX_CONTACT = 5
CREDIT_PER_COMPANY = 1
@@ -28,19 +29,25 @@ class CRMLeadMiningRequest(models.Model):
else:
return 'opportunity'
def _default_country_ids(self):
return self.env.user.company_id.country_id
name = fields.Char(string='Request Number', required=True, readonly=True, default=lambda self: _('New'), copy=False)
state = fields.Selection([('draft', 'Draft'), ('done', 'Done'), ('error', 'Error')], string='Status', required=True, default='draft')
# Request Data
lead_number = fields.Integer(string='Number of Leads', required=True, default=10)
lead_number = fields.Integer(string='Number of Leads', required=True, default=3)
search_type = fields.Selection([('companies', 'Companies'), ('people', 'Companies and their Contacts')], string='Target', required=True, default='companies')
error = fields.Text(string='Error', readonly=True)
# Lead / Opportunity Data
lead_type = fields.Selection([('lead', 'Leads'), ('opportunity', 'Opportunities')], string='Type', required=True, default=_default_lead_type)
display_lead_label = fields.Char(compute='_compute_display_lead_label')
team_id = fields.Many2one('crm.team', string='Sales Team', domain="[('use_opportunities', '=', True)]")
user_id = fields.Many2one('res.users', string='Salesperson')
team_id = fields.Many2one(
'crm.team', string='Sales Team',
domain="[('use_opportunities', '=', True)]", readonly=False, compute='_compute_team_id', store=True)
user_id = fields.Many2one('res.users', string='Salesperson', default=lambda self: self.env.user)
tag_ids = fields.Many2many('crm.tag', string='Tags')
lead_ids = fields.One2many('crm.lead', 'lead_mining_request_id', string='Generated Lead / Opportunity')
lead_count = fields.Integer(compute='_compute_lead_count', string='Number of Generated Leads')
@@ -49,12 +56,12 @@ class CRMLeadMiningRequest(models.Model):
filter_on_size = fields.Boolean(string='Filter on Size', default=False)
company_size_min = fields.Integer(string='Size', default=1)
company_size_max = fields.Integer(default=1000)
country_ids = fields.Many2many('res.country', string='Countries')
country_ids = fields.Many2many('res.country', string='Countries', default=_default_country_ids)
state_ids = fields.Many2many('res.country.state', string='States')
industry_ids = fields.Many2many('crm.iap.lead.industry', string='Industries')
# Contact Generation Filter
contact_number = fields.Integer(string='Number of Contacts', default=1)
contact_number = fields.Integer(string='Number of Contacts', default=10)
contact_filter_type = fields.Selection([('role', 'Role'), ('seniority', 'Seniority')], string='Filter on', default='role')
preferred_role_id = fields.Many2one('crm.iap.lead.role', string='Preferred Role')
role_ids = fields.Many2many('crm.iap.lead.role', string='Other Roles')
@@ -98,6 +105,11 @@ class CRMLeadMiningRequest(models.Model):
for request in self:
request.lead_count = mapped_data.get(request.id, 0)
@api.depends('user_id')
def _compute_team_id(self):
for record in self:
record.team_id = record.user_id.sale_team_id
@api.onchange('lead_number')
def _onchange_lead_number(self):
if self.lead_number <= 0:
@@ -0,0 +1,41 @@
odoo.define('crm_iap_lead.generate_leads_steps', function (require) {
"use strict";
var tour = require('web_tour.tour');
var core = require('web.core');
require('crm.tour');
var _t = core._t;
var DragOppToWonStepIndex = _.findIndex(tour.tours.crm_tour.steps, function (step) {
return (step.id === 'drag_opportunity_to_won_step');
});
tour.tours.crm_tour.steps.splice(DragOppToWonStepIndex + 1, 0, {
/**
* Add some steps between "Drag your opportunity to <b>Won</b> when you get
* the deal. Congrats !" and "Let’s have a look at an Opportunity." to
* include the steps related to the lead generation (crm_iap_lead).
* This eases the on boarding for the Lead Generation process.
*
*/
trigger: ".o_button_generate_leads",
content: _t("Looking for more opportunities ?<br>Try the <b>Lead Generation</b> tool."),
position: "bottom",
run: function (actions) {
actions.auto('.o_button_generate_leads');
},
}, {
trigger: '.modal-body .o_industry',
content: _t("Which Industry do you want to target?"),
position: "right",
}, {
trigger: '.modal-footer button[name=action_submit]',
content: _t("Now, just let the magic happen!"),
position: "bottom",
run: function (actions) {
actions.auto('.modal-footer button[special=cancel]');
}
});
});
@@ -3,6 +3,7 @@
<template id="assets_backend" name="crm_iap_lead assets" inherit_id="web.assets_backend">
<xpath expr="." position="inside">
<script type="text/javascript" src="/crm_iap_lead/static/src/js/leads_tree_generate_leads.js"/>
<script type="text/javascript" src="/crm_iap_lead/static/src/js/tours/crm_iap_lead.js"></script>
</xpath>
</template>
</odoo>
</odoo>
@@ -6,25 +6,19 @@
<field name="arch" type="xml">
<form>
<header>
<button name="action_submit" type="object"
string="Submit" states="draft"
class="oe_highlight" invisible="context.get('is_modal')"/>
<button name="action_submit" type="object"
string="Retry" states="error"
class="oe_highlight"/>
<button name="action_submit" type="object" string="Submit" states="draft" class="oe_highlight" invisible="context.get('is_modal')"/>
<button name="action_submit" type="object" string="Retry" states="error" class="oe_highlight"/>
<field name="state" widget="statusbar" statusbar_visible="draft,done" invisible="context.get('is_modal')"/>
</header>
<sheet>
<div class="oe_button_box" name="button_box">
<button name="action_get_opportunity_action" class="oe_stat_button" type="object" icon="fa-handshake-o"
attrs="{'invisible': ['|', ('lead_type', '!=', 'opportunity'), ('state', '!=' , 'done')]}">
<button name="action_get_opportunity_action" class="oe_stat_button" type="object" icon="fa-handshake-o" attrs="{'invisible': ['|', ('lead_type', '!=', 'opportunity'), ('state', '!=' , 'done')]}">
<div class="o_stat_info">
<field name="lead_count"/>
<span class="o_stat_text">Opportunities</span>
</div>
</button>
<button name="action_get_lead_action" class="oe_stat_button" type="object" icon="fa-handshake-o" groups="crm.group_use_lead"
attrs="{'invisible': ['|', ('lead_type', '!=', 'lead'), ('state', '!=' , 'done')]}">
<button name="action_get_lead_action" class="oe_stat_button" type="object" icon="fa-handshake-o" groups="crm.group_use_lead" attrs="{'invisible': ['|', ('lead_type', '!=', 'lead'), ('state', '!=' , 'done')]}">
<div class="o_stat_info">
<field name="lead_count"/>
<span class="o_stat_text">Leads</span>
@@ -42,21 +36,24 @@
</div>
</div>
</span>
<group>
<group name="requests" string="Request">
<field name="lead_number" attrs="{'readonly': [('state', '!=', 'draft')]}"/>
<field name="search_type" widget="radio" attrs="{'readonly': [('state', '!=', 'draft')]}"/>
<field name="error" attrs="{'invisible': [('state', '!=', 'error')]}"/>
</group>
<group name="lead_info" string="Lead Information">
<field name="lead_type" groups="crm.group_use_lead" invisible="context.get('is_modal')" attrs="{'readonly': [('state', '!=', 'draft')]}"/>
<field name="team_id" attrs="{'readonly': [('state', '!=', 'draft')]}" kanban_view_ref="%(sales_team.crm_team_view_kanban)s"/>
<field name="user_id" attrs="{'readonly': [('state', '!=', 'draft')]}" domain="[('share', '=', False)]"/>
<field name="tag_ids" widget="many2many_tags" attrs="{'readonly': [('state', '!=', 'draft')]}"/>
<h2>What do you need ?</h2>
<group name="requests">
<group>
<div class="o_row">
<field name="lead_number" attrs="{'readonly': [('state', '!=', 'draft')]}" nolabel="1" class="oe_inline col-md-2 pl-0"/>
<field name="search_type" widget="selection" attrs="{'readonly': [('state', '!=', 'draft')]}" nolabel="1" class="oe_inline col-md-6"/>
<field name="error" attrs="{'invisible': [('state', '!=', 'error')]}"/>
</div>
</group>
</group>
<group>
<group name="companies" string="Companies">
<group name="companies">
<field name="country_ids" widget="many2many_tags" attrs="{'readonly': [('state', '!=', 'draft')]}" required="True" options="{'no_create': True, 'no_open': True}"/>
<field name="state_ids" widget="many2many_tags" attrs="{'invisible': [('country_ids', '=', [])], 'readonly': [('state', '!=', 'draft')]}" domain="[('country_id', 'in', country_ids)]" options="{'no_create': True, 'no_open': True}"/>
<field name="industry_ids" widget="many2many_tags" attrs="{'readonly': [('state', '!=', 'draft')]}" options="{'no_create': True, 'no_open': True}" class="o_industry"/>
<field name="filter_on_size" attrs="{'readonly': [('state', '!=', 'draft')]}"/>
<label for="company_size_min" attrs="{'invisible': [('filter_on_size', '=', False)]}"/>
<div attrs="{'invisible': [('filter_on_size', '=', False)]}">
@@ -66,44 +63,32 @@
<field name="company_size_max" class="oe_inline col-sm-3" attrs="{'required': [('filter_on_size', '=', True)], 'readonly': [('state', '!=', 'draft')]}"/>
employees
</div>
<field name="country_ids" widget="many2many_tags" attrs="{'readonly': [('state', '!=', 'draft')]}" required="True" options="{'no_create': True, 'no_open': True}"/>
<field name="state_ids" widget="many2many_tags" attrs="{'invisible': [('country_ids', '=', [])], 'readonly': [('state', '!=', 'draft')]}" domain="[('country_id', 'in', country_ids)]" options="{'no_create': True, 'no_open': True}"/>
<field name="industry_ids" widget="many2many_tags" attrs="{'readonly': [('state', '!=', 'draft')]}" options="{'no_create': True, 'no_open': True}"/>
</group>
<group name="contacts" string="Contacts" attrs="{'invisible': [('search_type', '!=', 'people')]}">
<field name="contact_number" attrs="{'readonly': [('state', '!=', 'draft')], 'required': [('search_type', '=', 'people')]}"/>
<field name="contact_filter_type" widget="radio" attrs="{'readonly': [('state', '!=', 'draft')]}"/>
<field name="preferred_role_id"
options="{'no_create_edit': True, 'no_quick_create': True}"
attrs="{'invisible': [('contact_filter_type','!=', 'role')], 'required': [('search_type', '=', 'people'), ('contact_filter_type', '=', 'role')], 'readonly': [('state', '!=', 'draft')]}"/>
<field name="role_ids" widget="many2many_tags"
options="{'color_field': 'color', 'no_create_edit': True, 'no_quick_create': True}"
attrs="{'invisible': ['|', ('preferred_role_id','=', False), ('contact_filter_type','!=', 'role')], 'readonly': [('state', '!=', 'draft')]}"/>
<field name="seniority_id" options="{'no_create_edit': True, 'no_quick_create': True}"
attrs="{'invisible': [('contact_filter_type', '!=', 'seniority')], 'required': [('search_type', '=', 'people'), ('contact_filter_type', '=', 'seniority')], 'readonly': [('state', '!=', 'draft')]}"/>
<group name="lead_info">
<field name="lead_type" groups="crm.group_use_lead" invisible="context.get('is_modal')" attrs="{'readonly': [('state', '!=', 'draft')]}"/>
<field name="team_id" no_create="1" no_open="1" attrs="{'readonly': [('state', '!=', 'draft')]}" kanban_view_ref="812"/>
<field name="user_id" no_create="1" no_open="1" attrs="{'readonly': [('state', '!=', 'draft')]}"/>
<field name="tag_ids" string="Default Tags" widget="many2many_tags" attrs="{'readonly': [('state', '!=', 'draft')]}"/>
</group>
</group>
<div class="row">
<div class="col-md-6">
<div class="alert alert-info" role="alert">
<field name="lead_credits"/>
<br/>
<span attrs="{'invisible': [('search_type', '!=', 'people')]}">
<field name="lead_contacts_credits"/>
<br/>
<field name="lead_total_credits"/>
</span>
</div>
<group name="contacts" attrs="{'invisible': [('search_type', '!=', 'people')]}">
<div>
<field name="contact_number" attrs="{'readonly': [('state', '!=', 'draft')], 'required': [('search_type', '=', 'people')]}" nolabel="1" class="col-md-1"/>
<span class="col-md-6">Extra contacts per Company</span>
</div>
<div class="col-md-6">
<div class="alert alert-info" role="alert"
attrs="{'invisible': [('search_type', '!=', 'people')]}">
Make sure you know if you have to be GDPR compliant for storing personal data.
</div>
</div>
</div>
</group>
<group attrs="{'invisible': [('search_type', '!=', 'people')]}">
<group>
<field name="contact_filter_type" widget="radio" attrs="{'readonly': [('state', '!=', 'draft')]}" options="{'horizontal': true}"/>
<field name="preferred_role_id" options="{'no_create_edit': True, 'no_quick_create': True}" attrs="{'invisible': [('contact_filter_type','!=', 'role')], 'required': [('search_type', '=', 'people'), ('contact_filter_type', '=', 'role')], 'readonly': [('state', '!=', 'draft')]}"/>
<field name="role_ids" widget="many2many_tags" options="{'color_field': 'color', 'no_create_edit': True, 'no_quick_create': True}" attrs="{'invisible': ['|', ('preferred_role_id','=', False), ('contact_filter_type','!=', 'role')], 'readonly': [('state', '!=', 'draft')]}"/>
<field name="seniority_id" options="{'no_create_edit': True, 'no_quick_create': True}" attrs="{'invisible': [('contact_filter_type', '!=', 'seniority')], 'required': [('search_type', '=', 'people'), ('contact_filter_type', '=', 'seniority')], 'readonly': [('state', '!=', 'draft')]}"/>
</group>
</group>
<footer>
<button string="Submit" name="action_submit" type="object" default_focus="1" class="btn-primary" invisible="not context.get('is_modal')"/>
<button string="Generate Leads" name="action_submit" type="object" default_focus="1" class="btn-primary" invisible="not context.get('is_modal')"/>
<button string="Cancel" class="btn-secondary" special="cancel" invisible="not context.get('is_modal')"/>
</footer>
</sheet>