From 6ce6d6ea7bee1371817841537e920dcffb333fa7 Mon Sep 17 00:00:00 2001 From: "Adrien Guilliams (adgu)" Date: Mon, 10 Jul 2023 13:17:25 +0000 Subject: [PATCH] [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) --- .../src/app/navbar/back_button/back_button.js | 15 +- .../app/navbar/back_button/back_button.xml | 2 +- .../order_details/order_details.xml | 6 +- .../screens/ticket_screen/ticket_screen.js | 99 ++++-- .../screens/ticket_screen/ticket_screen.xml | 124 ++++--- .../static/src/app/store/pos_store.js | 11 +- addons/point_of_sale/static/src/scss/pos.scss | 14 +- .../static/tests/tours/Chrome.tour.js | 5 + .../static/tests/tours/TicketScreen.tour.js | 326 +++++++++--------- .../tours/helpers/TicketScreenTourMethods.js | 156 +++++++-- .../components/ticket_screen/ticket_screen.js | 2 +- .../navbar/back_button/back_button.js | 10 +- .../components/ticket_screen/ticket_screen.js | 4 +- .../tests/tours/SplitBillScreen.tour.js | 3 + .../static/tests/tours/TicketScreen.tour.js | 1 + .../static/tests/tours/TipScreen.tour.js | 275 +++++++-------- .../static/tests/tours/pos_restaurant.js | 1 + 17 files changed, 619 insertions(+), 435 deletions(-) diff --git a/addons/point_of_sale/static/src/app/navbar/back_button/back_button.js b/addons/point_of_sale/static/src/app/navbar/back_button/back_button.js index ea9abf06f9c..7ad26cfa1a4 100644 --- a/addons/point_of_sale/static/src/app/navbar/back_button/back_button.js +++ b/addons/point_of_sale/static/src/app/navbar/back_button/back_button.js @@ -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"); + } } } diff --git a/addons/point_of_sale/static/src/app/navbar/back_button/back_button.xml b/addons/point_of_sale/static/src/app/navbar/back_button/back_button.xml index 721f6d5ccd6..d8b3029378c 100644 --- a/addons/point_of_sale/static/src/app/navbar/back_button/back_button.xml +++ b/addons/point_of_sale/static/src/app/navbar/back_button/back_button.xml @@ -4,7 +4,7 @@ BACK diff --git a/addons/point_of_sale/static/src/app/screens/ticket_screen/order_details/order_details.xml b/addons/point_of_sale/static/src/app/screens/ticket_screen/order_details/order_details.xml index 25900d9b890..54978b97b6e 100644 --- a/addons/point_of_sale/static/src/app/screens/ticket_screen/order_details/order_details.xml +++ b/addons/point_of_sale/static/src/app/screens/ticket_screen/order_details/order_details.xml @@ -5,7 +5,7 @@
- +
@@ -13,14 +13,14 @@
-
+

Order is empty

-
+
Select the product(s) to refund and set the quantity
    diff --git a/addons/point_of_sale/static/src/app/screens/ticket_screen/ticket_screen.js b/addons/point_of_sale/static/src/app/screens/ticket_screen/ticket_screen.js index 6ecac76a537..acb734f42b6 100644 --- a/addons/point_of_sale/static/src/app/screens/ticket_screen/ticket_screen.js +++ b/addons/point_of_sale/static/src/app/screens/ticket_screen/ticket_screen.js @@ -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(); diff --git a/addons/point_of_sale/static/src/app/screens/ticket_screen/ticket_screen.xml b/addons/point_of_sale/static/src/app/screens/ticket_screen/ticket_screen.xml index e8e10b22e7d..4e04302a4fe 100644 --- a/addons/point_of_sale/static/src/app/screens/ticket_screen/ticket_screen.xml +++ b/addons/point_of_sale/static/src/app/screens/ticket_screen/ticket_screen.xml @@ -4,11 +4,11 @@
    -
    +
    - +
    -
    - - - - - - - + +