mirror of
https://github.com/SARL-PACIFIC-ERP/odoo-sh-test.git
synced 2025-06-25 09:32:22 +00:00
Compare commits
9 commits
5ebc65e096
...
7aa696f174
Author | SHA1 | Date | |
---|---|---|---|
|
7aa696f174 | ||
|
a9713b4667 | ||
|
f89514d21f | ||
|
100ce00a11 | ||
|
7d74834fb7 | ||
|
c0f193b52c | ||
|
ef7fb887b7 | ||
|
8217053199 | ||
|
98d33e57ec |
3
awesome_dashboard/__init__.py
Normal file
3
awesome_dashboard/__init__.py
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from . import controllers
|
34
awesome_dashboard/__manifest__.py
Normal file
34
awesome_dashboard/__manifest__.py
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
{
|
||||||
|
'name': "Awesome Dashboard",
|
||||||
|
|
||||||
|
'summary': """
|
||||||
|
Starting module for "Discover the JS framework, chapter 2: Build a dashboard"
|
||||||
|
""",
|
||||||
|
|
||||||
|
'description': """
|
||||||
|
Starting module for "Discover the JS framework, chapter 2: Build a dashboard"
|
||||||
|
""",
|
||||||
|
|
||||||
|
'author': "Odoo",
|
||||||
|
'website': "https://www.odoo.com/",
|
||||||
|
'category': 'Tutorials/AwesomeDashboard',
|
||||||
|
'version': '0.1',
|
||||||
|
'application': True,
|
||||||
|
'installable': True,
|
||||||
|
'depends': ['base', 'web', 'mail', 'crm'],
|
||||||
|
|
||||||
|
'data': [
|
||||||
|
'views/views.xml',
|
||||||
|
],
|
||||||
|
'assets': {
|
||||||
|
'web.assets_backend': [
|
||||||
|
'awesome_dashboard/static/src/**/*',
|
||||||
|
('remove', 'awesome_dashboard/static/src/dashboard/**/*'),
|
||||||
|
],
|
||||||
|
'awesome_dashboard.dashboard': [
|
||||||
|
'awesome_dashboard/static/src/dashboard/**/*'
|
||||||
|
],
|
||||||
|
},
|
||||||
|
'license': 'AGPL-3'
|
||||||
|
}
|
3
awesome_dashboard/controllers/__init__.py
Normal file
3
awesome_dashboard/controllers/__init__.py
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from . import controllers
|
36
awesome_dashboard/controllers/controllers.py
Normal file
36
awesome_dashboard/controllers/controllers.py
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import random
|
||||||
|
|
||||||
|
from odoo import http
|
||||||
|
from odoo.http import request
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
class AwesomeDashboard(http.Controller):
|
||||||
|
@http.route('/awesome_dashboard/statistics', type='json', auth='user')
|
||||||
|
def get_statistics(self):
|
||||||
|
"""
|
||||||
|
Returns a dict of statistics about the orders:
|
||||||
|
'average_quantity': the average number of t-shirts by order
|
||||||
|
'average_time': the average time (in hours) elapsed between the
|
||||||
|
moment an order is created, and the moment is it sent
|
||||||
|
'nb_cancelled_orders': the number of cancelled orders, this month
|
||||||
|
'nb_new_orders': the number of new orders, this month
|
||||||
|
'total_amount': the total amount of orders, this month
|
||||||
|
"""
|
||||||
|
|
||||||
|
return {
|
||||||
|
'average_quantity': random.randint(4, 12),
|
||||||
|
'average_time': random.randint(4, 123),
|
||||||
|
'nb_cancelled_orders': random.randint(0, 50),
|
||||||
|
'nb_new_orders': random.randint(10, 200),
|
||||||
|
'orders_by_size': {
|
||||||
|
'm': random.randint(0, 150),
|
||||||
|
's': random.randint(0, 150),
|
||||||
|
'xl': random.randint(0, 150),
|
||||||
|
},
|
||||||
|
'total_amount': random.randint(100, 1000)
|
||||||
|
}
|
||||||
|
|
38
awesome_dashboard/static/src/dashboard/dashboard.js
Normal file
38
awesome_dashboard/static/src/dashboard/dashboard.js
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
/** @odoo-module **/
|
||||||
|
|
||||||
|
import { Component, useState } from "@odoo/owl";
|
||||||
|
import { registry } from "@web/core/registry";
|
||||||
|
import { Layout } from "@web/search/layout";
|
||||||
|
import { useService } from "@web/core/utils/hooks"
|
||||||
|
import { DashboardItem } from "./dashboard_item/dashboard_item";
|
||||||
|
import { Piechart } from "./piechart/piechart";
|
||||||
|
|
||||||
|
class AwesomeDashboard extends Component {
|
||||||
|
static template = "awesome_dashboard.AwesomeDashboard";
|
||||||
|
static components = { Layout, DashboardItem, Piechart};
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
this.display = {
|
||||||
|
controlPanel: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
this.action = useService("action");
|
||||||
|
|
||||||
|
this.stats = useState(useService('awesome_dashboard.statistics'));
|
||||||
|
}
|
||||||
|
|
||||||
|
openCustomers() {
|
||||||
|
this.action.doAction("base.action_partner_form");
|
||||||
|
}
|
||||||
|
|
||||||
|
openLeads() {
|
||||||
|
this.action.doAction({
|
||||||
|
type: 'ir.actions.act_window',
|
||||||
|
name: 'Leads',
|
||||||
|
res_model: 'crm.lead',
|
||||||
|
views: [[false, 'tree'],[false, 'form']],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
registry.category("lazy_components").add("AwesomeDashboard", AwesomeDashboard);
|
3
awesome_dashboard/static/src/dashboard/dashboard.scss
Normal file
3
awesome_dashboard/static/src/dashboard/dashboard.scss
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
.o_dashboard {
|
||||||
|
background-color:rgb(0, 116, 151);
|
||||||
|
}
|
49
awesome_dashboard/static/src/dashboard/dashboard.xml
Normal file
49
awesome_dashboard/static/src/dashboard/dashboard.xml
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<templates xml:space="preserve">
|
||||||
|
|
||||||
|
<t t-name="awesome_dashboard.AwesomeDashboard">
|
||||||
|
<Layout display="display" className="'o_dashboard h-100'">
|
||||||
|
<t t-set-slot="layout-buttons">
|
||||||
|
<button class="btn btn-primary" t-on-click="openCustomers">Customers</button>
|
||||||
|
<button class="btn btn-primary" t-on-click="openLeads">Leads</button>
|
||||||
|
</t>
|
||||||
|
<div class="d-flex flex-wrap" t-if="stats.isReady">
|
||||||
|
<DashboardItem>
|
||||||
|
Number of new orders this month
|
||||||
|
<div class="fs-1 fw-bold text-success text-center">
|
||||||
|
<t t-out="stats.nb_new_orders"/>
|
||||||
|
</div>
|
||||||
|
</DashboardItem>
|
||||||
|
<DashboardItem>
|
||||||
|
Total amount of new orders this month
|
||||||
|
<div class="fs-1 fw-bold text-success text-center">
|
||||||
|
<t t-out="stats.total_amount"/>
|
||||||
|
</div>
|
||||||
|
</DashboardItem>
|
||||||
|
<DashboardItem>
|
||||||
|
Average amount of t-shirt by order this month
|
||||||
|
<div class="fs-1 fw-bold text-success text-center">
|
||||||
|
<t t-out="stats.average_quantity"/>
|
||||||
|
</div>
|
||||||
|
</DashboardItem>
|
||||||
|
<DashboardItem>
|
||||||
|
Number of cancelled orders this month
|
||||||
|
<div class="fs-1 fw-bold text-success text-center">
|
||||||
|
<t t-out="stats.nb_cancelled_orders"/>
|
||||||
|
</div>
|
||||||
|
</DashboardItem>
|
||||||
|
<DashboardItem>
|
||||||
|
Average time for an order to go from ‘new’ to ‘sent’ or ‘cancelled’
|
||||||
|
<div class="fs-1 fw-bold text-success text-center">
|
||||||
|
<t t-out="stats.average_time"/>
|
||||||
|
</div>
|
||||||
|
</DashboardItem>
|
||||||
|
<DashboardItem size='4'>
|
||||||
|
Shirt orders by size
|
||||||
|
<Piechart data="stats.orders_by_size" label="'Shirt orders by size'"/>
|
||||||
|
</DashboardItem>
|
||||||
|
</div>
|
||||||
|
</Layout>
|
||||||
|
</t>
|
||||||
|
|
||||||
|
</templates>
|
|
@ -0,0 +1,20 @@
|
||||||
|
/** @odoo-module **/
|
||||||
|
|
||||||
|
import { Component } from "@odoo/owl";
|
||||||
|
|
||||||
|
export class DashboardItem extends Component {
|
||||||
|
static template = "awesome_dashboard.DashboardItem";
|
||||||
|
static props = {
|
||||||
|
size: {
|
||||||
|
type: Number,
|
||||||
|
default: 1,
|
||||||
|
optional: true,
|
||||||
|
},
|
||||||
|
slots: {
|
||||||
|
type: Object,
|
||||||
|
shape: {
|
||||||
|
default: Object
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<templates xml:space="preserve">
|
||||||
|
|
||||||
|
<t t-name="awesome_dashboard.DashboardItem">
|
||||||
|
<section>
|
||||||
|
<div class="card d-inline-block m-2" t-attf-style="width:{{18*props.size}}rem;">
|
||||||
|
<div class="card-body">
|
||||||
|
<t t-slot="default">some content</t>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</t>
|
||||||
|
|
||||||
|
</templates>
|
45
awesome_dashboard/static/src/dashboard/piechart/piechart.js
Normal file
45
awesome_dashboard/static/src/dashboard/piechart/piechart.js
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
/** @odoo-module **/
|
||||||
|
|
||||||
|
import { loadJS } from "@web/core/assets";
|
||||||
|
import { getColor } from "@web/core/colors/colors";
|
||||||
|
import { Component, onWillStart, useRef, onMounted, onWillUnmount } from "@odoo/owl";
|
||||||
|
|
||||||
|
export class Piechart extends Component {
|
||||||
|
static template = "awesome_dashboard.Piechart";
|
||||||
|
static props = {
|
||||||
|
label: String,
|
||||||
|
data: Object,
|
||||||
|
};
|
||||||
|
|
||||||
|
setup() {
|
||||||
|
this.canvasRef = useRef("canvas");
|
||||||
|
onWillStart(() => loadJS(["/web/static/lib/Chart/Chart.js"]));
|
||||||
|
onMounted(() => {
|
||||||
|
this.renderChart();
|
||||||
|
});
|
||||||
|
onWillUnmount(() => {
|
||||||
|
this.chart.destroy();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
renderChart() {
|
||||||
|
const labels = Object.keys(this.props.data);
|
||||||
|
const data = Object.values(this.props.data);
|
||||||
|
const color = labels.map((_, index) => getColor(index));
|
||||||
|
this.chart = new Chart(this.canvasRef.el, {
|
||||||
|
type: "pie",
|
||||||
|
data: {
|
||||||
|
labels: labels,
|
||||||
|
datasets: [
|
||||||
|
{
|
||||||
|
label: this.props.label,
|
||||||
|
data: data,
|
||||||
|
backgroundColor: color,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
11
awesome_dashboard/static/src/dashboard/piechart/piechart.xml
Normal file
11
awesome_dashboard/static/src/dashboard/piechart/piechart.xml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<templates xml:space="preserve">
|
||||||
|
|
||||||
|
<t t-name="awesome_dashboard.Piechart">
|
||||||
|
<div t-att-class="'h-100 ' + props.class" t-ref="root">
|
||||||
|
<div class="h-100 position-relative" t-ref="container">
|
||||||
|
<canvas t-ref="canvas" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</t>
|
||||||
|
</templates>
|
21
awesome_dashboard/static/src/dashboard/statistics_service.js
Normal file
21
awesome_dashboard/static/src/dashboard/statistics_service.js
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
/** @odoo-module **/
|
||||||
|
|
||||||
|
import { registry } from "@web/core/registry";
|
||||||
|
import { reactive } from "@odoo/owl";
|
||||||
|
|
||||||
|
const statisticsService = {
|
||||||
|
dependencies: ["rpc"],
|
||||||
|
start(env, { rpc }) {
|
||||||
|
const statistics = reactive({ isReady: false });
|
||||||
|
async function loadData() {
|
||||||
|
const updates = await rpc("/awesome_dashboard/statistics");
|
||||||
|
Object.assign(statistics, updates, { isReady: true });
|
||||||
|
}
|
||||||
|
setInterval(loadData, 10*60*1000);
|
||||||
|
loadData();
|
||||||
|
return statistics;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
registry.category("services").add("awesome_dashboard.statistics", statisticsService);
|
15
awesome_dashboard/static/src/dashboard_loader.js
Normal file
15
awesome_dashboard/static/src/dashboard_loader.js
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
/** @odoo-module */
|
||||||
|
|
||||||
|
import { registry } from "@web/core/registry";
|
||||||
|
import { LazyComponent } from "@web/core/assets";
|
||||||
|
import { Component, xml } from "@odoo/owl";
|
||||||
|
|
||||||
|
class AwesomeDashboardLoader extends Component {
|
||||||
|
|
||||||
|
static components = { LazyComponent };
|
||||||
|
static template = xml`
|
||||||
|
<LazyComponent bundle="'awesome_dashboard.dashboard'" Component="'AwesomeDashboard'" props="props"/>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
registry.category("actions").add("awesome_dashboard.dashboard", AwesomeDashboardLoader);
|
11
awesome_dashboard/views/views.xml
Normal file
11
awesome_dashboard/views/views.xml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<odoo>
|
||||||
|
<data>
|
||||||
|
<record model="ir.actions.client" id="dashboard">
|
||||||
|
<field name="name">Dashboard</field>
|
||||||
|
<field name="tag">awesome_dashboard.dashboard</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<menuitem name="Awesome Dashboard" id="awesome_dashboard.menu_root" groups="base.group_user" web_icon="awesome_dashboard,static/description/icon.png"/>
|
||||||
|
<menuitem name="Dashboard" id="awesome_dashboard.dashboard_menu" parent="awesome_dashboard.menu_root" action="awesome_dashboard.dashboard" sequence="1"/>
|
||||||
|
</data>
|
||||||
|
</odoo>
|
Loading…
Reference in a new issue