mirror of
https://github.com/SARL-PACIFIC-ERP/odoo-sh-test.git
synced 2025-06-25 09:32: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 { useService } from "@web/core/utils/hooks"
|
||||
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 {
|
||||
static template = "awesome_dashboard.AwesomeDashboard";
|
||||
static components = { Layout, DashboardItem, Piechart};
|
||||
static components = { Layout, DashboardItem};
|
||||
|
||||
setup() {
|
||||
this.display = {
|
||||
|
@ -19,6 +21,14 @@ class AwesomeDashboard extends Component {
|
|||
this.action = useService("action");
|
||||
|
||||
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() {
|
||||
|
@ -33,6 +43,47 @@ class AwesomeDashboard extends Component {
|
|||
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);
|
|
@ -7,43 +7,36 @@
|
|||
<button class="btn btn-primary" t-on-click="openCustomers">Customers</button>
|
||||
<button class="btn btn-primary" t-on-click="openLeads">Leads</button>
|
||||
</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">
|
||||
<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'"/>
|
||||
<t t-foreach="items" t-as="item" t-key="item.id">
|
||||
<DashboardItem t-if="!state.disabledItems.includes(item.id)" size="item.size || 1">
|
||||
<t t-set="itemProp" t-value="item.props ? item.props(stats) : {'data': stats}"/>
|
||||
<t t-component="item.Component" t-props="itemProp" />
|
||||
</DashboardItem>
|
||||
</t>
|
||||
</div>
|
||||
</Layout>
|
||||
</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>
|
||||
|
|
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/estate_menus.xml',
|
||||
'security/ir.model.access.csv',
|
||||
'data/estate.property.type.csv',
|
||||
],
|
||||
'demo':[
|
||||
'demo/estate_property.xml',
|
||||
'demo/estate_property_offer.xml',
|
||||
],
|
||||
'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