mirror of
https://github.com/SARL-PACIFIC-ERP/odoo-sh-test.git
synced 2025-06-25 17:42:22 +00:00
Compare commits
4 commits
7aa696f174
...
41f85f9898
Author | SHA1 | Date | |
---|---|---|---|
|
41f85f9898 | ||
|
7a28c70b6e | ||
|
7f28d797c9 | ||
|
089ac45df2 |
|
@ -5,11 +5,13 @@ import { registry } from "@web/core/registry";
|
||||||
import { Layout } from "@web/search/layout";
|
import { Layout } from "@web/search/layout";
|
||||||
import { useService } from "@web/core/utils/hooks"
|
import { useService } from "@web/core/utils/hooks"
|
||||||
import { DashboardItem } from "./dashboard_item/dashboard_item";
|
import { DashboardItem } from "./dashboard_item/dashboard_item";
|
||||||
import { Piechart } from "./piechart/piechart";
|
import { Dialog } from "@web/core/dialog/dialog";
|
||||||
|
import { CheckBox } from "@web/core/checkbox/checkbox";
|
||||||
|
import { browser } from "@web/core/browser/browser";
|
||||||
|
|
||||||
class AwesomeDashboard extends Component {
|
class AwesomeDashboard extends Component {
|
||||||
static template = "awesome_dashboard.AwesomeDashboard";
|
static template = "awesome_dashboard.AwesomeDashboard";
|
||||||
static components = { Layout, DashboardItem, Piechart};
|
static components = { Layout, DashboardItem};
|
||||||
|
|
||||||
setup() {
|
setup() {
|
||||||
this.display = {
|
this.display = {
|
||||||
|
@ -19,6 +21,14 @@ class AwesomeDashboard extends Component {
|
||||||
this.action = useService("action");
|
this.action = useService("action");
|
||||||
|
|
||||||
this.stats = useState(useService('awesome_dashboard.statistics'));
|
this.stats = useState(useService('awesome_dashboard.statistics'));
|
||||||
|
|
||||||
|
this.items = registry.category("awesome_dashboard").getAll();
|
||||||
|
|
||||||
|
this.dialog = useService("dialog");
|
||||||
|
|
||||||
|
this.state = useState({
|
||||||
|
disabledItems: browser.localStorage.getItem("disabledDashboardItems")?.split(",") || []
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
openCustomers() {
|
openCustomers() {
|
||||||
|
@ -33,6 +43,47 @@ class AwesomeDashboard extends Component {
|
||||||
views: [[false, 'tree'],[false, 'form']],
|
views: [[false, 'tree'],[false, 'form']],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
openConfiguration() {
|
||||||
|
this.dialog.add(ConfigurationDialog, {
|
||||||
|
items: this.items,
|
||||||
|
disabledItems: this.state.disabledItems,
|
||||||
|
onUpdateConfiguration: this.updateConfiguration.bind(this),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
updateConfiguration(newDisabledItems) {
|
||||||
|
this.state.disabledItems = newDisabledItems;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ConfigurationDialog extends Component {
|
||||||
|
static template = "awesome_dashboard.ConfigurationDialog";
|
||||||
|
static components = { Dialog, CheckBox };
|
||||||
|
static props = ["close", "items", "disabledItems", "onUpdateConfiguration"];
|
||||||
|
setup() {
|
||||||
|
this.items = useState(this.props.items.map((item) => {
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
enabled: !this.props.disabledItems.includes(item.id),
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
done() {
|
||||||
|
this.props.close();
|
||||||
|
}
|
||||||
|
onChange(checked, changedItem) {
|
||||||
|
changedItem.enabled = checked;
|
||||||
|
const newDisabledItems = Object.values(this.items).filter(
|
||||||
|
(item) => !item.enabled
|
||||||
|
).map((item) => item.id)
|
||||||
|
browser.localStorage.setItem(
|
||||||
|
"disabledDashboardItems",
|
||||||
|
newDisabledItems,
|
||||||
|
);
|
||||||
|
this.props.onUpdateConfiguration(newDisabledItems);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
registry.category("lazy_components").add("AwesomeDashboard", AwesomeDashboard);
|
registry.category("lazy_components").add("AwesomeDashboard", AwesomeDashboard);
|
|
@ -7,43 +7,36 @@
|
||||||
<button class="btn btn-primary" t-on-click="openCustomers">Customers</button>
|
<button class="btn btn-primary" t-on-click="openCustomers">Customers</button>
|
||||||
<button class="btn btn-primary" t-on-click="openLeads">Leads</button>
|
<button class="btn btn-primary" t-on-click="openLeads">Leads</button>
|
||||||
</t>
|
</t>
|
||||||
|
<t t-set-slot="control-panel-additional-actions">
|
||||||
|
<button t-on-click="openConfiguration" class="btn p-0 ms-1 border-0">
|
||||||
|
<i class="fa fa-cog"></i>
|
||||||
|
</button>
|
||||||
|
</t>
|
||||||
<div class="d-flex flex-wrap" t-if="stats.isReady">
|
<div class="d-flex flex-wrap" t-if="stats.isReady">
|
||||||
<DashboardItem>
|
<t t-foreach="items" t-as="item" t-key="item.id">
|
||||||
Number of new orders this month
|
<DashboardItem t-if="!state.disabledItems.includes(item.id)" size="item.size || 1">
|
||||||
<div class="fs-1 fw-bold text-success text-center">
|
<t t-set="itemProp" t-value="item.props ? item.props(stats) : {'data': stats}"/>
|
||||||
<t t-out="stats.nb_new_orders"/>
|
<t t-component="item.Component" t-props="itemProp" />
|
||||||
</div>
|
</DashboardItem>
|
||||||
</DashboardItem>
|
</t>
|
||||||
<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>
|
</div>
|
||||||
</Layout>
|
</Layout>
|
||||||
</t>
|
</t>
|
||||||
|
|
||||||
|
<t t-name="awesome_dashboard.ConfigurationDialog">
|
||||||
|
<Dialog title="'Dashboard items configuration'">
|
||||||
|
Which cards do you whish to see ?
|
||||||
|
<t t-foreach="items" t-as="item" t-key="item.id">
|
||||||
|
<CheckBox value="item.enabled" onChange="(ev) => this.onChange(ev, item)">
|
||||||
|
<t t-esc="item.description"/>
|
||||||
|
</CheckBox>
|
||||||
|
</t>
|
||||||
|
<t t-set-slot="footer">
|
||||||
|
<button class="btn btn-primary" t-on-click="done">
|
||||||
|
Done
|
||||||
|
</button>
|
||||||
|
</t>
|
||||||
|
</Dialog>
|
||||||
|
</t>
|
||||||
|
|
||||||
</templates>
|
</templates>
|
||||||
|
|
67
awesome_dashboard/static/src/dashboard/dashboard_items.js
Normal file
67
awesome_dashboard/static/src/dashboard/dashboard_items.js
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
/** @odoo-module */
|
||||||
|
import { NumberCard } from "./number_card/number_card";
|
||||||
|
import { PieChartCard } from "./pie_chart_card/pie_chart_card";
|
||||||
|
import { registry } from "@web/core/registry";
|
||||||
|
|
||||||
|
const items = [
|
||||||
|
{
|
||||||
|
id: "average_quantity",
|
||||||
|
description: "Average amount of t-shirt",
|
||||||
|
Component: NumberCard,
|
||||||
|
props: (data) => ({
|
||||||
|
title: "Average amount of t-shirt by order this month",
|
||||||
|
value: data.average_quantity,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "average_time",
|
||||||
|
description: "Average time for an order",
|
||||||
|
Component: NumberCard,
|
||||||
|
props: (data) => ({
|
||||||
|
title: "Average time for an order to go from 'new' to 'sent' or 'cancelled'",
|
||||||
|
value: data.average_time,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "number_new_orders",
|
||||||
|
description: "New orders this month",
|
||||||
|
Component: NumberCard,
|
||||||
|
props: (data) => ({
|
||||||
|
title: "Number of new orders this month",
|
||||||
|
value: data.nb_new_orders,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "cancelled_orders",
|
||||||
|
description: "Cancelled orders this month",
|
||||||
|
Component: NumberCard,
|
||||||
|
props: (data) => ({
|
||||||
|
title: "Number of cancelled orders this month",
|
||||||
|
value: data.nb_cancelled_orders,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "amount_new_orders",
|
||||||
|
description: "amount orders this month",
|
||||||
|
Component: NumberCard,
|
||||||
|
props: (data) => ({
|
||||||
|
title: "Total amount of new orders this month",
|
||||||
|
value: data.total_amount,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "pie_chart",
|
||||||
|
description: "Shirt orders by size",
|
||||||
|
Component: PieChartCard,
|
||||||
|
size: 2,
|
||||||
|
props: (data) => ({
|
||||||
|
title: "Shirt orders by size",
|
||||||
|
values: data.orders_by_size,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
items.forEach(item => {
|
||||||
|
registry.category("awesome_dashboard").add(item.id, item);
|
||||||
|
});
|
|
@ -0,0 +1,13 @@
|
||||||
|
/** @odoo-module */
|
||||||
|
import { Component } from "@odoo/owl";
|
||||||
|
export class NumberCard extends Component {
|
||||||
|
static template = "awesome_dashboard.NumberCard";
|
||||||
|
static props = {
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
value: {
|
||||||
|
type: Number,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<templates xml:space="preserve">
|
||||||
|
<t t-name="awesome_dashboard.NumberCard" owl="1">
|
||||||
|
<t t-esc="props.title"/>
|
||||||
|
<div class="fs-1 fw-bold text-success text-center">
|
||||||
|
<t t-esc="props.value"/>
|
||||||
|
</div>
|
||||||
|
</t>
|
||||||
|
</templates>
|
|
@ -0,0 +1,15 @@
|
||||||
|
/** @odoo-module */
|
||||||
|
import { Component } from "@odoo/owl";
|
||||||
|
import { Piechart } from "../pie_chart/pie_chart";
|
||||||
|
export class PieChartCard extends Component {
|
||||||
|
static template = "awesome_dashboard.PieChartCard";
|
||||||
|
static components = { Piechart }
|
||||||
|
static props = {
|
||||||
|
title: {
|
||||||
|
type: String,
|
||||||
|
},
|
||||||
|
values: {
|
||||||
|
type: Object,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
<templates xml:space="preserve">
|
||||||
|
<t t-name="awesome_dashboard.PieChartCard" owl="1">
|
||||||
|
<t t-esc="props.title"/>
|
||||||
|
<Piechart data="props.values" label="''"/>
|
||||||
|
</t>
|
||||||
|
</templates>
|
|
@ -16,6 +16,11 @@
|
||||||
'views/res_users_views.xml',
|
'views/res_users_views.xml',
|
||||||
'views/estate_menus.xml',
|
'views/estate_menus.xml',
|
||||||
'security/ir.model.access.csv',
|
'security/ir.model.access.csv',
|
||||||
|
'data/estate.property.type.csv',
|
||||||
|
],
|
||||||
|
'demo':[
|
||||||
|
'demo/estate_property.xml',
|
||||||
|
'demo/estate_property_offer.xml',
|
||||||
],
|
],
|
||||||
'license': 'AGPL-3',
|
'license': 'AGPL-3',
|
||||||
}
|
}
|
5
estate/data/estate.property.type.csv
Normal file
5
estate/data/estate.property.type.csv
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
id,name
|
||||||
|
property_type_residential,Residential
|
||||||
|
property_type_commercial,Commercial
|
||||||
|
property_type_industrial,Industrial
|
||||||
|
property_type_land,Land
|
|
66
estate/demo/estate_property.xml
Normal file
66
estate/demo/estate_property.xml
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<odoo>
|
||||||
|
|
||||||
|
<record id="property_villa" model="estate.property">
|
||||||
|
<field name="name">Big Villa</field>
|
||||||
|
<field name="property_type_id" ref="property_type_residential" />
|
||||||
|
<field name="state">new</field>
|
||||||
|
<field name="description">A nice a big villa</field>
|
||||||
|
<field name="postcode">12345</field>
|
||||||
|
<field name="date_availability">2020-02-02</field>
|
||||||
|
<field name="expected_price">1600000.00</field>
|
||||||
|
<field name="bedrooms">6</field>
|
||||||
|
<field name="living_area">100</field>
|
||||||
|
<field name="facades">4</field>
|
||||||
|
<field name="garage">True</field>
|
||||||
|
<field name="garden">True</field>
|
||||||
|
<field name="garden_area">100000</field>
|
||||||
|
<field name="garden_orientation">south</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="property_trailer" model="estate.property">
|
||||||
|
<field name="name">Trailer home</field>
|
||||||
|
<field name="property_type_id" ref="property_type_residential" />
|
||||||
|
<field name="state">cancelled</field>
|
||||||
|
<field name="description">Home in a trailer park</field>
|
||||||
|
<field name="postcode">54321</field>
|
||||||
|
<field name="date_availability">1970-01-01</field>
|
||||||
|
<field name="expected_price">100000.00</field>
|
||||||
|
<field name="selling_price">120000.00</field>
|
||||||
|
<field name="bedrooms">1</field>
|
||||||
|
<field name="living_area">10</field>
|
||||||
|
<field name="facades">4</field>
|
||||||
|
<field name="garage">False</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="property_hutt" model="estate.property">
|
||||||
|
<field name="name">Cute Hutt</field>
|
||||||
|
<field name="property_type_id" ref="property_type_land" />
|
||||||
|
<field name="state">new</field>
|
||||||
|
<field name="description">A few logs stacked in a tree, in the middle of a huge land for sale</field>
|
||||||
|
<field name="postcode">04700</field>
|
||||||
|
<field name="date_availability">1988-05-16</field>
|
||||||
|
<field name="expected_price">80000.00</field>
|
||||||
|
<field name="bedrooms">1</field>
|
||||||
|
<field name="living_area">5</field>
|
||||||
|
<field name="facades">3</field>
|
||||||
|
<field name="garage">False</field>
|
||||||
|
<field name="garden">True</field>
|
||||||
|
<field name="garden_area">500000</field>
|
||||||
|
<field name="garden_orientation">north</field>
|
||||||
|
<field name="offer_ids" eval="[
|
||||||
|
Command.create({
|
||||||
|
'partner_id': 3,
|
||||||
|
'price': 150000,
|
||||||
|
'validity': 7,
|
||||||
|
}),
|
||||||
|
Command.create({
|
||||||
|
'partner_id': 5,
|
||||||
|
'price': 8000,
|
||||||
|
'validity': 30,
|
||||||
|
}),
|
||||||
|
]"/>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
|
||||||
|
</odoo>
|
39
estate/demo/estate_property_offer.xml
Normal file
39
estate/demo/estate_property_offer.xml
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<odoo>
|
||||||
|
<record id="property_offer_villa_1" model="estate.property.offer">
|
||||||
|
<field name="partner_id" ref="base.res_partner_12" />
|
||||||
|
<field name="property_id" ref="property_villa" />
|
||||||
|
<field name="price">10000</field>
|
||||||
|
<field name="validity">14</field>
|
||||||
|
<field name="create_date" eval="datetime.now()" />
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="property_offer_villa_2" model="estate.property.offer">
|
||||||
|
<field name="partner_id" ref="base.res_partner_12" />
|
||||||
|
<field name="property_id" ref="property_villa" />
|
||||||
|
<field name="price">1500000</field>
|
||||||
|
<field name="validity">14</field>
|
||||||
|
<field name="create_date" eval="datetime.now()" />
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="property_offer_villa_3" model="estate.property.offer">
|
||||||
|
<field name="partner_id" ref="base.res_partner_2" />
|
||||||
|
<field name="property_id" ref="property_villa" />
|
||||||
|
<field name="price">1500001</field>
|
||||||
|
<field name="validity">14</field>
|
||||||
|
<field name="create_date" eval="datetime.now()" />
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<function model="estate.property.offer" name="action_accept">
|
||||||
|
<value eval="[ref('property_offer_villa_2')]"/>
|
||||||
|
</function>
|
||||||
|
|
||||||
|
<function model="estate.property.offer" name="action_reject">
|
||||||
|
<value eval="[ref('property_offer_villa_1')]"/>
|
||||||
|
</function>
|
||||||
|
|
||||||
|
<function model="estate.property.offer" name="action_reject">
|
||||||
|
<value eval="[ref('property_offer_villa_3')]"/>
|
||||||
|
</function>
|
||||||
|
|
||||||
|
</odoo>
|
Loading…
Reference in a new issue