Skip to content

rhri - Technical Training #824

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 26 commits into
base: 18.0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
96ef7be
[ADD] estate: create new real estate property management module
rhri-odoo Jun 19, 2025
48651ba
[IMP] estate: create estate_property table to store properties data
rhri-odoo Jun 19, 2025
b28bb68
[IMP] estate: configure access rights for estate_property model
rhri-odoo Jun 19, 2025
a1bbac3
[IMP] estate: create basic views for estate module
rhri-odoo Jun 19, 2025
fb86dce
[IMP] estate: create basic list, product, and search view for estate …
rhri-odoo Jun 19, 2025
e793550
[IMP] estate: create property type, property tags, and property offer…
rhri-odoo Jun 20, 2025
6ab4709
[IMP] estate: create computed values and ochanges on property and pro…
rhri-odoo Jun 20, 2025
a915adc
[IMP] estate: add sold, cancel, accept offer, and refuse offer button
rhri-odoo Jun 23, 2025
12cb6c4
[IMP] estate: add sql and python constraints
rhri-odoo Jun 23, 2025
a598751
[IMP] estate: add stat button, widgets, inline views, and styling to UI
rhri-odoo Jun 23, 2025
0082e44
[IMP] estate: add inheritance on models and views
rhri-odoo Jun 23, 2025
400928f
[IMP] estate: create invoice after property is sold
rhri-odoo Jun 24, 2025
e481bb4
[IMP] estate: add kanban view to property view
rhri-odoo Jun 24, 2025
5ba1bec
[REF] estate: refactor code to respect coding guidelines
rhri-odoo Jun 24, 2025
46606d0
[ADD] sale_branch: add sale_branch module to customize quotation code
rhri-odoo Jun 24, 2025
bc3c3eb
[IMP] estate: add batch creation for property offer
rhri-odoo Jun 24, 2025
11c5887
[IMP] estate: add master and demo data for init
rhri-odoo Jun 25, 2025
654c77c
[IMP] estate: create report for property offers
rhri-odoo Jun 25, 2025
08202bd
[ADD] case_report: add case_report module to customize invoice report…
rhri-odoo Jun 26, 2025
d0a6a64
[IMP] awesome_owl: implement counter, todolist, and card using owl co…
rhri-odoo Jun 30, 2025
02e4c3c
[IMP] awesome_dashboard: create simple dashboard
rhri-odoo Jul 1, 2025
652cfa1
[ADD] case_javascript: create case_javascript module to answer case s…
rhri-odoo Jul 2, 2025
e59766e
[IMP] estate: add additional security rules to estate
rhri-odoo Jul 2, 2025
a73759f
[ADD] case_data_access: create sales team leader groups
rhri-odoo Jul 3, 2025
37a5b15
[IMP] estate: add unit test for estate property and estate property o…
rhri-odoo Jul 3, 2025
daefa07
[REM] estate: remove access rights for base user group
rhri-odoo Jul 3, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,6 @@ dmypy.json

# Pyre type checker
.pyre/

# VS Code
.vscode
3 changes: 3 additions & 0 deletions awesome_dashboard/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@
'web.assets_backend': [
'awesome_dashboard/static/src/**/*',
],
'awesome_dashboard.dashboard': [
'awesome_dashboard/static/src/dashboard/**/*',
],
},
'license': 'AGPL-3'
}
4 changes: 2 additions & 2 deletions awesome_dashboard/controllers/controllers.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@
import random

from odoo import http
from odoo.http import request
# 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):
Expand All @@ -33,4 +34,3 @@ def get_statistics(self):
},
'total_amount': random.randint(100, 1000)
}

10 changes: 0 additions & 10 deletions awesome_dashboard/static/src/dashboard.js

This file was deleted.

8 changes: 0 additions & 8 deletions awesome_dashboard/static/src/dashboard.xml

This file was deleted.

9 changes: 9 additions & 0 deletions awesome_dashboard/static/src/dashboard/card/number_card.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Component } from "@odoo/owl";

export class NumberCard extends Component {
static template = "awesome_dashboard.number_card";
static props = {
title: { type: String },
data: { type: Number }
}
}
13 changes: 13 additions & 0 deletions awesome_dashboard/static/src/dashboard/card/number_card.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8" ?>
<templates xml:space="preserve">

<t t-name="awesome_dashboard.number_card">
<div class="p-3">
<h5><t t-out="props.title"/></h5>
<h2 class="text-success">
<t t-out="props.data"/>
</h2>
</div>
</t>

</templates>
11 changes: 11 additions & 0 deletions awesome_dashboard/static/src/dashboard/card/pie_chart_card.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Component } from "@odoo/owl";
import { PieChart } from "../pie_chart/pie_chart";

export class PieChartCard extends Component {
static template = "awesome_dashboard.pie_chart_card";
static components = { PieChart };
static props = {
title: { type: String },
data: { type: Object },
}
}
11 changes: 11 additions & 0 deletions awesome_dashboard/static/src/dashboard/card/pie_chart_card.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8" ?>
<templates xml:space="preserve">

<t t-name="awesome_dashboard.pie_chart_card">
<div class="p-3">
<h5><t t-out="props.title"/></h5>
<PieChart data="props.data"/>
</div>
</t>

</templates>
79 changes: 79 additions & 0 deletions awesome_dashboard/static/src/dashboard/dashboard.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { Component, useState } from "@odoo/owl";
import { useService } from "@web/core/utils/hooks";
import { registry } from "@web/core/registry";
import { browser } from "@web/core/browser/browser";

import { Layout } from "@web/search/layout";
import { DashboardItem } from "./dashboard_item/dashboard_item";
import { PieChart } from "./pie_chart/pie_chart";
import { DashboardDialog } from "./dialog/dialog";

class AwesomeDashboard extends Component {
static template = "awesome_dashboard.dashboard";
static components = { Layout, DashboardItem, PieChart };

setup() {
this.display = {
controlPanel: {}
};

this.action = useService("action");
this.dialog = useService("dialog");

this.statisticsService = useService("awesome_dashboard.statistics");

this.statistics = useState(this.statisticsService.statistics);
this.items = registry.category("awesome_dashboard").getAll();

this.storageKey = ["awesome_dashboard_item"];
this.setupActiveDashboardItem();
};

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, "list"],
[false, "form"],
],
target: "current",
});
}

openDialog() {
this.dialog.add(DashboardDialog, {
items: this.items,
activeDashboardItem: this.activeDashboardItem,
storageKey: this.storageKey,
});
}

get activeItems() {
return this.items.filter(
(item) => this.activeDashboardItem[item.id]
);
}

setupActiveDashboardItem() {
const activeDashboardItemList = browser.localStorage.getItem(this.storageKey)?.split(",");

this.activeDashboardItem = useState({});
for (const item of this.items) {
if (activeDashboardItemList) {
this.activeDashboardItem[item.id] = activeDashboardItemList.includes(
item.id.toString()
);
} else {
this.activeDashboardItem[item.id] = true;
}
}
}
}

registry.category("lazy_components").add("AwesomeDashboard", AwesomeDashboard);
18 changes: 18 additions & 0 deletions awesome_dashboard/static/src/dashboard/dashboard.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
.o_dashboard {
background-color: gray;
overflow-y: auto;
}

.pie-chart-container {
width: 100%;
aspect-ratio: 1 / 1;
max-width: 350px;
margin: 0 auto;
}

.pie-chart-container canvas {
display: block;
width: 100% !important;
height: 100% !important;
max-width: 100% !important;
}
32 changes: 32 additions & 0 deletions awesome_dashboard/static/src/dashboard/dashboard.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8" ?>
<templates xml:space="preserve">

<t t-name="awesome_dashboard.dashboard">
<Layout display="display" className="'o_dashboard h-100 px-2'">
<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>

<t t-set-slot="control-panel-additional-actions">
<button class="btn p-0 ms-1 border-0" t-on-click="openDialog">
<i class="fa fa-cog"></i>
</button>
</t>

<div class="container-fluid mb-5">
<div class="row g-2">
<t t-foreach="activeItems" t-as="item" t-key="item.id">
<div class="col-12 col-sm-6 col-lg-4 mb-2">
<DashboardItem size="item.size || 1">
<t t-set="itemProp" t-value="item.props? item.props(statistics) : { 'data' : statistics }"/>
<t t-component="item.Component" t-props="itemProp" />
</DashboardItem>
</div>
</t>
</div>
</div>
</Layout>
</t>

</templates>
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Component } from "@odoo/owl";

export class DashboardItem extends Component {
static template = "awesome_dashboard.dashboard_item";
static props = {
size: { optional: true},
slots: { optional: true }
};
static defaultProps = {
size: 1
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8" ?>
<templates xml:space="preserve">

<t t-name="awesome_dashboard.dashboard_item">
<div class="d-flex flex-column p-2 m-1 bg-white text-center h-100 w-100">
<div class="card-body w-100 d-flex flex-column align-items-center justify-content-center">
<t t-slot="default"/>
</div>
</div>
</t>

</templates>
65 changes: 65 additions & 0 deletions awesome_dashboard/static/src/dashboard/dashboard_items.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { registry } from "@web/core/registry";
import { NumberCard } from "./card/number_card";
import { PieChartCard } from "./card/pie_chart_card";

const items = [
{
id: "avg_amount",
description: "Average amount of t-shirt",
Component: NumberCard,
props: (data) => ({
title: "Average amount of t-shirt by order this month",
data: data.average_quantity,
}),
},
{
id: "avg_time",
description: "Average time for an order to go",
Component: NumberCard,
props: (data) => ({
title: "Average time for an order to go from 'new' to 'sent' or 'cancelled'",
data: data.average_time,
}),
},
{
id: "new_order",
description: "Number of new orders",
Component: NumberCard,
props: (data) => ({
title: "Number of new orders this month",
data: data.nb_new_orders,
}),
},
{
id: "cancelled_order",
description: "Number of cancelled orders",
Component: NumberCard,
props: (data) => ({
title: "Number of cancelled orders this month",
data: data.nb_cancelled_orders,
}),
},
{
id: "total_order",
description: "Total amount of new orders",
Component: NumberCard,
props: (data) => ({
title: "Total amount of new orders this month",
data: data.total_amount,
}),
},
{
id: "order_by_size",
description: "Shirt orders by size",
Component: PieChartCard,
size: 2,
props: (data) => ({
title: "Shirt orders by size",
data: data.orders_by_size,
}),
},
];

items.forEach(item => {
registry.category("awesome_dashboard").add(item.id, item);
});
26 changes: 26 additions & 0 deletions awesome_dashboard/static/src/dashboard/dialog/dialog.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { Component } from "@odoo/owl";
import { browser } from "@web/core/browser/browser";
import { CheckBox } from "@web/core/checkbox/checkbox";
import { Dialog } from "@web/core/dialog/dialog";

export class DashboardDialog extends Component {
static template = "awesome_dashboard.dialog";
static components = { CheckBox, Dialog };
static props = [ "title", "items", "storageKey", "activeDashboardItem" ];

setup() {
this.items = this.props.items;
this.storageKey = this.props.storageKey;
this.activeDashboardItem = this.props.activeDashboardItem;
}

toggleActiveItem(itemId) {
this.activeDashboardItem[itemId] = !this.activeDashboardItem[itemId];
browser.localStorage.setItem(
this.storageKey.join(","),
Object.keys(this.activeDashboardItem).filter(
(itemId) => this.activeDashboardItem[itemId]
)
);
}
}
31 changes: 31 additions & 0 deletions awesome_dashboard/static/src/dashboard/dialog/dialog.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8" ?>
<templates xml:space="preserve">

<t t-name="awesome_dashboard.dialog">
<Dialog title="'Dashboard Items configuration'" fullscreen="false" footer="true">
<t t-set-slot="header">
<h4 class="modal-title text-break" t-out="'Dashboard Item configuration'"/>
<button type="button" class="btn-close" aria-label="Close" tabindex="-1" t-on-click="props.close"/>
</t>

<div>
<h5>Which cards do you wish to see?</h5>
<div class="d-flex flex-column">
<t t-foreach="items" t-as="item" t-key="item.id">
<CheckBox
onChange="() => this.toggleActiveItem(item.id)"
name="item.id"
value="activeDashboardItem[item.id]"
>
<t t-esc="item.description"/>
</CheckBox>
</t>
</div>
</div>
<t t-set-slot="footer">
<button class="btn btn-primary" t-on-click="props.close">Done</button>
</t>
</Dialog>
</t>

</templates>
Loading