[IMP] pos_self_order,pos_online_payment_self_order: improve success page
Before, when ordering on the kiosk/mobile, no confirmation page was displayed, only a notification. Now, a confirmation page displays the tracking number, the amount paid and, if present, the customer's table... Part-of: odoo/odoo#138013
This commit is contained in:
+1
-1
@@ -31,7 +31,7 @@ patch(OrderWidget.prototype, {
|
||||
} else {
|
||||
return {
|
||||
label: _t("Pay at cashier"),
|
||||
disabled: this.router.activeSlot !== "product_list",
|
||||
disabled: false,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,26 +19,35 @@ patch(CartPage.prototype, {
|
||||
const service = this.selfOrder.config.self_ordering_service_mode;
|
||||
const takeAway = this.selfOrder.currentOrder.take_away;
|
||||
|
||||
if (this.sendInProgress) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.selfOrder.table && service === "table" && !takeAway) {
|
||||
this.state.selectTable = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (mode === "meal" && isOnlinePayment) {
|
||||
if (mode === "meal" && isOnlinePayment && order.isSavedOnServer) {
|
||||
if (!order) {
|
||||
this.selfOrder.notification.add(_t("The current order is invalid."), {
|
||||
type: "danger",
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (!order.isSavedOnServer) {
|
||||
this.sendInProgress = true;
|
||||
await this.selfOrder.sendDraftOrderToServer();
|
||||
this.sendInProgress = false;
|
||||
} else {
|
||||
this.checkAndOpenPaymentPage(order);
|
||||
}
|
||||
|
||||
this.checkAndOpenPaymentPage(order);
|
||||
} else if (mode === "meal" && !isOnlinePayment && order.isSavedOnServer) {
|
||||
this.router.navigate("confirmation", {
|
||||
orderAccessToken: order.access_token,
|
||||
screenMode: "pay",
|
||||
});
|
||||
return;
|
||||
} else if (mode === "each") {
|
||||
this.sendInProgress = true;
|
||||
const order = await this.selfOrder.sendDraftOrderToServer();
|
||||
this.sendInProgress = false;
|
||||
|
||||
this.checkAndOpenPaymentPage(order);
|
||||
} else {
|
||||
return super.pay(...arguments);
|
||||
@@ -50,10 +59,11 @@ patch(CartPage.prototype, {
|
||||
if (order) {
|
||||
if (order.state === "draft") {
|
||||
if (!isOnlinePayment) {
|
||||
this.selfOrder.notification.add(
|
||||
_t("The current order cannot be paid (no online payment method)."),
|
||||
{ type: "danger" }
|
||||
);
|
||||
// if no payment method is available -> pay at cashier
|
||||
this.router.navigate("confirmation", {
|
||||
orderAccessToken: order.access_token,
|
||||
screenMode: "pay",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,12 +10,20 @@ patch(SelfOrder.prototype, {
|
||||
pos_config_id: order_pos_config_id,
|
||||
}) {
|
||||
const baseUrl = session.base_url;
|
||||
let exitRouteUrl =
|
||||
baseUrl + "/pos-self/" + order_pos_config_id + "?access_token=" + this.access_token;
|
||||
const order = this.currentOrder;
|
||||
const tableIdentifier = this.table?.identifier;
|
||||
if (tableIdentifier) {
|
||||
exitRouteUrl += "&table_identifier=" + tableIdentifier;
|
||||
let exitRouteUrl = `${baseUrl}/pos-self/${order_pos_config_id}`;
|
||||
|
||||
if (this.config.self_ordering_pay_after === "each") {
|
||||
exitRouteUrl += `/confirmation/${order.access_token}/order`;
|
||||
}
|
||||
|
||||
exitRouteUrl += `?access_token=${this.access_token}`;
|
||||
|
||||
if (tableIdentifier) {
|
||||
exitRouteUrl += `&table_identifier=${tableIdentifier}`;
|
||||
}
|
||||
|
||||
const exitRoute = encodeURIComponent(exitRouteUrl);
|
||||
window.open(
|
||||
baseUrl +
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<xpath expr="//div[@id='self-payment-after']" position="after">
|
||||
<div class="content-group row" invisible="not pos_self_ordering_mode == 'mobile'">
|
||||
<label string="Online Payment" for="pos_self_order_online_payment_method_id" class="col-lg-4" />
|
||||
<field name="pos_self_order_online_payment_method_id" placeholder="Select a payment method" />
|
||||
<field name="pos_self_order_online_payment_method_id" placeholder="Pay at cashier if empty" />
|
||||
</div>
|
||||
<div class="d-flex flex-column align-items-start w-50" invisible="not pos_self_ordering_mode == 'mobile' and not pos_self_ordering_pay_after == 'each'">
|
||||
<button name="%(point_of_sale.action_payment_methods_tree)d" icon="oi-arrow-right" type="action" string="Payment Methods" class="btn-link" />
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
<data noupdate="1">
|
||||
<record id="pos_restaurant.pos_config_main_restaurant" model="pos.config">
|
||||
<field name="self_ordering_mode">mobile</field>
|
||||
<field name="self_ordering_service_mode">table</field>
|
||||
<field name="self_ordering_pay_after">meal</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
<data noupdate="1">
|
||||
<record id="pos_restaurant.pos_config_main_restaurant" model="pos.config">
|
||||
<field name="self_ordering_mode">mobile</field>
|
||||
<field name="self_ordering_service_mode">table</field>
|
||||
<field name="self_ordering_pay_after">meal</field>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
|
||||
@@ -153,6 +153,9 @@ class PosConfig(models.Model):
|
||||
if (not vals.get('module_pos_restaurant') and not record.module_pos_restaurant) and vals.get('self_ordering_mode') == 'mobile':
|
||||
vals['self_ordering_pay_after'] = 'each'
|
||||
|
||||
if (vals.get('self_ordering_service_mode') == 'counter' or record.self_ordering_service_mode == 'counter') and vals.get('self_ordering_mode') == 'mobile':
|
||||
vals['self_ordering_pay_after'] = 'each'
|
||||
|
||||
if 'self_ordering_image_home_ids' in vals and self.env.context.get('from_settings_view'):
|
||||
linked_ids = set(record.self_ordering_image_home_ids.ids)
|
||||
|
||||
@@ -172,9 +175,6 @@ class PosConfig(models.Model):
|
||||
|
||||
if vals.get('self_ordering_mode') == 'mobile' and vals.get('self_ordering_pay_after') == 'meal':
|
||||
vals['self_ordering_service_mode'] = 'table'
|
||||
|
||||
if (vals.get('self_ordering_service_mode') == 'counter' or record.self_ordering_service_mode == 'counter') and vals.get('self_ordering_mode') == 'mobile':
|
||||
vals['self_ordering_pay_after'] = 'each'
|
||||
return super().write(vals)
|
||||
|
||||
@api.depends("module_pos_restaurant")
|
||||
|
||||
@@ -20,7 +20,11 @@ class RestaurantTable(models.Model):
|
||||
|
||||
def _get_self_order_data(self) -> Dict:
|
||||
self.ensure_one()
|
||||
return self.read(["name", "identifier"])[0]
|
||||
return {
|
||||
'name': self.name,
|
||||
'identifier': self.identifier,
|
||||
'floor_name': self.floor_id.name
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def _get_identifier():
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
/** @odoo-module */
|
||||
|
||||
import { Component } from "@odoo/owl";
|
||||
import { useSelfOrder } from "@pos_self_order/app/self_order_service";
|
||||
|
||||
export class CancelPopup extends Component {
|
||||
static template = "pos_self_order.CancelPopup";
|
||||
|
||||
setup() {
|
||||
this.selfOrder = useSelfOrder();
|
||||
}
|
||||
|
||||
confirm() {
|
||||
this.props.close();
|
||||
this.props.confirm();
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
<div class="modal-body p-5">
|
||||
<div class="pb-5 fs-3 text-center">
|
||||
Are you sure you want to cancel this order? <br/>
|
||||
<span class="text-muted fs-4">All the items will be removed from the cart.</span>
|
||||
<span t-if="selfOrder.config.self_ordering_mode === 'kiosk'" class="text-muted fs-4">All the items will be removed from the cart.</span>
|
||||
<span t-else="" class="text-muted fs-4">Any items already sent will not be canceled</span>
|
||||
</div>
|
||||
<div class="d-flex align-items-center justify-content-center w-100 gap-3">
|
||||
<button type="button" class="btn btn-primary btn-lg popup_button" t-on-click="() => this.confirm()">Cancel Order</button>
|
||||
|
||||
@@ -90,4 +90,36 @@ export class OrderWidget extends Component {
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
get leftButtonName() {
|
||||
const order = this.selfOrder.currentOrder;
|
||||
const back =
|
||||
order.isSavedOnServer || this.router.activeSlot === "cart" || order.lines.length === 0;
|
||||
|
||||
return {
|
||||
name: back ? _t("Back") : _t("Cancel"),
|
||||
icon: back ? "fa fa-arrow-left" : "btn-close",
|
||||
};
|
||||
}
|
||||
|
||||
leftButton() {
|
||||
const order = this.selfOrder.currentOrder;
|
||||
|
||||
if (
|
||||
order.lines.length === 0 ||
|
||||
order.isSavedOnServer ||
|
||||
this.router.activeSlot === "cart"
|
||||
) {
|
||||
this.router.back();
|
||||
return;
|
||||
} else {
|
||||
this.dialog.add(CancelPopup, {
|
||||
title: _t("Cancel order"),
|
||||
confirm: () => {
|
||||
this.selfOrder.cancelOrder();
|
||||
this.router.navigate("default");
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,12 +6,10 @@
|
||||
t-att-class="{
|
||||
'shadow-lg border-top' : !props.removeTopClasses
|
||||
}">
|
||||
<button t-attf-class="btn btn-secondary btn-lg btn-close h-auto w-auto opacity-75 px-4 d-sm-none {{ cancelAvailable ? '' : 'd-none' }}" t-on-click="cancel">
|
||||
<button t-attf-class="btn btn-secondary btn-lg h-auto w-auto opacity-75 px-4 d-sm-none" t-att-class="leftButtonName.icon" t-on-click="leftButton">
|
||||
<span class="px-1"/><!-- Spacer -->
|
||||
</button>
|
||||
<button t-attf-class="btn btn-secondary btn-lg d-none d-sm-inline text-nowrap {{ cancelAvailable ? '' : 'd-none' }}" t-on-click="cancel">
|
||||
Cancel Order
|
||||
</button>
|
||||
<button t-attf-class="btn btn-secondary btn-lg d-none d-sm-inline text-nowrap" t-on-click="leftButton" t-esc="leftButtonName.name" />
|
||||
<div class="d-flex align-items-center flex-grow-1 w-100 w-md-auto">
|
||||
<div class="to-order">
|
||||
<span t-if="!this.selfOrder.currentOrder.isSavedOnServer">To Order</span>
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
<div class="self_order_popup_table shadow-lg position-absolute fixed-bottom bg-white w-100 p-4 flex-column d-flex justify-content-between">
|
||||
<div class="mb-5 d-flex justify-content-between align-items-start">
|
||||
<div>
|
||||
<h3>Confirm your table</h3>
|
||||
<span>to place the order</span>
|
||||
<h3>Table detective time!</h3>
|
||||
<span>Could you please confirm your table number?<br/>Thanks a lot!</span>
|
||||
</div>
|
||||
<button class="btn btn-close" t-on-click="close"/>
|
||||
</div>
|
||||
|
||||
@@ -71,11 +71,14 @@ export class CartPage extends Component {
|
||||
if (mode === "meal" && !order.isSavedOnServer) {
|
||||
this.sendInProgress = true;
|
||||
await this.selfOrder.sendDraftOrderToServer();
|
||||
this.sendInProgress = false;
|
||||
|
||||
if (type !== "kiosk") {
|
||||
this.router.navigate("confirmation", {
|
||||
orderAccessToken: order.access_token,
|
||||
screenMode: "order",
|
||||
});
|
||||
return;
|
||||
}
|
||||
this.sendInProgress = false;
|
||||
}
|
||||
if (orderingMode === "table" && !takeAway) {
|
||||
if (type === "kiosk") {
|
||||
@@ -95,10 +98,7 @@ export class CartPage extends Component {
|
||||
}
|
||||
|
||||
this.state.selectTable = false;
|
||||
|
||||
if (this.selfOrder.config.self_ordering_pay_after === "each") {
|
||||
this.pay();
|
||||
}
|
||||
this.pay();
|
||||
}
|
||||
|
||||
getChildLines(line) {
|
||||
|
||||
@@ -2,12 +2,8 @@
|
||||
<templates id="template" xml:space="preserve">
|
||||
<t t-name="pos_self_order.CartPage">
|
||||
<div class="order-cart-content d-flex flex-column flex-grow-1 justify-content-between overflow-y-auto">
|
||||
<div class="d-flex align-items-center flex-shrink-0 justify-content-between gap-3 px-3 py-2 w-100 bg-view border-bottom overflow-x-auto z-index-1">
|
||||
<button class="btn btn-secondary btn-lg px-3 text-nowrap" t-on-click="() => this.router.back()">
|
||||
<i class="oi oi-chevron-left" aria-hidden="true"/><span class="ms-2 d-none d-md-inline">Back</span>
|
||||
</button>
|
||||
<div class="d-flex align-items-center flex-shrink-0 justify-content-between gap-3 p-3 w-100 bg-view border-bottom overflow-x-auto z-index-1">
|
||||
<h1 class="mb-0 fw-bolder text-nowrap">Your Order</h1>
|
||||
<span class="d-none d-md-inline px-5"/> <!-- Spacer -->
|
||||
</div>
|
||||
<div class="order-content flex-grow-1 overflow-auto pb-4">
|
||||
<t t-foreach="linesToDisplay" t-as="line" t-key="line.uuid">
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
/** @odoo-module */
|
||||
|
||||
import { Component, onMounted, useState } from "@odoo/owl";
|
||||
import { useSelfOrder } from "@pos_self_order/app/self_order_service";
|
||||
import { cookie } from "@web/core/browser/cookie";
|
||||
import { useService } from "@web/core/utils/hooks";
|
||||
|
||||
export class ConfirmationPage extends Component {
|
||||
static template = "pos_self_order.ConfirmationPage";
|
||||
static props = ["orderAccessToken", "screenMode"];
|
||||
|
||||
setup() {
|
||||
this.selfOrder = useSelfOrder();
|
||||
this.router = useService("router");
|
||||
this.confirmedOrder = {};
|
||||
this.changeToDisplay = [];
|
||||
this.state = useState({
|
||||
onReload: false,
|
||||
payment: this.props.screenMode === "pay",
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
if (this.selfOrder.config.self_ordering_mode === "kiosk") {
|
||||
setTimeout(() => {
|
||||
this.setDefautLanguage();
|
||||
}, 5000);
|
||||
}
|
||||
});
|
||||
|
||||
this.initOrder();
|
||||
}
|
||||
|
||||
async initOrder() {
|
||||
const order = this.selfOrder.orders.find(
|
||||
(o) => o.access_token === this.props.orderAccessToken
|
||||
);
|
||||
|
||||
const paymentMethods = this.selfOrder.pos_payment_methods.filter(
|
||||
(p) => p.is_online_payment
|
||||
);
|
||||
|
||||
if (
|
||||
!order ||
|
||||
(paymentMethods.length > 0 &&
|
||||
this.selfOrder.config.self_ordering_mode === "mobile" &&
|
||||
this.selfOrder.config.self_ordering_pay_after === "each" &&
|
||||
order.state !== "paid")
|
||||
) {
|
||||
this.router.navigate("default");
|
||||
return;
|
||||
}
|
||||
|
||||
this.confirmedOrder = order;
|
||||
}
|
||||
|
||||
backToHome() {
|
||||
if (!this.setDefautLanguage()) {
|
||||
this.router.navigate("default");
|
||||
}
|
||||
}
|
||||
|
||||
setDefautLanguage() {
|
||||
const defaultLanguage = this.selfOrder.config.self_ordering_default_language_id;
|
||||
|
||||
if (
|
||||
this.selfOrder.currentLanguage.code !== defaultLanguage.code &&
|
||||
!this.state.onReload &&
|
||||
this.selfOrder.config.self_ordering_mode === "kiosk"
|
||||
) {
|
||||
cookie.set("frontend_lang", defaultLanguage.code);
|
||||
window.location.reload();
|
||||
this.state.onReload = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return this.state.onReload;
|
||||
}
|
||||
|
||||
get showPayMessage() {
|
||||
const config = this.selfOrder.config;
|
||||
const paymentMethods = this.selfOrder.pos_payment_methods.filter((p) =>
|
||||
config.self_ordering_mode === "mobile" ? p.is_online_payment : !p.is_online_payment
|
||||
);
|
||||
|
||||
return paymentMethods.length === 0 && config.self_ordering_pay_after === "each";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<templates id="template" xml:space="preserve">
|
||||
<t t-name="pos_self_order.ConfirmationPage">
|
||||
<div t-if="this.state.onReload" class="self_order_success_loader position-absolute vh-100 w-100 d-flex justify-content-center align-items-center opacity-50 bg-dark">
|
||||
<div class="page-loader d-flex justify-content-center align-items-center">
|
||||
<div class="spinner-border text-primary" role="status">
|
||||
<span class="visually-hidden">Loading...</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex justify-content-center align-items-center flex-column h-100 px-3 text-center">
|
||||
<h1 t-if="state.payment and selfOrder.config.self_ordering_pay_after !== 'each'" class="mb-4">Hope you enjoyed your meal!</h1>
|
||||
<h1 t-else="" class="mb-4">We're preparing your order!</h1>
|
||||
<h3 t-if="state.payment" class="mt-3 text-muted">Pay at the cashier <t t-esc="selfOrder.formatMonetary(confirmedOrder.amount_total)" /></h3>
|
||||
<div class="d-inline-flex flex-column border rounded py-4 px-5 bg-view mb-3">
|
||||
<span class="fs-2 text-muted">Your tracking number</span>
|
||||
<span class="number lh-1" t-esc="confirmedOrder.trackingNumber" />
|
||||
</div>
|
||||
<h3 t-if="selfOrder.table.name || confirmedOrder.table_stand_number" class="text-muted mb-3">
|
||||
Service at table
|
||||
<t t-if="selfOrder.config.self_ordering_mode === 'mobile'" t-esc="selfOrder.table.name + ' (' + selfOrder.table.floor_name + ')'" />
|
||||
<t t-else="" t-esc="selfOrder.tablePadNumber" />
|
||||
</h3>
|
||||
<h3 t-else="">Order to pick-up at the counter</h3>
|
||||
</div>
|
||||
<div class="px-3 py-4 text-center">
|
||||
<button class="btn btn-primary btn-lg" t-on-click="backToHome">
|
||||
<t t-if="this.selfOrder.config.self_ordering_mode === 'kiosk'">Close</t>
|
||||
<t t-else="">Ok</t>
|
||||
</button>
|
||||
</div>
|
||||
</t>
|
||||
</templates>
|
||||
@@ -57,6 +57,29 @@ export class LandingPage extends Component {
|
||||
return "";
|
||||
}
|
||||
|
||||
get draftOrder() {
|
||||
return this.selfOrder.orders.filter((o) => o.access_token && o.state === "draft");
|
||||
}
|
||||
|
||||
hideBtn(link) {
|
||||
const arrayLink = link.url.split("/");
|
||||
const routeName = arrayLink[arrayLink.length - 1];
|
||||
|
||||
if (routeName !== "products") {
|
||||
return;
|
||||
}
|
||||
|
||||
return (
|
||||
routeName === "products" &&
|
||||
this.draftOrder.length > 0 &&
|
||||
this.selfOrder.config.self_ordering_pay_after === "each"
|
||||
);
|
||||
}
|
||||
|
||||
clickMyOrder() {
|
||||
this.router.navigate(this.draftOrder.length > 0 ? "cart" : "orderHistory");
|
||||
}
|
||||
|
||||
clickCustomLink(link) {
|
||||
const arrayLink = link.url.split("/");
|
||||
const routeName = arrayLink[arrayLink.length - 1];
|
||||
|
||||
@@ -22,9 +22,14 @@
|
||||
<t t-if="showMyOrderBtn()">
|
||||
<a
|
||||
type="button"
|
||||
t-on-click="() => this.router.navigate('orderHistory')"
|
||||
t-on-click="clickMyOrder"
|
||||
class="btn btn-lg btn-primary">
|
||||
My Orders
|
||||
<t t-if="draftOrder.length > 0">
|
||||
My Order
|
||||
</t>
|
||||
<t t-else="">
|
||||
My Orders
|
||||
</t>
|
||||
</a>
|
||||
</t>
|
||||
</div>
|
||||
@@ -32,7 +37,7 @@
|
||||
<t t-foreach="selfOrder.custom_links" t-as="link" t-key="link.id">
|
||||
<a type="button"
|
||||
t-on-click="(event) => this.clickCustomLink(link)"
|
||||
t-attf-class="btn btn-lg btn-{{link.style}}">
|
||||
t-attf-class="btn btn-lg btn-{{link.style}} {{ hideBtn(link) ? 'd-none' : ''}}">
|
||||
<t t-esc="link.name"/>
|
||||
</a>
|
||||
</t>
|
||||
|
||||
@@ -49,6 +49,10 @@ export class OrdersHistoryPage extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
getOrderState(state) {
|
||||
return state === "draft" ? _t("Current") : state;
|
||||
}
|
||||
|
||||
getNameAndDescription(line) {
|
||||
const fullName = line.full_product_name;
|
||||
const regex = /\(([^()]+)\)[^(]*$/;
|
||||
@@ -66,7 +70,7 @@ export class OrdersHistoryPage extends Component {
|
||||
editOrder(order) {
|
||||
if (order.state === "draft") {
|
||||
this.selfOrder.editedOrder = order;
|
||||
this.router.navigate("productList");
|
||||
this.router.navigate("cart");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+5
-3
@@ -15,15 +15,17 @@
|
||||
<div class="o_so_order d-flex flex-column flex-grow-1">
|
||||
<div class="o_so_order_header p-3 bg-white" t-on-click="() => this.editOrder(order)">
|
||||
<div class="d-flex align-items-center justify-content-between">
|
||||
<h6 class="m-0"
|
||||
t-esc="order.pos_reference"/>
|
||||
<div class="d-flex flex-column">
|
||||
<h6 class="m-0" t-esc="order.pos_reference"/>
|
||||
<span class="text-muted">Tracking number: <t t-esc="order.tracking_number" /></span>
|
||||
</div>
|
||||
<span
|
||||
class="badge py-2 rounded-pill text-capitalize"
|
||||
t-att-class="{
|
||||
'text-bg-success': order.state == 'paid',
|
||||
'text-bg-primary': order.state != 'paid'
|
||||
}"
|
||||
t-esc="order.state"/>
|
||||
t-esc="getOrderState(order.state)"/>
|
||||
</div>
|
||||
<p class="small m-0 fst-italic text-muted"
|
||||
t-esc="order.date"/>
|
||||
|
||||
@@ -23,19 +23,17 @@ export class PaymentPage extends Component {
|
||||
});
|
||||
|
||||
onWillStart(async () => {
|
||||
if (this.selfOrder.currentOrder.lines.length === 0) {
|
||||
this.router.navigate("default");
|
||||
return;
|
||||
}
|
||||
|
||||
const type = this.selfOrder.config.self_ordering_mode;
|
||||
const paymentMethods = this.selfOrder.pos_payment_methods.filter(
|
||||
(p) => !p.is_online_payment
|
||||
);
|
||||
|
||||
if (paymentMethods.length === 0 && type === "kiosk") {
|
||||
this.selfOrder.sendDraftOrderToServer();
|
||||
this.router.navigate("payment_success");
|
||||
await this.selfOrder.sendDraftOrderToServer();
|
||||
this.router.navigate("confirmation", {
|
||||
orderAccessToken: this.selfOrder.currentOrder.access_token,
|
||||
screenMode: "pay",
|
||||
});
|
||||
} else if (paymentMethods.length === 1 && type === "kiosk") {
|
||||
this.selectMethod(this.selfOrder.pos_payment_methods[0].id);
|
||||
}
|
||||
|
||||
@@ -16,21 +16,15 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div t-else="" class="h-100">
|
||||
<div class="d-flex flex-column gap-5 justify-content-center align-items-center h-100">
|
||||
<t t-if="!this.selfOrder.paymentError">
|
||||
<h1 class="text-center">Follow instructions<br/>on the terminal</h1>
|
||||
<i class="fa fa-credit-card-alt fs-1" aria-hidden="true"></i>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<h1 class="text-center">The payment has failed<br/>please retry</h1>
|
||||
<i class="fa fa-exclamation-circle fs-1" aria-hidden="true"></i>
|
||||
</t>
|
||||
<div class="d-flex justify-content-center align-items-center flex-column h-100 px-3 text-center">
|
||||
<h1 class="mb-4">Follow instructions on the terminal</h1>
|
||||
<div class="d-inline-flex flex-column border rounded p-4 bg-view mb-3">
|
||||
<i class="fa fa-credit-card-alt fs-1" aria-hidden="true"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex h-100 w-100">
|
||||
<button t-attf-class="{{ this.selfOrder.paymentError ? 'w-50' : 'w-100' }} h-100 btn btn-info p-0 m-0 rounded-0 fs-2 text-uppercase" t-on-click="() => this.router.back()">Back</button>
|
||||
<button t-attf-class="{{ this.selfOrder.paymentError ? 'w-50' : 'w-0' }} h-100 btn btn-success p-0 m-0 rounded-0 fs-2 text-uppercase" t-on-click="startPayment">Retry</button>
|
||||
<div t-if="showFooterBtn" class="px-3 py-4 d-flex gap-1 justify-content-center">
|
||||
<button class="btn btn-primary btn-lg" t-on-click="() => this.router.back()">Back</button>
|
||||
<button class="btn btn-info btn-lg" t-on-click="startPayment">Retry</button>
|
||||
</div>
|
||||
</t>
|
||||
</templates>
|
||||
|
||||
-44
@@ -1,44 +0,0 @@
|
||||
/** @odoo-module */
|
||||
|
||||
import { Component, onMounted, useState } from "@odoo/owl";
|
||||
import { useSelfOrder } from "@pos_self_order/app/self_order_service";
|
||||
import { cookie } from "@web/core/browser/cookie";
|
||||
import { useService } from "@web/core/utils/hooks";
|
||||
|
||||
// This component is only use in Kiosk mode
|
||||
export class PaymentSuccessPage extends Component {
|
||||
static template = "pos_self_order.PaymentSuccessPage";
|
||||
|
||||
setup() {
|
||||
this.selfOrder = useSelfOrder();
|
||||
this.selfOrder.isOrder();
|
||||
this.router = useService("router");
|
||||
this.state = useState({
|
||||
onReload: false,
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
setTimeout(() => {
|
||||
this.setDefautLanguage();
|
||||
}, 5000);
|
||||
});
|
||||
}
|
||||
|
||||
backToHome() {
|
||||
if (!this.setDefautLanguage()) {
|
||||
this.router.navigate("default");
|
||||
}
|
||||
}
|
||||
|
||||
setDefautLanguage() {
|
||||
const defaultLanguage = this.selfOrder.config.self_ordering_default_language_id;
|
||||
if (this.selfOrder.currentLanguage.code !== defaultLanguage.code && !this.state.onReload) {
|
||||
cookie.set("frontend_lang", defaultLanguage.code);
|
||||
window.location.reload();
|
||||
this.state.onReload = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return this.state.onReload;
|
||||
}
|
||||
}
|
||||
-31
@@ -1,31 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<templates id="template" xml:space="preserve">
|
||||
<t t-name="pos_self_order.PaymentSuccessPage">
|
||||
<div t-if="this.state.onReload" class="self_order_success_loader position-absolute vh-100 w-100 d-flex justify-content-center align-items-center opacity-50 bg-dark">
|
||||
<div class="page-loader d-flex justify-content-center align-items-center">
|
||||
<div class="spinner-border text-primary" role="status">
|
||||
<span class="visually-hidden">Loading...</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex justify-content-center align-items-center flex-column h-100 px-3 text-center">
|
||||
<h1 class="mb-4">We're preparing your order!</h1>
|
||||
<div class="d-inline-flex flex-column border rounded py-4 px-5 bg-view mb-3">
|
||||
<t t-if="selfOrder.currentOrder.take_away || selfOrder.config.self_ordering_service_mode !== 'table'">
|
||||
<span class="fs-2 text-muted">Your order number</span>
|
||||
<span class="number lh-1" t-esc="selfOrder.currentOrder.trackingNumber" />
|
||||
</t>
|
||||
<t t-else="">
|
||||
<span class="fs-2 text-muted">Your table number:</span>
|
||||
<span class="number lh-1 mb-4" t-esc="selfOrder.currentOrder.table_stand_number" />
|
||||
<span class="fs-2 text-muted">Order number:</span>
|
||||
<span class="number lh-1" t-esc="selfOrder.currentOrder.trackingNumber" />
|
||||
</t>
|
||||
</div>
|
||||
<h2 class="m-0 text-muted">Get your ticket below</h2>
|
||||
</div>
|
||||
<div class="px-3 py-4 text-center">
|
||||
<button class="btn btn-primary btn-lg" t-on-click="backToHome">Close</button>
|
||||
</div>
|
||||
</t>
|
||||
</templates>
|
||||
@@ -54,6 +54,7 @@
|
||||
data-bs-target="#listgroup-categories"
|
||||
data-bs-offset="10"
|
||||
tabindex="0">
|
||||
<t t-set="nbrItem" t-value="0" />
|
||||
<section
|
||||
t-foreach="Array.from(selfOrder.categoryList)"
|
||||
t-as="category"
|
||||
@@ -64,6 +65,7 @@
|
||||
class="product-list-category d-empty-none bg-view py-4 px-3 mb-3">
|
||||
<t t-set="products" t-value="selfOrder.productsGroupedByCategory[category.name]" />
|
||||
<t t-set="availableProducts" t-value="!state.searchInput ? products : getFilteredProducts(products)" />
|
||||
<t t-set="nbrItem" t-value="availableProducts.length + nbrItem" />
|
||||
<t t-if="availableProducts.length > 0">
|
||||
<h2 t-esc="category.name" class="mb-4 display-6 fw-bold"/>
|
||||
<div class="o-so-products-row">
|
||||
@@ -73,7 +75,7 @@
|
||||
</div>
|
||||
</t>
|
||||
</section>
|
||||
<p t-if="getFilteredProducts(selfOrder.products).length === 0" class="mx-auto mt-3 text-center">No products found</p>
|
||||
<p t-if="nbrItem === 0" class="mx-auto mt-3 text-center">No products found</p>
|
||||
</div>
|
||||
|
||||
<!-- Page buttons -->
|
||||
|
||||
@@ -63,7 +63,10 @@ export class SelfOrderBus {
|
||||
|
||||
if (payload.payment_result === "Success") {
|
||||
this.selfOrder.updateOrderFromServer(payload.order);
|
||||
this.selfOrder.router.navigate("payment_success");
|
||||
this.selfOrder.router.navigate("confirmation", {
|
||||
orderAccessToken: payload.order.access_token,
|
||||
screenMode: "order",
|
||||
});
|
||||
} else {
|
||||
this.selfOrder.paymentError = true;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ import { ComboPage } from "@pos_self_order/app/pages/combo_page/combo_page";
|
||||
import { ProductPage } from "@pos_self_order/app/pages/product_page/product_page";
|
||||
import { CartPage } from "@pos_self_order/app/pages/cart_page/cart_page";
|
||||
import { PaymentPage } from "@pos_self_order/app/pages/payment_page/payment_page";
|
||||
import { PaymentSuccessPage } from "@pos_self_order/app/pages/payment_success_page/payment_success_page";
|
||||
import { ConfirmationPage } from "@pos_self_order/app/pages/confirmation_page/confirmation_page";
|
||||
import { EatingLocationPage } from "@pos_self_order/app/pages/eating_location_page/eating_location_page";
|
||||
import { StandNumberPage } from "@pos_self_order/app/pages/stand_number_page/stand_number_page";
|
||||
import { OrdersHistoryPage } from "@pos_self_order/app/pages/order_history_page/order_history_page";
|
||||
@@ -27,7 +27,7 @@ class selfOrderIndex extends Component {
|
||||
OrdersHistoryPage,
|
||||
ComboPage,
|
||||
PaymentPage,
|
||||
PaymentSuccessPage,
|
||||
ConfirmationPage,
|
||||
ProductListPage,
|
||||
EatingLocationPage,
|
||||
StandNumberPage,
|
||||
|
||||
@@ -23,8 +23,8 @@
|
||||
<t t-set-slot="payment" route="`/pos-self/${selfOrder.pos_config_id}/payment`">
|
||||
<PaymentPage />
|
||||
</t>
|
||||
<t t-set-slot="payment_success" route="`/pos-self/${selfOrder.pos_config_id}/payment_success`">
|
||||
<PaymentSuccessPage />
|
||||
<t t-set-slot="confirmation" route="`/pos-self/${selfOrder.pos_config_id}/confirmation/{string:orderAccessToken}/{string:screenMode}`" t-slot-scope="url">
|
||||
<ConfirmationPage orderAccessToken="url.orderAccessToken" screenMode="url.screenMode" />
|
||||
</t>
|
||||
<t t-set-slot="location" route="`/pos-self/${selfOrder.pos_config_id}/location`">
|
||||
<EatingLocationPage />
|
||||
|
||||
@@ -216,7 +216,7 @@ export class SelfOrder extends Reactive {
|
||||
|
||||
async sendDraftOrderToServer() {
|
||||
if (this.currentOrder.isSavedOnServer || this.currentOrder.lines.length === 0) {
|
||||
return true;
|
||||
return this.currentOrder;
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -238,10 +238,6 @@ export class SelfOrder extends Reactive {
|
||||
this.editedOrder = null;
|
||||
}
|
||||
|
||||
if (this.config.self_ordering_mode !== "kiosk") {
|
||||
this.notification.add(_t("Your order has been placed!"), { type: "success" });
|
||||
}
|
||||
|
||||
return order;
|
||||
} catch (error) {
|
||||
this.handleErrorNotification(error, [this.editedOrder.access_token]);
|
||||
|
||||
Reference in New Issue
Block a user