From de5366ac33ea789ea9d06ad448054a97040b2bd7 Mon Sep 17 00:00:00 2001
From: Martin Geubelle <mge@odoo.com>
Date: Fri, 19 Jun 2015 13:28:09 +0200
Subject: [PATCH] [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
---
 addons/crm/__init__.py                        |   1 +
 addons/crm/crm_lead.py                        | 137 +++++++++-
 addons/crm/res_users.py                       |  13 +
 .../crm/static/src/js/sales_team_dashboard.js |  15 ++
 addons/crm/views/crm.xml                      |   3 +
 addons/sale_crm/__init__.py                   |   1 +
 addons/sale_crm/crm_lead.py                   |  30 ++-
 addons/sale_crm/res_users.py                  |  12 +
 addons/sales_team/__openerp__.py              |   3 +
 addons/sales_team/sales_team.xml              |   4 +-
 addons/sales_team/sales_team_dashboard.xml    |  16 +-
 .../static/src/js/sales_team_dashboard.js     | 126 +++++++++
 .../static/src/less/sales_team_dashboard.less | 114 +++++++++
 .../static/src/xml/sales_team_dashboard.xml   | 242 ++++++++++++++++++
 openerp/addons/base/ir/ir_ui_view.py          |   1 +
 15 files changed, 711 insertions(+), 7 deletions(-)
 create mode 100644 addons/crm/res_users.py
 create mode 100644 addons/crm/static/src/js/sales_team_dashboard.js
 create mode 100644 addons/sale_crm/res_users.py
 create mode 100644 addons/sales_team/static/src/js/sales_team_dashboard.js
 create mode 100644 addons/sales_team/static/src/less/sales_team_dashboard.less
 create mode 100644 addons/sales_team/static/src/xml/sales_team_dashboard.xml

diff --git a/addons/crm/__init__.py b/addons/crm/__init__.py
index e9a8b62b2da3..927f765e8156 100644
--- a/addons/crm/__init__.py
+++ b/addons/crm/__init__.py
@@ -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
diff --git a/addons/crm/crm_lead.py b/addons/crm/crm_lead.py
index c23619393656..4f38d41e9337 100644
--- a/addons/crm/crm_lead.py
+++ b/addons/crm/crm_lead.py
@@ -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"
diff --git a/addons/crm/res_users.py b/addons/crm/res_users.py
new file mode 100644
index 000000000000..b6c11b173a12
--- /dev/null
+++ b/addons/crm/res_users.py
@@ -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'),
+    }
diff --git a/addons/crm/static/src/js/sales_team_dashboard.js b/addons/crm/static/src/js/sales_team_dashboard.js
new file mode 100644
index 000000000000..b2bec86a7535
--- /dev/null
+++ b/addons/crm/static/src/js/sales_team_dashboard.js
@@ -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', []);
+    }
+});
+
+});
diff --git a/addons/crm/views/crm.xml b/addons/crm/views/crm.xml
index d29f5f7b3e95..4401c82d1534 100644
--- a/addons/crm/views/crm.xml
+++ b/addons/crm/views/crm.xml
@@ -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>
diff --git a/addons/sale_crm/__init__.py b/addons/sale_crm/__init__.py
index 0223759a9b48..0f8f154c60ff 100644
--- a/addons/sale_crm/__init__.py
+++ b/addons/sale_crm/__init__.py
@@ -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
diff --git a/addons/sale_crm/crm_lead.py b/addons/sale_crm/crm_lead.py
index 0c64496ba07a..0980eff5f782 100644
--- a/addons/sale_crm/crm_lead.py
+++ b/addons/sale_crm/crm_lead.py
@@ -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
diff --git a/addons/sale_crm/res_users.py b/addons/sale_crm/res_users.py
new file mode 100644
index 000000000000..9c393085186b
--- /dev/null
+++ b/addons/sale_crm/res_users.py
@@ -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'),
+    }
diff --git a/addons/sales_team/__openerp__.py b/addons/sales_team/__openerp__.py
index f9da1c53e002..c9044c904114 100644
--- a/addons/sales_team/__openerp__.py
+++ b/addons/sales_team/__openerp__.py
@@ -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,
diff --git a/addons/sales_team/sales_team.xml b/addons/sales_team/sales_team.xml
index 1b3ede5d430a..81e27b85597c 100644
--- a/addons/sales_team/sales_team.xml
+++ b/addons/sales_team/sales_team.xml
@@ -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>
 
diff --git a/addons/sales_team/sales_team_dashboard.xml b/addons/sales_team/sales_team_dashboard.xml
index 36e44c8e5353..79f2bfba168e 100644
--- a/addons/sales_team/sales_team_dashboard.xml
+++ b/addons/sales_team/sales_team_dashboard.xml
@@ -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>
\ No newline at end of file
+
+    <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>
diff --git a/addons/sales_team/static/src/js/sales_team_dashboard.js b/addons/sales_team/static/src/js/sales_team_dashboard.js
new file mode 100644
index 000000000000..0f6fe34ad9eb
--- /dev/null
+++ b/addons/sales_team/static/src/js/sales_team_dashboard.js
@@ -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
+
+});
diff --git a/addons/sales_team/static/src/less/sales_team_dashboard.less b/addons/sales_team/static/src/less/sales_team_dashboard.less
new file mode 100644
index 000000000000..9bd4f900bafb
--- /dev/null
+++ b/addons/sales_team/static/src/less/sales_team_dashboard.less
@@ -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;
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/addons/sales_team/static/src/xml/sales_team_dashboard.xml b/addons/sales_team/static/src/xml/sales_team_dashboard.xml
new file mode 100644
index 000000000000..985f7ca04310
--- /dev/null
+++ b/addons/sales_team/static/src/xml/sales_team_dashboard.xml
@@ -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>
diff --git a/openerp/addons/base/ir/ir_ui_view.py b/openerp/addons/base/ir/ir_ui_view.py
index 97b5fbe17fe6..c780e70a0885 100644
--- a/openerp/addons/base/ir/ir_ui_view.py
+++ b/openerp/addons/base/ir/ir_ui_view.py
@@ -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),
-- 
GitLab