mirror of
https://github.com/bringout/oca-ocb-vertical-industry.git
synced 2026-04-23 00:32:06 +02:00
Initial commit: Vertical Industry packages
This commit is contained in:
commit
d5567a0017
766 changed files with 733028 additions and 0 deletions
|
|
@ -0,0 +1,179 @@
|
|||
/** @odoo-module */
|
||||
|
||||
import { useBus, useService } from "@web/core/utils/hooks";
|
||||
import { Many2XAutocomplete } from "@web/views/fields/relational_utils";
|
||||
|
||||
const { Component, useState, onWillStart, markup, xml } = owl;
|
||||
|
||||
export class LunchCurrency extends Component {
|
||||
get amount() {
|
||||
return parseFloat(this.props.amount).toFixed(2);
|
||||
}
|
||||
}
|
||||
LunchCurrency.template = 'lunch.LunchCurrency';
|
||||
LunchCurrency.props = ["currency", "amount"];
|
||||
|
||||
export class LunchOrderLine extends Component {
|
||||
setup() {
|
||||
super.setup();
|
||||
this.orm = useService('orm');
|
||||
this.state = useState({ mobileOpen: false });
|
||||
}
|
||||
|
||||
get line() {
|
||||
return this.props.line;
|
||||
}
|
||||
|
||||
get canEdit() {
|
||||
return !['sent', 'confirmed'].includes(this.line.raw_state);
|
||||
}
|
||||
|
||||
get badgeClass() {
|
||||
const mapping = {'new': 'warning', 'confirmed': 'success', 'sent': 'info', 'ordered': 'danger'};
|
||||
return mapping[this.line.raw_state];
|
||||
}
|
||||
|
||||
get hasToppings() {
|
||||
return this.line.toppings.length !== 0;
|
||||
}
|
||||
|
||||
async updateQuantity(increment) {
|
||||
await this.orm.call('lunch.order', 'update_quantity', [
|
||||
this.props.line.id,
|
||||
increment
|
||||
]);
|
||||
|
||||
await this.props.onUpdateQuantity();
|
||||
}
|
||||
}
|
||||
LunchOrderLine.template = 'lunch.LunchOrderLine';
|
||||
LunchOrderLine.props = ["line", "currency", "onUpdateQuantity", "openOrderLine"];
|
||||
LunchOrderLine.components = {
|
||||
LunchCurrency,
|
||||
};
|
||||
|
||||
export class LunchAlert extends Component {
|
||||
get message() {
|
||||
return markup(this.props.message);
|
||||
}
|
||||
}
|
||||
LunchAlert.props = ["message"];
|
||||
LunchAlert.template = xml`<t t-out="message"/>`
|
||||
|
||||
export class LunchAlerts extends Component {}
|
||||
LunchAlerts.components = {
|
||||
LunchAlert,
|
||||
}
|
||||
LunchAlerts.props = ["alerts"];
|
||||
LunchAlerts.template = 'lunch.LunchAlerts';
|
||||
|
||||
export class LunchUser extends Component {
|
||||
getDomain() {
|
||||
return [['share', '=', false]];
|
||||
}
|
||||
}
|
||||
LunchUser.components = {
|
||||
Many2XAutocomplete,
|
||||
}
|
||||
LunchUser.props = ["username", "isManager", "onUpdateUser"];
|
||||
LunchUser.template = "lunch.LunchUser";
|
||||
|
||||
export class LunchLocation extends Component {
|
||||
getDomain() {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
LunchLocation.components = {
|
||||
Many2XAutocomplete,
|
||||
}
|
||||
LunchLocation.props = ["location", "onUpdateLunchLocation"];
|
||||
LunchLocation.template = "lunch.LunchLocation";
|
||||
|
||||
export class LunchDashboard extends Component {
|
||||
setup() {
|
||||
super.setup();
|
||||
this.rpc = useService("rpc");
|
||||
this.user = useService("user");
|
||||
this.state = useState({
|
||||
infos: {},
|
||||
});
|
||||
|
||||
useBus(this.env.bus, 'lunch_update_dashboard', () => this._fetchLunchInfos());
|
||||
onWillStart(async () => {
|
||||
await this._fetchLunchInfos()
|
||||
this.env.searchModel.updateLocationId(this.state.infos.user_location[0]);
|
||||
});
|
||||
}
|
||||
|
||||
async lunchRpc(route, args = {}) {
|
||||
return await this.rpc(route, {
|
||||
...args,
|
||||
context: this.user.context,
|
||||
user_id: this.env.searchModel.lunchState.userId,
|
||||
})
|
||||
}
|
||||
|
||||
async _fetchLunchInfos() {
|
||||
this.state.infos = await this.lunchRpc('/lunch/infos');
|
||||
}
|
||||
|
||||
async emptyCart() {
|
||||
await this.lunchRpc('/lunch/trash');
|
||||
await this._fetchLunchInfos();
|
||||
}
|
||||
|
||||
get hasLines() {
|
||||
return this.state.infos.lines && this.state.infos.lines.length !== 0;
|
||||
}
|
||||
|
||||
get canOrder() {
|
||||
return this.state.infos.raw_state === 'new';
|
||||
}
|
||||
|
||||
get location() {
|
||||
return this.state.infos.user_location && this.state.infos.user_location[1];
|
||||
}
|
||||
|
||||
async orderNow() {
|
||||
if (!this.canOrder) {
|
||||
return;
|
||||
}
|
||||
|
||||
await this.lunchRpc('/lunch/pay');
|
||||
await this._fetchLunchInfos();
|
||||
}
|
||||
|
||||
async onUpdateQuantity() {
|
||||
await this._fetchLunchInfos();
|
||||
}
|
||||
|
||||
async onUpdateUser(value) {
|
||||
if (!value) {
|
||||
return;
|
||||
}
|
||||
this.env.searchModel.updateUserId(value[0].id);
|
||||
await this._fetchLunchInfos();
|
||||
}
|
||||
|
||||
async onUpdateLunchLocation(value) {
|
||||
if (!value) {
|
||||
return;
|
||||
}
|
||||
|
||||
await this.lunchRpc('/lunch/user_location_set', {
|
||||
location_id: value[0].id,
|
||||
});
|
||||
await this._fetchLunchInfos();
|
||||
this.env.searchModel.updateLocationId(value[0].id);
|
||||
}
|
||||
}
|
||||
LunchDashboard.components = {
|
||||
LunchAlerts,
|
||||
LunchCurrency,
|
||||
LunchLocation,
|
||||
LunchOrderLine,
|
||||
LunchUser,
|
||||
Many2XAutocomplete,
|
||||
};
|
||||
LunchDashboard.props = ["openOrderLine"];
|
||||
LunchDashboard.template = 'lunch.LunchDashboard';
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
.lunch_topping:before {
|
||||
content: '+ ';
|
||||
}
|
||||
|
||||
.o_lunch_content {
|
||||
.o-autocomplete--input {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,142 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<templates id="template" xml:space="preserve">
|
||||
<t t-name="lunch.LunchCurrency" owl="1">
|
||||
<span>
|
||||
<t t-if="props.currency.position == 'before'" t-esc="props.currency.symbol"/>
|
||||
<t t-esc="amount"/>
|
||||
<t t-if="props.currency.position == 'after'" t-esc="props.currency.symbol"/>
|
||||
</span>
|
||||
</t>
|
||||
|
||||
<t t-name="lunch.LunchOrderLine" owl="1">
|
||||
<div class="d-flex align-items-center pe-3">
|
||||
<div class="btn-group">
|
||||
<button class="btn btn-sm btn-icon btn-link fa fa-minus-circle p-0" t-if="canEdit" t-on-click="() => this.updateQuantity(-1)"/>
|
||||
<span t-esc="line.quantity" class="px-2 py-1"/>
|
||||
<button class="btn btn-sm btn-icon btn-link fa fa-plus-circle p-0" t-if="canEdit" t-on-click="() => this.updateQuantity(1)"/>
|
||||
</div>
|
||||
<span class="flex-grow-1 ps-2 text-700">
|
||||
<a t-on-click="() => props.openOrderLine(line.product[0], line.id)" t-if="canEdit" role="button" title="Edit order">
|
||||
<t t-esc="line.product[1]"/>
|
||||
</a>
|
||||
<t t-else="" t-esc="line.product[1]"/>
|
||||
<span t-esc="line.state" t-attf-class="badge ms-2 rounded-pill text-bg-#{badgeClass} border-#{badgeClass} "/>
|
||||
</span>
|
||||
<LunchCurrency currency="props.currency" amount="line.product[2]"/>
|
||||
</div>
|
||||
<ul t-if="hasToppings" class="list-unstyled ps-4">
|
||||
<li t-foreach="line.toppings" t-as="topping" t-key="topping" class="d-flex pe-3">
|
||||
<span class="flex-grow-1 lunch_topping" t-esc="topping[0]"/>
|
||||
<LunchCurrency currency="props.currency" amount="topping[1]"/>
|
||||
</li>
|
||||
</ul>
|
||||
<div t-if="line.note" t-esc="line.note" class="text-muted ps-4"/>
|
||||
</t>
|
||||
|
||||
<t t-name="lunch.LunchAlerts" owl="1">
|
||||
<div class="alert alert-warning mb-0" t-if="props.alerts.length !== 0" role="alert">
|
||||
<t t-foreach="props.alerts" t-as="alert" t-key="alert.id">
|
||||
<LunchAlert message="alert.message" />
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="lunch.LunchUser" owl="1">
|
||||
<div class="lunch_user pb-1">
|
||||
<span t-if="!props.isManager" t-esc="props.username"/>
|
||||
<Many2XAutocomplete
|
||||
t-else=""
|
||||
value="props.username"
|
||||
resModel="'res.users'"
|
||||
getDomain="getDomain"
|
||||
activeActions="{}"
|
||||
update.bind="props.onUpdateUser"
|
||||
/>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="lunch.LunchLocation" owl="1">
|
||||
<div class="lunch_location pb-1">
|
||||
<t t-if="props.location">
|
||||
<Many2XAutocomplete
|
||||
value="props.location"
|
||||
resModel="'lunch.location'"
|
||||
getDomain="getDomain"
|
||||
activeActions="{}"
|
||||
update.bind="props.onUpdateLunchLocation"
|
||||
/>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<p>No lunch location available.</p>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="lunch.LunchDashboardOrder" owl="1">
|
||||
<LunchAlerts alerts="state.infos.alerts"/>
|
||||
|
||||
<div class="o_lunch_banner container-fluid p-4 border-bottom bg-view">
|
||||
<div class="row h-100">
|
||||
<div class="col-12 col-md-4">
|
||||
<div class="row h-100 align-content-center">
|
||||
<div class="col-3">
|
||||
<img class="o_image_64_cover rounded-circle" t-att-src="state.infos.userimage"/>
|
||||
</div>
|
||||
<div class="col-9">
|
||||
<LunchUser
|
||||
isManager="state.infos.is_manager"
|
||||
username="state.infos.username"
|
||||
onUpdateUser.bind="onUpdateUser"/>
|
||||
|
||||
<LunchLocation
|
||||
location="location"
|
||||
onUpdateLunchLocation.bind="onUpdateLunchLocation"/>
|
||||
|
||||
<div class="d-flex pb-1">
|
||||
<span class="flex-grow-1">Your Account</span>
|
||||
<LunchCurrency currency="currency" amount="state.infos.wallet"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-md-5" t-if="hasLines">
|
||||
<h4 class="mb-0">
|
||||
Your Order
|
||||
<button t-if="state.infos.raw_state != 'confirmed'" class="btn btn-sm btn-icon btn-link fa fa-trash" t-on-click.prevent="emptyCart"/>
|
||||
</h4>
|
||||
<ul class="o_lunch_widget_lines overflow-auto list-unstyled">
|
||||
<li t-foreach="state.infos.lines" t-as="line" t-key="line.id">
|
||||
<LunchOrderLine line="line" currency="currency" onUpdateQuantity.bind="onUpdateQuantity" openOrderLine.bind="props.openOrderLine"/>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-12 col-md-3 d-flex flex-column justify-content-between" t-if="hasLines">
|
||||
<h4 class="d-flex flex-row mt-1">
|
||||
<span class="flex-grow-1">
|
||||
Total
|
||||
</span>
|
||||
<LunchCurrency currency="currency" amount="state.infos.total"/>
|
||||
</h4>
|
||||
<button class="btn btn-primary" t-if="canOrder" t-on-click="orderNow">Order Now</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="lunch.LunchDashboard" owl="1">
|
||||
<t t-set="currency" t-value="state.infos.currency"/>
|
||||
<t t-if="!env.isSmall">
|
||||
<t t-call="lunch.LunchDashboardOrder"/>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<details class="fixed-bottom bg-view p-2" t-att-open="state.mobileOpen">
|
||||
<summary class="btn btn-primary w-100" t-on-click="() => state.mobileOpen = !state.mobileOpen">
|
||||
<i class="fa fa-fw fa-shopping-cart"/>
|
||||
Your Cart (<LunchCurrency currency="currency" amount="state.infos.total || 0"/>)
|
||||
</summary>
|
||||
|
||||
<t t-call="lunch.LunchDashboardOrder"/>
|
||||
</details>
|
||||
</t>
|
||||
</t>
|
||||
</templates>
|
||||
Loading…
Add table
Add a link
Reference in a new issue