[ADD] sales_team: new sales dashboard with figures
A new view type has been created : sales_dashboard. It is used to display some figure in the sales_team_dashboard. Also added in this commit : 3 fields on res.users to fix sales target - target of won opportunities - target of activities done - target of invoiced sale orders
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import res_users
|
||||
import crm_stage
|
||||
import crm_lead
|
||||
import sales_team
|
||||
|
||||
+136
-1
@@ -1,7 +1,8 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
from datetime import datetime, timedelta, date
|
||||
from dateutil.relativedelta import relativedelta
|
||||
import logging
|
||||
from operator import itemgetter
|
||||
|
||||
@@ -1036,6 +1037,140 @@ Update your business card, phone book, social media,... Send an email right now
|
||||
break
|
||||
return res
|
||||
|
||||
def retrieve_sales_dashboard(self, cr, uid, context=None):
|
||||
|
||||
res = {
|
||||
'meeting': {
|
||||
'today': 0,
|
||||
'next_7_days': 0,
|
||||
},
|
||||
'activity': {
|
||||
'today': 0,
|
||||
'overdue': 0,
|
||||
'next_7_days': 0,
|
||||
},
|
||||
'closing': {
|
||||
'today': 0,
|
||||
'overdue': 0,
|
||||
'next_7_days': 0,
|
||||
},
|
||||
'done': {
|
||||
'this_month': 0,
|
||||
'last_month': 0,
|
||||
},
|
||||
'won': {
|
||||
'this_month': 0,
|
||||
'last_month': 0,
|
||||
},
|
||||
'nb_opportunities': 0,
|
||||
}
|
||||
|
||||
opportunities = self.search_read(
|
||||
cr, uid,
|
||||
[('type', '=', 'opportunity'), ('user_id', '=', uid)],
|
||||
['date_deadline', 'next_activity_id', 'date_action', 'date_closed', 'planned_revenue'], context=context)
|
||||
|
||||
for opp in opportunities:
|
||||
|
||||
# Expected closing
|
||||
if opp['date_deadline']:
|
||||
date_deadline = datetime.strptime(opp['date_deadline'], tools.DEFAULT_SERVER_DATE_FORMAT).date()
|
||||
|
||||
if date_deadline == date.today():
|
||||
res['closing']['today'] += 1
|
||||
if date_deadline >= date.today() and date_deadline <= date.today() + timedelta(days=7):
|
||||
res['closing']['next_7_days'] += 1
|
||||
if date_deadline < date.today():
|
||||
res['closing']['overdue'] += 1
|
||||
|
||||
# Next activities
|
||||
if opp['next_activity_id'] and opp['date_action']:
|
||||
date_action = datetime.strptime(opp['date_action'], tools.DEFAULT_SERVER_DATE_FORMAT).date()
|
||||
|
||||
if date_action == date.today():
|
||||
res['activity']['today'] += 1
|
||||
if date_action >= date.today() and date_action <= date.today() + timedelta(days=7):
|
||||
res['activity']['next_7_days'] += 1
|
||||
if date_action < date.today():
|
||||
res['activity']['overdue'] += 1
|
||||
|
||||
# Won in Opportunities
|
||||
if opp['date_closed']:
|
||||
date_closed = datetime.strptime(opp['date_closed'], tools.DEFAULT_SERVER_DATETIME_FORMAT).date()
|
||||
|
||||
if date_closed <= date.today() and date_closed >= date.today().replace(day=1):
|
||||
if opp['planned_revenue']:
|
||||
res['won']['this_month'] += opp['planned_revenue']
|
||||
elif date_closed < date.today().replace(day=1) and date_closed >= date.today().replace(day=1) - relativedelta(months=+1):
|
||||
if opp['planned_revenue']:
|
||||
res['won']['last_month'] += opp['planned_revenue']
|
||||
|
||||
# crm.activity is a very messy model so we need to do that in order to retrieve the actions done.
|
||||
cr.execute("""
|
||||
SELECT
|
||||
m.id,
|
||||
m.subtype_id,
|
||||
m.date,
|
||||
l.user_id,
|
||||
l.type
|
||||
FROM
|
||||
"mail_message" m
|
||||
LEFT JOIN
|
||||
"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') AND (l.user_id = %s) AND (l.type = 'opportunity')
|
||||
""", (uid,))
|
||||
activites_done = cr.dictfetchall()
|
||||
|
||||
for act in activites_done:
|
||||
if act['date']:
|
||||
date_act = datetime.strptime(act['date'], tools.DEFAULT_SERVER_DATETIME_FORMAT).date()
|
||||
if date_act <= date.today() and date_act >= date.today().replace(day=1):
|
||||
res['done']['this_month'] += 1
|
||||
elif date_act < date.today().replace(day=1) and date_act >= date.today().replace(day=1) - relativedelta(months=+1):
|
||||
res['done']['last_month'] += 1
|
||||
|
||||
# Meetings
|
||||
min_date = datetime.now().strftime(tools.DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
max_date = (datetime.now() + timedelta(days=8)).strftime(tools.DEFAULT_SERVER_DATETIME_FORMAT)
|
||||
meetings_domain = [
|
||||
('start', '>=', min_date),
|
||||
('start', '<=', max_date)
|
||||
]
|
||||
# We need to add 'mymeetings' in the context for the search to be correct.
|
||||
meetings = self.pool.get('calendar.event').search_read(cr, uid, meetings_domain, ['start'], context=context.update({'mymeetings': 1}) if context else {'mymeetings': 1})
|
||||
for meeting in meetings:
|
||||
if meeting['start']:
|
||||
start = datetime.strptime(meeting['start'], tools.DEFAULT_SERVER_DATETIME_FORMAT).date()
|
||||
|
||||
if start == date.today():
|
||||
res['meeting']['today'] += 1
|
||||
if start >= date.today() and start <= date.today() + timedelta(days=7):
|
||||
res['meeting']['next_7_days'] += 1
|
||||
|
||||
res['nb_opportunities'] = len(opportunities)
|
||||
|
||||
user = self.pool('res.users').browse(cr, uid, uid, context=context)
|
||||
res['done']['target'] = user.target_sales_done
|
||||
res['won']['target'] = user.target_sales_won
|
||||
|
||||
return res
|
||||
|
||||
def modify_target_sales_dashboard(self, cr, uid, target_name, target_value, context=None):
|
||||
|
||||
if target_name in ['won', 'done', 'invoiced']:
|
||||
# bypass rights (with superuser_id)
|
||||
self.pool('res.users').write(cr, SUPERUSER_ID, [uid], {'target_sales_' + target_name: target_value}, context=context)
|
||||
else:
|
||||
raise UserError(_('This target does not exist.'))
|
||||
|
||||
|
||||
class crm_lead_tag(osv.Model):
|
||||
_name = "crm.lead.tag"
|
||||
_description = "Category of lead"
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from openerp.osv import osv, fields
|
||||
|
||||
import openerp.addons.product.product
|
||||
|
||||
|
||||
class res_users(osv.osv):
|
||||
_inherit = 'res.users'
|
||||
_columns = {
|
||||
'target_sales_won': fields.integer('Won in Opportunities Target'),
|
||||
'target_sales_done': fields.integer('Activities Done Target'),
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
odoo.define('crm.sales_team_dashboard', function (require) {
|
||||
"use strict";
|
||||
|
||||
var SalesTeamDashboardView = require('sales_team.dashboard');
|
||||
var Model = require('web.Model');
|
||||
|
||||
SalesTeamDashboardView.include({
|
||||
|
||||
fetch_data: function() {
|
||||
return new Model('crm.lead')
|
||||
.call('retrieve_sales_dashboard', []);
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
@@ -6,6 +6,9 @@
|
||||
<link rel="stylesheet" href="/crm/static/src/css/crm.css"/>
|
||||
<!-- Planner assets -->
|
||||
<script type="text/javascript" src="/crm/static/src/js/web_planner_crm.js"></script>
|
||||
|
||||
<!-- Salesteam dashboard asset -->
|
||||
<script type="text/javascript" src="/crm/static/src/js/sales_team_dashboard.js"></script>
|
||||
</xpath>
|
||||
</template>
|
||||
</data>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import res_users
|
||||
import sale_crm
|
||||
import crm_lead
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
|
||||
from openerp import models, fields, api, _
|
||||
from openerp import models, fields, api, _, tools
|
||||
from datetime import datetime, date
|
||||
from dateutil.relativedelta import relativedelta
|
||||
import openerp.addons.decimal_precision as dp
|
||||
|
||||
class crm_lead(models.Model):
|
||||
@@ -21,3 +23,29 @@ class crm_lead(models.Model):
|
||||
sale_amount_total= fields.Float(compute='_get_sale_amount_total', string="Sum of Orders", readonly=True, digits=0)
|
||||
sale_number = fields.Integer(compute='_get_sale_amount_total', string="Number of Quotations", readonly=True)
|
||||
order_ids = fields.One2many('sale.order', 'opportunity_id', string='Orders')
|
||||
|
||||
def retrieve_sales_dashboard(self, cr, uid, context=None):
|
||||
res = super(crm_lead, self).retrieve_sales_dashboard(cr, uid, context=None)
|
||||
|
||||
res['invoiced'] = {
|
||||
'this_month': 0,
|
||||
'last_month': 0,
|
||||
}
|
||||
account_invoice_domain = [
|
||||
('state', 'in', ['open', 'paid']),
|
||||
('user_id', '=', uid),
|
||||
('date', '>=', date.today().replace(day=1) - relativedelta(months=+1))
|
||||
]
|
||||
|
||||
invoice_ids = self.pool.get('account.invoice').search_read(cr, uid, account_invoice_domain, ['date', 'amount_untaxed_signed'], context=context)
|
||||
for inv in invoice_ids:
|
||||
if inv['date']:
|
||||
inv_date = datetime.strptime(inv['date'], tools.DEFAULT_SERVER_DATE_FORMAT).date()
|
||||
if inv_date <= date.today() and inv_date >= date.today().replace(day=1):
|
||||
res['invoiced']['this_month'] += inv['amount_untaxed_signed']
|
||||
elif inv_date < date.today().replace(day=1) and inv_date >= date.today().replace(day=1) - relativedelta(months=+1):
|
||||
res['invoiced']['last_month'] += inv['amount_untaxed_signed']
|
||||
|
||||
res['invoiced']['target'] = self.pool('res.users').browse(cr, uid, uid, context=context).target_sales_invoiced
|
||||
|
||||
return res
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from openerp.osv import osv, fields
|
||||
|
||||
import openerp.addons.product.product
|
||||
|
||||
|
||||
class res_users(osv.osv):
|
||||
_inherit = 'res.users'
|
||||
_columns = {
|
||||
'target_sales_invoiced': fields.integer('Invoiced in Sale Orders Target'),
|
||||
}
|
||||
@@ -17,6 +17,9 @@ Using this application you can manage Sales Team with CRM and/or Sales
|
||||
'sales_team.xml',
|
||||
'sales_team_dashboard.xml',
|
||||
],
|
||||
'qweb': [
|
||||
"static/src/xml/sales_team_dashboard.xml",
|
||||
],
|
||||
'demo': ['sales_team_demo.xml'],
|
||||
'css': ['static/src/css/sales_team.css'],
|
||||
'installable': True,
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
<field name="name">Sales Teams</field>
|
||||
<field name="res_model">crm.team</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">kanban,tree,form</field>
|
||||
<field name="view_mode">sales_team_dashboard</field>
|
||||
<field name="context">{}</field>
|
||||
<field name="view_id" ref="crm_team_salesteams_search"/>
|
||||
<field name="help" type="html">
|
||||
@@ -144,7 +144,9 @@
|
||||
<template id="assets_backend" name="sales_team assets" inherit_id="web.assets_backend">
|
||||
<xpath expr="." position="inside">
|
||||
<link rel="stylesheet" href="/sales_team/static/src/css/sales_team.css"/>
|
||||
<link rel="stylesheet" href="/sales_team/static/src/less/sales_team_dashboard.less"/>
|
||||
<script type="text/javascript" src="/sales_team/static/src/js/sales_team.js"></script>
|
||||
<script type="text/javascript" src="/sales_team/static/src/js/sales_team_dashboard.js"></script>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<odoo>
|
||||
<!-- Case Teams Salesteams dashboard view -->
|
||||
<record id="crm_team_salesteams_view_kanban" model="ir.ui.view" >
|
||||
<field name="name">crm.team.kanban</field>
|
||||
<field name="name">crm.team.dashboard</field>
|
||||
<field name="model">crm.team</field>
|
||||
<field name="arch" type="xml">
|
||||
<kanban class="oe_background_grey o_kanban_dashboard o_salesteam_kanban" create="0">
|
||||
<sales_team_dashboard class="oe_background_grey o_kanban_dashboard o_salesteam_kanban" create="0">
|
||||
<field name="name"/>
|
||||
<field name="user_id"/>
|
||||
<field name="member_ids"/>
|
||||
@@ -58,7 +58,15 @@
|
||||
</div>
|
||||
</t>
|
||||
</templates>
|
||||
</kanban>
|
||||
</sales_team_dashboard>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
|
||||
<record id="action_sales_team_dashboard" model="ir.actions.client">
|
||||
<field name="name">Sales Team Dashboard</field>
|
||||
<field name="res_model">crm.team</field>
|
||||
<field name="tag">sales_team_dashboard</field>
|
||||
</record>
|
||||
|
||||
<menuitem action="action_sales_team_dashboard" id="menu_sales_team_dashboard" parent="base.menu_sales" sequence="20" groups="base.group_sale_salesman,base.group_sale_manager"/>
|
||||
</odoo>
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
odoo.define('sales_team.dashboard', function (require) {
|
||||
"use strict";
|
||||
|
||||
var core = require('web.core');
|
||||
var KanbanView = require('web_kanban.KanbanView');
|
||||
var Model = require('web.Model');
|
||||
|
||||
var QWeb = core.qweb;
|
||||
|
||||
var _t = core._t;
|
||||
var _lt = core._lt;
|
||||
|
||||
var SalesTeamDashboardView = KanbanView.extend({
|
||||
display_name: _lt('Dashboard'),
|
||||
icon: 'fa-dashboard',
|
||||
view_type: "sales_team_dashboard",
|
||||
searchview_hidden: true,
|
||||
events: {
|
||||
'click .o_dashboard_action': 'on_dashboard_action_clicked',
|
||||
'click .o_target_to_set': 'on_dashboard_target_clicked',
|
||||
},
|
||||
|
||||
fetch_data: function() {
|
||||
// Overwrite this function with useful data
|
||||
return $.Deferred().resolve();
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var super_render = this._super;
|
||||
var self = this;
|
||||
|
||||
this.fetch_data().then(function(result){
|
||||
|
||||
self.show_demo = !(result && result['nb_opportunities'] > 0);
|
||||
|
||||
var sales_dashboard = QWeb.render('sales_team.SalesDashboard', {
|
||||
show_demo: self.show_demo,
|
||||
values: result,
|
||||
});
|
||||
super_render.call(self);
|
||||
$(sales_dashboard).prependTo(self.$el);
|
||||
});
|
||||
},
|
||||
|
||||
on_dashboard_action_clicked: function(ev){
|
||||
ev.preventDefault();
|
||||
|
||||
var self = this;
|
||||
var $action = $(ev.currentTarget);
|
||||
var action_name = $action.attr('name');
|
||||
var additional_context = {}
|
||||
|
||||
// TODO: find a better way to add defaults to search view
|
||||
if (action_name === 'calendar.action_calendar_event') {
|
||||
additional_context['search_default_mymeetings'] = 1;
|
||||
}
|
||||
if (action_name === 'crm.crm_lead_opportunities') {
|
||||
additional_context['search_default_assigned_to_me'] = 1;
|
||||
}
|
||||
|
||||
new Model("ir.model.data")
|
||||
.call("xmlid_to_res_id", [action_name])
|
||||
.then(function(data) {
|
||||
if (data){
|
||||
self.do_action(data, {additional_context: additional_context});
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
on_change_input_target: function(e) {
|
||||
|
||||
var self = this;
|
||||
var $input = $(e.target);
|
||||
var target_name = $input.attr('name');
|
||||
var target_value = $input.val();
|
||||
|
||||
if(isNaN($input.val())) {
|
||||
this.do_warn(_t("Wrong value entered!"), _t("Only Integer Value should be valid."));
|
||||
} else {
|
||||
this.modify_target(target_name, target_value).then(function() {
|
||||
self.render();
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
modify_target: function(target_name, value){
|
||||
return new Model('crm.lead')
|
||||
.call('modify_target_sales_dashboard', [target_name, value])
|
||||
|
||||
},
|
||||
|
||||
on_dashboard_target_clicked: function(ev){
|
||||
|
||||
if (this.show_demo) {
|
||||
// The user is not allowed to modify the targets in demo mode
|
||||
return;
|
||||
}
|
||||
|
||||
var self = this;
|
||||
var $target = $(ev.currentTarget);
|
||||
var target_name = $target.attr('name');
|
||||
var target_value = $target.attr('value');
|
||||
|
||||
var $input = $('<input/>');
|
||||
$input.attr('name', target_name);
|
||||
if (target_value) {
|
||||
$input.attr('value', target_value);
|
||||
}
|
||||
$input.on('keyup input', function(e) {
|
||||
if(e.which === $.ui.keyCode.ENTER) {
|
||||
self.on_change_input_target(e);
|
||||
}
|
||||
});
|
||||
$input.on('blur', function(e) {
|
||||
self.on_change_input_target(e);
|
||||
});
|
||||
$target.replaceWith($input);
|
||||
$input.focus().select();
|
||||
},
|
||||
});
|
||||
|
||||
core.view_registry.add('sales_team_dashboard', SalesTeamDashboardView);
|
||||
|
||||
return SalesTeamDashboardView
|
||||
|
||||
});
|
||||
@@ -0,0 +1,114 @@
|
||||
.o_kanban_view.o_kanban_dashboard.o_salesteam_kanban {
|
||||
|
||||
padding: 0; // remove the padding of the kanban view
|
||||
|
||||
.o_kanban_record {
|
||||
min-width: 450px;
|
||||
|
||||
@media (max-width: @grid-float-breakpoint) {
|
||||
min-width: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
.o_sales_dashboard {
|
||||
padding-top: 20px;
|
||||
background-color: @odoo-view-background-color;
|
||||
position: relative;
|
||||
.o-flex(0, 0,100%);
|
||||
.o-flex-display();
|
||||
|
||||
.o_welcome_message {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
.o-flex-display();
|
||||
justify-content: center;
|
||||
|
||||
.o_welcome_image {
|
||||
padding: 20px;
|
||||
}
|
||||
.o_welcome_content {
|
||||
> a {
|
||||
color: white;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.o_demo {
|
||||
opacity: 0.07;
|
||||
}
|
||||
|
||||
.o_left_panel {
|
||||
.o-flex(1, 0, 0);
|
||||
}
|
||||
.o_right_panel {
|
||||
.o-flex(1, 0, 0);
|
||||
|
||||
@media (max-width: @grid-float-breakpoint) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
table {
|
||||
-webkit-border-horizontal-spacing: 10px;
|
||||
border-collapse: separate;
|
||||
|
||||
> tbody {
|
||||
> tr {
|
||||
> td {
|
||||
vertical-align: middle;
|
||||
text-align: center;
|
||||
border-top: 1px solid @odoo-view-background-color;
|
||||
|
||||
span {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.o_target_reached {
|
||||
color: green;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
&.o_main {
|
||||
background-color: @odoo-brand-optional;
|
||||
&:hover {
|
||||
background-color: darken(@odoo-brand-optional, 10%);
|
||||
}
|
||||
a {
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
&.o_warning {
|
||||
background-color: orange;
|
||||
&:hover {
|
||||
background-color: darken(orange, 10%);
|
||||
}
|
||||
a {
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
&.o_secondary {
|
||||
background-color: lightgrey;
|
||||
&:hover {
|
||||
background-color: darken(lightgrey, 10%);
|
||||
}
|
||||
a {
|
||||
color: black;
|
||||
}
|
||||
}
|
||||
&.o_highlight, .o_highlight {
|
||||
font-size: 20px;
|
||||
}
|
||||
&.o_text {
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,242 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<templates>
|
||||
|
||||
<!--
|
||||
This template is the rubbon at the top of the salesteam dashboard that adds
|
||||
some figures to it. We call this rubbon the "SalesDashboard".
|
||||
-->
|
||||
<t t-name="sales_team.SalesDashboard">
|
||||
|
||||
<div class="o_sales_dashboard">
|
||||
<div t-attf-class="o_left_panel #{show_demo ? 'o_demo' : ''}">
|
||||
<table border="0" class="table">
|
||||
<tr>
|
||||
<td class="o_highlight o_text">
|
||||
Today
|
||||
</td>
|
||||
<td class="o_main" title="To Calendar">
|
||||
<a href="#" class="o_dashboard_action" name="calendar.action_calendar_event">
|
||||
<span class="o_highlight">
|
||||
<t t-if="!show_demo">
|
||||
<t t-esc="values['meeting']['today']"/>
|
||||
</t>
|
||||
<t t-if="show_demo">
|
||||
0
|
||||
</t>
|
||||
</span><br/>
|
||||
Meetings
|
||||
</a>
|
||||
</td>
|
||||
<td class="o_main" title="To Activities">
|
||||
<a href="#" class="o_dashboard_action" name="crm.crm_lead_action_activities">
|
||||
<span class="o_highlight">
|
||||
<t t-if="!show_demo">
|
||||
<t t-esc="values['activity']['today']"/>
|
||||
</t>
|
||||
<t t-if="show_demo">
|
||||
7
|
||||
</t>
|
||||
</span> <br/>
|
||||
Next Actions
|
||||
</a>
|
||||
</td>
|
||||
<td class="o_main" title="To Opportunities">
|
||||
<a href="#" class="o_dashboard_action" name="crm.crm_lead_opportunities">
|
||||
<span class="o_highlight">
|
||||
<t t-if="!show_demo">
|
||||
<t t-esc="values['closing']['today']"/>
|
||||
</t>
|
||||
<t t-if="show_demo">
|
||||
4
|
||||
</t>
|
||||
</span> <br/>
|
||||
Expected Closing
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<!-- Hide overdue when there is none -->
|
||||
<td t-if="show_demo or (values and values['activity']['overdue'] != 0)" class="o_warning" title="To Activities">
|
||||
<a href="#" class="o_dashboard_action" name="crm.crm_lead_action_activities">
|
||||
<t t-if="!show_demo">
|
||||
<t t-esc="values['activity']['overdue']"/> overdue
|
||||
</t>
|
||||
<t t-if="show_demo">
|
||||
2
|
||||
</t>
|
||||
</a>
|
||||
</td>
|
||||
<td t-if="show_demo or (values and values['closing']['overdue'] != 0)" class="o_warning" title="To Opportunities">
|
||||
<a href="#" class="o_dashboard_action" name="crm.crm_lead_opportunities">
|
||||
<t t-if="!show_demo">
|
||||
<t t-esc="values['closing']['overdue']"/> overdue
|
||||
</t>
|
||||
<t t-if="show_demo">
|
||||
3
|
||||
</t>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="o_text">Next 7 days</td>
|
||||
<td class="o_main" title="To Calendar">
|
||||
<a href="#" class="o_dashboard_action" name="calendar.action_calendar_event">
|
||||
<t t-if="!show_demo">
|
||||
<t t-esc="values['meeting']['next_7_days']"/>
|
||||
</t>
|
||||
<t t-if="show_demo">
|
||||
9
|
||||
</t>
|
||||
</a>
|
||||
</td>
|
||||
<td class="o_main" title="To Activities">
|
||||
<a href="#" class="o_dashboard_action" name="crm.crm_lead_action_activities">
|
||||
<t t-if="!show_demo">
|
||||
<t t-esc="values['activity']['next_7_days']"/>
|
||||
</t>
|
||||
<t t-if="show_demo">
|
||||
28
|
||||
</t>
|
||||
</a>
|
||||
</td>
|
||||
<td class="o_main" title="To Opportunities">
|
||||
<a href="#" class="o_dashboard_action" name="crm.crm_lead_opportunities">
|
||||
<t t-if="!show_demo">
|
||||
<t t-esc="values['closing']['next_7_days']"/>
|
||||
</t>
|
||||
<t t-if="show_demo">
|
||||
17
|
||||
</t>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div t-attf-class="o_right_panel #{show_demo ? 'o_demo' : ''}">
|
||||
<table class="table">
|
||||
<tr>
|
||||
<td class="o_highlight o_text">
|
||||
This Month
|
||||
</td>
|
||||
<td class="o_secondary" title="To Activity Report">
|
||||
<a href="#" class="o_dashboard_action" name="crm.crm_activity_report_action">
|
||||
<span t-attf-class="o_highlight #{values and values['done']['target'] and values['done']['this_month'] >= values['done']['target'] ? 'o_target_reached' : ''}">
|
||||
<t t-if="!show_demo">
|
||||
<t t-esc="values['done']['this_month']"/>
|
||||
</t>
|
||||
<t t-if="show_demo">
|
||||
94
|
||||
</t>
|
||||
</span> <br/>
|
||||
Activities Done
|
||||
</a>
|
||||
</td>
|
||||
<td class="o_secondary" title="To Opportunity Report">
|
||||
<a href="#" class="o_dashboard_action" name="crm.crm_opportunity_report_action">
|
||||
<span t-attf-class="o_highlight #{values and values['won']['target'] and values['won']['this_month'] >= values['won']['target'] ? 'o_target_reached' : ''}">
|
||||
<t t-if="!show_demo">
|
||||
<t t-esc="values['won']['this_month']"/>
|
||||
</t>
|
||||
<t t-if="show_demo" class="o_target_reached">
|
||||
78,140.03€
|
||||
</t>
|
||||
</span> <br/>
|
||||
Won in Opportunities
|
||||
</a>
|
||||
</td>
|
||||
<td t-if="values['invoiced']" class="o_secondary" title="To Invoice Report">
|
||||
<a href="#" class="o_dashboard_action" name="account.action_account_invoice_report_all">
|
||||
<span t-attf-class="o_highlight #{values and values['invoiced']['target'] and values['invoiced']['this_month'] >= values['invoiced']['target'] ? 'o_target_reached' : ''}">
|
||||
<t t-if="!show_demo">
|
||||
<t t-esc="values['invoiced']['this_month']"/>
|
||||
</t>
|
||||
<t t-if="show_demo">
|
||||
35,029.39€
|
||||
</t>
|
||||
</span> <br/>
|
||||
Invoiced
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="o_text">Target</td>
|
||||
<td class="o_secondary">
|
||||
<span t-if="!show_demo" class="o_target_to_set" name='done' t-att-value="values['done']['target'] ? values['done']['target'] : undefined" title="Click to set">
|
||||
<t t-if="values['done']['target']">
|
||||
<t t-esc="values['done']['target']"/>
|
||||
</t>
|
||||
<t t-if="!values['done']['target']">
|
||||
Click to set
|
||||
</t>
|
||||
</span>
|
||||
<span t-if="show_demo">
|
||||
100
|
||||
</span>
|
||||
</td>
|
||||
<td class="o_secondary">
|
||||
<span t-if="!show_demo" class="o_target_to_set" name='won' t-att-value="values['won']['target'] ? values['won']['target'] : undefined" title="Click to set">
|
||||
<t t-if="values['won']['target']">
|
||||
<t t-esc="values['won']['target']"/>
|
||||
</t>
|
||||
<t t-if="!values['won']['target']">
|
||||
Click to set
|
||||
</t>
|
||||
</span>
|
||||
<span t-if="show_demo">
|
||||
80.000€
|
||||
</span>
|
||||
</td>
|
||||
<td t-if="show_demo or values['invoiced']" class="o_secondary">
|
||||
<span t-if="!show_demo" class="o_target_to_set" name='invoiced' t-att-value="values['invoiced']['target'] ? values['invoiced']['target'] : undefined" title="Click to set">
|
||||
<t t-if="values['invoiced']['target']">
|
||||
<t t-esc="values['invoiced']['target']"/>
|
||||
</t>
|
||||
<t t-if="!values['invoiced']['target']">
|
||||
Click to set
|
||||
</t>
|
||||
</span>
|
||||
<span t-if="show_demo">
|
||||
Click to set
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="o_text">Last Month</td>
|
||||
<td class="o_secondary" title="To Activity Report">
|
||||
<a href="#" class="o_dashboard_action" name="crm.crm_activity_report_action">
|
||||
<t t-esc="values['done']['last_month']"/>
|
||||
</a>
|
||||
</td>
|
||||
<td class="o_secondary" title="To Opportunity Report">
|
||||
<a href="#" class="o_dashboard_action" name="crm.crm_opportunity_report_action">
|
||||
<t t-esc="values['won']['last_month']"/>
|
||||
</a>
|
||||
</td>
|
||||
<td t-if="values['invoiced']" class="o_secondary" title="To Invoice Report">
|
||||
<a href="#" class="o_dashboard_action" name="account.action_account_invoice_report_all">
|
||||
<t t-esc="values['invoiced']['last_month']"/>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div t-if="show_demo" class="o_welcome_message">
|
||||
<div class="o_welcome_image">
|
||||
<i class="fa fa-smile-o fa-5x"></i>
|
||||
</div>
|
||||
<div class="o_welcome_content">
|
||||
<h2>Hi there!</h2>
|
||||
<h4>Great sales journeys start with a clean pipeline.</h4>
|
||||
<h4>Have fun playing with Odoo CRM.</h4>
|
||||
<a class="btn btn-primary o_dashboard_action" name="crm.crm_lead_opportunities">Your Pipeline</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
</templates>
|
||||
@@ -205,6 +205,7 @@ class view(osv.osv):
|
||||
('diagram','Diagram'),
|
||||
('gantt', 'Gantt'),
|
||||
('kanban', 'Kanban'),
|
||||
('sales_team_dashboard', 'Sales Team Dashboard'),
|
||||
('search','Search'),
|
||||
('qweb', 'QWeb')], string='View Type'),
|
||||
'arch': fields.function(_arch_get, fnct_inv=_arch_set, string='View Architecture', type="text", nodrop=True),
|
||||
|
||||
Reference in New Issue
Block a user