[MERGE][IMP] website_crm_partner_assign: globally improve module usability
PURPOSE
Light Usability improvements for Reseller module.
SPECIFICATIONS
- Adding some demo data for the menu items Partner Level and Activations to
make sure that user's aren't completely stuck until they find the menu items.
-> Partner Level : Bronze, Silver, Gold
-> Partner Activations : First Contact, Ramp-up, Fully Operational
- Adding action helper for menu items Partner Level and Partner Activations.
-> Partner Level :
Create a Partner Level
Partner Levels allow you to rank up your Partners based on their
performances.
-> Partner Activations :
Create a Partner Activation
Those are used to know where your Partners stand in your onboarding
process.
- Changing name of the menu item "Partner Level" to "Partner Levels".
- Changing Partner Levels and Activation in res.partner form selection to
standard many2one.
- In the partner form changing the location of geolocation to below the groups.
- In kanban view displaying the record to which the partner is assigned, if
there is no assigned partners it will show nothing.
- Change the "Title" label to "Opportunity" in portal, because people think it's
a title as "Doctor" or "Mister".
- In portal while creating new Opportunity the "Opportunity" field will
auto-filled as "contact name's opportunity" when contact name is entered.
- The "opportunities" stat button (res.partner) will show opportunities where
the partner is either customer or assignated partner.
- From crm.lead form letting users to create new Assigned Partner on the fly.
But since the domain requires some basic configs, a new partner won't appear
in the next searches to prevent this, when a new partner is created through
here, we will add it the lowest activation and level possible.
LINKS
PR #67524
Task 2443894
Signed-off-by: awa-odoo <awa-odoo@users.noreply.github.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
from odoo import api, fields, models
|
||||
from odoo import api, fields, models, _
|
||||
|
||||
|
||||
class ResPartner(models.Model):
|
||||
@@ -18,6 +18,7 @@ class ResPartner(models.Model):
|
||||
|
||||
def geo_localize(self):
|
||||
# We need country names in English below
|
||||
partners_not_geo_localized = self.env['res.partner']
|
||||
for partner in self.with_context(lang='en_US'):
|
||||
result = self._geo_localize(partner.street,
|
||||
partner.zip,
|
||||
@@ -31,4 +32,15 @@ class ResPartner(models.Model):
|
||||
'partner_longitude': result[1],
|
||||
'date_localization': fields.Date.context_today(partner)
|
||||
})
|
||||
else:
|
||||
partners_not_geo_localized |= partner
|
||||
if partners_not_geo_localized:
|
||||
self.env['bus.bus'].sendone(
|
||||
(self.env.cr.dbname, 'res.partner', self.env.user.partner_id.id),
|
||||
{'type': 'simple_notification',
|
||||
'title': _("Warning"),
|
||||
'message': _('No address found for %(partner_names)s.',
|
||||
partner_names=', '.join(partners_not_geo_localized.mapped('name'))
|
||||
)
|
||||
})
|
||||
return True
|
||||
|
||||
@@ -27,6 +27,8 @@ The automatic assignment is figured from the weight of partner levels and the ge
|
||||
'data/crm_lead_merge_template.xml',
|
||||
'data/crm_tag_data.xml',
|
||||
'data/mail_template_data.xml',
|
||||
'data/res_partner_activation_data.xml',
|
||||
'data/res_partner_grade_data.xml',
|
||||
'security/ir.model.access.csv',
|
||||
'security/ir_rule.xml',
|
||||
'wizard/crm_forward_to_partner_view.xml',
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<odoo>
|
||||
<record id="res_partner_activation_data_fully_operational" model="res.partner.activation">
|
||||
<field name="name">Fully Operational</field>
|
||||
<field name="sequence">3</field>
|
||||
</record>
|
||||
<record id="res_partner_activation_data_ramp_up" model="res.partner.activation">
|
||||
<field name="name">Ramp-up</field>
|
||||
<field name="sequence">2</field>
|
||||
</record>
|
||||
<record id="res_partner_activation_data_first_contact" model="res.partner.activation">
|
||||
<field name="name">First Contact</field>
|
||||
<field name="sequence">1</field>
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -1,70 +1,44 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<odoo>
|
||||
<record id="res_partner_grade_platinium" model="res.partner.grade">
|
||||
<field name="name">Platinum</field>
|
||||
<field name="sequence">4</field>
|
||||
</record>
|
||||
<record id="res_partner_grade_gold" model="res.partner.grade">
|
||||
<field name="name">Gold</field>
|
||||
<field name="sequence">3</field>
|
||||
</record>
|
||||
<record id="res_partner_grade_silver" model="res.partner.grade">
|
||||
<field name="name">Silver</field>
|
||||
<field name="sequence">2</field>
|
||||
</record>
|
||||
<record id="res_partner_grade_bronze" model="res.partner.grade">
|
||||
<field name="name">Bronze</field>
|
||||
<field name="sequence">1</field>
|
||||
</record>
|
||||
|
||||
<record id="base.res_partner_3" model="res.partner">
|
||||
<field name="grade_id" ref="res_partner_grade_bronze"/>
|
||||
<field name="grade_id" ref="res_partner_grade_data_bronze"/>
|
||||
<field name="partner_weight">10</field>
|
||||
</record>
|
||||
<record model="res.partner" id="base.res_partner_2">
|
||||
<field name="assigned_partner_id" ref="base.res_partner_3"/>
|
||||
</record>
|
||||
<record id="base.res_partner_4" model="res.partner">
|
||||
<field name="grade_id" ref="res_partner_grade_bronze"/>
|
||||
<field name="grade_id" ref="res_partner_grade_data_bronze"/>
|
||||
<field name="partner_weight">10</field>
|
||||
</record>
|
||||
<record id="base.res_partner_12" model="res.partner">
|
||||
<field name="grade_id" ref="res_partner_grade_bronze"/>
|
||||
<field name="grade_id" ref="res_partner_grade_data_bronze"/>
|
||||
<field name="partner_weight">10</field>
|
||||
</record>
|
||||
|
||||
<record id="base.res_partner_3" model="res.partner">
|
||||
<field name="grade_id" ref="res_partner_grade_silver"/>
|
||||
<field name="grade_id" ref="res_partner_grade_data_silver"/>
|
||||
<field name="partner_weight">10</field>
|
||||
</record>
|
||||
<record id="base.res_partner_12" model="res.partner">
|
||||
<field name="grade_id" ref="res_partner_grade_silver"/>
|
||||
<field name="grade_id" ref="res_partner_grade_data_silver"/>
|
||||
<field name="partner_weight">10</field>
|
||||
</record>
|
||||
<record id="base.res_partner_12" model="res.partner">
|
||||
<field name="grade_id" ref="res_partner_grade_silver"/>
|
||||
<field name="grade_id" ref="res_partner_grade_data_silver"/>
|
||||
<field name="partner_weight">10</field>
|
||||
</record>
|
||||
|
||||
<record id="base.res_partner_10" model="res.partner">
|
||||
<field name="grade_id" ref="res_partner_grade_gold"/>
|
||||
<field name="grade_id" ref="res_partner_grade_data_gold"/>
|
||||
<field name="partner_weight">10</field>
|
||||
</record>
|
||||
<record id="base.res_partner_18" model="res.partner">
|
||||
<field name="grade_id" ref="res_partner_grade_gold"/>
|
||||
<field name="grade_id" ref="res_partner_grade_data_gold"/>
|
||||
<field name="partner_weight">10</field>
|
||||
</record>
|
||||
<record id="base.res_partner_1" model="res.partner">
|
||||
<field name="grade_id" ref="res_partner_grade_gold"/>
|
||||
<field name="partner_weight">10</field>
|
||||
</record>
|
||||
|
||||
<record id="base.res_partner_12" model="res.partner">
|
||||
<field name="grade_id" ref="res_partner_grade_platinium"/>
|
||||
<field name="partner_weight">10</field>
|
||||
</record>
|
||||
<record id="base.res_partner_4" model="res.partner">
|
||||
<field name="grade_id" ref="res_partner_grade_platinium"/>
|
||||
<field name="grade_id" ref="res_partner_grade_data_gold"/>
|
||||
<field name="partner_weight">10</field>
|
||||
</record>
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<odoo>
|
||||
<record id="res_partner_grade_data_gold" model="res.partner.grade">
|
||||
<field name="name">Gold</field>
|
||||
<field name="sequence">3</field>
|
||||
</record>
|
||||
<record id="res_partner_grade_data_silver" model="res.partner.grade">
|
||||
<field name="name">Silver</field>
|
||||
<field name="sequence">2</field>
|
||||
</record>
|
||||
<record id="res_partner_grade_data_bronze" model="res.partner.grade">
|
||||
<field name="name">Bronze</field>
|
||||
<field name="sequence">1</field>
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -1,21 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
<record id="website_crm_partner_assign.res_partner_grade_platinium" model="res.partner.grade">
|
||||
<record id="website_crm_partner_assign.res_partner_grade_data_gold" model="res.partner.grade">
|
||||
<field name="is_published" eval="True" />
|
||||
</record>
|
||||
<record id="website_crm_partner_assign.res_partner_grade_gold" model="res.partner.grade">
|
||||
<record id="website_crm_partner_assign.res_partner_grade_data_silver" model="res.partner.grade">
|
||||
<field name="is_published" eval="True" />
|
||||
</record>
|
||||
<record id="website_crm_partner_assign.res_partner_grade_silver" model="res.partner.grade">
|
||||
<record id="website_crm_partner_assign.res_partner_grade_data_bronze" model="res.partner.grade">
|
||||
<field name="is_published" eval="True" />
|
||||
</record>
|
||||
<record id="website_crm_partner_assign.res_partner_grade_bronze" model="res.partner.grade">
|
||||
<field name="is_published" eval="True" />
|
||||
</record>
|
||||
<record id="base.partner_demo_portal" model="res.partner">
|
||||
<field name="grade_id" ref="website_crm_partner_assign.res_partner_grade_platinium"/>
|
||||
<field name="partner_weight">10</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
|
||||
@@ -51,7 +51,21 @@ class CrmLead(models.Model):
|
||||
leads.write({'user_id': salesman_id})
|
||||
|
||||
def action_assign_partner(self):
|
||||
return self.assign_partner(partner_id=False)
|
||||
""" While assigning a partner, geo-localization is performed only for leads having country
|
||||
set (see method 'assign_geo_localize' and 'search_geo_partner'). So for leads that does not
|
||||
have country set, we show the notification, and for the rest, we geo-localize them.
|
||||
"""
|
||||
leads_with_country = self.filtered(lambda lead: lead.country_id)
|
||||
leads_without_country = self - leads_with_country
|
||||
if leads_without_country:
|
||||
self.env['bus.bus'].sendone(
|
||||
(self.env.cr.dbname, 'res.partner', self.env.user.partner_id.id),
|
||||
{'type': 'simple_notification',
|
||||
'title': _("Warning"),
|
||||
'message': _('There is no country set in addresses for %(lead_names)s.',
|
||||
lead_names=', '.join(leads_without_country.mapped('name')))
|
||||
})
|
||||
return leads_with_country.assign_partner(partner_id=False)
|
||||
|
||||
def assign_partner(self, partner_id=False):
|
||||
partner_dict = {}
|
||||
|
||||
@@ -2,12 +2,13 @@
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import api, fields, models
|
||||
from odoo.osv import expression
|
||||
from odoo.addons.http_routing.models.ir_http import slug
|
||||
|
||||
|
||||
class ResPartnerGrade(models.Model):
|
||||
_name = 'res.partner.grade'
|
||||
_order = 'sequence'
|
||||
_order = 'sequence desc'
|
||||
_inherit = ['website.published.mixin']
|
||||
_description = 'Partner Grade'
|
||||
|
||||
@@ -28,7 +29,7 @@ class ResPartnerGrade(models.Model):
|
||||
|
||||
class ResPartnerActivation(models.Model):
|
||||
_name = 'res.partner.activation'
|
||||
_order = 'sequence'
|
||||
_order = 'sequence desc'
|
||||
_description = 'Partner Activation'
|
||||
|
||||
sequence = fields.Integer('Sequence')
|
||||
@@ -38,6 +39,18 @@ class ResPartnerActivation(models.Model):
|
||||
class ResPartner(models.Model):
|
||||
_inherit = "res.partner"
|
||||
|
||||
@api.model
|
||||
def default_get(self, fields_list):
|
||||
default_vals = super().default_get(fields_list)
|
||||
if self.env.context.get('partner_set_default_grade_activation'):
|
||||
# sets the lowest grade and activation if no default values given, mainly useful while
|
||||
# creating assigned partner on the fly (to make it visible in same m2o again)
|
||||
if 'grade_id' in fields_list and not default_vals.get('grade_id'):
|
||||
default_vals['grade_id'] = self.env['res.partner.grade'].search([], order='sequence', limit=1).id
|
||||
if 'activation' in fields_list and not default_vals.get('activation'):
|
||||
default_vals['activation'] = self.env['res.partner.activation'].search([], order='sequence', limit=1).id
|
||||
return default_vals
|
||||
|
||||
partner_weight = fields.Integer(
|
||||
'Level Weight', compute='_compute_partner_weight',
|
||||
readonly=False, store=True, tracking=True,
|
||||
@@ -67,3 +80,20 @@ class ResPartner(models.Model):
|
||||
def _compute_partner_weight(self):
|
||||
for partner in self:
|
||||
partner.partner_weight = partner.grade_id.partner_weight if partner.grade_id else 0
|
||||
|
||||
def _compute_opportunity_count(self):
|
||||
super()._compute_opportunity_count()
|
||||
assign_counts = {}
|
||||
if self.ids:
|
||||
opportunity_data = self.env['crm.lead'].with_context(active_test=False).read_group(
|
||||
[('partner_assigned_id', 'in', self.ids)],
|
||||
['partner_assigned_id'], ['partner_assigned_id']
|
||||
)
|
||||
assign_counts = {datum['partner_assigned_id'][0]: datum['partner_assigned_id_count'] for datum in opportunity_data}
|
||||
for partner in self:
|
||||
partner.opportunity_count += assign_counts.get(partner.id, 0)
|
||||
|
||||
def action_view_opportunity(self):
|
||||
action = super().action_view_opportunity()
|
||||
action['domain'] = expression.OR([action.get('domain', []), [('partner_assigned_id', '=', self.id)]])
|
||||
return action
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
odoo.define('crm.partner_assign', function (require) {
|
||||
'use strict';
|
||||
|
||||
const {_t} = require('web.core');
|
||||
var publicWidget = require('web.public.widget');
|
||||
var time = require('web.time');
|
||||
|
||||
@@ -15,6 +16,7 @@ publicWidget.registry.crmPartnerAssign = publicWidget.Widget.extend({
|
||||
'click .new_opp_confirm': '_onNewOppConfirm',
|
||||
'click .edit_opp_confirm': '_onEditOppConfirm',
|
||||
'change .edit_opp_form .next_activity': '_onChangeNextActivity',
|
||||
'change #new-opp-dialog .contact_name': '_onChangeContactName',
|
||||
'click div.input-group.date[data-target-input="nearest"]': '_onCalendarInputGroupClick',
|
||||
},
|
||||
|
||||
@@ -229,6 +231,17 @@ publicWidget.registry.crmPartnerAssign = publicWidget.Widget.extend({
|
||||
ev.stopPropagation();
|
||||
this._buttonExec($(ev.currentTarget), this._editOpportunity);
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {Event} ev
|
||||
*/
|
||||
_onChangeContactName: function (ev) {
|
||||
const contactName = ev.currentTarget.value.trim();
|
||||
let titleEl = this.el.querySelector('.title');
|
||||
if (!titleEl.value.trim()) {
|
||||
titleEl.value = contactName ? _.str.sprintf(_t("%s's Opportunity"), contactName) : '';
|
||||
}
|
||||
},
|
||||
/**
|
||||
* @private
|
||||
* @param {Event} ev
|
||||
@@ -259,12 +272,6 @@ publicWidget.registry.crmPartnerAssign = publicWidget.Widget.extend({
|
||||
down: 'fa fa-chevron-down',
|
||||
},
|
||||
};
|
||||
// in some screen sizes, the automatic position opens the picker below input,
|
||||
// but because #next_activity_div is the last element, we always open the
|
||||
// picker on top the input to prevent extra scroll
|
||||
if ($calendarInputGroup.is('#next_activity_div')) {
|
||||
calendarOptions.widgetPositioning = {vertical: 'top'};
|
||||
}
|
||||
$calendarInputGroup.datetimepicker(calendarOptions);
|
||||
},
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
</div>
|
||||
<button string="Automatic Assignment" name="action_assign_partner" type="object" class="btn-link"/>
|
||||
|
||||
<field name="partner_assigned_id" domain="[('grade_id','!=',False)]"/>
|
||||
<field name="partner_assigned_id" domain="[('grade_id','!=',False)]" context="{'partner_set_default_grade_activation': 1}"/>
|
||||
<button string="Send Email" type="action" class="btn-link"
|
||||
attrs="{'invisible':[('partner_assigned_id','=',False)]}"
|
||||
name="%(crm_lead_forward_to_partner_act)d"
|
||||
@@ -136,4 +136,26 @@
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="crm_lead_view_kanban" model="ir.ui.view">
|
||||
<field name="name">crm.lead.view.kanban.inherit.website.crm.partner.assign</field>
|
||||
<field name="model">crm.lead</field>
|
||||
<field name="inherit_id" ref="crm.crm_case_kanban_view_leads"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="user_id" position="after">
|
||||
<field name="partner_assigned_id"/>
|
||||
</field>
|
||||
<xpath expr="//span[@t-esc='record.partner_id.value']" position="replace">
|
||||
<t t-if="record.partner_id.value or record.partner_assigned_id.value">
|
||||
<span class="o_text_overflow">
|
||||
<t t-esc="record.partner_id.value"/>
|
||||
<t t-if="record.partner_assigned_id.value">
|
||||
<i class="fa fa-arrow-circle-right" aria-label="Arrow icon" title="Arrow"/>
|
||||
<t t-esc="record.partner_assigned_id.value"/>
|
||||
</t>
|
||||
</span>
|
||||
</t>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
|
||||
@@ -34,6 +34,13 @@
|
||||
<field name="name">Partner Activations</field>
|
||||
<field name="res_model">res.partner.activation</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="help" type="html">
|
||||
<p class="o_view_nocontent_smiling_face">
|
||||
Create a Partner Activation
|
||||
</p><p>
|
||||
Those are used to know where your Partners stand in your onboarding process.
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<menuitem id="res_partner_activation_config_mi" parent="crm_menu_resellers" action="res_partner_activation_act"
|
||||
@@ -90,9 +97,16 @@
|
||||
</record>
|
||||
|
||||
<record id="res_partner_grade_action" model="ir.actions.act_window">
|
||||
<field name="name">Partner Level</field>
|
||||
<field name="name">Partner Levels</field>
|
||||
<field name="res_model">res.partner.grade</field>
|
||||
<field name="search_view_id" ref="res_partner_grade_view_search"/>
|
||||
<field name="help" type="html">
|
||||
<p class="o_view_nocontent_smiling_face">
|
||||
Create a Partner Level
|
||||
</p><p>
|
||||
Partner Levels allow you to rank your Partners based on their performances.
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<menuitem action="res_partner_grade_action" id="menu_res_partner_grade_action"
|
||||
@@ -130,12 +144,12 @@
|
||||
<field name="inherit_id" ref="base_geolocalize.view_crm_partner_geo_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<data>
|
||||
<xpath expr="//page[@name='geo_location']" position="inside">
|
||||
<group>
|
||||
<xpath expr="//page[@name='geo_location']/group" position="before">
|
||||
<group name="group_partner_activation_review">
|
||||
<group>
|
||||
<separator string="Partner Activation" colspan="2"/>
|
||||
<field name="grade_id" options="{'no_open': True, 'no_create': True}"/>
|
||||
<field name="activation" options="{'no_open': True, 'no_create': True}"/>
|
||||
<field name="grade_id" options="{'no_open': True}"/>
|
||||
<field name="activation" options="{'no_open': True}"/>
|
||||
<field name="partner_weight"/>
|
||||
</group>
|
||||
<group>
|
||||
|
||||
@@ -254,7 +254,7 @@
|
||||
|
||||
<div class="form-inline ml-lg-4" t-if="request.env.user.partner_id.grade_id or request.env.user.commercial_partner_id.grade_id">
|
||||
<button class="btn btn-success btn-sm" name='new_opp' data-toggle="modal" data-target=".modal_new_opp" title="Add an opportunity" aria-label="Add an opportunity">
|
||||
<i class="fa fa-plus"/> Create New
|
||||
Create Opportunity
|
||||
</button>
|
||||
</div>
|
||||
</t>
|
||||
@@ -273,7 +273,7 @@
|
||||
<input type='text' name="contact_name" class="form-control contact_name"/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-form-label h4dd" for="title">Title</label>
|
||||
<label class="col-form-label h4dd" for="title">Opportunity</label>
|
||||
<input type='text' name="title" class="form-control title"/>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
@@ -569,31 +569,29 @@
|
||||
<div class="row mb-3" t-if="opportunity.partner_name or opportunity.email_from or opportunity.contact_name">
|
||||
<strong class="col-12 col-sm-3">Customer</strong>
|
||||
<div class="col">
|
||||
<div>
|
||||
<div t-if="opportunity.partner_name or opportunity.contact_name">
|
||||
<span class="fa fa-user fa-fw" role="img" aria-label="User" title="User"/>
|
||||
<strong class="font-italic" t-if="opportunity.partner_name" itemprop="name" t-field="opportunity.partner_name" />
|
||||
<strong class="font-italic" t-else="" itemprop="name" t-field="opportunity.contact_name" />
|
||||
</div>
|
||||
<div>
|
||||
<div t-if="opportunity.phone">
|
||||
<span class="fa fa-phone fa-fw" role="img" aria-label="Phone" title="Phone"/>
|
||||
<span t-if="opportunity.phone" itemprop="telephone" t-field="opportunity.phone"/>
|
||||
<span t-else="" class="text-muted"> - </span>
|
||||
<span itemprop="telephone" t-field="opportunity.phone"/>
|
||||
</div>
|
||||
<div>
|
||||
<div t-if="opportunity.mobile">
|
||||
<span class="fa fa-mobile fa-fw" role="img" aria-label="Mobile" title="Mobile"/>
|
||||
<span t-if="opportunity.mobile" itemprop="mobile" t-field="opportunity.mobile"/>
|
||||
<span t-else="" class="text-muted"> - </span>
|
||||
<span itemprop="mobile" t-field="opportunity.mobile"/>
|
||||
</div>
|
||||
<div>
|
||||
<div t-if="opportunity.email_from">
|
||||
<span class="fa fa-envelope fa-fw" role="img" aria-label="Email" title="Email"/>
|
||||
<span t-if="opportunity.email_from" itemprop="email" t-field="opportunity.email_from"/>
|
||||
<span t-else="" class="text-muted"> - </span>
|
||||
<span itemprop="email" t-field="opportunity.email_from"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<strong class="col-12 col-sm-3">Address</strong>
|
||||
<address class="col d-flex align-items-baseline mb-0">
|
||||
<address t-if="opportunity.street or opportunity.street2 or opportunity.city or opportunity.zip or opportunity.state_id or opportunity.country_id"
|
||||
class="col d-flex align-items-baseline mb-0">
|
||||
<span class="fa fa-map-marker fa-fw" role="img" aria-label="Address" title="Address"/>
|
||||
<div>
|
||||
<div t-if="opportunity.street"><span t-field="opportunity.street"/></div>
|
||||
@@ -602,7 +600,7 @@
|
||||
<div t-if="opportunity.city or opportunity.zip">
|
||||
<span t-field="opportunity.city"/> <span t-field="opportunity.zip"/>
|
||||
</div>
|
||||
<div t-if="opportunity.state_id or country_id">
|
||||
<div t-if="opportunity.state_id or opportunity.country_id">
|
||||
<span t-field="opportunity.state_id"/> <span t-field="opportunity.country_id"/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -684,28 +682,35 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-form-label" for="next_activity">Next Activity</label>
|
||||
<select class="form-control next_activity" name="next_activity">
|
||||
<t t-foreach="activity_types" t-as="activity_type">
|
||||
<option t-att-data="activity_type.id" t-att-selected="activity_type.id == user_activity.activity_type_id.id" t-att-name="activity_type.name" t-att-delay_count="activity_type.delay_count" t-att-delay_unit="activity_type.delay_unit" t-att-summary="activity_type.summary"><t t-esc="activity_type.name"/></option>
|
||||
</t>
|
||||
</select>
|
||||
<div class="row">
|
||||
<div class="col-md-5">
|
||||
<label class="col-form-label" for="next_activity">Next Activity</label>
|
||||
<select class="form-control next_activity" name="next_activity">
|
||||
<t t-foreach="activity_types" t-as="activity_type">
|
||||
<option t-att-data="activity_type.id" t-att-selected="activity_type.id == user_activity.activity_type_id.id"
|
||||
t-att-name="activity_type.name" t-att-delay_count="activity_type.delay_count"
|
||||
t-att-delay_unit="activity_type.delay_unit" t-att-summary="activity_type.summary">
|
||||
<t t-esc="activity_type.name"/></option>
|
||||
</t>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-md-7">
|
||||
<label class="col-form-label" for="activity_date_deadline">Next Activity Date</label>
|
||||
<div class="input-group date" id="next_activity_div" data-target-input="nearest">
|
||||
<t t-set='date_formatted'><t t-options='{"widget": "date"}' t-esc="user_activity.date_deadline"/></t>
|
||||
<input type="text" name="activity_date_deadline" data-target="#next_activity_div" t-att-value="date_formatted" class="form-control activity_date_deadline datetimepicker-input" t-att-name="prefix"/>
|
||||
<div class="input-group-append" data-target="#next_activity_div" data-toggle="datetimepicker">
|
||||
<span class="input-group-text">
|
||||
<span class="fa fa-calendar" role="img" aria-label="Calendar" title="Calendar"></span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-form-label" for="activity_summary">Details Next Activity</label>
|
||||
<textarea rows="3" name="activity_summary" class="form-control activity_summary"><t t-esc="user_activity.summary"/></textarea>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-form-label" for="activity_date_deadline">Next Activity Date</label>
|
||||
<div class="input-group date" id="next_activity_div" data-target-input="nearest">
|
||||
<t t-set='date_formatted'><t t-options='{"widget": "date"}' t-esc="user_activity.date_deadline"/></t>
|
||||
<input type="text" name="activity_date_deadline" data-target="#next_activity_div" t-att-value="date_formatted" class="form-control activity_date_deadline datetimepicker-input" t-att-name="prefix"/>
|
||||
<div class="input-group-append" data-target="#next_activity_div" data-toggle="datetimepicker">
|
||||
<span class="input-group-text">
|
||||
<span class="fa fa-calendar" role="img" aria-label="Calendar" title="Calendar"></span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<textarea rows="6" name="activity_summary" class="form-control activity_summary"><t t-esc="user_activity.summary"/></textarea>
|
||||
</div>
|
||||
</main>
|
||||
<footer class="modal-footer">
|
||||
|
||||
Reference in New Issue
Block a user