[MERGE] website(_sale): improve website dashboard and merge website menu items
There is now a single menu item for Website and Website Admin. Depending on current user access rights it redirects to the dasboard or the website itself. It allows to simplify the application choice and management when installing notably ecommerce. Dashboard itself is renewed. It now contains a header including important data about sales as well as links towards other web applications. Sales part of the dashboard is improved to display relevant data.
This commit is contained in:
@@ -17,18 +17,16 @@ Odoo Website CMS
|
||||
'installable': True,
|
||||
'data': [
|
||||
'data/website_data.xml',
|
||||
'data/web_planner_data.xml',
|
||||
'security/website_security.xml',
|
||||
'security/ir.model.access.csv',
|
||||
|
||||
'views/website_templates.xml',
|
||||
'views/website_navbar_templates.xml',
|
||||
'views/snippets.xml',
|
||||
'views/website_views.xml',
|
||||
'views/res_config_views.xml',
|
||||
'views/ir_actions_views.xml',
|
||||
|
||||
'wizard/base_language_install_views.xml',
|
||||
'data/web_planner_data.xml',
|
||||
],
|
||||
'demo': [
|
||||
'data/website_demo.xml',
|
||||
|
||||
@@ -9,16 +9,29 @@ class WebsiteBackend(http.Controller):
|
||||
|
||||
@http.route('/website/fetch_dashboard_data', type="json", auth='user')
|
||||
def fetch_dashboard_data(self, date_from, date_to):
|
||||
|
||||
params = request.env['ir.config_parameter']
|
||||
ga_client_id = params.sudo().get_param('google_management_client_id', default='')
|
||||
|
||||
return {
|
||||
'groups': {'system': request.env['res.users'].has_group('base.group_system')},
|
||||
has_group_system = request.env['res.users'].has_group('base.group_system')
|
||||
has_group_designer = request.env['res.users'].has_group('website.group_website_designer')
|
||||
if has_group_system:
|
||||
apps_data = dict((app['name'], app) for app in request.env['ir.module.module'].sudo().search_read(
|
||||
['|', ('name', 'ilike', 'website'), ('application', '=', True)],
|
||||
['id', 'sequence', 'name', 'shortdesc', 'state'],
|
||||
order='sequence ASC'))
|
||||
else:
|
||||
apps_data = {}
|
||||
dashboard_data = {
|
||||
'groups': {
|
||||
'system': has_group_system,
|
||||
'website_designer': has_group_designer
|
||||
},
|
||||
'currency': request.env.user.company_id.currency_id.id,
|
||||
'dashboards': {
|
||||
'visits': {
|
||||
'ga_client_id': ga_client_id,
|
||||
}
|
||||
'apps_data': apps_data,
|
||||
'visits': {},
|
||||
}
|
||||
}
|
||||
if has_group_designer:
|
||||
ga_dashboard = request.env['ir.values'].sudo().get_default('website.config.settings', 'has_google_analytics_dashboard')
|
||||
if ga_dashboard:
|
||||
ga_client_id = request.env['ir.config_parameter'].sudo().get_param('google_management_client_id', default='')
|
||||
dashboard_data['dashboards']['visits']['ga_client_id'] = ga_client_id
|
||||
return dashboard_data
|
||||
|
||||
@@ -709,7 +709,7 @@
|
||||
<record id="planner_website" model="web.planner">
|
||||
<field name="name">Website Planner</field>
|
||||
<field name="view_id" ref="website_planner"/>
|
||||
<field name="menu_id" ref="website.menu_website"/>
|
||||
<field name="menu_id" ref="website.menu_website_configuration"/>
|
||||
<field name="planner_application">planner_website</field>
|
||||
<field name="tooltip_planner"><![CDATA[
|
||||
Plan your website strategy, design your pages, sell your products and grow your online business!
|
||||
|
||||
@@ -65,13 +65,6 @@
|
||||
<field name="target">self</field>
|
||||
</record>
|
||||
|
||||
<record id="menu_website" model="ir.ui.menu">
|
||||
<field name="name">Website</field>
|
||||
<field name="sequence" eval="200"/>
|
||||
<field name="web_icon">website,static/description/icon.png</field>
|
||||
<field name="action" ref="action_website"/>
|
||||
</record>
|
||||
|
||||
<record id="base.open_menu" model="ir.actions.todo">
|
||||
<field name="action_id" ref="action_website"/>
|
||||
<field name="state">open</field>
|
||||
|
||||
@@ -601,6 +601,12 @@ class Website(models.Model):
|
||||
return urlparse.urljoin(cdn_url, uri)
|
||||
return uri
|
||||
|
||||
@api.model
|
||||
def action_dashboard_redirect(self):
|
||||
if self.env.user.has_group('base.group_system') or self.env.user.has_group('website.group_website_designer'):
|
||||
return self.env.ref('website.backend_dashboard').read()[0]
|
||||
return self.env.ref('website.action_website').read()[0]
|
||||
|
||||
|
||||
class Menu(models.Model):
|
||||
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 21 KiB |
@@ -6,12 +6,14 @@ var ajax = require('web.ajax');
|
||||
var ControlPanelMixin = require('web.ControlPanelMixin');
|
||||
var core = require('web.core');
|
||||
var Dialog = require('web.Dialog');
|
||||
var formats = require('web.formats');
|
||||
var Model = require('web.Model');
|
||||
var session = require('web.session');
|
||||
var utils = require('web.utils');
|
||||
var web_client = require('web.web_client');
|
||||
var Widget = require('web.Widget');
|
||||
|
||||
var local_storage = require('web.local_storage');
|
||||
|
||||
var _t = core._t;
|
||||
var QWeb = core.qweb;
|
||||
|
||||
@@ -19,6 +21,9 @@ var Dashboard = Widget.extend(ControlPanelMixin, {
|
||||
template: "website.WebsiteDashboardMain",
|
||||
events: {
|
||||
'click .js_link_analytics_settings': 'on_link_analytics_settings',
|
||||
'click .o_dashboard_action': 'on_dashboard_action',
|
||||
'click .o_dashboard_action_form': 'on_dashboard_action_form',
|
||||
'click .o_dashboard_hide_panel': 'on_dashboard_hide_panel',
|
||||
},
|
||||
|
||||
init: function(parent, context) {
|
||||
@@ -27,6 +32,7 @@ var Dashboard = Widget.extend(ControlPanelMixin, {
|
||||
this.date_range = 'week'; // possible values : 'week', 'month', year'
|
||||
this.date_from = moment().subtract(1, 'week');
|
||||
this.date_to = moment();
|
||||
this.hidden_apps = JSON.parse(local_storage.getItem('website_dashboard_hidden_app_ids') || '[]');
|
||||
|
||||
this.dashboards_templates = ['website.dashboard_visits'];
|
||||
this.graphs = [];
|
||||
@@ -106,7 +112,7 @@ var Dashboard = Widget.extend(ControlPanelMixin, {
|
||||
render_dashboards: function() {
|
||||
var self = this;
|
||||
_.each(this.dashboards_templates, function(template) {
|
||||
self.$('.o_website_dashboard').append(QWeb.render(template, {widget: self}));
|
||||
self.$('.o_website_dashboard_content').append(QWeb.render(template, {widget: self}));
|
||||
});
|
||||
},
|
||||
|
||||
@@ -139,7 +145,7 @@ var Dashboard = Widget.extend(ControlPanelMixin, {
|
||||
.append("svg");
|
||||
|
||||
svg
|
||||
.attr("height", '20em')
|
||||
.attr("height", '24em')
|
||||
.datum(chart_values)
|
||||
.call(chart);
|
||||
|
||||
@@ -205,7 +211,7 @@ var Dashboard = Widget.extend(ControlPanelMixin, {
|
||||
|
||||
var self = this;
|
||||
$.when(this.fetch_data()).then(function() {
|
||||
self.$('.o_website_dashboard').empty();
|
||||
self.$('.o_website_dashboard_content').empty();
|
||||
self.render_dashboards();
|
||||
self.render_graphs();
|
||||
});
|
||||
@@ -217,6 +223,49 @@ var Dashboard = Widget.extend(ControlPanelMixin, {
|
||||
this.update_cp();
|
||||
},
|
||||
|
||||
on_dashboard_action: function (ev) {
|
||||
ev.preventDefault();
|
||||
var $action = $(ev.currentTarget);
|
||||
var additional_context = {};
|
||||
if (this.date_range === 'week') {
|
||||
additional_context = {'search_default_week': true}
|
||||
} else if (this.date_range === 'month') {
|
||||
additional_context = {'search_default_month': true}
|
||||
} else if (this.date_range === 'year') {
|
||||
additional_context = {'search_default_year': true}
|
||||
}
|
||||
this.do_action($action.attr('name'), {
|
||||
additional_context: additional_context,
|
||||
on_reverse_breadcrumb: this.on_reverse_breadcrumb
|
||||
});
|
||||
},
|
||||
|
||||
on_dashboard_action_form: function (ev) {
|
||||
ev.preventDefault();
|
||||
var $action = $(ev.currentTarget);
|
||||
this.do_action({
|
||||
name: $action.attr('name'),
|
||||
res_model: $action.data('res_model'),
|
||||
res_id: $action.data('res_id'),
|
||||
views: [[false, 'form']],
|
||||
type: 'ir.actions.act_window',
|
||||
}, {
|
||||
on_reverse_breadcrumb: this.on_reverse_breadcrumb
|
||||
});
|
||||
},
|
||||
|
||||
on_dashboard_hide_panel: function (ev) {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
var $action = $(ev.currentTarget);
|
||||
// update hidden module list
|
||||
this.hidden_apps = JSON.parse(local_storage.getItem('website_dashboard_hidden_app_ids') || '[]');
|
||||
this.hidden_apps.push(JSON.parse($action.data('module_id')));
|
||||
local_storage.setItem('website_dashboard_hidden_app_ids', JSON.stringify(this.hidden_apps));
|
||||
// remove box
|
||||
$action.closest(".o_box_item").remove();
|
||||
},
|
||||
|
||||
update_cp: function() {
|
||||
var self = this;
|
||||
if (!this.$searchview) {
|
||||
@@ -517,24 +566,24 @@ var Dashboard = Widget.extend(ControlPanelMixin, {
|
||||
return i % keep_one_of === 0;
|
||||
});
|
||||
},
|
||||
format_number: function(value, symbol) {
|
||||
value = utils.human_number(value);
|
||||
if (symbol === 'currency') {
|
||||
format_number: function(value, type, digits, symbol) {
|
||||
if (type === 'currency') {
|
||||
return this.render_monetary_field(value, this.currency_id);
|
||||
} else {
|
||||
return value + (symbol || '');
|
||||
return formats.format_value(value || 0, {type: type, digits: digits}) + ' ' + symbol;
|
||||
}
|
||||
},
|
||||
render_monetary_field: function(value, currency_id) {
|
||||
var currency = session.get_currency(currency_id);
|
||||
var formatted_value = formats.format_value(value || 0, {type: "float", digits: currency && currency.digits});
|
||||
if (currency) {
|
||||
if (currency.position === "after") {
|
||||
value += currency.symbol;
|
||||
formatted_value += currency.symbol;
|
||||
} else {
|
||||
value = currency.symbol + value;
|
||||
formatted_value = currency.symbol + formatted_value;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
return formatted_value;
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
@@ -27,9 +27,9 @@
|
||||
|
||||
h4 { margin: 0 0 0 8px; }
|
||||
|
||||
h2 { color: @odoo-brand-primary; }
|
||||
h2, h4 { color: @odoo-brand-primary; }
|
||||
|
||||
.col-md-6 {
|
||||
.col-md-5, .col-md-7 {
|
||||
padding: 15px;
|
||||
|
||||
.js_field_selection {
|
||||
@@ -80,12 +80,6 @@
|
||||
.translate(45; 30) !important;
|
||||
}
|
||||
|
||||
g.nv-y.nv-axis, g.nv-x.nv-axis, g.nv-y.nv-axis .nv-axisMaxMin {
|
||||
text {
|
||||
opacity: .3 !important;
|
||||
}
|
||||
}
|
||||
|
||||
g.nv-x.nv-axis .tick > line {
|
||||
opacity: 0 !important;
|
||||
}
|
||||
@@ -122,14 +116,86 @@
|
||||
background-color: @odoo-brand-optional !important;
|
||||
}
|
||||
tr:last-child .legend-color-guide > div {
|
||||
background-color: darken(@odoo-brand-optional, 10%) !important;
|
||||
background-color: darken(@odoo-brand-lightsecondary, 10%) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.o_dashboard_common {
|
||||
.o_box {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
justify-content: flex-start;
|
||||
> .o_box_item {
|
||||
@media (max-width: @screen-sm-min) {
|
||||
flex: 1 1 200px;
|
||||
display: block !important;
|
||||
}
|
||||
@media (min-width: @screen-sm-min) {
|
||||
flex: 0 0 16.6%;
|
||||
}
|
||||
}
|
||||
}
|
||||
.o_inner_box {
|
||||
padding-top: 10px;
|
||||
text-align: center;
|
||||
border: 1px solid @odoo-view-background-color;
|
||||
height: 80px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
&.o_main {
|
||||
background-color: @odoo-brand-optional;
|
||||
&:hover {
|
||||
background-color: darken(@odoo-brand-optional, 10%);
|
||||
}
|
||||
a {
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
&.o_primary {
|
||||
background-color: @odoo-brand-primary;
|
||||
color: white;
|
||||
&:hover {
|
||||
background-color: darken(@odoo-brand-primary, 10%);
|
||||
}
|
||||
}
|
||||
&.o_apps {
|
||||
position: relative;
|
||||
background-color: @odoo-brand-optional;
|
||||
color: white;
|
||||
.o_apps_hidden {
|
||||
display: none;
|
||||
&.o_dashboard_hide_panel {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
right: 0px;
|
||||
background: @brand-danger;
|
||||
padding: 6px;
|
||||
}
|
||||
}
|
||||
&:hover {
|
||||
background-color: #45818E;
|
||||
.o_apps_show {
|
||||
display: none;
|
||||
}
|
||||
.o_apps_hidden {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
.o_highlight {
|
||||
font-size: 27px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.o_dashboard_visits {
|
||||
|
||||
h2 {
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.o_demo_background {
|
||||
|
||||
margin-top: 16px;
|
||||
|
||||
@@ -8,17 +8,69 @@
|
||||
<t t-name="website.WebsiteDashboardMain">
|
||||
<div class="o_dashboards">
|
||||
<div class="container-fluid o_website_dashboard">
|
||||
<t t-call="website.dashboard_header"/>
|
||||
<div class="o_website_dashboard_content"/>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="website.dashboard_header">
|
||||
<div class="row o_dashboard_common">
|
||||
<div class="o_box">
|
||||
<a href="#" class="o_box_item o_dashboard_action" name="website.action_website" title="Go to Website">
|
||||
<div class="o_inner_box o_primary">
|
||||
<i class="fa fa-globe fa-3x"></i><br/>
|
||||
Go to Website
|
||||
</div>
|
||||
</a>
|
||||
<t t-if="widget.groups.system">
|
||||
<t t-set="apps" t-value="{
|
||||
'website_crm': {'icon': 'fa-file-text-o', 'help': _('Add a contact form to your Contact Us page.')},
|
||||
'website_sale': {'icon': 'fa-shopping-cart', 'help': _('Sell online to reach new customers.')},
|
||||
'website_blog': {'icon': 'fa-rss-square', 'help': _('Build up a community with an efficient content strategy.')},
|
||||
'website_hr_recruitment': {'icon': 'fa-suitcase', 'help': _('Promote your job announces to attract new talents.')},
|
||||
'website_event': {'icon': 'fa-ticket', 'help': _('Promote your events, manage attendance and sell tickets.')},
|
||||
'im_livechat': {'icon': 'fa-comments-o', 'help': _('Chat with your visitors in real time.')},
|
||||
}"/>
|
||||
</t>
|
||||
<t t-if="! widget.groups.system"><t t-set="apps" t-value="{}"/></t>
|
||||
<t t-set="vignette_max" t-value="6"/>
|
||||
<t t-set="vignette_nbr" t-value="1"/>
|
||||
<t t-foreach="apps" t-as="app">
|
||||
<t t-set="app_data" t-value="widget.dashboards_data.apps_data[app]"/>
|
||||
<t t-set="app_dashboard" t-value="apps[app]"/>
|
||||
<t t-if="vignette_nbr < vignette_max && widget.hidden_apps.indexOf(app_data['id']) == -1 && app_data['state'] == 'uninstalled'">
|
||||
<t t-set="vignette_nbr" t-value="vignette_nbr + 1"/>
|
||||
<a href="#" class="o_box_item o_dashboard_action_form"
|
||||
name="Apps"
|
||||
data-res_model="ir.module.module"
|
||||
t-att-data-res_id="app_data['id']"
|
||||
t-att-title="app_dashboard['help']">
|
||||
<div class="o_inner_box o_apps">
|
||||
<div class="o_apps_show">
|
||||
<i t-attf-class="fa #{app_dashboard['icon']} fa-3x"></i><br/>
|
||||
<t t-esc="app_data['shortdesc']"/>
|
||||
</div>
|
||||
<div class="o_apps_hidden">
|
||||
<i class="fa fa-plus-circle fa-3x"></i><br/>
|
||||
Add this feature
|
||||
</div>
|
||||
<i class="o_apps_hidden o_dashboard_hide_panel fa fa-close" t-att-data-module_id="app_data['id']" title="Remove this suggestion from dashboard"/>
|
||||
</div>
|
||||
</a>
|
||||
</t>
|
||||
</t>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="website.dashboard_visits">
|
||||
<div class="row o_dashboard_visits">
|
||||
<div class="row o_dashboard_visits" t-if="widget.groups.website_designer">
|
||||
<div class="col-xs-12 o_box">
|
||||
<h2>Visits</h2>
|
||||
<div t-if="widget.dashboards_data.visits && widget.dashboards_data.visits.ga_client_id">
|
||||
<div class="row js_analytics_components"/>
|
||||
<a href="#" t-if="widget.groups.system" class="js_link_analytics_settings">Edit my Analytics Client ID</a>
|
||||
<a href="#" class="js_link_analytics_settings">Edit my Analytics Client ID</a>
|
||||
</div>
|
||||
<div t-if="!(widget.dashboards_data.visits && widget.dashboards_data.visits.ga_client_id)" class="col-md-12">
|
||||
<div class="o_demo_background">
|
||||
@@ -26,8 +78,7 @@
|
||||
</div>
|
||||
<div class="o_buttons text-center">
|
||||
<h3>There is no data currently available.</h3>
|
||||
<button t-if="widget.groups.system" class="btn btn-sm btn-primary js_link_analytics_settings center-block mb8">Link my Analytics Account</button>
|
||||
<h5 t-if="!widget.groups.system">You do not have sufficient access rights to configure the Google Analytics account.</h5>
|
||||
<button class="btn btn-sm btn-primary js_link_analytics_settings center-block mb8">Link my Analytics Account</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -42,14 +93,14 @@
|
||||
|
||||
<div t-name="website.ga_dialog_content">
|
||||
Your Google Analytic Client ID: <input type="text" name="ga_client_id" t-att-value="ga_key" style="width: 100%"></input>
|
||||
<br/>Go to our <a href="https://www.odoo.com/documentation/user/online/website/google_analytics.html" target="_blank">User Documentation</a> to get more information.
|
||||
<br/>Go to our <a href="https://www.odoo.com/documentation/user/online/website/optimize/google_analytics.html" target="_blank">User Documentation</a> to get more information.
|
||||
</div>
|
||||
|
||||
<t t-name="website.DateRangeButtons">
|
||||
<div class="btn-group btn-group-sm o_date_range_buttons">
|
||||
<button class="btn btn-sm btn-default js_date_range active" data-date="week">Week</button>
|
||||
<button class="btn btn-sm btn-default js_date_range" data-date="month">Month</button>
|
||||
<button class="btn btn-sm btn-default js_date_range" data-date="year">Year</button>
|
||||
<div class="btn-group btn-group-sm o_date_range_buttons pull-right">
|
||||
<button class="btn btn-sm btn-default js_date_range active" data-date="week">Last Week</button>
|
||||
<button class="btn btn-sm btn-default js_date_range" data-date="month">Last Month</button>
|
||||
<button class="btn btn-sm btn-default js_date_range" data-date="year">Last Year</button>
|
||||
</div>
|
||||
</t>
|
||||
</templates>
|
||||
|
||||
@@ -98,7 +98,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div attrs="{'invisible': [('has_google_analytics_dashboard', '=', False)]}">
|
||||
<a href="https://www.odoo.com/documentation/user/online/website/google_analytics.html"
|
||||
<a href="https://www.odoo.com/documentation/user/online/website/optimize/google_analytics.html"
|
||||
class="oe_link fa fa-arrow-right" target="_blank">
|
||||
Tutorial
|
||||
</a>
|
||||
@@ -371,18 +371,12 @@ You can also edit the fields of the Extra Step page in eCommerce checkout.">
|
||||
<field name="target">inline</field>
|
||||
</record>
|
||||
|
||||
<record id="backend_dashboard" model="ir.actions.client">
|
||||
<field name="name">Website Dashboard</field>
|
||||
<field name="tag">backend_dashboard</field>
|
||||
</record>
|
||||
|
||||
<menuitem id="menu_website_configuration" sequence="215" name="Website Admin"
|
||||
groups="website.group_website_designer" web_icon="website,static/description/icon_admin.png"/>
|
||||
|
||||
<menuitem id="menu_dashboard" name="Dashboard" action="website.backend_dashboard" parent="website.menu_website_configuration" sequence="1"/>
|
||||
|
||||
<menuitem id="menu_website_global_configuration" parent="menu_website_configuration"
|
||||
sequence="100" name="Configuration" groups="base.group_system"/>
|
||||
<menuitem id="menu_website_website_settings" parent="menu_website_global_configuration" name="Settings" action="action_website_configuration"/>
|
||||
<menuitem name="Settings"
|
||||
id="menu_website_website_settings"
|
||||
action="action_website_configuration"
|
||||
parent="menu_website_global_configuration"
|
||||
groups="base.group_system"/>
|
||||
|
||||
</odoo>
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
<!-- Menu items -->
|
||||
<menuitem name="Website"
|
||||
id="menu_website_configuration"
|
||||
sequence="9"
|
||||
groups="base.group_user"
|
||||
web_icon="website,static/description/icon.png"/>
|
||||
|
||||
<!-- website views -->
|
||||
<record id="view_website_form" model="ir.ui.view">
|
||||
@@ -112,5 +118,24 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Dashboard -->
|
||||
<record id="backend_dashboard" model="ir.actions.client">
|
||||
<field name="name">Dashboard</field>
|
||||
<field name="tag">backend_dashboard</field>
|
||||
</record>
|
||||
|
||||
<record id="ir_actions_server_website_dashboard" model="ir.actions.server">
|
||||
<field name="name">Website: Dashboard</field>
|
||||
<field name="model_id" ref="website.model_website"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">action = model.action_dashboard_redirect()</field>
|
||||
</record>
|
||||
|
||||
<menuitem id="menu_dashboard"
|
||||
name="Dashboard"
|
||||
sequence="1"
|
||||
action="website.ir_actions_server_website_dashboard"
|
||||
parent="website.menu_website_configuration"/>
|
||||
|
||||
</data>
|
||||
</odoo>
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
<?xml version="1.0"?>
|
||||
<odoo>
|
||||
<menuitem name="Blog" id="menu_website_blog_root" sequence="20" parent="website.menu_website_configuration"/>
|
||||
<menuitem name="Blog"
|
||||
id="menu_website_blog_root"
|
||||
sequence="20"
|
||||
parent="website.menu_website_configuration"
|
||||
groups="website.group_website_designer"/>
|
||||
|
||||
<!-- Blog views -->
|
||||
<record id="view_blog_blog_list" model="ir.ui.view">
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import controllers
|
||||
import models
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
'name': 'Contact Form',
|
||||
'category': 'Website',
|
||||
'sequence': 54,
|
||||
'website': 'https://www.odoo.com/page/website-builder',
|
||||
'summary': 'Create Leads From Contact Form',
|
||||
'version': '2.0',
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import main
|
||||
@@ -1,91 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
import babel
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from odoo import http
|
||||
from odoo.http import request
|
||||
|
||||
from odoo.addons.website.controllers.backend import WebsiteBackend
|
||||
from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT, DEFAULT_SERVER_DATE_FORMAT
|
||||
|
||||
|
||||
class WebsiteCrmBackend(WebsiteBackend):
|
||||
|
||||
@http.route()
|
||||
def fetch_dashboard_data(self, date_from, date_to):
|
||||
|
||||
results = super(WebsiteCrmBackend, self).fetch_dashboard_data(date_from, date_to)
|
||||
results['groups']['sale_salesman'] = request.env['res.users'].has_group('sales_team.group_sale_salesman')
|
||||
if not results['groups']['sale_salesman']:
|
||||
return results
|
||||
|
||||
date_from = datetime.strptime(date_from, DEFAULT_SERVER_DATE_FORMAT)
|
||||
date_to = datetime.strptime(date_to, DEFAULT_SERVER_DATE_FORMAT)
|
||||
|
||||
lead_domain = []
|
||||
|
||||
website_utm = request.env['ir.model.data'].xmlid_to_res_id('utm.utm_medium_website')
|
||||
if website_utm:
|
||||
lead_domain += [('medium_id', '=', website_utm)]
|
||||
|
||||
lead_ids = request.env['crm.lead'].search(
|
||||
lead_domain + [
|
||||
('create_date', '>=', date_from.strftime(DEFAULT_SERVER_DATE_FORMAT)),
|
||||
('create_date', '<=', date_to.strftime(DEFAULT_SERVER_DATE_FORMAT))],
|
||||
)
|
||||
|
||||
leads = [{
|
||||
'create_date': datetime.strptime(lead.create_date, DEFAULT_SERVER_DATETIME_FORMAT).strftime(DEFAULT_SERVER_DATE_FORMAT),
|
||||
'campaign_id': lead.campaign_id.name,
|
||||
'medium_id': lead.medium_id.name,
|
||||
'source_id': lead.source_id.name,
|
||||
} for lead in lead_ids]
|
||||
|
||||
leads_graph = self._compute_lead_graph(date_from, date_to, lead_domain)
|
||||
previous_leads_graph = self._compute_lead_graph(date_from - timedelta(days=(date_to - date_from).days), date_from, lead_domain, previous=True)
|
||||
|
||||
results['dashboards']['leads'] = {
|
||||
'graph': [
|
||||
{
|
||||
'values': leads_graph,
|
||||
'key': 'Leads',
|
||||
},
|
||||
{
|
||||
'values': previous_leads_graph,
|
||||
'key': 'Previous Leads',
|
||||
},
|
||||
],
|
||||
'leads': leads,
|
||||
'lead_fields': {
|
||||
'create_date': 'Create Date',
|
||||
'campaign_id': 'Campaign',
|
||||
'medium_id': 'Medium',
|
||||
'source_id': 'Source',
|
||||
},
|
||||
}
|
||||
|
||||
return results
|
||||
|
||||
def _compute_lead_graph(self, date_from, date_to, lead_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_leads = request.env['crm.lead'].read_group(
|
||||
domain=lead_domain + [
|
||||
('create_date', '>=', date_from.strftime(DEFAULT_SERVER_DATE_FORMAT)),
|
||||
('create_date', '<=', date_to.strftime(DEFAULT_SERVER_DATE_FORMAT))],
|
||||
fields=['create_date'],
|
||||
groupby='create_date:day')
|
||||
|
||||
daily_leads_dict = {l['create_date:day']: l['create_date_count'] for l in daily_leads}
|
||||
|
||||
leads_graph = [{
|
||||
'0': d.strftime(DEFAULT_SERVER_DATE_FORMAT) if not previous else (d + timedelta(days=days_between)).strftime(DEFAULT_SERVER_DATE_FORMAT),
|
||||
# Respect read_group format in models.py
|
||||
'1': daily_leads_dict.get(babel.dates.format_date(d, format='dd MMM yyyy', locale=request.env.context.get('lang', 'en_US')), 0)
|
||||
} for d in date_list]
|
||||
|
||||
return leads_graph
|
||||
@@ -1,64 +0,0 @@
|
||||
odoo.define('website_crm.backend', function (require) {
|
||||
"use strict";
|
||||
|
||||
var core = require('web.core');
|
||||
var WebsiteBackend = require('website.backendDashboard');
|
||||
|
||||
var QWeb = core.qweb;
|
||||
|
||||
WebsiteBackend.include({
|
||||
|
||||
events: _.defaults({
|
||||
'change .js_field_selection': 'on_field_selection',
|
||||
}, WebsiteBackend.prototype.events),
|
||||
|
||||
init: function(parent, context) {
|
||||
this._super(parent, context);
|
||||
|
||||
this.dashboards_templates.push('website_crm.dashboard_leads');
|
||||
this.graphs.push({'name': 'leads', 'group': 'sale_salesman'});
|
||||
|
||||
this.leads_table = [];
|
||||
this.lead_fields = [];
|
||||
this.lead_field = '';
|
||||
},
|
||||
|
||||
compute_percentages: function() {
|
||||
if (!this.dashboards_data.leads.leads || !this.dashboards_data.leads.leads.length) {
|
||||
return;
|
||||
}
|
||||
var leads = this.dashboards_data.leads.leads;
|
||||
var lead_field_keys = _.pluck(leads, this.lead_field);
|
||||
var leads_counter = _.groupBy(lead_field_keys);
|
||||
this.leads_table = $.map(leads_counter, function(e, key) {
|
||||
return {
|
||||
'value': e.length,
|
||||
'key': key,
|
||||
'perc': Math.round(e.length*100/leads.length)
|
||||
};
|
||||
});
|
||||
this.leads_table.sort(function(a, b) { return b.value - a.value; });
|
||||
},
|
||||
|
||||
fetch_data: function() {
|
||||
var self = this;
|
||||
return this._super().then(function() {
|
||||
if (self.dashboards_data.leads) {
|
||||
var leads = self.dashboards_data.leads.leads;
|
||||
if (leads && leads.length) {
|
||||
self.lead_fields = self.dashboards_data.leads.lead_fields;
|
||||
self.lead_field = Object.keys(self.lead_fields)[0];
|
||||
self.compute_percentages();
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
on_field_selection: function(ev) {
|
||||
this.lead_field = ev.currentTarget.value;
|
||||
this.compute_percentages();
|
||||
this.$('.js_leads_table').replaceWith(QWeb.render("website_crm.LeadsTable", {'widget': this}));
|
||||
},
|
||||
});
|
||||
|
||||
});
|
||||
@@ -1,44 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<templates>
|
||||
<t t-name="website_crm.dashboard_leads">
|
||||
<div t-if="widget.dashboards_data.leads" class="row o_dashboard_leads">
|
||||
<div class="col-xs-12 o_box">
|
||||
<div class="col-md-6 col-xs-12">
|
||||
<h2>Leads Acquisition / <t t-esc="widget.date_range"></t></h2>
|
||||
<div id="o_graph_leads" class="o_graph" data-type="leads"/>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 col-xs-12">
|
||||
<h4>Leads Analysis</h4>
|
||||
<div t-if="!widget.leads_table || !widget.leads_table.length">
|
||||
<i>There is no recent lead.</i>
|
||||
</div>
|
||||
|
||||
<div t-if="widget.leads_table && widget.leads_table.length" class="table-responsive">
|
||||
<select class="js_field_selection">
|
||||
<option t-foreach="widget.lead_fields" t-as="field" t-att-value="field"><t t-esc="widget.lead_fields[field]"/></option>
|
||||
</select>
|
||||
|
||||
<t t-call="website_crm.LeadsTable"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="website_crm.LeadsTable">
|
||||
<table class="table table-hover js_leads_table">
|
||||
<tr>
|
||||
<th></th>
|
||||
<th>Leads</th>
|
||||
<th>% Leads</th>
|
||||
</tr>
|
||||
<tr t-foreach="widget.leads_table" t-as="row">
|
||||
<td><t t-esc="row.key"/></td>
|
||||
<td><t t-esc="row.value"/></td>
|
||||
<td><t t-esc="row.perc"/>%</td>
|
||||
</tr>
|
||||
</table>
|
||||
</t>
|
||||
</templates>
|
||||
@@ -89,10 +89,4 @@
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<template id="assets_backend" inherit_id="web.assets_backend">
|
||||
<xpath expr="." position="inside">
|
||||
<script type="text/javascript" src="/website_crm/static/src/js/website_crm_backend.js"></script>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
</odoo>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
{
|
||||
'name': 'Online Events',
|
||||
'category': 'Marketing',
|
||||
'sequence': 135,
|
||||
'sequence': 166,
|
||||
'summary': 'Publish Events and Manage Online Registrations on your Website',
|
||||
'website': 'https://www.odoo.com/page/website-builder',
|
||||
'description': """
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
{
|
||||
'name': 'Online Jobs',
|
||||
'category': 'Website',
|
||||
'sequence': 142,
|
||||
'version': '1.0',
|
||||
'summary': 'Job Descriptions And Application Forms',
|
||||
'description': """
|
||||
|
||||
@@ -16,13 +16,13 @@ Odoo E-Commerce
|
||||
'security/website_sale.xml',
|
||||
'data/data.xml',
|
||||
'data/web_planner_data.xml',
|
||||
'views/views.xml',
|
||||
'views/backend.xml',
|
||||
'views/product_views.xml',
|
||||
'views/account_views.xml',
|
||||
'views/sale_report_views.xml',
|
||||
'views/sale_order_views.xml',
|
||||
'views/crm_team_views.xml',
|
||||
'views/templates.xml',
|
||||
'views/payment.xml',
|
||||
'views/product_attribute_views.xml',
|
||||
'views/sale_order.xml',
|
||||
'views/payment_views.xml',
|
||||
'views/snippets.xml',
|
||||
'views/report_shop_saleorder.xml',
|
||||
'views/res_config_view.xml',
|
||||
|
||||
@@ -1,72 +1,121 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from odoo import http
|
||||
from odoo.http import request
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from datetime import datetime, date, timedelta
|
||||
from math import floor
|
||||
import time
|
||||
import operator
|
||||
|
||||
import babel
|
||||
|
||||
from datetime import datetime, timedelta, time
|
||||
|
||||
from odoo import fields, http, _
|
||||
from odoo.addons.website.controllers.backend import WebsiteBackend
|
||||
from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT, DEFAULT_SERVER_DATE_FORMAT
|
||||
from odoo.http import request
|
||||
|
||||
|
||||
class WebsiteSaleBackend(WebsiteBackend):
|
||||
|
||||
@http.route()
|
||||
def fetch_dashboard_data(self, date_from, date_to):
|
||||
|
||||
results = super(WebsiteSaleBackend, self).fetch_dashboard_data(date_from, date_to)
|
||||
|
||||
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_abandonned_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
|
||||
|
||||
date_from = datetime.strptime(date_from, DEFAULT_SERVER_DATE_FORMAT)
|
||||
date_to = datetime.strptime(date_to, DEFAULT_SERVER_DATE_FORMAT)
|
||||
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)
|
||||
|
||||
# Best seller products
|
||||
product_lines = request.env['sale.order.line'].read_group(
|
||||
# Product-based computation
|
||||
report_product_lines = request.env['sale.report'].read_group(
|
||||
domain=[
|
||||
('product_id.website_published', '=', True),
|
||||
('order_id.state', 'in', ['sent', 'sale', 'done']),
|
||||
('order_id.team_id.website_ids', '!=', False),
|
||||
('order_id.date_order', '>=', date_from.strftime(DEFAULT_SERVER_DATE_FORMAT)),
|
||||
('order_id.date_order', '<=', date_to.strftime(DEFAULT_SERVER_DATE_FORMAT))],
|
||||
fields=['product_id', 'product_uom_qty', 'price_total'],
|
||||
('team_id.team_type', '=', 'website'),
|
||||
('state', 'in', ['sale', 'done']),
|
||||
('date', '>=', date_from),
|
||||
('date', '<=', date_to)],
|
||||
fields=['product_id', 'product_uom_qty', 'price_subtotal'],
|
||||
groupby='product_id', orderby='product_uom_qty desc', limit=5)
|
||||
|
||||
best_sellers = []
|
||||
for product_line in product_lines:
|
||||
for product_line in report_product_lines:
|
||||
product_id = request.env['product.product'].browse(product_line['product_id'][0])
|
||||
best_sellers.append({
|
||||
sales_values['best_sellers'].append({
|
||||
'id': product_id.id,
|
||||
'name': product_id.name,
|
||||
'qty': product_line['product_uom_qty'],
|
||||
'sales': product_line['price_total'],
|
||||
'sales': product_line['price_subtotal'],
|
||||
})
|
||||
|
||||
# Graphes computation
|
||||
sales_domain = [
|
||||
('team_id.website_ids', '!=', False),
|
||||
('state', 'in', ['sent', 'sale', 'done']),
|
||||
]
|
||||
sales_graph = self._compute_sale_graph(date_from, date_to, sales_domain)
|
||||
previous_sales_graph = self._compute_sale_graph(date_from - timedelta(days=(date_to - date_from).days), date_from, sales_domain, previous=True)
|
||||
# Sale-based results computation
|
||||
sale_order_domain = [
|
||||
('team_id', 'in', request.env['crm.team'].search([('team_type', '=', 'website')]).ids),
|
||||
('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, fields=['state'], groupby='state')
|
||||
for res in so_group_data:
|
||||
if res.get('state') == 'sent':
|
||||
sales_values['summary']['order_unpaid_count'] += res['state_count']
|
||||
elif res.get('state') in ['sale', 'done']:
|
||||
sales_values['summary']['order_count'] += res['state_count']
|
||||
sales_values['summary']['order_carts_count'] += res['state_count']
|
||||
|
||||
results['dashboards']['sales'] = {
|
||||
'graph': [
|
||||
{
|
||||
'values': sales_graph,
|
||||
'key': 'Sales',
|
||||
},
|
||||
{
|
||||
'values': previous_sales_graph,
|
||||
'key': 'Previous Sales',
|
||||
},
|
||||
],
|
||||
'best_sellers': best_sellers,
|
||||
}
|
||||
sales_values['summary'].update(
|
||||
order_to_invoice_count=request.env['sale.order'].search_count(sale_order_domain + [
|
||||
('state', 'in', ['sale', 'done']),
|
||||
('invoice_status', '=', 'to invoice'),
|
||||
]),
|
||||
order_carts_abandonned_count=request.env['sale.order'].search_count(sale_order_domain + [
|
||||
('state', '=', 'draft'),
|
||||
('date_order', '<=', fields.Datetime.to_string(datetime.now() - timedelta(hours=1))),
|
||||
]),
|
||||
payment_to_capture_count=request.env['payment.transaction'].search_count([
|
||||
('state', '=', 'authorized'),
|
||||
('sale_order_id.state', '!=', 'cancel')
|
||||
]),
|
||||
total_sold=sum(request.env['sale.report'].search([
|
||||
('state', 'in', ['sale', 'done']),
|
||||
('team_id.team_type', '=', 'website'),
|
||||
('date', '>=', date_from),
|
||||
('date', '<=', date_to)]).mapped('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_domain = [
|
||||
('team_id.team_type', '=', 'website'),
|
||||
('state', 'in', ['sale', 'done']),
|
||||
('date', '>=', date_from),
|
||||
('date', '<=', date_to)
|
||||
]
|
||||
sales_values['graph'] += [{
|
||||
'values': self._compute_sale_graph(date_date_from, date_date_to, sales_domain),
|
||||
'key': 'Untaxed Total',
|
||||
}, {
|
||||
'values': self._compute_sale_graph(date_date_from - timedelta(days=date_diff_days), date_date_from, sales_domain, previous=True),
|
||||
'key': previous_sale_label,
|
||||
}]
|
||||
|
||||
return results
|
||||
|
||||
@@ -75,17 +124,15 @@ class WebsiteSaleBackend(WebsiteBackend):
|
||||
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.order'].read_group(
|
||||
domain=sales_domain + [
|
||||
('date_order', '>=', date_from.strftime(DEFAULT_SERVER_DATE_FORMAT)),
|
||||
('date_order', '<=', date_to.strftime(DEFAULT_SERVER_DATE_FORMAT))],
|
||||
fields=['date_order', 'amount_total'],
|
||||
groupby='date_order:day')
|
||||
daily_sales = request.env['sale.report'].read_group(
|
||||
domain=sales_domain,
|
||||
fields=['date', 'price_subtotal'],
|
||||
groupby='date:day')
|
||||
|
||||
daily_sales_dict = {p['date_order:day']: p['amount_total'] for p in daily_sales}
|
||||
daily_sales_dict = {p['date:day']: p['price_subtotal'] for p in daily_sales}
|
||||
|
||||
sales_graph = [{
|
||||
'0': d.strftime(DEFAULT_SERVER_DATE_FORMAT) if not previous else (d + timedelta(days=days_between)).strftime(DEFAULT_SERVER_DATE_FORMAT),
|
||||
'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(babel.dates.format_date(d, format='dd MMM yyyy', locale=request.env.context.get('lang', 'en_US')), 0)
|
||||
} for d in date_list]
|
||||
|
||||
+118
-111
@@ -794,20 +794,11 @@ Weight: 31 grams</field>
|
||||
|
||||
<record id="website_sale_order_line_1" model="sale.order.line">
|
||||
<field name="order_id" ref="website_sale_order_1"/>
|
||||
<field name="name">Laptop E5023</field>
|
||||
<field name="product_id" ref="product.product_product_25"/>
|
||||
<field name="name">iPad Mini</field>
|
||||
<field name="product_id" ref="product.product_product_6"/>
|
||||
<field name="product_uom_qty">1</field>
|
||||
<field name="product_uom" ref="product.product_uom_unit"/>
|
||||
<field name="price_unit">2950.00</field>
|
||||
</record>
|
||||
|
||||
<record id="website_sale_order_line_2" model="sale.order.line">
|
||||
<field name="order_id" ref="website_sale_order_1"/>
|
||||
<field name="name">Mouse, Wireless</field>
|
||||
<field name="product_id" ref="product.product_product_12"/>
|
||||
<field name="product_uom_qty">1</field>
|
||||
<field name="product_uom" ref="product.product_uom_unit"/>
|
||||
<field name="price_unit">12.50</field>
|
||||
<field name="price_unit">599.0</field>
|
||||
</record>
|
||||
|
||||
<record id="website_sale_order_2" model="sale.order">
|
||||
@@ -820,22 +811,13 @@ Weight: 31 grams</field>
|
||||
<field name="date_order" eval="(datetime.now()-relativedelta(days=6)).strftime('%Y-%m-%d %H:%M:%S')"/>
|
||||
</record>
|
||||
|
||||
<record id="website_sale_order_line_3" model="sale.order.line">
|
||||
<record id="website_sale_order_line_2" model="sale.order.line">
|
||||
<field name="order_id" ref="website_sale_order_2"/>
|
||||
<field name="name">Laptop E5023</field>
|
||||
<field name="product_id" ref="product.product_product_25"/>
|
||||
<field name="product_uom_qty">2</field>
|
||||
<field name="name">iPad Retina Display</field>
|
||||
<field name="product_id" ref="product.product_product_4"/>
|
||||
<field name="product_uom_qty">1</field>
|
||||
<field name="product_uom" ref="product.product_uom_unit"/>
|
||||
<field name="price_unit">3150.00</field>
|
||||
</record>
|
||||
|
||||
<record id="website_sale_order_line_4" model="sale.order.line">
|
||||
<field name="order_id" ref="website_sale_order_2"/>
|
||||
<field name="name">Mouse, Wireless</field>
|
||||
<field name="product_id" ref="product.product_product_12"/>
|
||||
<field name="product_uom_qty">2</field>
|
||||
<field name="product_uom" ref="product.product_uom_unit"/>
|
||||
<field name="price_unit">12.50</field>
|
||||
<field name="price_unit">900</field>
|
||||
</record>
|
||||
|
||||
<record id="website_sale_order_3" model="sale.order">
|
||||
@@ -848,22 +830,13 @@ Weight: 31 grams</field>
|
||||
<field name="date_order" eval="(datetime.now()-relativedelta(days=5)).strftime('%Y-%m-%d %H:%M:%S')"/>
|
||||
</record>
|
||||
|
||||
<record id="website_sale_order_line_5" model="sale.order.line">
|
||||
<record id="website_sale_order_line_3" model="sale.order.line">
|
||||
<field name="order_id" ref="website_sale_order_3"/>
|
||||
<field name="name">Laptop E5023</field>
|
||||
<field name="product_id" ref="product.product_product_25"/>
|
||||
<field name="name">iPad Retina Display</field>
|
||||
<field name="product_id" ref="product.product_product_4"/>
|
||||
<field name="product_uom_qty">1</field>
|
||||
<field name="product_uom" ref="product.product_uom_unit"/>
|
||||
<field name="price_unit">3300.00</field>
|
||||
</record>
|
||||
|
||||
<record id="website_sale_order_line_6" model="sale.order.line">
|
||||
<field name="order_id" ref="website_sale_order_3"/>
|
||||
<field name="name">Mouse, Wireless</field>
|
||||
<field name="product_id" ref="product.product_product_12"/>
|
||||
<field name="product_uom_qty">2</field>
|
||||
<field name="product_uom" ref="product.product_uom_unit"/>
|
||||
<field name="price_unit">12.50</field>
|
||||
<field name="price_unit">750</field>
|
||||
</record>
|
||||
|
||||
<record id="website_sale_order_4" model="sale.order">
|
||||
@@ -876,22 +849,13 @@ Weight: 31 grams</field>
|
||||
<field name="date_order" eval="(datetime.now()-relativedelta(days=4)).strftime('%Y-%m-%d %H:%M:%S')"/>
|
||||
</record>
|
||||
|
||||
<record id="website_sale_order_line_7" model="sale.order.line">
|
||||
<record id="website_sale_order_line_4" model="sale.order.line">
|
||||
<field name="order_id" ref="website_sale_order_4"/>
|
||||
<field name="name">Laptop E5023</field>
|
||||
<field name="product_id" ref="product.product_product_25"/>
|
||||
<field name="product_uom_qty">3</field>
|
||||
<field name="name">iMac</field>
|
||||
<field name="product_id" ref="product.product_product_8"/>
|
||||
<field name="product_uom_qty">1</field>
|
||||
<field name="product_uom" ref="product.product_uom_unit"/>
|
||||
<field name="price_unit">2750.00</field>
|
||||
</record>
|
||||
|
||||
<record id="website_sale_order_line_8" model="sale.order.line">
|
||||
<field name="order_id" ref="website_sale_order_4"/>
|
||||
<field name="name">Mouse, Wireless</field>
|
||||
<field name="product_id" ref="product.product_product_12"/>
|
||||
<field name="product_uom_qty">3</field>
|
||||
<field name="product_uom" ref="product.product_uom_unit"/>
|
||||
<field name="price_unit">12.50</field>
|
||||
<field name="price_unit">1199.0</field>
|
||||
</record>
|
||||
|
||||
<record id="website_sale_order_5" model="sale.order">
|
||||
@@ -904,22 +868,13 @@ Weight: 31 grams</field>
|
||||
<field name="date_order" eval="(datetime.now()-relativedelta(days=3)).strftime('%Y-%m-%d %H:%M:%S')"/>
|
||||
</record>
|
||||
|
||||
<record id="website_sale_order_line_9" model="sale.order.line">
|
||||
<record id="website_sale_order_line_5" model="sale.order.line">
|
||||
<field name="order_id" ref="website_sale_order_5"/>
|
||||
<field name="name">Laptop E5023</field>
|
||||
<field name="product_id" ref="product.product_product_25"/>
|
||||
<field name="product_uom_qty">2</field>
|
||||
<field name="name">iPad Retina Display</field>
|
||||
<field name="product_id" ref="product.product_product_4"/>
|
||||
<field name="product_uom_qty">3</field>
|
||||
<field name="product_uom" ref="product.product_uom_unit"/>
|
||||
<field name="price_unit">2950.00</field>
|
||||
</record>
|
||||
|
||||
<record id="website_sale_order_line_10" model="sale.order.line">
|
||||
<field name="order_id" ref="website_sale_order_5"/>
|
||||
<field name="name">Mouse, Wireless</field>
|
||||
<field name="product_id" ref="product.product_product_12"/>
|
||||
<field name="product_uom_qty">2</field>
|
||||
<field name="product_uom" ref="product.product_uom_unit"/>
|
||||
<field name="price_unit">12.50</field>
|
||||
<field name="price_unit">349.0</field>
|
||||
</record>
|
||||
|
||||
<record id="website_sale_order_6" model="sale.order">
|
||||
@@ -932,22 +887,13 @@ Weight: 31 grams</field>
|
||||
<field name="date_order" eval="(datetime.now()-relativedelta(days=2)).strftime('%Y-%m-%d %H:%M:%S')"/>
|
||||
</record>
|
||||
|
||||
<record id="website_sale_order_line_11" model="sale.order.line">
|
||||
<record id="website_sale_order_line_6" model="sale.order.line">
|
||||
<field name="order_id" ref="website_sale_order_6"/>
|
||||
<field name="name">Laptop E5023</field>
|
||||
<field name="product_id" ref="product.product_product_25"/>
|
||||
<field name="product_uom_qty">3</field>
|
||||
<field name="name">iMac</field>
|
||||
<field name="product_id" ref="product.product_product_8"/>
|
||||
<field name="product_uom_qty">1</field>
|
||||
<field name="product_uom" ref="product.product_uom_unit"/>
|
||||
<field name="price_unit">3250.00</field>
|
||||
</record>
|
||||
|
||||
<record id="website_sale_order_line_12" model="sale.order.line">
|
||||
<field name="order_id" ref="website_sale_order_6"/>
|
||||
<field name="name">Mouse, Wireless</field>
|
||||
<field name="product_id" ref="product.product_product_12"/>
|
||||
<field name="product_uom_qty">3</field>
|
||||
<field name="product_uom" ref="product.product_uom_unit"/>
|
||||
<field name="price_unit">12.50</field>
|
||||
<field name="price_unit">1599.00</field>
|
||||
</record>
|
||||
|
||||
<record id="website_sale_order_7" model="sale.order">
|
||||
@@ -960,22 +906,13 @@ Weight: 31 grams</field>
|
||||
<field name="date_order" eval="(datetime.now()-relativedelta(days=1)).strftime('%Y-%m-%d %H:%M:%S')"/>
|
||||
</record>
|
||||
|
||||
<record id="website_sale_order_line_12" model="sale.order.line">
|
||||
<record id="website_sale_order_line_7" model="sale.order.line">
|
||||
<field name="order_id" ref="website_sale_order_7"/>
|
||||
<field name="name">Laptop E5023</field>
|
||||
<field name="product_id" ref="product.product_product_25"/>
|
||||
<field name="product_uom_qty">2</field>
|
||||
<field name="name">iMac</field>
|
||||
<field name="product_id" ref="product.product_product_8"/>
|
||||
<field name="product_uom_qty">1</field>
|
||||
<field name="product_uom" ref="product.product_uom_unit"/>
|
||||
<field name="price_unit">2850.00</field>
|
||||
</record>
|
||||
|
||||
<record id="website_sale_order_line_13" model="sale.order.line">
|
||||
<field name="order_id" ref="website_sale_order_7"/>
|
||||
<field name="name">Mouse, Wireless</field>
|
||||
<field name="product_id" ref="product.product_product_12"/>
|
||||
<field name="product_uom_qty">2</field>
|
||||
<field name="product_uom" ref="product.product_uom_unit"/>
|
||||
<field name="price_unit">12.50</field>
|
||||
<field name="price_unit">1349.00</field>
|
||||
</record>
|
||||
|
||||
<record id="website_sale_order_8" model="sale.order">
|
||||
@@ -988,22 +925,13 @@ Weight: 31 grams</field>
|
||||
<field name="date_order" eval="datetime.now()"/>
|
||||
</record>
|
||||
|
||||
<record id="website_sale_order_line_14" model="sale.order.line">
|
||||
<record id="website_sale_order_line_8" model="sale.order.line">
|
||||
<field name="order_id" ref="website_sale_order_8"/>
|
||||
<field name="name">Laptop E5023</field>
|
||||
<field name="product_id" ref="product.product_product_25"/>
|
||||
<field name="product_uom_qty">4</field>
|
||||
<field name="name">iMac</field>
|
||||
<field name="product_id" ref="product.product_product_8"/>
|
||||
<field name="product_uom_qty">1</field>
|
||||
<field name="product_uom" ref="product.product_uom_unit"/>
|
||||
<field name="price_unit">3050.00</field>
|
||||
</record>
|
||||
|
||||
<record id="website_sale_order_line_15" model="sale.order.line">
|
||||
<field name="order_id" ref="website_sale_order_8"/>
|
||||
<field name="name">Mouse, Wireless</field>
|
||||
<field name="product_id" ref="product.product_product_12"/>
|
||||
<field name="product_uom_qty">4</field>
|
||||
<field name="product_uom" ref="product.product_uom_unit"/>
|
||||
<field name="price_unit">12.50</field>
|
||||
<field name="price_unit">1799.00</field>
|
||||
</record>
|
||||
|
||||
<record id="website_sale_order_9" model="sale.order">
|
||||
@@ -1016,7 +944,7 @@ Weight: 31 grams</field>
|
||||
<field name="date_order" eval="(datetime.now()-relativedelta(hours=2)).strftime('%Y-%m-%d %H:%M:%S')"/>
|
||||
</record>
|
||||
|
||||
<record id="website_sale_order_line_16" model="sale.order.line">
|
||||
<record id="website_sale_order_line_9" model="sale.order.line">
|
||||
<field name="order_id" ref="website_sale_order_9"/>
|
||||
<field name="name">Laptop E5023</field>
|
||||
<field name="product_id" ref="product.product_product_25"/>
|
||||
@@ -1025,7 +953,7 @@ Weight: 31 grams</field>
|
||||
<field name="price_unit">2950.00</field>
|
||||
</record>
|
||||
|
||||
<record id="website_sale_order_line_17" model="sale.order.line">
|
||||
<record id="website_sale_order_line_10" model="sale.order.line">
|
||||
<field name="order_id" ref="website_sale_order_9"/>
|
||||
<field name="name">Mouse, Wireless</field>
|
||||
<field name="product_id" ref="product.product_product_12"/>
|
||||
@@ -1044,4 +972,83 @@ Weight: 31 grams</field>
|
||||
<function model="sale.order" name="action_confirm" eval="[[ref('website_sale_order_6')]]"/>
|
||||
<function model="sale.order" name="action_confirm" eval="[[ref('website_sale_order_7')]]"/>
|
||||
<function model="sale.order" name="action_confirm" eval="[[ref('website_sale_order_8')]]"/>
|
||||
|
||||
<!-- Active Carts -->
|
||||
<record id="website_sale_order_10" model="sale.order">
|
||||
<field name="partner_id" ref="base.res_partner_3"/>
|
||||
<field name="partner_invoice_id" ref="base.res_partner_address_25"/>
|
||||
<field name="partner_shipping_id" ref="base.res_partner_address_25"/>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field name="pricelist_id" ref="product.list0"/>
|
||||
<field name="team_id" ref="sales_team.salesteam_website_sales"/>
|
||||
<field name="date_order" eval="datetime.now()"/>
|
||||
</record>
|
||||
|
||||
<record id="website_sale_order_line_11" model="sale.order.line">
|
||||
<field name="order_id" ref="website_sale_order_10"/>
|
||||
<field name="name">iPod</field>
|
||||
<field name="product_id" ref="product.product_product_11"/>
|
||||
<field name="product_uom_qty">2</field>
|
||||
<field name="product_uom" ref="product.product_uom_unit"/>
|
||||
<field name="price_unit">16.50</field>
|
||||
</record>
|
||||
|
||||
<!-- Abandoned Carts -->
|
||||
<record id="website_sale_order_11" model="sale.order">
|
||||
<field name="partner_id" ref="base.res_partner_3"/>
|
||||
<field name="partner_invoice_id" ref="base.res_partner_address_25"/>
|
||||
<field name="partner_shipping_id" ref="base.res_partner_address_25"/>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field name="pricelist_id" ref="product.list0"/>
|
||||
<field name="team_id" ref="sales_team.salesteam_website_sales"/>
|
||||
<field name="date_order" eval="(datetime.now()-timedelta(hours=1)).strftime('%Y-%m-%d %H:%M:%S')"/>
|
||||
</record>
|
||||
|
||||
<record id="website_sale_order_line_12" model="sale.order.line">
|
||||
<field name="order_id" ref="website_sale_order_11"/>
|
||||
<field name="name">Apple Wireless Keyboard</field>
|
||||
<field name="product_id" ref="product.product_product_9"/>
|
||||
<field name="product_uom_qty">1</field>
|
||||
<field name="product_uom" ref="product.product_uom_unit"/>
|
||||
<field name="price_unit">47.0</field>
|
||||
</record>
|
||||
|
||||
<!-- Payments to Capture -->
|
||||
<record id="website_sale_order_13" model="sale.order">
|
||||
<field name="partner_id" ref="base.res_partner_3"/>
|
||||
<field name="partner_invoice_id" ref="base.res_partner_address_25"/>
|
||||
<field name="partner_shipping_id" ref="base.res_partner_address_25"/>
|
||||
<field name="user_id" ref="base.user_demo"/>
|
||||
<field name="pricelist_id" ref="product.list0"/>
|
||||
<field name="team_id" ref="sales_team.salesteam_website_sales"/>
|
||||
<field name="payment_term_id" ref="account.account_payment_term_immediate"/>
|
||||
<field name="date_order" eval="(datetime.now()-timedelta(hours=1)).strftime('%Y-%m-%d %H:%M:%S')"/>
|
||||
<field name="state">sent</field>
|
||||
</record>
|
||||
|
||||
<record id="website_sale_order_line_14" model="sale.order.line">
|
||||
<field name="order_id" ref="website_sale_order_13"/>
|
||||
<field name="name">iMac</field>
|
||||
<field name="product_id" ref="product.product_product_8"/>
|
||||
<field name="product_uom_qty">1</field>
|
||||
<field name="product_uom" ref="product.product_uom_unit"/>
|
||||
<field name="price_unit">1799.0</field>
|
||||
</record>
|
||||
|
||||
<record id="website_payment_transaction_2" model="payment.transaction">
|
||||
<field name="create_date" eval="datetime.now()"/>
|
||||
<field name="acquirer_id" ref="payment.payment_acquirer_transfer"/>
|
||||
<field name="sale_order_id" ref="website_sale_order_13"/>
|
||||
<field name="reference" ref="website_sale_order_13"/>
|
||||
<field name="type">form</field>
|
||||
<field name="state">authorized</field>
|
||||
<field name="amount">1799.0</field>
|
||||
<field name="currency_id" ref="base.USD"/>
|
||||
<field name="partner_id" ref="base.res_partner_3"/>
|
||||
</record>
|
||||
|
||||
<record id="website_sale_order_13" model="sale.order">
|
||||
<field name="payment_acquirer_id" ref="payment.payment_acquirer_transfer"/>
|
||||
<field name="payment_tx_id" ref="website_payment_transaction_2"/>
|
||||
</record>
|
||||
</odoo>
|
||||
|
||||
@@ -4,3 +4,4 @@ import product
|
||||
import sale_order
|
||||
import crm_team
|
||||
import res_config
|
||||
import website
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from odoo import api, models
|
||||
|
||||
|
||||
class Website(models.Model):
|
||||
_inherit = 'website'
|
||||
|
||||
@api.model
|
||||
def action_dashboard_redirect(self):
|
||||
if self.env.user.has_group('sales_team.group_sale_salesman'):
|
||||
return self.env.ref('website.backend_dashboard').read()[0]
|
||||
return super(Website, self).action_dashboard_redirect()
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 55 KiB |
@@ -12,7 +12,7 @@ WebsiteBackend.include({
|
||||
init: function(parent, context) {
|
||||
this._super(parent, context);
|
||||
|
||||
this.dashboards_templates.push('website_sale.dashboard_sales');
|
||||
this.dashboards_templates.unshift('website_sale.dashboard_sales');
|
||||
this.graphs.push({'name': 'sales', 'group': 'sale_salesman'});
|
||||
},
|
||||
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
.o_dashboard_sales {
|
||||
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");
|
||||
position: relative;
|
||||
opacity: 0.2;
|
||||
}
|
||||
.o_demo_message {
|
||||
color: @odoo-main-color-muted;
|
||||
width: 100%;
|
||||
.o-position-absolute(@left: 0, @top: 12%);
|
||||
.o-flex-display();
|
||||
.o-justify-content(center);
|
||||
}
|
||||
.o_link_enable {
|
||||
@media (min-width: @screen-md-min) {
|
||||
border-right: 1px solid #ccc;
|
||||
}
|
||||
height: initial;
|
||||
padding: 5px;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
a {
|
||||
color: darken(@odoo-brand-lightsecondary, 40%);
|
||||
}
|
||||
&:hover {
|
||||
background-color: @odoo-brand-lightsecondary;
|
||||
}
|
||||
.o_highlight {
|
||||
color: @odoo-brand-optional;
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
.o_link_disable {
|
||||
@media (min-width: @screen-md-min) {
|
||||
border-right: 1px solid #ccc;
|
||||
}
|
||||
height: initial;
|
||||
padding: 5px;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
margin: 10px 0px;
|
||||
color: darken(@odoo-brand-lightsecondary, 40%);
|
||||
.o_highlight {
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
.o_invisible_border {
|
||||
border-right: 0px;
|
||||
}
|
||||
.o_top_margin {
|
||||
margin-top: 20px;
|
||||
}
|
||||
}
|
||||
@@ -1,41 +1,128 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<templates>
|
||||
<t t-extend="website.dashboard_header">
|
||||
<t t-jquery="t[t-foreach='apps']" t-operation="before">
|
||||
<div t-if="widget.dashboards_data.sales.summary.order_unpaid_count" class="o_inner_box o_main o_box_item" title="Confirm orders when you get paid.">
|
||||
<a href="#" class="o_dashboard_action" 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
|
||||
</a>
|
||||
<t t-set="vignette_nbr" t-value="vignette_nbr + 1"/>
|
||||
</div>
|
||||
<div t-if="widget.dashboards_data.sales.summary.order_to_invoice_count" class="o_inner_box o_main o_box_item" title="Generate an invoice from orders ready for invoicing.">
|
||||
<a href="#" class="o_dashboard_action" 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
|
||||
</a>
|
||||
<t t-set="vignette_nbr" t-value="vignette_nbr + 1"/>
|
||||
</div>
|
||||
<div t-if="widget.dashboards_data.sales.summary.payment_to_capture_count" class="o_inner_box o_main o_box_item" title="Capture order payments when the delivery is completed.">
|
||||
<a href="#" class="o_dashboard_action" 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
|
||||
</a>
|
||||
<t t-set="vignette_nbr" t-value="vignette_nbr + 1"/>
|
||||
</div>
|
||||
<div t-if="widget.dashboards_data.sales.summary.order_carts_abandonned_count" class="o_inner_box o_main o_box_item" title="Send a recovery email to visitors who haven't completed their order.">
|
||||
<a href="#" class="o_dashboard_action" name="website_sale.action_abandonned_orders_ecommerce">
|
||||
<div class="o_highlight"><t t-esc="widget.dashboards_data.sales.summary.order_carts_abandonned_count"/></div>
|
||||
Abandoned Carts
|
||||
</a>
|
||||
<t t-set="vignette_nbr" t-value="vignette_nbr + 1"/>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<t t-name="website_sale.dashboard_sales">
|
||||
<div t-if="widget.dashboards_data.sales" class="row o_dashboard_sales">
|
||||
<div t-if="widget.groups.sale_salesman" class="row o_dashboard_sales">
|
||||
<div class="col-xs-12 o_box">
|
||||
<div class="col-md-6 col-xs-12">
|
||||
<h2>Sales / <t t-esc="widget.date_range"></t></h2>
|
||||
<div id="o_graph_sales" class="o_graph" data-type="sales"/>
|
||||
<div t-if="widget.dashboards_data.sales.summary.order_count">
|
||||
<div class="col-md-7 col-xs-12">
|
||||
<t t-if="widget.date_range">
|
||||
<h2>Sales Since Last <t t-esc="widget.date_range"></t></h2>
|
||||
</t>
|
||||
<t t-else=""><h2>Sales</h2></t>
|
||||
<div id="o_graph_sales" class="o_graph" data-type="sales"/>
|
||||
</div>
|
||||
<div class="col-md-5 col-xs-12">
|
||||
<t t-call="website_sale.products_table"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6 col-xs-12">
|
||||
<t t-call="website_sale.products_table"/>
|
||||
<div t-if="! widget.dashboards_data.sales.summary.order_count">
|
||||
<div class="col-md-12 col-xs-12">
|
||||
<t t-if="widget.date_range">
|
||||
<h2>Sales Since Last <t t-esc="widget.date_range"></t></h2>
|
||||
</t>
|
||||
<t t-else=""><h2>Sales</h2></t>
|
||||
<div class="o_demo_background">
|
||||
</div>
|
||||
<div class="o_demo_message">
|
||||
<h3>There is no recent confirmed order.</h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="website_sale.products_table">
|
||||
<h4>Best Sellers</h4>
|
||||
<div t-if="!widget.dashboards_data.sales.best_sellers || !widget.dashboards_data.sales.best_sellers.length">
|
||||
<i>There is no recent online sale.</i>
|
||||
</div>
|
||||
|
||||
<div t-if="widget.dashboards_data.sales.best_sellers && widget.dashboards_data.sales.best_sellers.length" class="table-responsive">
|
||||
<table class="table table-hover">
|
||||
<tr>
|
||||
<th>Product</th>
|
||||
<th>Qty Sold</th>
|
||||
<th>Amount</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.format_number(product.sales, 'currency')"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
<div class="row">
|
||||
<div class="col-md-12 col-xs-12">
|
||||
<div class="row">
|
||||
<h4>AT A GLANCE</h4>
|
||||
<a href="#" class="o_dashboard_action" name="website_sale.sale_report_action_dashboard">
|
||||
<div class="col-sm-4 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="o_dashboard_action" name="website_sale.sale_report_action_dashboard">
|
||||
<div class="col-sm-4 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="o_dashboard_action" name="website_sale.sale_report_action_carts">
|
||||
<div class="col-sm-4 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-sm-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-sm-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-sm-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>
|
||||
<div class="col-md-12 col-xs-12 o_top_margin">
|
||||
<div class="row">
|
||||
<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>
|
||||
</templates>
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="action_invoices_ecommerce" model="ir.actions.act_window">
|
||||
<field name="name">Invoices</field>
|
||||
<field name="res_model">account.invoice</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="domain">[('team_id.website_ids', '!=', False)]</field>
|
||||
<field name="view_id" ref="account.invoice_tree"/>
|
||||
<field name="context">{'type':'out_invoice'}</field>
|
||||
<field name="search_view_id" ref="account.view_account_invoice_filter"/>
|
||||
</record>
|
||||
|
||||
<record id="website_product_pricelist3" model="ir.actions.act_window">
|
||||
<field name="name">Pricelists</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">product.pricelist</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="domain">[('website_id', '!=', False)]</field>
|
||||
<field name="search_view_id" ref="product.product_pricelist_view_search" />
|
||||
<field name="context">{"default_base":'list_price'}</field>
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -1,105 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<record id="product_template_search_view_website" model="ir.ui.view">
|
||||
<field name="name">product.template.search.published</field>
|
||||
<field name="model">product.template</field>
|
||||
<field name="inherit_id" ref="product.product_template_search_view"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//filter[@name='consumable']" position="after">
|
||||
<separator/>
|
||||
<filter string="Published" name="published" domain="[('website_published', '=', True)]"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="product_template_action" model="ir.actions.act_window">
|
||||
<field name="name">Products</field>
|
||||
<field name="res_model">product.template</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">kanban,tree,form</field>
|
||||
<field name="context">{'search_default_published': 1, 'default_website_published': True}</field>
|
||||
</record>
|
||||
|
||||
<record id="view_sales_order_filter_ecommerce" model="ir.ui.view">
|
||||
<field name="name">sale.order.ecommerce.search.view</field>
|
||||
<field name="model">sale.order</field>
|
||||
<field name="inherit_id" ref="sale.view_sales_order_filter"/>
|
||||
<field name="arch" type="xml">
|
||||
<search>
|
||||
<filter string="From Website" name="from_website" domain="[('team_id.website_ids', '!=', False)]"/>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_orders_ecommerce" model="ir.actions.act_window">
|
||||
<field name="name">eCommerce Orders</field>
|
||||
<field name="res_model">sale.order</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="domain">[('state', 'in', ('sale', 'done'))]</field>
|
||||
<field name="context">{'show_sale': True, 'search_default_from_website': 1}</field>
|
||||
<field name="search_view_id" ref="view_sales_order_filter_ecommerce"/>
|
||||
<field name="help">You don't have any confirmed order from the website.</field>
|
||||
</record>
|
||||
|
||||
<record id="action_unpaid_orders_ecommerce" model="ir.actions.act_window">
|
||||
<field name="name">Unpaid eCommerce Orders</field>
|
||||
<field name="res_model">sale.order</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="domain">[('state', '=', 'sent')]</field>
|
||||
<field name="context">{'show_sale': True, 'search_default_from_website': 1}</field>
|
||||
<field name="search_view_id" ref="view_sales_order_filter_ecommerce"/>
|
||||
<field name="help">You don't have any unpaid order from the website.</field>
|
||||
</record>
|
||||
|
||||
<record id="action_abandonned_orders_ecommerce" model="ir.actions.act_window">
|
||||
<field name="name">Abandoned eCommerce Orders</field>
|
||||
<field name="res_model">sale.order</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="domain">[('state', '=', 'cancel')]</field>
|
||||
<field name="context">{'show_sale': True, 'search_default_from_website': 1}</field>
|
||||
<field name="search_view_id" ref="view_sales_order_filter_ecommerce"/>
|
||||
<field name="help">You don't have any cancelled order from the website.</field>
|
||||
</record>
|
||||
|
||||
<record id="action_invoices_ecommerce" model="ir.actions.act_window">
|
||||
<field name="name">Invoices</field>
|
||||
<field name="res_model">account.invoice</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="domain">[('team_id.website_ids', '!=', False)]</field>
|
||||
<field name="view_id" ref="account.invoice_tree"/>
|
||||
<field name="context">{'type':'out_invoice'}</field>
|
||||
<field name="search_view_id" ref="account.view_account_invoice_filter"/>
|
||||
</record>
|
||||
|
||||
<record id="website_product_pricelist3" model="ir.actions.act_window">
|
||||
<field name="name">Pricelists</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">product.pricelist</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="domain">[('website_id', '!=', False)]</field>
|
||||
<field name="search_view_id" ref="product.product_pricelist_view_search" />
|
||||
<field name="context">{"default_base":'list_price'}</field>
|
||||
</record>
|
||||
|
||||
<menuitem id="menu_orders" name="Orders" parent="website.menu_website_configuration" sequence="2"/>
|
||||
<menuitem id="menu_catalog" name="Catalog" parent="website.menu_website_configuration" sequence="3"/>
|
||||
<menuitem id="menu_ecommerce_settings" parent="website.menu_website_global_configuration" name="eCommerce"/>
|
||||
|
||||
<!-- Orders sub-menus -->
|
||||
<menuitem id="menu_orders_orders" name="Orders" parent="menu_orders" action="action_orders_ecommerce" sequence="1"/>
|
||||
<menuitem id="menu_orders_unpaid_orders" name="Unpaid Orders" parent="menu_orders" action="action_unpaid_orders_ecommerce" sequence="2"/>
|
||||
<menuitem id="menu_orders_abandonned_orders" name="Abandoned Orders" parent="menu_orders" action="action_abandonned_orders_ecommerce" sequence="3"/>
|
||||
<menuitem id="menu_orders_invoices" name="Invoices" parent="menu_orders" action="action_invoices_ecommerce" sequence="4"/>
|
||||
|
||||
<!-- Catalog sub-menus -->
|
||||
<menuitem id="menu_catalog_products" name="Products" parent="menu_catalog" action="product_template_action" sequence="1"/>
|
||||
<menuitem id="menu_catalog_pricelists" name="Pricelists" parent="menu_catalog" action="product.product_pricelist_action2" groups="product.group_sale_pricelist" sequence="3"/>
|
||||
<menuitem id="menu_catalog_categories" parent="menu_ecommerce_settings" action="product_public_category_action" sequence="2"/>
|
||||
|
||||
<!-- Configuration sub-menus -->
|
||||
<menuitem id="menu_ecommerce_payment_acquirers" parent="menu_ecommerce_settings" name="Payment Acquirers" action="payment.action_payment_acquirer"/>
|
||||
|
||||
</odoo>
|
||||
@@ -1,15 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<record id="transaction_form_website_sale" model="ir.ui.view">
|
||||
<field name="name">payment.transaction.form.website_sale</field>
|
||||
<field name="model">payment.transaction</field>
|
||||
<field name="inherit_id" ref="payment.transaction_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='reference']" position="after">
|
||||
<field name="sale_order_id"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="payment_transaction_view_form_inherit_website_sale" model="ir.ui.view">
|
||||
<field name="name">payment.transaction.view.form.inherit.website_sale</field>
|
||||
<field name="model">payment.transaction</field>
|
||||
<field name="inherit_id" ref="payment.transaction_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='reference']" position="after">
|
||||
<field name="sale_order_id"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="payment_transaction_action_payments_to_capture" model="ir.actions.act_window">
|
||||
<field name="name">Payments To Capture</field>
|
||||
<field name="res_model">payment.transaction</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="domain">[('state', '=', 'authorized'), ('sale_order_id.state', '!=', 'cancel')]</field>
|
||||
<field name="context">{'create': False}</field>
|
||||
<field name="view_id" ref="payment.transaction"/>
|
||||
<field name="help">You don't have any payments to capture from the website.</field>
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -1,33 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<record id="product_attribute_line_form" model="ir.ui.view">
|
||||
<field name="name">product.attribute.line.form.inherit</field>
|
||||
<field name="model">product.attribute.line</field>
|
||||
<field name="inherit_id" ref="product.product_attribute_line_form"/>
|
||||
<field name="priority" eval="8"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='value_ids']/tree/field[@name='name']" position="after">
|
||||
<field name="html_color"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="product_attribute_view_form" model="ir.ui.view">
|
||||
<field name="name">product.attribute.form.inherit</field>
|
||||
<field name="model">product.attribute</field>
|
||||
<field name="inherit_id" ref="product.product_attribute_view_form"/>
|
||||
<field name="priority" eval="8"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//group[@name='main_fields']" position="after">
|
||||
<group>
|
||||
<field name="type"/>
|
||||
</group>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='value_ids']/tree/field[@name='name']" position="after">
|
||||
<field name="html_color"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
@@ -1,5 +1,54 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="product_template_search_view_website" model="ir.ui.view">
|
||||
<field name="name">product.template.search.published</field>
|
||||
<field name="model">product.template</field>
|
||||
<field name="inherit_id" ref="product.product_template_search_view"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//filter[@name='consumable']" position="after">
|
||||
<separator/>
|
||||
<filter string="Published" name="published" domain="[('website_published', '=', True)]"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="product_template_action_website" model="ir.actions.act_window">
|
||||
<field name="name">Products</field>
|
||||
<field name="res_model">product.template</field>
|
||||
<field name="view_type">form</field>
|
||||
<field name="view_mode">kanban,tree,form</field>
|
||||
<field name="context">{'search_default_published': 1, 'default_website_published': True}</field>
|
||||
</record>
|
||||
|
||||
<record id="product_attribute_line_form" model="ir.ui.view">
|
||||
<field name="name">product.attribute.line.form.inherit</field>
|
||||
<field name="model">product.attribute.line</field>
|
||||
<field name="inherit_id" ref="product.product_attribute_line_form"/>
|
||||
<field name="priority" eval="8"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='value_ids']/tree/field[@name='name']" position="after">
|
||||
<field name="html_color"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="product_attribute_view_form" model="ir.ui.view">
|
||||
<field name="name">product.attribute.form.inherit</field>
|
||||
<field name="model">product.attribute</field>
|
||||
<field name="inherit_id" ref="product.product_attribute_view_form"/>
|
||||
<field name="priority" eval="8"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//group[@name='main_fields']" position="after">
|
||||
<group>
|
||||
<field name="type"/>
|
||||
</group>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='value_ids']/tree/field[@name='name']" position="after">
|
||||
<field name="html_color"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="product_pricelist_view">
|
||||
<field name="name">product.pricelist.website.form</field>
|
||||
<field name="model">product.pricelist</field>
|
||||
@@ -1,15 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<record id="view_order_form_acquirer" model="ir.ui.view">
|
||||
<field name="name">sale.order.form.acquirer</field>
|
||||
<field name="model">sale.order</field>
|
||||
<field name="inherit_id" ref="sale.view_order_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='amount_total']" position="after">
|
||||
<field name="payment_acquirer_id" readonly="1" attrs="{'invisible': [('payment_acquirer_id', '=', False)]}" options='{"no_open":True}'/>
|
||||
<field name="payment_tx_id" readonly="1" attrs="{'invisible': [('payment_acquirer_id', '=', False)]}"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -0,0 +1,139 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="view_sales_order_filter_ecommerce" model="ir.ui.view">
|
||||
<field name="name">sale.order.ecommerce.search.view</field>
|
||||
<field name="model">sale.order</field>
|
||||
<field name="inherit_id" ref="sale.view_sales_order_filter"/>
|
||||
<field name="arch" type="xml">
|
||||
<search>
|
||||
<filter string="Confirmed Orders" name="order_confirmed" domain="[('state', 'in', ('sale', 'done'))]"/>
|
||||
<separator/>
|
||||
<filter string="From Website" name="from_website" domain="[('team_id.team_type', '=', 'website')]"/>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_order_form_acquirer" model="ir.ui.view">
|
||||
<field name="name">sale.order.form.acquirer</field>
|
||||
<field name="model">sale.order</field>
|
||||
<field name="inherit_id" ref="sale.view_order_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='amount_total']" position="after">
|
||||
<field name="payment_acquirer_id" readonly="1" attrs="{'invisible': [('payment_acquirer_id', '=', False)]}" options='{"no_open":True}'/>
|
||||
<field name="payment_tx_id" readonly="1" attrs="{'invisible': [('payment_acquirer_id', '=', False)]}"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_orders_ecommerce" model="ir.actions.act_window">
|
||||
<field name="name">Orders</field>
|
||||
<field name="res_model">sale.order</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="domain">[]</field>
|
||||
<field name="context">{'show_sale': True, 'search_default_confirm_order': 1, 'search_default_from_website': 1}</field>
|
||||
<field name="search_view_id" ref="view_sales_order_filter_ecommerce"/>
|
||||
<field name="help">You don't have any confirmed order from the website.</field>
|
||||
</record>
|
||||
|
||||
<record id="action_unpaid_orders_ecommerce" model="ir.actions.act_window">
|
||||
<field name="name">Unpaid Orders</field>
|
||||
<field name="res_model">sale.order</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="domain">[('state', '=', 'sent')]</field>
|
||||
<field name="context">{'show_sale': True, 'search_default_from_website': 1, 'create': False}</field>
|
||||
<field name="search_view_id" ref="view_sales_order_filter_ecommerce"/>
|
||||
<field name="help">You don't have any unpaid order from the website.</field>
|
||||
</record>
|
||||
|
||||
<record id="action_abandonned_orders_ecommerce" model="ir.actions.act_window">
|
||||
<field name="name">Abandoned Carts</field>
|
||||
<field name="res_model">sale.order</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="domain">[('state', '=', 'draft'), ('order_line', '!=', False), ('date_order', '<=', (context_today() + datetime.timedelta(hours=-1)).strftime('%Y-%m-%d'))]</field>
|
||||
<field name="context">{'show_sale': True, 'search_default_from_website': 1, 'create': False}</field>
|
||||
<field name="search_view_id" ref="view_sales_order_filter_ecommerce"/>
|
||||
<field name="help" type="xml">
|
||||
<p>Find here all the abandoned carts, i.e. the carts generated by your website's visitors more than one hour ago and not confirmed.</p>
|
||||
<p>You should send an email to revive them!</p></field>
|
||||
</record>
|
||||
|
||||
<record id="sale_order_action_to_invoice" model="ir.actions.act_window">
|
||||
<field name="name">Orders To Invoice</field>
|
||||
<field name="res_model">sale.order</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<field name="domain">[('state', 'in', ('sale', 'done')), ('invoice_status', '=', 'to invoice')]</field>
|
||||
<field name="context">{'show_sale': True, 'search_default_from_website': 1}</field>
|
||||
<field name="search_view_id" ref="view_sales_order_filter_ecommerce"/>
|
||||
<field name="help">You don't have any order from the website.</field>
|
||||
</record>
|
||||
|
||||
<!-- Main website sale menu items -->
|
||||
<menuitem id="menu_orders" name="Orders"
|
||||
parent="website.menu_website_configuration" sequence="2"
|
||||
groups="sales_team.group_sale_salesman"/>
|
||||
<menuitem id="menu_catalog" name="Catalog"
|
||||
parent="website.menu_website_configuration" sequence="3"
|
||||
groups="sales_team.group_sale_salesman"/>
|
||||
<menuitem id="menu_reporting" name="Reporting"
|
||||
parent="website.menu_website_configuration" sequence="99"
|
||||
groups="sales_team.group_sale_manager"/>
|
||||
<menuitem id="website.menu_website_global_configuration" name="Configuration"
|
||||
parent="website.menu_website_configuration" sequence="100"
|
||||
groups="base.group_system,sales_team.group_sale_manager"/>
|
||||
|
||||
<menuitem id="menu_ecommerce_settings" name="eCommerce"
|
||||
parent="website.menu_website_global_configuration"/>
|
||||
<menuitem id="menu_product_settings" name="Products"
|
||||
parent="website.menu_website_global_configuration"/>
|
||||
|
||||
<!-- Orders sub-menus -->
|
||||
<menuitem id="menu_orders_orders" name="Orders"
|
||||
action="action_orders_ecommerce"
|
||||
parent="menu_orders" sequence="1"/>
|
||||
<menuitem id="menu_orders_unpaid_orders" name="Unpaid Orders"
|
||||
action="action_unpaid_orders_ecommerce"
|
||||
parent="menu_orders" sequence="2"/>
|
||||
<menuitem id="menu_orders_abandonned_orders" name="Abandoned Carts"
|
||||
action="action_abandonned_orders_ecommerce"
|
||||
parent="menu_orders" sequence="3"/>
|
||||
<menuitem id="menu_orders_customers" name="Customers"
|
||||
action="base.action_partner_customer_form"
|
||||
parent="menu_orders" sequence="4"/>
|
||||
|
||||
|
||||
<!-- <menuitem id="menu_orders_invoices" name="Invoices" parent="menu_orders" action="action_invoices_ecommerce" sequence="4"/> -->
|
||||
|
||||
<!-- Catalog sub-menus -->
|
||||
<menuitem id="menu_catalog_products" name="Products"
|
||||
action="product_template_action_website"
|
||||
parent="menu_catalog" sequence="1"/>
|
||||
<menuitem id="product_catalog_variants" name="Product Variants"
|
||||
action="product.product_normal_action"
|
||||
parent="menu_catalog" groups="product.group_product_variant" sequence="2"/>
|
||||
<menuitem id="menu_catalog_pricelists" name="Pricelists"
|
||||
action="product.product_pricelist_action2"
|
||||
parent="menu_catalog" groups="product.group_sale_pricelist" sequence="3"/>
|
||||
|
||||
<!-- Reporting sub-menus -->
|
||||
<menuitem id="menu_report_sales" name="Sales"
|
||||
action="sale_report_action_dashboard"
|
||||
parent="menu_reporting" sequence="1"/>
|
||||
|
||||
<!-- Configuration sub-menus -->
|
||||
<menuitem id="menu_ecommerce_payment_acquirers"
|
||||
action="payment.action_payment_acquirer"
|
||||
parent="menu_ecommerce_settings" name="Payment Methods" />
|
||||
<menuitem id="menu_product_attribute_action"
|
||||
action="product.attribute_action"
|
||||
parent="menu_product_settings" groups="product.group_product_variant" sequence="1"/>
|
||||
<menuitem id="menu_catalog_variants_action"
|
||||
action="product.variants_action"
|
||||
parent="menu_product_settings" groups="product.group_product_variant" sequence="2"/>
|
||||
<menuitem id="menu_catalog_categories" name="Website Categories"
|
||||
action="product_public_category_action"
|
||||
parent="menu_product_settings" sequence="3"/>
|
||||
<menuitem id="menu_internal_product_categories" name="Internal Categories"
|
||||
action="product.product_category_action_form"
|
||||
parent="menu_product_settings" sequence="4"/>
|
||||
|
||||
</odoo>
|
||||
@@ -0,0 +1,98 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="sale_report_view_search_website" model="ir.ui.view">
|
||||
<field name="name">sale.report.search</field>
|
||||
<field name="model">sale.report</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Sales">
|
||||
<filter name="week" string="Last Week"
|
||||
domain="[
|
||||
'&',
|
||||
('date', '>=', (context_today()-relativedelta(days=7)).strftime('%Y-%m-%d')),
|
||||
('date', '<=', context_today().strftime('%Y-%m-%d')),
|
||||
]"/>
|
||||
<filter name="month" string="Last Month"
|
||||
domain="[
|
||||
'&',
|
||||
('date', '>=', (context_today()-relativedelta(months=1)).strftime('%Y-%m-%d')),
|
||||
('date', '<=', context_today().strftime('%Y-%m-%d')),
|
||||
]"/>
|
||||
<filter name="year" string="Last Year"
|
||||
domain="[
|
||||
'&',
|
||||
('date', '>=', (context_today()-relativedelta(years=1)).strftime('%Y-%m-%d')),
|
||||
('date', '<=', context_today().strftime('%Y-%m-%d')),
|
||||
]"/>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="sale_report_view_pivot_website" model="ir.ui.view">
|
||||
<field name="name">sale.report.view.pivot.website</field>
|
||||
<field name="model">sale.report</field>
|
||||
<field name="arch" type="xml">
|
||||
<pivot string="Sales Report">
|
||||
<field name="date" type="row"/>
|
||||
<field name="state" type="col"/>
|
||||
<field name="price_subtotal" type="measure"/>
|
||||
</pivot>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="sale_report_view_graph_website" model="ir.ui.view">
|
||||
<field name="name">sale.report.view.graph.website</field>
|
||||
<field name="model">sale.report</field>
|
||||
<field name="arch" type="xml">
|
||||
<graph string="Sale Report" type="bar">
|
||||
<field name="date"/>
|
||||
<field name="price_subtotal" type='measure'/>
|
||||
</graph>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="sale_report_action_dashboard" model="ir.actions.act_window">
|
||||
<field name="name">Sales</field>
|
||||
<field name="res_model">sale.report</field>
|
||||
<field name="view_mode">pivot,graph</field>
|
||||
<field name="domain">[('state','in',('sale', 'done')), ('team_id.team_type', '=', 'website')]</field>
|
||||
<field name="search_view_id" ref="sale_report_view_search_website"/>
|
||||
<field name="help">You don't have any order from the website.</field>
|
||||
</record>
|
||||
|
||||
<record id="sale_report_action_view_pivot_website" model="ir.actions.act_window.view">
|
||||
<field name="sequence" eval="1"/>
|
||||
<field name="view_mode">pivot</field>
|
||||
<field name="view_id" ref="sale_report_view_pivot_website"/>
|
||||
<field name="act_window_id" ref="sale_report_action_dashboard"/>
|
||||
</record>
|
||||
|
||||
<record id="sale_report_action_view_graph_website" model="ir.actions.act_window.view">
|
||||
<field name="sequence" eval="1"/>
|
||||
<field name="view_mode">graph</field>
|
||||
<field name="view_id" ref="sale_report_view_graph_website"/>
|
||||
<field name="act_window_id" ref="sale_report_action_dashboard"/>
|
||||
</record>
|
||||
|
||||
<record id="sale_report_action_carts" model="ir.actions.act_window">
|
||||
<field name="name">Sales</field>
|
||||
<field name="res_model">sale.report</field>
|
||||
<field name="view_mode">pivot,graph</field>
|
||||
<field name="domain">[('team_id.team_type', '=', 'website')]</field>
|
||||
<field name="search_view_id" ref="sale_report_view_search_website"/>
|
||||
<field name="help">You don't have any order from the website.</field>
|
||||
</record>
|
||||
|
||||
<record id="sale_report_action_view_pivot_carts" model="ir.actions.act_window.view">
|
||||
<field name="sequence" eval="1"/>
|
||||
<field name="view_mode">pivot</field>
|
||||
<field name="view_id" ref="sale_report_view_pivot_website"/>
|
||||
<field name="act_window_id" ref="sale_report_action_carts"/>
|
||||
</record>
|
||||
|
||||
<record id="sale_report_action_view_graph_carts" model="ir.actions.act_window.view">
|
||||
<field name="sequence" eval="1"/>
|
||||
<field name="view_mode">graph</field>
|
||||
<field name="view_id" ref="sale_report_view_graph_website"/>
|
||||
<field name="act_window_id" ref="sale_report_action_carts"/>
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -4,6 +4,7 @@
|
||||
<template id="assets_backend" inherit_id="web.assets_backend">
|
||||
<xpath expr="." position="inside">
|
||||
<script type="text/javascript" src="/website_sale/static/src/js/website_sale_backend.js"></script>
|
||||
<link rel="stylesheet" href="/website_sale/static/src/less/website_sale_dashboard.less"/>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
<menuitem name="Slides" id="menu_website_slides_root" sequence="32" parent="website.menu_website_configuration"/>
|
||||
<menuitem name="Slides"
|
||||
id="menu_website_slides_root"
|
||||
sequence="32"
|
||||
parent="website.menu_website_configuration"
|
||||
groups="website.group_website_designer"/>
|
||||
|
||||
<!-- SLIDE.TAG -->
|
||||
<record id="view_slide_tag_form" model="ir.ui.view">
|
||||
|
||||
Reference in New Issue
Block a user