forked from alaguraj/odoo-testing-addons
new fix updated
This commit is contained in:
parent
bdea15d7f0
commit
c29a74a41b
@ -1,74 +1,55 @@
|
||||
/** @odoo-module */
|
||||
|
||||
import { SplitBillScreen } from "@pos_restaurant/overrides/components/split_bill_screen/split_bill_screen";
|
||||
import { patch } from "@web/core/utils/patch";
|
||||
import { useState } from "@odoo/owl";
|
||||
import { registry } from "@web/core/registry";
|
||||
import { usePos } from "@point_of_sale/app/store/pos_hook";
|
||||
import { Component, useState } from "@odoo/owl";
|
||||
|
||||
export class EqualSplitScreen extends Component {
|
||||
static template = "dine360_restaurant.EqualSplitScreen";
|
||||
|
||||
patch(SplitBillScreen.prototype, {
|
||||
setup() {
|
||||
super.setup(...arguments);
|
||||
this.equalSplit = useState({
|
||||
active: false,
|
||||
numPeople: 2,
|
||||
});
|
||||
},
|
||||
|
||||
toggleEqualSplit() {
|
||||
this.equalSplit.active = !this.equalSplit.active;
|
||||
},
|
||||
|
||||
decreasePeople() {
|
||||
if (this.equalSplit.numPeople > 2) {
|
||||
this.equalSplit.numPeople--;
|
||||
this.pos = usePos();
|
||||
this.state = useState({ numPeople: 2 });
|
||||
}
|
||||
},
|
||||
|
||||
increasePeople() {
|
||||
if (this.equalSplit.numPeople < 20) {
|
||||
this.equalSplit.numPeople++;
|
||||
get order() {
|
||||
return this.pos.get_order();
|
||||
}
|
||||
},
|
||||
|
||||
get equalAmountPerPerson() {
|
||||
const order = this.pos.get_order();
|
||||
if (!order || this.equalSplit.numPeople < 1) return 0;
|
||||
return order.getTotalWithTax() / this.equalSplit.numPeople;
|
||||
},
|
||||
get formattedTotal() {
|
||||
const order = this.order;
|
||||
return this.env.utils.formatCurrency(order ? order.getTotalWithTax() : 0);
|
||||
}
|
||||
|
||||
get formattedEqualAmount() {
|
||||
return this.env.utils.formatCurrency(this.equalAmountPerPerson);
|
||||
},
|
||||
|
||||
get formattedOrderTotal() {
|
||||
const order = this.pos.get_order();
|
||||
if (!order) return this.env.utils.formatCurrency(0);
|
||||
return this.env.utils.formatCurrency(order.getTotalWithTax());
|
||||
},
|
||||
|
||||
// Intercept pay() to auto-assign proportional lines when equal split is active
|
||||
async pay() {
|
||||
if (this.equalSplit.active) {
|
||||
await this._payEqualSplit();
|
||||
} else {
|
||||
await super.pay(...arguments);
|
||||
const order = this.order;
|
||||
if (!order || this.state.numPeople < 1) return this.env.utils.formatCurrency(0);
|
||||
return this.env.utils.formatCurrency(order.getTotalWithTax() / this.state.numPeople);
|
||||
}
|
||||
},
|
||||
|
||||
async _payEqualSplit() {
|
||||
const order = this.pos.get_order();
|
||||
decreasePeople() {
|
||||
if (this.state.numPeople > 2) this.state.numPeople--;
|
||||
}
|
||||
|
||||
increasePeople() {
|
||||
if (this.state.numPeople < 20) this.state.numPeople++;
|
||||
}
|
||||
|
||||
back() {
|
||||
this.pos.showScreen("SplitBillScreen");
|
||||
}
|
||||
|
||||
async chargeCurrentPerson() {
|
||||
const order = this.order;
|
||||
if (!order) return;
|
||||
|
||||
const lines = order.get_orderlines();
|
||||
if (lines.length === 0) return;
|
||||
|
||||
const N = this.equalSplit.numPeople;
|
||||
const N = this.state.numPeople;
|
||||
const total = order.getTotalWithTax();
|
||||
const target = Math.round((total / N) * 100) / 100;
|
||||
|
||||
const lines = order.get_orderlines();
|
||||
const splitlines = {};
|
||||
let accumulated = 0;
|
||||
const splitData = {};
|
||||
|
||||
// Greedy fill: assign lines until we reach the per-person target amount
|
||||
for (const line of lines) {
|
||||
if (accumulated >= target - 0.005) break;
|
||||
|
||||
@ -79,53 +60,27 @@ patch(SplitBillScreen.prototype, {
|
||||
const needed = target - accumulated;
|
||||
|
||||
if (lineTotal <= needed + 0.005) {
|
||||
// Take the full line
|
||||
splitData[line.uid] = line.qty;
|
||||
splitlines[line.uid] = line.qty;
|
||||
accumulated += lineTotal;
|
||||
} else {
|
||||
// Take a partial quantity to fill up to target
|
||||
const qtyToTake = Math.round((needed / perUnit) * 1000) / 1000;
|
||||
if (qtyToTake > 0.001) {
|
||||
splitData[line.uid] = qtyToTake;
|
||||
splitlines[line.uid] = qtyToTake;
|
||||
accumulated += qtyToTake * perUnit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Write into whichever splitlines object the screen uses
|
||||
this._setSplitlines(splitData);
|
||||
|
||||
await super.pay(...arguments);
|
||||
},
|
||||
if (typeof this.pos.splitOrder === "function") {
|
||||
await this.pos.splitOrder(order, splitlines);
|
||||
}
|
||||
this.pos.showScreen("PaymentScreen");
|
||||
}
|
||||
|
||||
_getLineTotal(line) {
|
||||
// Try the standard Odoo 17 method, fall back to price * qty
|
||||
if (typeof line.get_price_with_tax === "function") {
|
||||
return line.get_price_with_tax();
|
||||
}
|
||||
if (typeof line.getDisplayData === "function") {
|
||||
const d = line.getDisplayData();
|
||||
return d.totalPrice || line.price * line.qty;
|
||||
}
|
||||
if (typeof line.get_price_with_tax === "function") return line.get_price_with_tax();
|
||||
return (line.price || 0) * (line.qty || 1);
|
||||
},
|
||||
|
||||
_setSplitlines(newLines) {
|
||||
// Odoo 17 may store splitlines on this.splitlines or this.state.splitlines
|
||||
const target =
|
||||
this.splitlines !== undefined
|
||||
? this.splitlines
|
||||
: this.state && this.state.splitlines !== undefined
|
||||
? this.state.splitlines
|
||||
: null;
|
||||
|
||||
if (!target) return;
|
||||
|
||||
for (const key of Object.keys(target)) {
|
||||
delete target[key];
|
||||
}
|
||||
for (const [uid, qty] of Object.entries(newLines)) {
|
||||
target[uid] = qty;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
registry.category("pos_screens").add("EqualSplitScreen", EqualSplitScreen);
|
||||
|
||||
@ -1,79 +1,85 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<templates id="template" xml:space="preserve">
|
||||
|
||||
<!--
|
||||
Extends the pos_restaurant SplitBillScreen to add an "Equal Split" panel.
|
||||
The panel is injected at the top of the screen via xpath on the root div.
|
||||
Cashier picks the number of people → presses "Charge" → the system
|
||||
auto-assigns proportional items to the split order and navigates to payment.
|
||||
-->
|
||||
<t t-name="dine360_restaurant.EqualSplitPatch"
|
||||
t-inherit="pos_restaurant.SplitBillScreen"
|
||||
t-inherit-mode="extension"
|
||||
owl="1">
|
||||
<!-- Standalone Equal Split screen — no SplitBillScreen import needed -->
|
||||
<t t-name="dine360_restaurant.EqualSplitScreen" owl="1">
|
||||
<div class="equal-split-screen screen d-flex flex-column h-100">
|
||||
|
||||
<xpath expr="//div[hasclass('split-bill-screen')]" position="prepend">
|
||||
|
||||
<!-- Toggle bar — always visible at the top of the split screen -->
|
||||
<div class="equal-split-toggle-bar d-flex align-items-center justify-content-between px-3 py-2 border-bottom bg-light">
|
||||
<span class="fw-semibold text-muted small">
|
||||
<i class="fa fa-cut me-1"/>By Item
|
||||
</span>
|
||||
<button
|
||||
t-attf-class="btn btn-sm equal-split-toggle-btn {{ equalSplit.active ? 'btn-primary' : 'btn-outline-primary' }}"
|
||||
t-on-click="toggleEqualSplit">
|
||||
<i class="fa fa-users me-1"/>
|
||||
Equal Split
|
||||
<i t-attf-class="fa ms-1 {{ equalSplit.active ? 'fa-chevron-up' : 'fa-chevron-down' }}"/>
|
||||
<!-- Header -->
|
||||
<div class="d-flex align-items-center px-3 py-3 border-bottom bg-light">
|
||||
<button class="btn btn-secondary me-3" t-on-click="back">
|
||||
<i class="fa fa-arrow-left me-1"/>Back to Split
|
||||
</button>
|
||||
<h4 class="mb-0 fw-bold">
|
||||
<i class="fa fa-users me-2"/>Equal Split
|
||||
</h4>
|
||||
</div>
|
||||
|
||||
<!-- Equal Split panel — shown only when toggled on -->
|
||||
<div t-if="equalSplit.active" class="equal-split-panel d-flex flex-column align-items-center gap-3 p-4 border-bottom bg-white shadow-sm">
|
||||
<!-- Body -->
|
||||
<div class="d-flex flex-column align-items-center justify-content-center flex-grow-1 gap-4 p-4">
|
||||
|
||||
<!-- Order total reference -->
|
||||
<div class="text-muted small">
|
||||
Order Total: <strong t-esc="formattedOrderTotal"/>
|
||||
<div class="text-muted fs-6">
|
||||
Order Total: <strong t-esc="formattedTotal"/>
|
||||
</div>
|
||||
|
||||
<!-- People counter -->
|
||||
<div class="d-flex align-items-center gap-3">
|
||||
<button
|
||||
class="btn btn-outline-secondary btn-lg equal-split-counter-btn"
|
||||
<div class="d-flex align-items-center gap-4">
|
||||
<button class="btn btn-outline-secondary equal-split-counter-btn"
|
||||
t-on-click="decreasePeople"
|
||||
t-att-disabled="equalSplit.numPeople <= 2">
|
||||
t-att-disabled="state.numPeople <= 2">
|
||||
<i class="fa fa-minus"/>
|
||||
</button>
|
||||
|
||||
<div class="text-center equal-split-count-display">
|
||||
<div class="equal-split-count-number fw-bold" t-esc="equalSplit.numPeople"/>
|
||||
<div class="text-center">
|
||||
<div class="equal-split-count-number fw-bold" t-esc="state.numPeople"/>
|
||||
<div class="text-muted small">people</div>
|
||||
</div>
|
||||
|
||||
<button
|
||||
class="btn btn-outline-secondary btn-lg equal-split-counter-btn"
|
||||
<button class="btn btn-outline-secondary equal-split-counter-btn"
|
||||
t-on-click="increasePeople"
|
||||
t-att-disabled="equalSplit.numPeople >= 20">
|
||||
t-att-disabled="state.numPeople >= 20">
|
||||
<i class="fa fa-plus"/>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Per-person amount -->
|
||||
<div class="equal-split-amount-box text-center p-3 rounded">
|
||||
<div class="text-muted small mb-1">Each person pays</div>
|
||||
<div class="equal-split-amount-box text-center p-4 rounded">
|
||||
<div class="text-muted mb-1 small">Each person pays</div>
|
||||
<div class="equal-split-amount fw-bold" t-esc="formattedEqualAmount"/>
|
||||
</div>
|
||||
|
||||
<div class="text-muted small text-center">
|
||||
<!-- Charge button -->
|
||||
<button class="btn btn-primary btn-lg px-5" t-on-click="chargeCurrentPerson">
|
||||
<i class="fa fa-credit-card me-2"/>Charge This Person
|
||||
</button>
|
||||
|
||||
<div class="text-muted small text-center" style="max-width: 320px;">
|
||||
<i class="fa fa-info-circle me-1"/>
|
||||
Press <strong>Charge</strong> to collect from the first person.
|
||||
Repeat for each person.
|
||||
After payment, return to the table and press Split again.
|
||||
Decrease the count by 1 each time.
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<!-- Inject "Equal Split" button at the top of the standard SplitBillScreen -->
|
||||
<t t-name="dine360_restaurant.EqualSplitButton"
|
||||
t-inherit="pos_restaurant.SplitBillScreen"
|
||||
t-inherit-mode="extension"
|
||||
owl="1">
|
||||
<xpath expr="//div[hasclass('split-bill-screen')]" position="prepend">
|
||||
<div class="equal-split-toggle-bar d-flex align-items-center justify-content-between px-3 py-2 border-bottom">
|
||||
<span class="fw-semibold text-muted small">
|
||||
<i class="fa fa-cut me-1"/>Split By Item
|
||||
</span>
|
||||
<button class="btn btn-sm btn-primary"
|
||||
t-on-click="() => pos.showScreen('EqualSplitScreen')">
|
||||
<i class="fa fa-users me-1"/>Equal Split
|
||||
</button>
|
||||
</div>
|
||||
</xpath>
|
||||
|
||||
</t>
|
||||
|
||||
</templates>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user