[REM] website_sale: remove website sale community dashboard
This dashboard depends on the website dashboard which is to be re-done in OWL. Instead of keeping this dashboard as a separate component, it will be re-done in the Dashboard App (see task-3222991). task-3164163 Part-of: odoo/odoo#112819
This commit is contained in:
committed by
qsm-odoo
parent
caa5ee0e0b
commit
1434382ece
@@ -87,10 +87,7 @@
|
||||
],
|
||||
'web.assets_backend': [
|
||||
'website_sale/static/src/js/website_sale_video_field_preview.js',
|
||||
'website_sale/static/src/js/website_sale_backend.js',
|
||||
'website_sale/static/src/scss/website_sale_dashboard.scss',
|
||||
'website_sale/static/src/scss/website_sale_backend.scss',
|
||||
'website_sale/static/src/xml/website_sale_dashboard.xml',
|
||||
'website_sale/static/src/js/tours/website_sale_shop.js',
|
||||
'website_sale/static/src/xml/website_sale.xml',
|
||||
],
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from . import backend
|
||||
from . import delivery
|
||||
from . import main
|
||||
from . import variant
|
||||
|
||||
@@ -1,181 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import babel.dates
|
||||
|
||||
from datetime import datetime, timedelta, time
|
||||
|
||||
from odoo import fields, http, _
|
||||
from odoo.addons.website.controllers.backend import WebsiteBackend
|
||||
from odoo.http import request
|
||||
from odoo.tools.misc import get_lang
|
||||
|
||||
|
||||
class WebsiteSaleBackend(WebsiteBackend):
|
||||
|
||||
@http.route()
|
||||
def fetch_dashboard_data(self, website_id, date_from, date_to):
|
||||
Website = request.env['website']
|
||||
current_website = website_id and Website.browse(website_id) or Website.get_current_website()
|
||||
|
||||
results = super(WebsiteSaleBackend, self).fetch_dashboard_data(website_id, date_from, date_to)
|
||||
|
||||
date_date_from = fields.Date.from_string(date_from)
|
||||
date_date_to = fields.Date.from_string(date_to)
|
||||
date_diff_days = (date_date_to - date_date_from).days
|
||||
datetime_from = datetime.combine(date_date_from, time.min)
|
||||
datetime_to = datetime.combine(date_date_to, time.max)
|
||||
|
||||
sales_values = dict(
|
||||
graph=[],
|
||||
best_sellers=[],
|
||||
summary=dict(
|
||||
order_count=0, order_carts_count=0, order_unpaid_count=0,
|
||||
order_to_invoice_count=0, order_carts_abandoned_count=0,
|
||||
payment_to_capture_count=0, total_sold=0,
|
||||
order_per_day_ratio=0, order_sold_ratio=0, order_convertion_pctg=0,
|
||||
)
|
||||
)
|
||||
|
||||
results['dashboards']['sales'] = sales_values
|
||||
|
||||
results['groups']['sale_salesman'] = request.env['res.users'].has_group('sales_team.group_sale_salesman')
|
||||
|
||||
if not results['groups']['sale_salesman']:
|
||||
return results
|
||||
|
||||
results['dashboards']['sales']['utm_graph'] = self.fetch_utm_data(datetime_from, datetime_to)
|
||||
# Product-based computation
|
||||
sale_report_domain = [
|
||||
('website_id', '=', current_website.id),
|
||||
('state', '=', 'sale'),
|
||||
('date', '>=', datetime_from),
|
||||
('date', '<=', fields.Datetime.now())
|
||||
]
|
||||
report_product_lines = request.env['sale.report']._read_group(
|
||||
domain=sale_report_domain,
|
||||
groupby=['product_tmpl_id'],
|
||||
aggregates=['product_uom_qty:sum', 'price_subtotal:sum'], order='product_uom_qty:sum desc', limit=5)
|
||||
for product_tmpl, product_uom_qty_sum, price_subtotal_sum in report_product_lines:
|
||||
sales_values['best_sellers'].append({
|
||||
'id': product_tmpl.id,
|
||||
'name': product_tmpl.name,
|
||||
'qty': product_uom_qty_sum,
|
||||
'sales': price_subtotal_sum,
|
||||
})
|
||||
|
||||
# Sale-based results computation
|
||||
sale_order_domain = [
|
||||
('website_id', '=', current_website.id),
|
||||
('date_order', '>=', fields.Datetime.to_string(datetime_from)),
|
||||
('date_order', '<=', fields.Datetime.to_string(datetime_to))]
|
||||
so_group_data = request.env['sale.order']._read_group(sale_order_domain, groupby=['state'], aggregates=['__count'])
|
||||
for state, count in so_group_data:
|
||||
if state == 'sent':
|
||||
sales_values['summary']['order_unpaid_count'] += count
|
||||
elif state == 'sale':
|
||||
sales_values['summary']['order_count'] += count
|
||||
sales_values['summary']['order_carts_count'] += count
|
||||
|
||||
[price_subtotal] = request.env['sale.report']._read_group(
|
||||
domain=[
|
||||
('website_id', '=', current_website.id),
|
||||
('state', '=', 'sale'),
|
||||
('date', '>=', datetime_from),
|
||||
('date', '<=', datetime_to)],
|
||||
aggregates=['price_subtotal:sum'],
|
||||
)[0]
|
||||
sales_values['summary'].update(
|
||||
order_to_invoice_count=request.env['sale.order'].search_count(sale_order_domain + [
|
||||
('state', '=', 'sale'),
|
||||
('order_line', '!=', False),
|
||||
('partner_id', '!=', request.env.ref('base.public_partner').id),
|
||||
('invoice_status', '=', 'to invoice'),
|
||||
]),
|
||||
order_carts_abandoned_count=request.env['sale.order'].search_count(sale_order_domain + [
|
||||
('is_abandoned_cart', '=', True),
|
||||
('cart_recovery_email_sent', '=', False)
|
||||
]),
|
||||
payment_to_capture_count=request.env['payment.transaction'].search_count([
|
||||
('state', '=', 'authorized'),
|
||||
# that part perform a search on sale.order in order to comply with access rights as tx do not have any
|
||||
('sale_order_ids', 'in', request.env['sale.order'].search(sale_order_domain + [('state', '!=', 'cancel')]).ids),
|
||||
]),
|
||||
total_sold=price_subtotal,
|
||||
)
|
||||
|
||||
# Ratio computation
|
||||
sales_values['summary']['order_per_day_ratio'] = round(float(sales_values['summary']['order_count']) / date_diff_days, 2)
|
||||
sales_values['summary']['order_sold_ratio'] = round(float(sales_values['summary']['total_sold']) / sales_values['summary']['order_count'], 2) if sales_values['summary']['order_count'] else 0
|
||||
sales_values['summary']['order_convertion_pctg'] = 100.0 * sales_values['summary']['order_count'] / sales_values['summary']['order_carts_count'] if sales_values['summary']['order_carts_count'] else 0
|
||||
|
||||
# Graphes computation
|
||||
if date_diff_days == 7:
|
||||
previous_sale_label = _('Previous Week')
|
||||
elif date_diff_days > 7 and date_diff_days <= 31:
|
||||
previous_sale_label = _('Previous Month')
|
||||
else:
|
||||
previous_sale_label = _('Previous Year')
|
||||
|
||||
sales_values['graph'] += [{
|
||||
'values': self._compute_sale_graph(date_date_from, date_date_to, sale_report_domain),
|
||||
'key': 'Untaxed Total',
|
||||
}, {
|
||||
'values': self._compute_sale_graph(date_date_from - timedelta(days=date_diff_days), date_date_from, sale_report_domain, previous=True),
|
||||
'key': previous_sale_label,
|
||||
}]
|
||||
|
||||
return results
|
||||
|
||||
def fetch_utm_data(self, date_from, date_to):
|
||||
sale_utm_domain = [
|
||||
('website_id', '!=', False),
|
||||
('state', '=', 'sale'),
|
||||
('date_order', '>=', date_from),
|
||||
('date_order', '<=', date_to)
|
||||
]
|
||||
|
||||
orders_data_groupby_campaign_id = request.env['sale.order']._read_group(
|
||||
domain=sale_utm_domain + [('campaign_id', '!=', False)],
|
||||
groupby=['campaign_id'],
|
||||
aggregates=['amount_total:sum'])
|
||||
|
||||
orders_data_groupby_medium_id = request.env['sale.order']._read_group(
|
||||
domain=sale_utm_domain + [('medium_id', '!=', False)],
|
||||
groupby=['medium_id'],
|
||||
aggregates=['amount_total:sum'])
|
||||
|
||||
orders_data_groupby_source_id = request.env['sale.order']._read_group(
|
||||
domain=sale_utm_domain + [('source_id', '!=', False)],
|
||||
groupby=['source_id'],
|
||||
aggregates=['amount_total:sum'])
|
||||
|
||||
return {
|
||||
'campaign_id': self.compute_utm_graph_data(orders_data_groupby_campaign_id),
|
||||
'medium_id': self.compute_utm_graph_data(orders_data_groupby_medium_id),
|
||||
'source_id': self.compute_utm_graph_data(orders_data_groupby_source_id),
|
||||
}
|
||||
|
||||
def compute_utm_graph_data(self, utm_graph_data):
|
||||
return [{
|
||||
'utm_type': utm_type.display_name,
|
||||
'amount_total': amount_total,
|
||||
} for utm_type, amount_total in utm_graph_data]
|
||||
|
||||
def _compute_sale_graph(self, date_from, date_to, sales_domain, previous=False):
|
||||
days_between = (date_to - date_from).days
|
||||
date_list = [(date_from + timedelta(days=x)) for x in range(0, days_between + 1)]
|
||||
|
||||
daily_sales = request.env['sale.report']._read_group(
|
||||
domain=sales_domain,
|
||||
groupby=['date:day'],
|
||||
aggregates=['price_subtotal:sum'])
|
||||
|
||||
daily_sales_dict = {date_day: price_subtotal_sum for date_day, price_subtotal_sum in daily_sales}
|
||||
|
||||
sales_graph = [{
|
||||
'0': fields.Date.to_string(d) if not previous else fields.Date.to_string(d + timedelta(days=days_between)),
|
||||
# Respect read_group format in models.py
|
||||
'1': daily_sales_dict.get(d, 0),
|
||||
} for d in date_list]
|
||||
|
||||
return sales_graph
|
||||
@@ -1,124 +0,0 @@
|
||||
/** @odoo-module alias=website_sale.backend **/
|
||||
|
||||
import WebsiteBackend from "website.backend.dashboard";
|
||||
var COLORS = ['#875a7b', '#21b799', '#E4A900', '#D5653E', '#5B899E', '#E46F78', '#8F8F8F'];
|
||||
|
||||
WebsiteBackend.include({
|
||||
jsLibs: [
|
||||
'/web/static/lib/Chart/Chart.js',
|
||||
],
|
||||
|
||||
events: Object.assign(WebsiteBackend.prototype.events, {
|
||||
"click tr.o_product_template": "on_product_template",
|
||||
"click .js_utm_selector": "_onClickUtmButton",
|
||||
}),
|
||||
|
||||
init: function (parent, context) {
|
||||
this._super(parent, context);
|
||||
|
||||
this.graphs.push({'name': 'sales', 'group': 'sale_salesman'});
|
||||
},
|
||||
|
||||
/**
|
||||
* @override method from website backendDashboard
|
||||
* @private
|
||||
*/
|
||||
render_graphs: function() {
|
||||
this._super();
|
||||
this.utmGraphData = this.dashboards_data.sales.utm_graph;
|
||||
this.utmGraphData && this._renderUtmGraph();
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Private
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Method used to generate Pie chart, depending on user selected UTM option(campaign, medium, source)
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_renderUtmGraph: function() {
|
||||
var self = this;
|
||||
this.$(".utm_button_name").html(this.btnName); // change drop-down button name
|
||||
var utmDataType = this.utmType || 'campaign_id';
|
||||
var graphData = this.utmGraphData[utmDataType];
|
||||
if (graphData.length) {
|
||||
this.$(".o_utm_no_data_img").hide();
|
||||
this.$(".o_utm_data_graph").empty().show();
|
||||
var $canvas = $('<canvas/>');
|
||||
this.$(".o_utm_data_graph").append($canvas);
|
||||
var context = $canvas[0].getContext('2d');
|
||||
console.log(graphData);
|
||||
|
||||
var data = [];
|
||||
var labels = [];
|
||||
graphData.forEach(function(pt) {
|
||||
data.push(pt.amount_total);
|
||||
labels.push(pt.utm_type);
|
||||
});
|
||||
var config = {
|
||||
type: 'pie',
|
||||
data: {
|
||||
labels: labels,
|
||||
datasets: [{
|
||||
data: data,
|
||||
backgroundColor: COLORS,
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
tooltips: {
|
||||
callbacks: {
|
||||
label: function(tooltipItem, data) {
|
||||
var label = data.labels[tooltipItem.index] || '';
|
||||
if (label) {
|
||||
label += ': ';
|
||||
}
|
||||
var amount = data.datasets[0].data[tooltipItem.index];
|
||||
amount = self.render_monetary_field(amount, self.data.currency);
|
||||
label += amount;
|
||||
return label;
|
||||
}
|
||||
}
|
||||
},
|
||||
legend: {display: false}
|
||||
}
|
||||
};
|
||||
new Chart(context, config);
|
||||
} else {
|
||||
this.$(".o_utm_no_data_img").show();
|
||||
this.$(".o_utm_data_graph").hide();
|
||||
}
|
||||
},
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Handlers
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Onchange on UTM dropdown button, this method is called.
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
_onClickUtmButton: function(ev) {
|
||||
this.utmType = $(ev.currentTarget).attr('name');
|
||||
this.btnName = $(ev.currentTarget).text();
|
||||
this._renderUtmGraph();
|
||||
},
|
||||
|
||||
on_product_template: function (ev) {
|
||||
ev.preventDefault();
|
||||
|
||||
var product_tmpl_id = $(ev.currentTarget).data('productId');
|
||||
this.do_action({
|
||||
type: 'ir.actions.act_window',
|
||||
res_model: 'product.template',
|
||||
res_id: product_tmpl_id,
|
||||
views: [[false, 'form']],
|
||||
target: 'current',
|
||||
}, {
|
||||
on_reverse_breadcrumb: this.on_reverse_breadcrumb,
|
||||
});
|
||||
},
|
||||
});
|
||||
export default WebsiteBackend;
|
||||
@@ -1,81 +0,0 @@
|
||||
.o_dashboard_sales {
|
||||
|
||||
h2 {
|
||||
padding: 15px;
|
||||
}
|
||||
h4 { margin: 3px 0 4px 0 !important; }
|
||||
.o_demo_background {
|
||||
margin-top: 16px;
|
||||
height: 350px;
|
||||
background-size: 100% !important;
|
||||
background: url("/website_sale/static/src/img/website_sale_dashboard_sales_demo.png") no-repeat;
|
||||
position: relative;
|
||||
opacity: 0.2;
|
||||
}
|
||||
.o_demo_message {
|
||||
color: $o-main-color-muted;
|
||||
width: 100%;
|
||||
@include o-position-absolute($left: 0, $top: 12%);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
.o_link_enable {
|
||||
@include media-breakpoint-up(lg) {
|
||||
border-right: 1px solid #ccc;
|
||||
}
|
||||
height: initial;
|
||||
padding: 5px;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
a {
|
||||
color: darken($o-brand-lightsecondary, 40%);
|
||||
}
|
||||
&:hover {
|
||||
background-color: $o-brand-lightsecondary;
|
||||
}
|
||||
.o_highlight {
|
||||
color: $o-brand-primary;
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
.o_link_disable {
|
||||
@include media-breakpoint-up(lg) {
|
||||
border-right: 1px solid #ccc;
|
||||
}
|
||||
height: initial;
|
||||
padding: 5px;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
margin: 10px 0px;
|
||||
color: darken($o-brand-lightsecondary, 40%);
|
||||
.o_highlight {
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
.o_invisible_border {
|
||||
border-right: 0px;
|
||||
}
|
||||
.o_top_margin {
|
||||
margin-top: 20px;
|
||||
}
|
||||
.o_graph_canvas_container {
|
||||
position: relative;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
width: 100%;
|
||||
height: 30em;
|
||||
}
|
||||
.o_dashboard_utms {
|
||||
.utm_chart_image {
|
||||
display: block;
|
||||
margin: auto;
|
||||
}
|
||||
.utm_dropdown {
|
||||
margin-top: -5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,169 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<templates>
|
||||
<t t-extend="website.dashboard_header">
|
||||
<t t-jquery="div.o_dashboard_common" t-operation="append">
|
||||
<div class="col-12 o_box" t-if="widget.dashboards_data.sales.summary.order_unpaid_count || widget.dashboards_data.sales.summary.order_to_invoice_count || widget.dashboards_data.sales.summary.payment_to_capture_count || widget.dashboards_data.sales.summary.order_carts_abandoned_count">
|
||||
<div t-if="widget.dashboards_data.sales.summary.order_unpaid_count" class="o_inner_box o_dashboard_action" title="Confirm orders when you get paid." name="website_sale.action_unpaid_orders_ecommerce">
|
||||
<div class="o_highlight"><t t-esc="widget.dashboards_data.sales.summary.order_unpaid_count"/></div>
|
||||
Unpaid Orders
|
||||
</div>
|
||||
<div t-if="widget.dashboards_data.sales.summary.order_to_invoice_count" class="o_inner_box o_dashboard_action" title="Generate an invoice from orders ready for invoicing." name="website_sale.sale_order_action_to_invoice">
|
||||
<div class="o_highlight"><t t-esc="widget.dashboards_data.sales.summary.order_to_invoice_count"/></div>
|
||||
Orders to Invoice
|
||||
</div>
|
||||
<div t-if="widget.dashboards_data.sales.summary.payment_to_capture_count" class="o_inner_box o_dashboard_action" title="Capture order payments when the delivery is completed." name="website_sale.payment_transaction_action_payments_to_capture">
|
||||
<div class="o_highlight"><t t-esc="widget.dashboards_data.sales.summary.payment_to_capture_count"/></div>
|
||||
Payments to Capture
|
||||
</div>
|
||||
<div t-if="widget.dashboards_data.sales.summary.order_carts_abandoned_count" class="o_inner_box o_dashboard_action" title="Send a recovery email to visitors who haven't completed their order." name="website_sale.action_view_abandoned_tree">
|
||||
<div class="o_highlight"><t t-esc="widget.dashboards_data.sales.summary.order_carts_abandoned_count"/></div>
|
||||
Abandoned Carts
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<t t-name="website_sale.dashboard_content" t-inherit="website.dashboard_content" t-inherit-mode="extension">
|
||||
<xpath expr="//div[hasclass('o_website_dashboard_content')]/*[1]" position="before">
|
||||
<div t-if="widget.groups.sale_salesman" class="row o_dashboard_sales">
|
||||
<div class="col-12 row o_box">
|
||||
<t t-if="widget.dashboards_data.sales.summary.order_count">
|
||||
<h2 class="col-lg-7 col-12">
|
||||
<t t-if="widget.date_range=='week'">
|
||||
Sales Since Last Week
|
||||
</t>
|
||||
<t t-elif="widget.date_range=='month'">
|
||||
Sales Since Last Month
|
||||
</t>
|
||||
<t t-elif="widget.date_range=='year'">
|
||||
Sales Since Last Year
|
||||
</t>
|
||||
<t t-else="">Sales</t>
|
||||
</h2>
|
||||
<h4 class='col-lg-5 col-12'>AT A GLANCE</h4>
|
||||
<div class="col-lg-7 col-12">
|
||||
<div class="o_graph_sales" data-type="sales"/>
|
||||
</div>
|
||||
<div class="col-lg-5 col-12">
|
||||
<t t-call="website_sale.products_table"/>
|
||||
</div>
|
||||
</t>
|
||||
<t t-if="! widget.dashboards_data.sales.summary.order_count">
|
||||
<t t-if="widget.date_range=='week'">
|
||||
<h2>Sales Since Last Week</h2>
|
||||
</t>
|
||||
<t t-elif="widget.date_range=='month'">
|
||||
<h2>Sales Since Last Month</h2>
|
||||
</t>
|
||||
<t t-elif="widget.date_range=='year'">
|
||||
<h2>Sales Since Last Year</h2>
|
||||
</t>
|
||||
<t t-else=""><h2>Sales</h2></t>
|
||||
<div class="col-lg-12 col-12">
|
||||
<div class="o_demo_background">
|
||||
</div>
|
||||
<div class="o_demo_message">
|
||||
<h3>There is no recent confirmed order.</h3>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</xpath>
|
||||
</t>
|
||||
|
||||
<t t-name="website_sale.products_table">
|
||||
<div class="row">
|
||||
<a href="#" class="col-md-4 o_dashboard_action" name="website_sale.sale_report_action_dashboard">
|
||||
<div class="o_link_enable" title="Orders">
|
||||
<div class="o_highlight">
|
||||
<t t-esc="widget.dashboards_data.sales.summary.order_count"/>
|
||||
</div>
|
||||
Orders
|
||||
</div>
|
||||
</a>
|
||||
<a href="#" class="col-md-4 o_dashboard_action" name="website_sale.sale_report_action_dashboard">
|
||||
<div class="o_link_enable" title="Untaxed Total Sold">
|
||||
<div class="o_highlight">
|
||||
<t t-esc="widget.render_monetary_field(widget.dashboards_data.sales.summary.total_sold, widget.data.currency)"/>
|
||||
</div>
|
||||
Sold
|
||||
</div>
|
||||
</a>
|
||||
<a href="#" class="col-md-4 o_dashboard_action" name="website_sale.sale_report_action_carts">
|
||||
<div class="o_link_enable o_invisible_border" title="Carts">
|
||||
<div class="o_highlight"><t t-esc="widget.dashboards_data.sales.summary.order_carts_count"/></div>
|
||||
Carts
|
||||
</div>
|
||||
</a>
|
||||
<div class="col-md-4 o_link_disable" title="Orders/Day">
|
||||
<div class="o_highlight"><t t-esc="widget.dashboards_data.sales.summary.order_per_day_ratio"/></div>
|
||||
Orders/Day
|
||||
</div>
|
||||
<div class="col-md-4 o_link_disable" title="Average Order">
|
||||
<div class="o_highlight"><t t-esc="widget.render_monetary_field(widget.dashboards_data.sales.summary.order_sold_ratio, widget.data.currency)"/></div>
|
||||
Average Order
|
||||
</div>
|
||||
<div class="col-md-4 o_link_disable o_invisible_border" title="Conversion">
|
||||
<div class="o_highlight"><t t-esc="widget.format_number(widget.dashboards_data.sales.summary.order_convertion_pctg, 'float', [3, 2], '%')"/></div>
|
||||
Conversion
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-12 col-12 o_top_margin">
|
||||
<div class="row">
|
||||
<div class="col-lg-12 col-12">
|
||||
<h4>Best Sellers</h4>
|
||||
<table class="table table-responsive table-hover">
|
||||
<tr>
|
||||
<th>Product</th>
|
||||
<th>Quantity</th>
|
||||
<th>Sold</th>
|
||||
</tr>
|
||||
<tr class="o_product_template" t-foreach="widget.dashboards_data.sales.best_sellers" t-as="product" t-att-data-product-id="product.id">
|
||||
<td><t t-esc="product.name"/></td>
|
||||
<td><t t-esc="product.qty"/></td>
|
||||
<td><t t-esc="widget.render_monetary_field(product.sales, widget.data.currency)"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-extend="website_sale.products_table">
|
||||
<t t-jquery=".o_top_margin .row .col-12" t-operation="attributes">
|
||||
<attribute name="class" value="col-lg-6 col-12" />
|
||||
</t>
|
||||
<t t-jquery=".o_top_margin .row" t-operation="append">
|
||||
<div class="col-lg-6 col-12 o_dashboard_utms">
|
||||
<div>
|
||||
<h4 class="float-start">REVENUE BY</h4>
|
||||
<t t-call="website_sale.LinkTrackersDropDown"/>
|
||||
</div>
|
||||
<div class="o_utm_no_data_img">
|
||||
<img src="website_sale/static/src/img/website_sale_chart_demo.png" alt="There isn't any UTM tag detected in orders" class="utm_chart_image image-responsive mt8"/>
|
||||
</div>
|
||||
<div class="o_utm_data_graph"/>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<t t-name="website_sale.LinkTrackersDropDown">
|
||||
<div class="dropdown">
|
||||
<button class="btn btn-secondary dropdown-toggle utm_dropdown ml4" type="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="true"><span class="utm_button_name">Campaigns</span>
|
||||
</button>
|
||||
<div class="dropdown-menu" role="menu" aria-labelledby="utm_dropdown">
|
||||
<a name="campaign_id" class="dropdown-item js_utm_selector" role="menuitem">Campaigns</a>
|
||||
<a name="medium_id" class="dropdown-item js_utm_selector" role="menuitem">Medium</a>
|
||||
<a name="source_id" class="dropdown-item js_utm_selector" role="menuitem">Sources</a>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<!-- Show the date range buttons related to the 'community' Sales Dashboard -->
|
||||
<t t-extend="website.DateRangeButtons">
|
||||
<t t-jquery="t[t-set='show_range_buttons']" t-operation="attributes">
|
||||
<attribute name="t-value" value="1" />
|
||||
</t>
|
||||
</t>
|
||||
</templates>
|
||||
Reference in New Issue
Block a user