[IMP] point_of_sale,*: order visualization on ticket screen

*: pos_loyalty,pos_restaurant

The ticket screen contains a widget showing orderlines
and information about them for paid orders. This commit introduces
the use of this widget for open orders. On the ticket screen,
the cashier will be able to have information about the orderlines
for each order without necessarly loading the order in full screen.
The user now have to click on the order on the ticket screen and click
on the new button "Load order" to display it in the main screen.

closes odoo/odoo#128288

Signed-off-by: Joseph Caburnay (jcb) <jcb@odoo.com>
This commit is contained in:
Adrien Guilliams (adgu)
2023-08-24 18:37:10 +02:00
committed by Joseph Caburnay
parent 6f560990b1
commit 6ce6d6ea7b
17 changed files with 619 additions and 435 deletions
@@ -3,6 +3,7 @@
import { Component, useState } from "@odoo/owl";
import { useService } from "@web/core/utils/hooks";
import { usePos } from "@point_of_sale/app/store/pos_hook";
import { TicketScreen } from "@point_of_sale/app/screens/ticket_screen/ticket_screen";
export class BackButton extends Component {
static template = "point_of_sale.BackButton";
@@ -11,8 +12,16 @@ export class BackButton extends Component {
this.pos = usePos();
this.ui = useState(useService("ui"));
}
async backToFloorScreen() {
this.pos.mobile_pane = "right";
this.pos.showScreen("ProductScreen");
async onClick() {
if (this.pos.mainScreen.component === TicketScreen) {
if (this.pos.ticket_screen_mobile_pane == "left") {
this.pos.closeScreen();
} else {
this.pos.ticket_screen_mobile_pane = "left";
}
} else {
this.pos.mobile_pane = "right";
this.pos.showScreen("ProductScreen");
}
}
}
@@ -4,7 +4,7 @@
<t t-name="point_of_sale.BackButton">
<span
class="order-button floor-button d-flex align-items-center gap-2 px-4 fw-bolder cursor-pointer"
t-on-click="backToFloorScreen"
t-on-click="onClick"
>
<i class="fa fa-2x fa-angle-left pb-1" role="img" aria-label="Go Back" title="Go Back" />
<span t-if="!ui.isSmall">BACK</span>
@@ -5,7 +5,7 @@
<div class="order-container h-100 overflow-y-auto bg-view">
<div t-ref="scrollable" class="order-scroller touch-scrollable h-100">
<div class="order d-flex flex-column h-100 text-start">
<t t-if="!props.order">
<t t-if="!order">
<div class="order-empty d-flex flex-column align-items-center justify-content-center h-100 text-muted">
<i class="fa fa fa-4x fa-shopping-cart" role="img" aria-label="Shopping cart"
title="Shopping cart" />
@@ -13,14 +13,14 @@
</div>
</t>
<t t-elif="orderlines.length === 0">
<div class="order-empty">
<div class="order-empty d-flex flex-column align-items-center justify-content-center h-100 text-muted">
<i class="fa fa fa-4x fa-shopping-cart" role="img" aria-label="Shopping cart"
title="Shopping cart" />
<h3 class="mt-2">Order is empty</h3>
</div>
</t>
<t t-else="">
<div class="header-note text-bg-view py-2 px-3 border-bottom" t-att-class="{ 'highlight text-danger': props.highlightHeaderNote }">
<div t-if="order.locked" class="header-note text-bg-view py-2 px-3 border-bottom" t-att-class="{ 'highlight text-danger': props.highlightHeaderNote }">
Select the product(s) to refund and set the quantity
</div>
<ul class="orderlines flex-grow-1 overflow-auto">
@@ -54,13 +54,10 @@ export class TicketScreen extends Component {
triggerAtInput: (event) => this._onUpdateSelectedOrderline(event),
});
this._state = this.pos.TICKET_SCREEN_STATE;
this.state = useState({
showSearchBar: !this.ui.isSmall,
});
const defaultUIState = this.props.reuseSavedUIState
? this._state.ui
: {
selectedSyncedOrderId: null,
selectedOrder: this.pos.get_order(),
searchDetails: this.pos.getDefaultSearchDetails(),
filter: null,
selectedOrderlineIds: {},
@@ -80,6 +77,10 @@ export class TicketScreen extends Component {
//#region EVENT HANDLERS
async onFilterSelected(selectedFilter) {
this._state.ui.filter = selectedFilter;
this._state.ui.selectedOrder = null;
if (this._state.ui.filter == "ACTIVE_ORDERS" || this._state.ui.filter === null) {
this._state.ui.selectedOrder = this.pos.get_order();
}
if (this._state.ui.filter == "SYNCED") {
await this._fetchSyncedOrders();
}
@@ -93,21 +94,31 @@ export class TicketScreen extends Component {
}
onClickOrder(clickedOrder) {
if (!clickedOrder || clickedOrder.locked) {
if (this._state.ui.selectedSyncedOrderId == clickedOrder.backendId) {
this._state.ui.selectedSyncedOrderId = null;
} else {
this._state.ui.selectedSyncedOrderId = clickedOrder.backendId;
}
this._state.ui.selectedOrder = clickedOrder;
if (!this.getSelectedOrderlineId()) {
// Automatically select the first orderline of the selected order.
const firstLine = clickedOrder.get_orderlines()[0];
const firstLine = this._state.ui.selectedOrder.get_orderlines()[0];
if (firstLine) {
this._state.ui.selectedOrderlineIds[clickedOrder.backendId] = firstLine.id;
}
}
this.numberBuffer.reset();
} else {
this._setOrder(clickedOrder);
if (
!this._state.ui.selectedOrder ||
clickedOrder.uid !== this._state.ui.selectedOrder.uid
) {
this.dbclk_time = new Date().getTime();
} else if (!this.dbclk_time) {
this.dbclk_time = new Date().getTime();
} else if (this.dbclk_time + 500 > new Date().getTime()) {
this._setOrder(clickedOrder);
this.dbclk_time = 0;
} else {
this.dbclk_time = new Date().getTime();
}
this._state.ui.selectedOrder = clickedOrder;
this.numberBuffer.reset();
}
}
onCreateNewOrder() {
@@ -145,10 +156,20 @@ export class TicketScreen extends Component {
this._selectNextOrder(order);
}
this.pos.removeOrder(order);
if (this._state.ui.selectedOrder === order) {
if (this.pos.get_order_list().length > 0) {
this._state.ui.selectedOrder = this.pos.get_order_list()[0];
} else {
this._state.ui.selectedOrder = null;
}
}
}
if (this.pos.isOpenOrderShareable()) {
this.pos._removeOrdersFromServer();
}
// When deleting an order, the double click time should be reset, so that it's not taken into account
// when clicking on another order.
this.dbclk_time = 0;
}
async onNextPage() {
if (this._state.syncedOrders.currentPage < this._getLastPage()) {
@@ -167,9 +188,11 @@ export class TicketScreen extends Component {
await this._fetchSyncedOrders();
}
onClickOrderline(orderline) {
const order = this.getSelectedSyncedOrder();
this._state.ui.selectedOrderlineIds[order.backendId] = orderline.id;
this.numberBuffer.reset();
if (this._state.ui.selectedOrder.locked) {
const order = this.getSelectedOrder();
this._state.ui.selectedOrderlineIds[order.backendId] = orderline.id;
this.numberBuffer.reset();
}
}
onClickRefundOrderUid(orderUid) {
// Open the refund order.
@@ -179,7 +202,7 @@ export class TicketScreen extends Component {
}
}
_onUpdateSelectedOrderline({ key, buffer }) {
const order = this.getSelectedSyncedOrder();
const order = this.getSelectedOrder();
if (!order) {
return this.numberBuffer.reset();
}
@@ -221,7 +244,7 @@ export class TicketScreen extends Component {
}
}
async onDoRefund() {
const order = this.getSelectedSyncedOrder();
const order = this.getSelectedOrder();
if (order && this._doesOrderHaveSoleItem(order)) {
if (!this._prepareAutoRefundOnOrder(order)) {
@@ -277,7 +300,7 @@ export class TicketScreen extends Component {
this.pos.set_order(destinationOrder);
}
this.pos.closeScreen();
this.closeTicketScreen();
}
setPartnerToRefundOrder(partner, destinationOrder) {
if (partner && !destinationOrder.get_partner()) {
@@ -286,15 +309,17 @@ export class TicketScreen extends Component {
}
//#endregion
//#region PUBLIC METHODS
getSelectedSyncedOrder() {
if (this._state.ui.filter == "SYNCED") {
return this._state.syncedOrders.cache[this._state.ui.selectedSyncedOrderId];
getSelectedOrder() {
if (this._state.ui.filter == "SYNCED" && this._state.ui.selectedOrder) {
return this._state.syncedOrders.cache[this._state.ui.selectedOrder.backendId];
} else {
return null;
return this._state.ui.selectedOrder;
}
}
getSelectedOrderlineId() {
return this._state.ui.selectedOrderlineIds[this._state.ui.selectedSyncedOrderId];
if (this._state.ui.selectedOrder?.backendId) {
return this._state.ui.selectedOrderlineIds[this._state.ui.selectedOrder.backendId];
}
}
/**
* Override to conditionally show the new order button, or prevent order
@@ -305,6 +330,9 @@ export class TicketScreen extends Component {
get allowNewOrders() {
return true;
}
get isOrderSynced() {
return this._state.ui.selectedOrder?.locked;
}
getFilteredOrderList() {
if (this._state.ui.filter == "SYNCED") {
return this._state.syncedOrders.toShow;
@@ -377,6 +405,7 @@ export class TicketScreen extends Component {
*/
shouldHideDeleteButton(order) {
return (
(this.ui.isSmall && order != this._state.ui.selectedOrder) ||
this.isDefaultOrderEmpty(order) ||
order.locked ||
order
@@ -387,13 +416,12 @@ export class TicketScreen extends Component {
);
}
isHighlighted(order) {
if (this._state.ui.filter == "SYNCED") {
const selectedOrder = this.getSelectedSyncedOrder();
return selectedOrder ? order.backendId == selectedOrder.backendId : false;
} else {
const activeOrder = this.pos.get_order();
return activeOrder ? activeOrder.uid == order.uid : false;
}
const selectedOrder = this.getSelectedOrder();
return selectedOrder
? (order.backendId && order.backendId == selectedOrder.backendId) ||
order.uid === selectedOrder.uid
: false;
}
showCardholderName() {
return this.pos.payment_methods.some((method) => method.use_payment_terminal);
@@ -419,11 +447,11 @@ export class TicketScreen extends Component {
}
}
getSelectedPartner() {
const order = this.getSelectedSyncedOrder();
const order = this.getSelectedOrder();
return order ? order.get_partner() : null;
}
getHasItemsToRefund() {
const order = this.getSelectedSyncedOrder();
const order = this.getSelectedOrder();
if (!order) {
return false;
}
@@ -440,6 +468,13 @@ export class TicketScreen extends Component {
.reduce((acc, val) => acc + val, 0);
return !this.pos.isProductQtyZero(total);
}
switchPane() {
this.pos.switchPaneTicketScreen();
}
closeTicketScreen() {
this.pos.ticket_screen_mobile_pane = "left";
this.pos.closeScreen();
}
//#endregion
//#region PRIVATE METHODS
/**
@@ -563,7 +598,7 @@ export class TicketScreen extends Component {
this.pos.sendDraftToServer();
}
this.pos.set_order(order);
this.pos.closeScreen();
this.closeTicketScreen();
}
_getOrderList() {
return this.pos.get_order_list();
@@ -4,11 +4,11 @@
<t t-name="point_of_sale.TicketScreen">
<div class="ticket-screen screen h-100 bg-100" t-att-class="{ 'd-none': !props.isShown }">
<div class="screen-full-width d-flex w-100 h-100">
<div class="rightpane pane-border d-flex flex-column flex-grow-1 w-100 h-50 h-md-100 bg-300 overflow-y-auto">
<div t-if="!ui.isSmall || pos.ticket_screen_mobile_pane === 'left'" class="rightpane pane-border d-flex flex-column flex-grow-1 w-100 h-100 h-md-100 bg-300 overflow-y-auto">
<div class="controls d-flex align-items-center justify-content-between mt-1 mt-md-0 p-2 bg-400">
<t t-if="!ui.isSmall || !state.showSearchBar">
<t t-if="!ui.isSmall">
<div class="buttons d-flex gap-2">
<button class="discard btn btn-lg btn-light" t-on-click="() => this.pos.closeScreen()">
<button t-if="!ui.isSmall" class="discard btn btn-lg btn-light" t-on-click="() => this.closeTicketScreen()">
<span class="search-icon">
<i class="fa fa-angle-double-left"/>
</span>
@@ -19,24 +19,14 @@
<button t-if="allowNewOrders" class="highlight btn btn-lg btn-primary" t-on-click="() => this.onCreateNewOrder()">New Order</button>
</div>
</t>
<t t-if="ui.isSmall">
<t t-if="state.showSearchBar">
<button class="arrow-left btn btn-lg btn-light" t-on-click="() => { state.showSearchBar = !state.showSearchBar }">
<span class="search-icon">
<i class="fa fa-angle-double-left"/>
</span>
</button>
</t>
<t t-else="">
<button class="search btn btn-lg btn-light" t-on-click="() => { state.showSearchBar = !state.showSearchBar }">
<span class="search-icon">
<i class="fa fa-search"/>
</span>
</button>
</t>
<t t-if="ui.isSmall and allowNewOrders">
<button class="highlight btn btn-lg btn-primary" t-on-click="() => this.onCreateNewOrder()">
<span class="search-icon">
<i class="fa fa-plus" aria-hidden="true"/>
</span>
</button>
</t>
<SearchBar
t-if="state.showSearchBar"
config="getSearchBarConfig()"
placeholder="constructor.searchPlaceholder"
onSearch.bind="onSearch"
@@ -55,7 +45,7 @@
</div>
</div>
</div>
<div class="orders overflow-y-auto">
<div class="orders overflow-y-auto flex-grow-1">
<t t-set="_filteredOrderList" t-value="getFilteredOrderList()" />
<t t-if="_filteredOrderList.length !== 0">
<div class="header-row d-flex text-bg-700 fw-bolder" t-att-class="{ 'd-none': ui.isSmall }">
@@ -69,7 +59,7 @@
<div class="col very-narrow p-2" name="delete"></div>
</div>
<t t-foreach="_filteredOrderList" t-as="order" t-key="order.cid">
<div class="order-row" t-att-class="{ 'highlight': isHighlighted(order) }" t-on-click="() => this.onClickOrder(order)">
<div class="order-row" t-att-class="{ 'highlight bg-primary text-white': isHighlighted(order) }" t-on-click="() => this.onClickOrder(order)">
<div class="col wide p-2 ">
<div><t t-esc="getDate(order)"></t></div>
<div t-if="ui.isSmall"><t t-esc="getTotal(order)"></t></div>
@@ -84,9 +74,12 @@
<div t-if="showCardholderName() and !ui.isSmall" class="col p-2">
<div><t t-esc="getCardholderName(order)"></t></div>
</div>
<div class="col p-2">
<div t-if="ui.isSmall"><t t-esc="getPartner(order)"></t></div>
<div class="col p-2 d-flex justify-content-between align-items-center">
<div t-if="ui.isSmall and getPartner(order)"><t t-esc="getPartner(order)"></t></div>
<div t-att-class = "ui.isSmall ? 'cashier':''"><t t-esc="getCashier(order)"></t></div>
<div t-if="ui.isSmall and !shouldHideDeleteButton(order)" class="col very-narrow delete-button p-2 rounded-2" name="delete" t-on-click.stop="() => this.onDeleteOrder(order)">
<i class="fa fa-trash" aria-hidden="true"/> Delete
</div>
</div>
<div class="col end p-2" t-if="!ui.isSmall">
<div><t t-esc="getTotal(order)"></t></div>
@@ -94,7 +87,7 @@
<div class="col narrow p-2" t-if="!ui.isSmall">
<div><t t-esc="getStatus(order)"></t></div>
</div>
<div t-if="!shouldHideDeleteButton(order)" class="col very-narrow delete-button p-2" name="delete" t-on-click.stop="() => this.onDeleteOrder(order)">
<div t-if="!shouldHideDeleteButton(order) and !ui.isSmall" class="col very-narrow delete-button p-2" name="delete" t-on-click.stop="() => this.onDeleteOrder(order)">
<i class="fa fa-trash" aria-hidden="true"/><t t-if="ui.isSmall"> Delete</t>
</div>
<div t-else="" class="col very-narrow p-2"></div>
@@ -108,38 +101,61 @@
</div>
</t>
</div>
</div>
<div class="leftpane d-flex flex-column flex-grow-1 w-100 h-50 h-md-100 bg-200">
<t t-set="_selectedSyncedOrder" t-value="getSelectedSyncedOrder()" />
<t t-set="_selectedOrderlineId" t-value="getSelectedOrderlineId()" />
<OrderDetails
onClickOrderline.bind="onClickOrderline"
onClickRefundOrderUid.bind="onClickRefundOrderUid"
order="_selectedSyncedOrder"
selectedOrderlineId="_selectedOrderlineId"
highlightHeaderNote="_state.ui.highlightHeaderNote" />
<div class="pads border-top">
<div class="control-buttons d-flex flex-wrap border-bottom overflow-hidden bg-300">
<InvoiceButton
onInvoiceOrder.bind="onInvoiceOrder"
order="_selectedSyncedOrder" />
<ReprintReceiptButton order="_selectedSyncedOrder" />
</div>
<div class="subpads d-flex">
<ActionpadWidget
partner="getSelectedPartner()"
actionName="constructor.numpadActionName"
actionType="'refund'"
actionToTrigger.bind="onDoRefund"
isActionButtonHighlighted="getHasItemsToRefund()" />
<NumpadWidget
disabledModes="['price', 'discount']"
setNumpadMode="() => {}"
activeMode="_selectedOrderlineId and 'quantity'"
disableSign="true" />
</div>
<div class="switchpane d-flex w-100" t-if="ui.isSmall">
<t t-set="_selectedSyncedOrder" t-value="getSelectedOrder()" />
<button class="btn-switchpane load-order-button primary btn btn-primary rounded-0 w-50 fw-bolder py-3" t-if="!isOrderSynced" t-on-click="() => this._setOrder(_selectedSyncedOrder)">
<span class="fs-1 d-block">Load Order</span>
</button>
<button class="btn-switchpane flex-fill btn rounded-0 fw-bolder secondary" t-att-class="{'btn-primary': isOrderSynced, 'btn-secondary': !isOrderSynced}" t-on-click="switchPane">
<span class="fs-1 d-block">Review</span>
</button>
</div>
</div>
<div class="leftpane d-flex flex-column flex-grow-1 w-100 h-100 h-md-100 bg-200" t-if="!ui.isSmall || pos.ticket_screen_mobile_pane === 'right'">
<t t-set="_selectedSyncedOrder" t-value="getSelectedOrder()" />
<t t-set="_selectedOrderlineId" t-value="getSelectedOrderlineId()" />
<t t-if="isOrderSynced">
<OrderDetails
onClickOrderline.bind="onClickOrderline"
onClickRefundOrderUid.bind="onClickRefundOrderUid"
order="_selectedSyncedOrder"
selectedOrderlineId="_selectedOrderlineId"
highlightHeaderNote="_state.ui.highlightHeaderNote" />
<div class="pads border-top">
<div class="control-buttons d-flex flex-wrap border-bottom overflow-hidden bg-300">
<InvoiceButton
onInvoiceOrder.bind="onInvoiceOrder"
order="_selectedSyncedOrder" />
<ReprintReceiptButton order="_selectedSyncedOrder" />
</div>
<div class="subpads d-flex">
<ActionpadWidget
partner="getSelectedPartner()"
actionName="constructor.numpadActionName"
actionType="'refund'"
actionToTrigger.bind="onDoRefund"
isActionButtonHighlighted="getHasItemsToRefund()" />
<NumpadWidget
disabledModes="['price', 'discount']"
setNumpadMode="() => {}"
activeMode="_selectedOrderlineId and 'quantity'"
disableSign="true" />
</div>
</div>
</t>
<t t-else="">
<OrderDetails
onClickOrderline.bind="onClickOrderline"
onClickRefundOrderUid.bind="onClickRefundOrderUid"
order="_selectedSyncedOrder"
highlightHeaderNote="_state.ui.highlightHeaderNote" />
<div class="pads border-top" t-if="_selectedSyncedOrder">
<button class="button validation load-order-button w-100 btn btn-lg btn-primary rounded-0 fw-bolder py-3" t-on-click="() => this._setOrder(_selectedSyncedOrder)">
<span class="fs-1 d-block">Load Order</span>
</button>
</div>
</t>
</div>
</div>
</div>
</t>
@@ -20,6 +20,7 @@ import { PaymentScreen } from "@point_of_sale/app/screens/payment_screen/payment
import { ProductScreen } from "@point_of_sale/app/screens/product_screen/product_screen";
import { renderToString } from "@web/core/utils/render";
import { batched } from "@web/core/utils/timing";
import { TicketScreen } from "@point_of_sale/app/screens/ticket_screen/ticket_screen";
/* Returns an array containing all elements of the given
* array corresponding to the rule function {agg} and without duplicates
@@ -121,6 +122,7 @@ export class PosStore extends Reactive {
this.numpadMode = "quantity";
this.mobile_pane = "right";
this.ticket_screen_mobile_pane = "left";
this.productListView = window.localStorage.getItem("productListView") || "grid";
// Record<orderlineId, { 'qty': number, 'orderline': { qty: number, refundedQty: number, orderUid: string }, 'destinationOrderUid': string }>
@@ -135,7 +137,7 @@ export class PosStore extends Reactive {
cacheDate: null,
},
ui: {
selectedSyncedOrderId: null,
selectedOrder: null,
searchDetails: this.getDefaultSearchDetails(),
filter: null,
// maps the order's backendId to it's selected orderline
@@ -1634,6 +1636,10 @@ export class PosStore extends Reactive {
switchPane() {
this.mobile_pane = this.mobile_pane === "left" ? "right" : "left";
}
switchPaneTicketScreen() {
this.ticket_screen_mobile_pane =
this.ticket_screen_mobile_pane === "left" ? "right" : "left";
}
async logEmployeeMessage(action, message) {
await this.orm.call("pos.session", "log_partner_message", [
this.pos_session.id,
@@ -1876,7 +1882,8 @@ export class PosStore extends Reactive {
showBackButton() {
return (
this.mainScreen.component === PaymentScreen ||
(this.mainScreen.component === ProductScreen && this.mobile_pane == "left")
(this.mainScreen.component === ProductScreen && this.mobile_pane == "left") ||
this.mainScreen.component === TicketScreen
);
}
+11 -3
View File
@@ -52,6 +52,17 @@ button {
}
}
.pos .button.validation.load-order-button {
height: calc(var(--btn-height-size) * 2);
}
@media screen and (max-width: 768px) {
.pos .button.validation.load-order-button {
height: 70px;
}
}
.z-1000 {
z-index: 1000;
}
@@ -81,9 +92,6 @@ button {
.o-fade {
transition: opacity .2s;
}
.pos .button.validation.with-more-button {
height: calc(var(--btn-height-size) * 2);
}
.o-fade-enter, .o-fade-leave {
opacity: 0;
@@ -48,6 +48,7 @@ registry
// Select order 1, should be at Product Screen
TicketScreen.do.selectOrder("-0001");
TicketScreen.do.loadSelectedOrder();
ProductScreen.check.productIsDisplayed("Desk Pad");
ProductScreen.check.selectedOrderlineHas("Desk Pad", "1.0", "2.0");
@@ -55,6 +56,7 @@ registry
Chrome.do.clickMenuButton();
Chrome.do.clickTicketButton();
TicketScreen.do.selectOrder("-0002");
TicketScreen.do.loadSelectedOrder();
PaymentScreen.check.emptyPaymentlines("12.0");
PaymentScreen.check.validateButtonIsHighlighted(false);
@@ -62,12 +64,14 @@ registry
Chrome.do.clickMenuButton();
Chrome.do.clickTicketButton();
TicketScreen.do.selectOrder("-0003");
TicketScreen.do.loadSelectedOrder();
ReceiptScreen.check.totalAmountContains("30.0");
// Pay order 1, with change
Chrome.do.clickMenuButton();
Chrome.do.clickTicketButton();
TicketScreen.do.selectOrder("-0001");
TicketScreen.do.loadSelectedOrder();
ProductScreen.check.isShown();
ProductScreen.do.clickPayButton();
PaymentScreen.do.clickPaymentMethod("Cash");
@@ -85,6 +89,7 @@ registry
// Select order 3, should still be at Receipt Screen
// and the total amount doesn't change.
TicketScreen.do.selectOrder("-0003");
TicketScreen.do.loadSelectedOrder();
ReceiptScreen.check.totalAmountContains("30.0");
// click next screen on order 3
@@ -10,166 +10,168 @@ import { Chrome } from "@point_of_sale/../tests/tours/helpers/ChromeTourMethods"
import { getSteps, startSteps } from "@point_of_sale/../tests/tours/helpers/utils";
import { registry } from "@web/core/registry";
registry
.category("web_tour.tours")
.add("TicketScreenTour", {
test: true,
url: "/pos/ui",
steps: () => {
startSteps();
ProductScreen.do.confirmOpeningPopup();
ProductScreen.do.clickHomeCategory();
Chrome.do.clickMenuButton();
Chrome.do.clickTicketButton();
TicketScreen.do.clickNewTicket();
ProductScreen.exec.addOrderline("Desk Pad", "1", "3");
Chrome.do.clickMenuButton();
Chrome.do.clickTicketButton();
TicketScreen.do.deleteOrder("-0002");
Chrome.do.confirmPopup();
TicketScreen.do.clickDiscard();
ProductScreen.check.orderIsEmpty();
ProductScreen.exec.addOrderline("Desk Pad", "1", "2");
Chrome.do.clickMenuButton();
Chrome.do.clickTicketButton();
TicketScreen.do.deleteOrder("-0001");
Chrome.do.confirmPopup();
TicketScreen.do.clickDiscard();
Chrome.do.clickMenuButton();
Chrome.do.clickTicketButton();
TicketScreen.check.nthRowContains(2, "-0003");
TicketScreen.do.clickDiscard();
ProductScreen.exec.addOrderline("Desk Pad", "1", "2");
ProductScreen.do.clickPartnerButton();
ProductScreen.do.clickCustomer("Nicole Ford");
Chrome.do.clickMenuButton();
Chrome.do.clickTicketButton();
TicketScreen.check.nthRowContains(2, "Nicole Ford");
TicketScreen.do.clickNewTicket();
ProductScreen.exec.addOrderline("Desk Pad", "1", "3");
ProductScreen.do.clickPartnerButton();
ProductScreen.do.clickCustomer("Brandon Freeman");
ProductScreen.do.clickPayButton();
PaymentScreen.check.isShown();
Chrome.do.clickMenuButton();
Chrome.do.clickTicketButton();
TicketScreen.check.nthRowContains(3, "Brandon Freeman");
TicketScreen.do.clickNewTicket();
ProductScreen.exec.addOrderline("Desk Pad", "2", "4");
ProductScreen.do.clickPayButton();
PaymentScreen.do.clickPaymentMethod("Bank");
PaymentScreen.do.clickValidate();
ReceiptScreen.check.isShown();
Chrome.do.clickMenuButton();
Chrome.do.clickTicketButton();
TicketScreen.check.nthRowContains(4, "Receipt");
TicketScreen.do.selectFilter("Receipt");
TicketScreen.check.nthRowContains(2, "Receipt");
TicketScreen.do.selectFilter("Payment");
TicketScreen.check.nthRowContains(2, "Payment");
TicketScreen.do.selectFilter("Ongoing");
TicketScreen.check.nthRowContains(2, "Ongoing");
TicketScreen.do.selectFilter("All active orders");
TicketScreen.check.nthRowContains(4, "Receipt");
TicketScreen.do.search("Customer", "Nicole");
TicketScreen.check.nthRowContains(2, "Nicole");
TicketScreen.do.search("Customer", "Brandon");
TicketScreen.check.nthRowContains(2, "Brandon");
TicketScreen.do.search("Receipt Number", "-0005");
TicketScreen.check.nthRowContains(2, "Receipt");
// Close the TicketScreen to see the current order which is in ReceiptScreen.
// This is just to remove the search string in the search bar.
TicketScreen.do.clickDiscard();
ReceiptScreen.check.isShown();
// Open again the TicketScreen to check the Paid filter.
Chrome.do.clickMenuButton();
Chrome.do.clickTicketButton();
TicketScreen.do.selectFilter("Paid");
TicketScreen.check.nthRowContains(2, "-0005");
// Pay the order that was in PaymentScreen.
TicketScreen.do.selectFilter("Payment");
TicketScreen.do.selectOrder("-0004");
PaymentScreen.do.clickPaymentMethod("Cash");
PaymentScreen.do.clickValidate();
ReceiptScreen.check.isShown();
ReceiptScreen.do.clickNextOrder();
ProductScreen.check.isShown();
// Check that the Paid filter will show the 2 synced orders.
Chrome.do.clickMenuButton();
Chrome.do.clickTicketButton();
TicketScreen.do.selectFilter("Paid");
TicketScreen.check.nthRowContains(2, "Brandon Freeman");
TicketScreen.check.nthRowContains(3, "-0005");
// Invoice order
TicketScreen.do.selectOrder("-0005");
TicketScreen.check.orderWidgetIsNotEmpty();
TicketScreen.do.clickControlButton("Invoice");
Chrome.do.confirmPopup();
PartnerListScreen.check.isShown();
PartnerListScreen.do.clickPartner("Colleen Diaz");
TicketScreen.check.partnerIs("Colleen Diaz");
// Reprint receipt
TicketScreen.do.clickControlButton("Print Receipt");
ReceiptScreen.check.isShown();
ReceiptScreen.do.clickBack();
// When going back, the ticket screen should be in its previous state.
TicketScreen.check.filterIs("Paid");
// Test refund //
TicketScreen.do.clickDiscard();
ProductScreen.check.isShown();
ProductScreen.check.orderIsEmpty();
ProductScreen.do.clickRefund();
// Filter should be automatically 'Paid'.
TicketScreen.check.filterIs("Paid");
TicketScreen.do.selectOrder("-0005");
TicketScreen.check.partnerIs("Colleen Diaz");
TicketScreen.do.clickOrderline("Desk Pad");
TicketScreen.do.pressNumpad("3");
// Error should show because 2 is more than the number
// that can be refunded.
ErrorPopup.do.clickConfirm();
TicketScreen.do.clickDiscard();
ProductScreen.do.goBackToMainScreen();
ProductScreen.check.isShown();
ProductScreen.check.orderIsEmpty();
ProductScreen.do.clickRefund();
TicketScreen.do.selectOrder("-0005");
TicketScreen.do.clickOrderline("Desk Pad");
TicketScreen.do.pressNumpad("1");
TicketScreen.check.toRefundTextContains("To Refund: 1.00");
TicketScreen.do.confirmRefund();
ProductScreen.do.goBackToMainScreen();
ProductScreen.check.isShown();
ProductScreen.check.selectedOrderlineHas("Desk Pad", "-1.00");
// Try changing the refund line to positive number.
// Error popup should show.
ProductScreen.do.pressNumpad("2");
ErrorPopup.do.clickConfirm();
// Change the refund line quantity to -3 -- not allowed
// so error popup.
ProductScreen.do.pressNumpad("+/- 3");
ErrorPopup.do.clickConfirm();
// Change the refund line quantity to -2 -- allowed.
ProductScreen.do.pressNumpad("+/- 2");
ProductScreen.check.selectedOrderlineHas("Desk Pad", "-2.00");
// Check if the amount being refunded changed to 2.
ProductScreen.do.clickRefund();
TicketScreen.do.selectOrder("-0005");
TicketScreen.check.toRefundTextContains("Refunding 2.00");
TicketScreen.do.clickDiscard();
ProductScreen.do.goBackToMainScreen();
// Pay the refund order.
ProductScreen.do.clickPayButton();
PaymentScreen.do.clickPaymentMethod("Bank");
PaymentScreen.do.clickValidate();
ReceiptScreen.check.isShown();
ReceiptScreen.do.clickNextOrder();
// Check refunded quantity.
ProductScreen.do.clickRefund();
TicketScreen.do.selectOrder("-0005");
TicketScreen.check.refundedNoteContains("2.00 Refunded");
registry.category("web_tour.tours").add("TicketScreenTour", {
test: true,
url: "/pos/ui",
steps: () => {
startSteps();
ProductScreen.do.confirmOpeningPopup();
ProductScreen.do.clickHomeCategory();
Chrome.do.clickMenuButton();
Chrome.do.clickTicketButton();
TicketScreen.do.clickNewTicket();
ProductScreen.exec.addOrderline("Desk Pad", "1", "3");
Chrome.do.clickMenuButton();
Chrome.do.clickTicketButton();
TicketScreen.do.deleteOrder("-0002");
Chrome.do.confirmPopup();
TicketScreen.do.clickDiscard();
ProductScreen.check.orderIsEmpty();
ProductScreen.exec.addOrderline("Desk Pad", "1", "2");
Chrome.do.clickMenuButton();
Chrome.do.clickTicketButton();
TicketScreen.do.deleteOrder("-0001");
Chrome.do.confirmPopup();
TicketScreen.do.clickDiscard();
Chrome.do.clickMenuButton();
Chrome.do.clickTicketButton();
TicketScreen.check.nthRowContains(2, "-0003");
TicketScreen.do.clickDiscard();
ProductScreen.exec.addOrderline("Desk Pad", "1", "2");
ProductScreen.do.clickPartnerButton();
ProductScreen.do.clickCustomer("Nicole Ford");
Chrome.do.clickMenuButton();
Chrome.do.clickTicketButton();
TicketScreen.check.nthRowContains(2, "Nicole Ford");
TicketScreen.do.clickNewTicket();
ProductScreen.exec.addOrderline("Desk Pad", "1", "3");
ProductScreen.do.clickPartnerButton();
ProductScreen.do.clickCustomer("Brandon Freeman");
ProductScreen.do.clickPayButton();
PaymentScreen.check.isShown();
Chrome.do.clickMenuButton();
Chrome.do.clickTicketButton();
TicketScreen.check.nthRowContains(3, "Brandon Freeman");
TicketScreen.do.clickNewTicket();
ProductScreen.exec.addOrderline("Desk Pad", "2", "4");
ProductScreen.do.clickPayButton();
PaymentScreen.do.clickPaymentMethod("Bank");
PaymentScreen.do.clickValidate();
ReceiptScreen.check.isShown();
Chrome.do.clickMenuButton();
Chrome.do.clickTicketButton();
TicketScreen.check.nthRowContains(4, "Receipt");
TicketScreen.do.selectFilter("Receipt");
TicketScreen.check.nthRowContains(2, "Receipt");
TicketScreen.do.selectFilter("Payment");
TicketScreen.check.nthRowContains(2, "Payment");
TicketScreen.do.selectFilter("Ongoing");
TicketScreen.check.nthRowContains(2, "Ongoing");
TicketScreen.do.selectFilter("All active orders");
TicketScreen.check.nthRowContains(4, "Receipt");
TicketScreen.do.search("Customer", "Nicole");
TicketScreen.check.nthRowContains(2, "Nicole");
TicketScreen.do.search("Customer", "Brandon");
TicketScreen.check.nthRowContains(2, "Brandon");
TicketScreen.do.search("Receipt Number", "-0005");
TicketScreen.check.nthRowContains(2, "Receipt");
// Close the TicketScreen to see the current order which is in ReceiptScreen.
// This is just to remove the search string in the search bar.
TicketScreen.do.clickDiscard();
ReceiptScreen.check.isShown();
// Open again the TicketScreen to check the Paid filter.
Chrome.do.clickMenuButton();
Chrome.do.clickTicketButton();
TicketScreen.do.selectFilter("Paid");
TicketScreen.check.nthRowContains(2, "-0005");
// Pay the order that was in PaymentScreen.
TicketScreen.do.selectFilter("Payment");
TicketScreen.do.selectOrder("-0004");
TicketScreen.do.loadSelectedOrder();
PaymentScreen.do.clickPaymentMethod("Cash");
PaymentScreen.do.clickValidate();
ReceiptScreen.check.isShown();
ReceiptScreen.do.clickNextOrder();
ProductScreen.check.isShown();
// Check that the Paid filter will show the 2 synced orders.
Chrome.do.clickMenuButton();
Chrome.do.clickTicketButton();
TicketScreen.do.selectFilter("Paid");
TicketScreen.check.nthRowContains(2, "Brandon Freeman");
TicketScreen.check.nthRowContains(3, "-0005");
// Invoice order
TicketScreen.do.selectOrder("-0005");
TicketScreen.check.orderWidgetIsNotEmpty();
TicketScreen.do.clickControlButton("Invoice");
Chrome.do.confirmPopup();
PartnerListScreen.check.isShown();
PartnerListScreen.do.clickPartner("Colleen Diaz");
TicketScreen.check.invoicePrinted();
TicketScreen.do.clickBackToMainTicketScreen();
TicketScreen.check.partnerIs("Colleen Diaz");
// Reprint receipt
TicketScreen.do.clickControlButton("Print Receipt");
ReceiptScreen.check.isShown();
ReceiptScreen.do.clickBack();
TicketScreen.do.clickBackToMainTicketScreen();
// When going back, the ticket screen should be in its previous state.
TicketScreen.check.filterIs("Paid");
return getSteps();
}
});
// Test refund //
TicketScreen.do.clickDiscard();
ProductScreen.check.isShown();
ProductScreen.check.orderIsEmpty();
ProductScreen.do.clickRefund();
// Filter should be automatically 'Paid'.
TicketScreen.check.filterIs("Paid");
TicketScreen.do.selectOrder("-0005");
TicketScreen.check.partnerIs("Colleen Diaz");
TicketScreen.do.clickOrderline("Desk Pad");
TicketScreen.do.pressNumpad("3");
// Error should show because 2 is more than the number
// that can be refunded.
ErrorPopup.do.clickConfirm();
TicketScreen.do.clickDiscard();
ProductScreen.do.goBackToMainScreen();
ProductScreen.check.isShown();
ProductScreen.check.orderIsEmpty();
ProductScreen.do.clickRefund();
TicketScreen.do.selectOrder("-0005");
TicketScreen.do.clickOrderline("Desk Pad");
TicketScreen.do.pressNumpad("1");
TicketScreen.check.toRefundTextContains("To Refund: 1.00");
TicketScreen.do.confirmRefund();
ProductScreen.do.goBackToMainScreen();
ProductScreen.check.isShown();
ProductScreen.check.selectedOrderlineHas("Desk Pad", "-1.00");
// Try changing the refund line to positive number.
// Error popup should show.
ProductScreen.do.pressNumpad("2");
ErrorPopup.do.clickConfirm();
// Change the refund line quantity to -3 -- not allowed
// so error popup.
ProductScreen.do.pressNumpad("+/- 3");
ErrorPopup.do.clickConfirm();
// Change the refund line quantity to -2 -- allowed.
ProductScreen.do.pressNumpad("+/- 2");
ProductScreen.check.selectedOrderlineHas("Desk Pad", "-2.00");
// Check if the amount being refunded changed to 2.
ProductScreen.do.clickRefund();
TicketScreen.do.selectOrder("-0005");
TicketScreen.check.toRefundTextContains("Refunding 2.00");
TicketScreen.do.clickDiscard();
ProductScreen.do.goBackToMainScreen();
// Pay the refund order.
ProductScreen.do.clickPayButton();
PaymentScreen.do.clickPaymentMethod("Bank");
PaymentScreen.do.clickValidate();
ReceiptScreen.check.isShown();
ReceiptScreen.do.clickNextOrder();
// Check refunded quantity.
ProductScreen.do.clickRefund();
TicketScreen.do.selectOrder("-0005");
TicketScreen.check.refundedNoteContains("2.00 Refunded");
return getSteps();
},
});
@@ -7,7 +7,27 @@ class Do {
return [{ trigger: ".ticket-screen .highlight" }];
}
clickDiscard() {
return [{ trigger: ".ticket-screen button.discard" }];
return [
{
content: "go back",
trigger: ".ticket-screen button.discard",
mobile: false,
},
{
content: "go back",
trigger: ".pos-rightheader .floor-button",
mobile: true,
},
];
}
clickReview() {
return [
{
content: "click review button",
trigger: ".btn-switchpane:contains('Review')",
mobile: true,
},
];
}
selectOrder(orderName) {
return [
@@ -16,20 +36,36 @@ class Do {
},
];
}
loadSelectedOrder() {
return [
{
content: "click review button",
trigger: ".btn-switchpane:contains('Review')",
mobile: true,
},
{
trigger: ".ticket-screen .pads .button.validation.load-order-button",
},
];
}
deleteOrder(orderName) {
return [
{
trigger: `.ticket-screen .order-row > .col:nth-child(2):contains("${orderName}")`,
mobile: true,
},
{
trigger: `.ticket-screen .order-row:has(.col:nth-child(2):contains("${orderName}")) .delete-button`,
mobile: true,
},
{
trigger: `.ticket-screen .orders > .order-row > .col:contains("${orderName}") ~ .col[name="delete"]`,
mobile: false,
},
];
}
selectFilter(name) {
return [
{
content: "open search bar",
trigger: "button.search",
mobile: true,
},
{
trigger: `.pos-search-bar .filter`,
},
@@ -40,20 +76,10 @@ class Do {
{
trigger: `.pos-search-bar .filter ul li:contains("${name}")`,
},
{
content: "close search bar",
trigger: "button.arrow-left",
mobile: true,
},
];
}
search(field, searchWord) {
return [
{
content: "open search bar",
trigger: "button.search",
mobile: true,
},
{
trigger: ".pos-search-bar input",
run: `text ${searchWord}`,
@@ -73,11 +99,6 @@ class Do {
{
trigger: `.pos-search-bar .search ul li:contains("${field}")`,
},
{
content: "close search bar",
trigger: "button.arrow-left",
mobile: true,
},
];
}
settleTips() {
@@ -89,13 +110,32 @@ class Do {
}
clickControlButton(name) {
return [
{
content: "click review button",
trigger: ".btn-switchpane:contains('Review')",
mobile: true,
},
{
trigger: `.ticket-screen .control-button:contains("${name}")`,
},
];
}
clickBackToMainTicketScreen() {
return [
{
content: "Go back to main TicketScreen when in mobile",
trigger: ".pos-rightheader .floor-button",
mobile: true,
},
];
}
clickOrderline(name) {
return [
{
content: "click review button",
trigger: ".btn-switchpane:contains('Review')",
mobile: true,
},
{
trigger: `.ticket-screen .orderline:not(:has(.selected)) .product-name:contains("${name}")`,
},
@@ -103,6 +143,11 @@ class Do {
trigger: `.ticket-screen .orderline.selected .product-name:contains("${name}")`,
run: () => {},
},
{
content: "go back",
trigger: ".pos-rightheader .floor-button",
mobile: true,
},
];
}
pressNumpad(key) {
@@ -115,13 +160,28 @@ class Do {
trigger = `.numpad .numpad-minus`;
}
return [
{
content: "click review button",
trigger: ".btn-switchpane:contains('Review')",
mobile: true,
},
{
trigger,
},
{
content: "go back",
trigger: ".pos-rightheader .floor-button",
mobile: true,
},
];
}
confirmRefund() {
return [
{
content: "click review button",
trigger: ".btn-switchpane:contains('Review')",
mobile: true,
},
{
trigger: ".ticket-screen .button.pay-order-button",
},
@@ -174,52 +234,90 @@ class Check {
}
orderWidgetIsNotEmpty() {
return [
{
content: "click review button",
trigger: ".btn-switchpane:contains('Review')",
mobile: true,
},
{
trigger: ".ticket-screen:not(:has(.order-empty))",
run: () => {},
},
{
content: "go back",
trigger: ".pos-rightheader .floor-button",
mobile: true,
},
];
}
filterIs(name) {
return [
{
content: "open search bar",
trigger: "button.search",
mobile: true,
},
{
trigger: `.ticket-screen .pos-search-bar .filter span:contains("${name}")`,
run: () => {},
},
];
}
invoicePrinted() {
return [
{
content: "close search bar",
trigger: "button.arrow-left",
mobile: true,
trigger: '.ticket-screen .control-button:contains("Reprint Invoice")',
run: () => {},
},
];
}
partnerIs(name) {
return [
{
content: "click review button",
trigger: ".btn-switchpane:contains('Review')",
mobile: true,
},
{
trigger: `.ticket-screen .set-partner:contains("${name}")`,
run: () => {},
},
{
content: "Go back to main TicketScreen when in mobile",
trigger: ".pos-rightheader .floor-button",
mobile: true,
},
];
}
toRefundTextContains(text) {
return [
{
content: "click review button",
trigger: ".btn-switchpane:contains('Review')",
mobile: true,
},
{
trigger: `.ticket-screen .to-refund-highlight:contains("${text}")`,
run: () => {},
},
{
content: "Go back to main TicketScreen when in mobile",
trigger: ".pos-rightheader .floor-button",
mobile: true,
},
];
}
refundedNoteContains(text) {
return [
{
content: "click review button",
trigger: ".btn-switchpane:contains('Review')",
mobile: true,
},
{
trigger: `.ticket-screen .refund-note:contains("${text}")`,
run: () => {},
},
{
content: "Go back to main TicketScreen when in mobile",
trigger: ".pos-rightheader .floor-button",
mobile: true,
},
];
}
tipContains(amount) {
@@ -14,7 +14,7 @@ patch(TicketScreen.prototype, {
this.notification = useService("pos_notification");
},
_onUpdateSelectedOrderline() {
const order = this.getSelectedSyncedOrder();
const order = this.getSelectedOrder();
if (!order) {
return this.numberBuffer.reset();
}
@@ -17,7 +17,7 @@ patch(BackButton.prototype, {
* If we have a floor screen,
* the logic of the back button changes a bit.
*/
async backToFloorScreen() {
async onClick() {
if (this.pos.mainScreen.component && this.pos.config.module_pos_restaurant) {
if (
(this.pos.mainScreen.component === ProductScreen &&
@@ -26,12 +26,10 @@ patch(BackButton.prototype, {
) {
this.pos.showScreen("FloorScreen", { floor: this.floor });
} else {
this.pos.mobile_pane = "right";
this.pos.showScreen("ProductScreen");
super.onClick(...arguments);
}
} else {
this.pos.mobile_pane = "right";
this.pos.showScreen("ProductScreen");
return;
}
super.onClick(...arguments);
},
});
@@ -50,7 +50,7 @@ patch(TicketScreen.prototype, {
// we came from the FloorScreen
const orderTable = order.getTable();
await this.pos.setTable(orderTable, order.uid);
this.pos.closeScreen();
this.closeTicketScreen();
},
get allowNewOrders() {
return this.pos.config.module_pos_restaurant
@@ -126,7 +126,7 @@ patch(TicketScreen.prototype, {
return result;
},
async onDoRefund() {
const order = this.getSelectedSyncedOrder();
const order = this.getSelectedOrder();
if (this.pos.config.module_pos_restaurant && order && !this.pos.table) {
this.pos.setTable(order.table ? order.table : Object.values(this.pos.tables_by_id)[0]);
}
@@ -53,6 +53,7 @@ registry
Chrome.do.clickMenuButton();
Chrome.do.clickTicketButton();
TicketScreen.do.selectOrder("-0001");
TicketScreen.do.loadSelectedOrder();
ProductScreen.check.isShown();
ProductScreen.do.clickOrderline("Water", "2.0");
ProductScreen.do.clickOrderline("Minute Maid", "3.0");
@@ -86,12 +87,14 @@ registry
Chrome.do.clickMenuButton();
Chrome.do.clickTicketButton();
TicketScreen.do.selectOrder("-0002");
TicketScreen.do.loadSelectedOrder();
ProductScreen.do.clickOrderline("Water", "1.0");
ProductScreen.do.clickOrderline("Coca-Cola", "1.0");
ProductScreen.check.totalAmountIs("4.00");
Chrome.do.clickMenuButton();
Chrome.do.clickTicketButton();
TicketScreen.do.selectOrder("-0001");
TicketScreen.do.loadSelectedOrder();
ProductScreen.do.clickOrderline("Minute Maid", "1.0");
ProductScreen.check.totalAmountIs("2.00");
return getSteps();
@@ -48,6 +48,7 @@ registry
TicketScreen.do.deleteOrder("-0003");
Chrome.do.confirmPopup();
TicketScreen.do.selectOrder("-0002");
TicketScreen.do.loadSelectedOrder();
ProductScreen.check.isShown();
ProductScreen.check.totalAmountIs("2.0");
Chrome.do.backToFloor();
@@ -11,146 +11,147 @@ import { Chrome } from "@pos_restaurant/../tests/tours/helpers/ChromeTourMethods
import { getSteps, startSteps } from "@point_of_sale/../tests/tours/helpers/utils";
import { registry } from "@web/core/registry";
registry.category("web_tour.tours").add("PosResTipScreenTour", {
test: true,
url: "/pos/ui",
steps: () => {
startSteps();
registry
.category("web_tour.tours")
.add("PosResTipScreenTour", {
test: true,
url: "/pos/ui",
steps: () => {
startSteps();
// Create order that is synced when draft.
// order 1
ProductScreen.do.confirmOpeningPopup();
FloorScreen.do.clickTable("2");
ProductScreen.exec.addOrderline("Minute Maid", "1", "2");
ProductScreen.check.totalAmountIs("2.0");
Chrome.do.backToFloor();
FloorScreen.check.orderCountSyncedInTableIs("2", "1");
FloorScreen.do.clickTable("2");
ProductScreen.check.totalAmountIs("2.0");
ProductScreen.do.clickPayButton();
PaymentScreen.do.clickPaymentMethod("Bank");
PaymentScreen.do.clickValidate();
TipScreen.check.isShown();
Chrome.do.clickMenuButton();
Chrome.do.clickTicketButton();
TicketScreen.do.clickNewTicket();
// order 2
ProductScreen.exec.addOrderline("Coca-Cola", "2", "2");
ProductScreen.check.totalAmountIs("4.0");
Chrome.do.backToFloor();
FloorScreen.check.orderCountSyncedInTableIs("2", "2");
Chrome.do.clickMenuButton();
Chrome.do.clickTicketButton();
TicketScreen.check.nthRowContains("2", "Tipping");
TicketScreen.do.clickDiscard();
// Create without syncing the draft.
// order 3
FloorScreen.do.clickTable("5");
ProductScreen.exec.addOrderline("Minute Maid", "3", "2");
ProductScreen.check.totalAmountIs("6.0");
ProductScreen.do.clickPayButton();
PaymentScreen.do.clickPaymentMethod("Bank");
PaymentScreen.do.clickValidate();
TipScreen.check.isShown();
Chrome.do.clickMenuButton();
Chrome.do.clickTicketButton();
TicketScreen.do.clickNewTicket();
// order 4
ProductScreen.exec.addOrderline("Coca-Cola", "4", "2");
ProductScreen.check.totalAmountIs("8.0");
Chrome.do.backToFloor();
FloorScreen.check.orderCountSyncedInTableIs("5", "4");
Chrome.do.clickMenuButton();
Chrome.do.clickTicketButton();
TicketScreen.check.nthRowContains("4", "Tipping");
// Create order that is synced when draft.
// order 1
ProductScreen.do.confirmOpeningPopup();
FloorScreen.do.clickTable("2");
ProductScreen.exec.addOrderline("Minute Maid", "1", "2");
ProductScreen.check.totalAmountIs("2.0");
Chrome.do.backToFloor();
FloorScreen.check.orderCountSyncedInTableIs("2", "1");
FloorScreen.do.clickTable("2");
ProductScreen.check.totalAmountIs("2.0");
ProductScreen.do.clickPayButton();
PaymentScreen.do.clickPaymentMethod("Bank");
PaymentScreen.do.clickValidate();
TipScreen.check.isShown();
Chrome.do.clickMenuButton();
Chrome.do.clickTicketButton();
TicketScreen.do.clickNewTicket();
// order 2
ProductScreen.exec.addOrderline("Coca-Cola", "2", "2");
ProductScreen.check.totalAmountIs("4.0");
Chrome.do.backToFloor();
FloorScreen.check.orderCountSyncedInTableIs("2", "2");
Chrome.do.clickMenuButton();
Chrome.do.clickTicketButton();
TicketScreen.check.nthRowContains("2", "Tipping");
TicketScreen.do.clickDiscard();
// Tip 20% on order1
TicketScreen.do.selectOrder("-0001");
TipScreen.check.isShown();
TipScreen.check.totalAmountIs("2.0");
TipScreen.check.percentAmountIs("15%", "0.30");
TipScreen.check.percentAmountIs("20%", "0.40");
TipScreen.check.percentAmountIs("25%", "0.50");
TipScreen.do.clickPercentTip("20%");
TipScreen.check.inputAmountIs("0.40");
Chrome.do.backToFloor();
FloorScreen.check.isShown();
Chrome.do.clickMenuButton();
Chrome.do.clickTicketButton();
// Create without syncing the draft.
// order 3
FloorScreen.do.clickTable("5");
ProductScreen.exec.addOrderline("Minute Maid", "3", "2");
ProductScreen.check.totalAmountIs("6.0");
ProductScreen.do.clickPayButton();
PaymentScreen.do.clickPaymentMethod("Bank");
PaymentScreen.do.clickValidate();
TipScreen.check.isShown();
Chrome.do.clickMenuButton();
Chrome.do.clickTicketButton();
TicketScreen.do.clickNewTicket();
// order 4
ProductScreen.exec.addOrderline("Coca-Cola", "4", "2");
ProductScreen.check.totalAmountIs("8.0");
Chrome.do.backToFloor();
FloorScreen.check.orderCountSyncedInTableIs("5", "4");
Chrome.do.clickMenuButton();
Chrome.do.clickTicketButton();
TicketScreen.check.nthRowContains("4", "Tipping");
// Tip 25% on order3
TicketScreen.do.selectOrder("-0003");
TipScreen.check.isShown();
TipScreen.check.totalAmountIs("6.0");
TipScreen.check.percentAmountIs("15%", "0.90");
TipScreen.check.percentAmountIs("20%", "1.20");
TipScreen.check.percentAmountIs("25%", "1.50");
TipScreen.do.clickPercentTip("25%");
TipScreen.check.inputAmountIs("1.50");
Chrome.do.backToFloor();
FloorScreen.check.isShown();
Chrome.do.clickMenuButton();
Chrome.do.clickTicketButton();
// Tip 20% on order1
TicketScreen.do.selectOrder("-0001");
TicketScreen.do.loadSelectedOrder();
TipScreen.check.isShown();
TipScreen.check.totalAmountIs("2.0");
TipScreen.check.percentAmountIs("15%", "0.30");
TipScreen.check.percentAmountIs("20%", "0.40");
TipScreen.check.percentAmountIs("25%", "0.50");
TipScreen.do.clickPercentTip("20%");
TipScreen.check.inputAmountIs("0.40");
Chrome.do.backToFloor();
FloorScreen.check.isShown();
Chrome.do.clickMenuButton();
Chrome.do.clickTicketButton();
// finalize order 4 then tip custom amount
TicketScreen.do.selectOrder("-0004");
ProductScreen.check.isShown();
ProductScreen.check.totalAmountIs("8.0");
ProductScreen.do.clickPayButton();
PaymentScreen.do.clickPaymentMethod("Bank");
PaymentScreen.do.clickValidate();
TipScreen.check.isShown();
TipScreen.check.totalAmountIs("8.0");
TipScreen.check.percentAmountIs("15%", "1.20");
TipScreen.check.percentAmountIs("20%", "1.60");
TipScreen.check.percentAmountIs("25%", "2.00");
TipScreen.do.setCustomTip("1.00");
TipScreen.check.inputAmountIs("1.00");
Chrome.do.backToFloor();
FloorScreen.check.isShown();
// Tip 25% on order3
TicketScreen.do.selectOrder("-0003");
TicketScreen.do.loadSelectedOrder();
TipScreen.check.isShown();
TipScreen.check.totalAmountIs("6.0");
TipScreen.check.percentAmountIs("15%", "0.90");
TipScreen.check.percentAmountIs("20%", "1.20");
TipScreen.check.percentAmountIs("25%", "1.50");
TipScreen.do.clickPercentTip("25%");
TipScreen.check.inputAmountIs("1.50");
Chrome.do.backToFloor();
FloorScreen.check.isShown();
Chrome.do.clickMenuButton();
Chrome.do.clickTicketButton();
// settle tips here
Chrome.do.clickMenuButton();
Chrome.do.clickTicketButton();
TicketScreen.do.selectFilter("Tipping");
TicketScreen.check.tipContains("1.00");
TicketScreen.do.settleTips();
TicketScreen.do.selectFilter("All active orders");
TicketScreen.check.nthRowContains(2, "Ongoing");
// tip order2 during payment
// tip screen should not show after validating payment screen
TicketScreen.do.selectOrder("-0002");
ProductScreen.check.isShown();
ProductScreen.do.clickPayButton();
PaymentScreen.do.clickTipButton();
NumberPopup.check.isShown();
NumberPopup.do.enterValue("1");
NumberPopup.check.inputShownIs("1");
NumberPopup.do.clickConfirm();
PaymentScreen.check.emptyPaymentlines("5.0");
PaymentScreen.do.clickPaymentMethod("Cash");
PaymentScreen.do.clickValidate();
ReceiptScreen.check.isShown();
// finalize order 4 then tip custom amount
TicketScreen.do.selectOrder("-0004");
TicketScreen.do.loadSelectedOrder();
ProductScreen.check.isShown();
ProductScreen.check.totalAmountIs("8.0");
ProductScreen.do.clickPayButton();
PaymentScreen.do.clickPaymentMethod("Bank");
PaymentScreen.do.clickValidate();
TipScreen.check.isShown();
TipScreen.check.totalAmountIs("8.0");
TipScreen.check.percentAmountIs("15%", "1.20");
TipScreen.check.percentAmountIs("20%", "1.60");
TipScreen.check.percentAmountIs("25%", "2.00");
TipScreen.do.setCustomTip("1.00");
TipScreen.check.inputAmountIs("1.00");
Chrome.do.backToFloor();
FloorScreen.check.isShown();
// order 5
// Click directly on "settle" without selecting a Tip
ReceiptScreen.do.clickNextOrder();
FloorScreen.do.clickTable("2");
ProductScreen.exec.addOrderline("Minute Maid", "3", "2");
ProductScreen.check.totalAmountIs("6.0");
ProductScreen.do.clickPayButton();
PaymentScreen.do.clickPaymentMethod("Bank");
PaymentScreen.do.clickValidate();
TipScreen.check.isShown();
TipScreen.do.clickSettle();
ReceiptScreen.check.isShown();
ReceiptScreen.do.clickNextOrder();
FloorScreen.check.isShown();
return getSteps();
}
});
// settle tips here
Chrome.do.clickMenuButton();
Chrome.do.clickTicketButton();
TicketScreen.do.selectFilter("Tipping");
TicketScreen.check.tipContains("1.00");
TicketScreen.do.settleTips();
TicketScreen.do.selectFilter("All active orders");
TicketScreen.check.nthRowContains(2, "Ongoing");
// tip order2 during payment
// tip screen should not show after validating payment screen
TicketScreen.do.selectOrder("-0002");
TicketScreen.do.loadSelectedOrder();
ProductScreen.check.isShown();
ProductScreen.do.clickPayButton();
PaymentScreen.do.clickTipButton();
NumberPopup.check.isShown();
NumberPopup.do.enterValue("1");
NumberPopup.check.inputShownIs("1");
NumberPopup.do.clickConfirm();
PaymentScreen.check.emptyPaymentlines("5.0");
PaymentScreen.do.clickPaymentMethod("Cash");
PaymentScreen.do.clickValidate();
ReceiptScreen.check.isShown();
// order 5
// Click directly on "settle" without selecting a Tip
ReceiptScreen.do.clickNextOrder();
FloorScreen.do.clickTable("2");
ProductScreen.exec.addOrderline("Minute Maid", "3", "2");
ProductScreen.check.totalAmountIs("6.0");
ProductScreen.do.clickPayButton();
PaymentScreen.do.clickPaymentMethod("Bank");
PaymentScreen.do.clickValidate();
TipScreen.check.isShown();
TipScreen.do.clickSettle();
ReceiptScreen.check.isShown();
ReceiptScreen.do.clickNextOrder();
FloorScreen.check.isShown();
return getSteps();
},
});
@@ -75,6 +75,7 @@ registry.category("web_tour.tours").add("pos_restaurant_sync", {
Chrome.check.isSyncStatusPending();
Chrome.check.isSyncStatusConnected();
TicketScreen.do.selectOrder("-0003");
TicketScreen.do.loadSelectedOrder();
Chrome.do.backToFloor();
// There should be 1 synced draft order.