From b71e05e804b24fcb516c7ef467a8dfcc273668e7 Mon Sep 17 00:00:00 2001 From: vlst Date: Sat, 12 Aug 2023 22:16:21 +0200 Subject: [PATCH] [REF] point_of_sale: unify numpads At the moment, the point_of_sale module has 3 different implementations of numpads. This is absurd. In this PR we unify them all into a single numpad component. One of the reasons why there are multiple numpads is because each requires a slightly different set of buttons. The new `Numpad` component provides a simple API which allows the consumer to specify what the buttons should be. This is done by proving the `buttons` prop, which has the following type: ```js buttons: { type: Array, element: { type: Object, shape: { value: String, text: { type: String, optional: true }, class: { type: String, optional: true }, disabled: { type: Boolean, optional: true }, }, }, } ``` In this PR we also provide a simple set of helper functions for the tours and adapt all of the existing tests accordingly. closes odoo/odoo#132245 Task: 3470346 Related: odoo/enterprise#46427 Signed-off-by: Joseph Caburnay (jcb) --- .../app/generic_components/numpad/numpad.js | 35 ++ .../app/generic_components/numpad/numpad.scss | 3 + .../app/generic_components/numpad/numpad.xml | 12 + .../screens/payment_screen/numpad/numpad.js | 14 - .../screens/payment_screen/numpad/numpad.scss | 15 - .../screens/payment_screen/numpad/numpad.xml | 28 -- .../numpad/numpad_button/numpad_button.js | 16 - .../numpad/numpad_button/numpad_button.xml | 18 - .../screens/payment_screen/payment_screen.js | 24 +- .../screens/payment_screen/payment_screen.xml | 8 +- .../category_button/category_button.xml | 15 - .../screens/product_screen/numpad/numpad.js | 48 -- .../screens/product_screen/numpad/numpad.scss | 10 - .../screens/product_screen/numpad/numpad.xml | 40 -- .../screens/product_screen/product_screen.js | 38 +- .../screens/product_screen/product_screen.xml | 4 +- .../screens/ticket_screen/ticket_screen.js | 24 +- .../screens/ticket_screen/ticket_screen.xml | 6 +- .../app/utils/input_popups/number_popup.js | 28 +- .../app/utils/input_popups/number_popup.scss | 5 - .../app/utils/input_popups/number_popup.xml | 43 +- .../static/src/img/backspace.png | Bin 5970 -> 0 bytes .../tests/tours/FixedPriceNegativeQty.tour.js | 2 +- .../static/tests/tours/PaymentScreen.tour.js | 2 +- .../static/tests/tours/PosComboTour.js | 2 +- .../static/tests/tours/ProductScreen.tour.js | 48 +- .../static/tests/tours/TicketScreen.tour.js | 9 +- .../static/tests/tours/acceptance_tour.js | 14 +- .../tours/helpers/NumberPopupTourMethods.js | 32 +- .../tests/tours/helpers/NumpadTourMethods.js | 20 + .../tours/helpers/PaymentScreenTourMethods.js | 20 +- .../tours/helpers/ProductScreenTourMethods.js | 53 +- .../tours/helpers/TicketScreenTourMethods.js | 25 - .../static/tests/tours/pricelist_tour.js | 33 +- .../tests/tours/GiftCardProgramTours.js | 2 +- .../tours/MultipleGiftWalletProgramsTour.js | 8 +- .../tours/PosLoyaltyLoyaltyProgramTour.js | 343 +++++++------ .../tests/tours/PosLoyaltyRewardButtonTour.js | 380 +++++++------- .../static/tests/tours/PosLoyaltyTour.js | 476 +++++++++--------- .../tests/tours/PosLoyaltyTourMethods.js | 2 +- .../static/tests/tours/FloorScreen.tour.js | 234 +++++---- .../static/tests/tours/Refund.tour.js | 6 +- .../tests/helpers/ProductScreenTourMethods.js | 2 +- .../static/tests/tours/PosSaleTour.js | 6 +- 44 files changed, 956 insertions(+), 1197 deletions(-) create mode 100644 addons/point_of_sale/static/src/app/generic_components/numpad/numpad.js create mode 100644 addons/point_of_sale/static/src/app/generic_components/numpad/numpad.scss create mode 100644 addons/point_of_sale/static/src/app/generic_components/numpad/numpad.xml delete mode 100644 addons/point_of_sale/static/src/app/screens/payment_screen/numpad/numpad.js delete mode 100644 addons/point_of_sale/static/src/app/screens/payment_screen/numpad/numpad.scss delete mode 100644 addons/point_of_sale/static/src/app/screens/payment_screen/numpad/numpad.xml delete mode 100644 addons/point_of_sale/static/src/app/screens/payment_screen/numpad/numpad_button/numpad_button.js delete mode 100644 addons/point_of_sale/static/src/app/screens/payment_screen/numpad/numpad_button/numpad_button.xml delete mode 100644 addons/point_of_sale/static/src/app/screens/product_screen/category_button/category_button.xml delete mode 100644 addons/point_of_sale/static/src/app/screens/product_screen/numpad/numpad.js delete mode 100644 addons/point_of_sale/static/src/app/screens/product_screen/numpad/numpad.scss delete mode 100644 addons/point_of_sale/static/src/app/screens/product_screen/numpad/numpad.xml delete mode 100644 addons/point_of_sale/static/src/app/utils/input_popups/number_popup.scss delete mode 100644 addons/point_of_sale/static/src/img/backspace.png create mode 100644 addons/point_of_sale/static/tests/tours/helpers/NumpadTourMethods.js diff --git a/addons/point_of_sale/static/src/app/generic_components/numpad/numpad.js b/addons/point_of_sale/static/src/app/generic_components/numpad/numpad.js new file mode 100644 index 00000000000..d61390065a6 --- /dev/null +++ b/addons/point_of_sale/static/src/app/generic_components/numpad/numpad.js @@ -0,0 +1,35 @@ +/** @odoo-module */ + +import { useService } from "@web/core/utils/hooks"; +import { Component } from "@odoo/owl"; + +export class Numpad extends Component { + static template = "point_of_sale.Numpad"; + static props = { + class: { type: String, optional: true }, + onClick: { type: Function, optional: true }, + buttons: { + type: Array, + element: { + type: Object, + shape: { + value: String, + text: { type: String, optional: true }, + class: { type: String, optional: true }, + disabled: { type: Boolean, optional: true }, + }, + }, + }, + }; + static defaultProps = { + class: "", + }; + setup() { + if (!this.props.onClick) { + this.numberBuffer = useService("number_buffer"); + this.onClick = (buttonValue) => this.numberBuffer.sendKey(buttonValue); + } else { + this.onClick = this.props.onClick; + } + } +} diff --git a/addons/point_of_sale/static/src/app/generic_components/numpad/numpad.scss b/addons/point_of_sale/static/src/app/generic_components/numpad/numpad.scss new file mode 100644 index 00000000000..947c50b5bb7 --- /dev/null +++ b/addons/point_of_sale/static/src/app/generic_components/numpad/numpad.scss @@ -0,0 +1,3 @@ +.max-width-325px { + max-width: 325px; +} diff --git a/addons/point_of_sale/static/src/app/generic_components/numpad/numpad.xml b/addons/point_of_sale/static/src/app/generic_components/numpad/numpad.xml new file mode 100644 index 00000000000..bf2e4ad0f02 --- /dev/null +++ b/addons/point_of_sale/static/src/app/generic_components/numpad/numpad.xml @@ -0,0 +1,12 @@ + + + +
+
+
+
diff --git a/addons/point_of_sale/static/src/app/screens/payment_screen/numpad/numpad.js b/addons/point_of_sale/static/src/app/screens/payment_screen/numpad/numpad.js deleted file mode 100644 index 920bf2b959f..00000000000 --- a/addons/point_of_sale/static/src/app/screens/payment_screen/numpad/numpad.js +++ /dev/null @@ -1,14 +0,0 @@ -/** @odoo-module */ - -import { PSNumpadInputButton } from "@point_of_sale/app/screens/payment_screen/numpad/numpad_button/numpad_button"; -import { Component } from "@odoo/owl"; -import { useService } from "@web/core/utils/hooks"; - -export class PaymentScreenNumpad extends Component { - static components = { PSNumpadInputButton }; - static template = "point_of_sale.PaymentScreenNumpad"; - - setup() { - this.decimalPoint = useService("localization").decimalPoint; - } -} diff --git a/addons/point_of_sale/static/src/app/screens/payment_screen/numpad/numpad.scss b/addons/point_of_sale/static/src/app/screens/payment_screen/numpad/numpad.scss deleted file mode 100644 index 2cea5999814..00000000000 --- a/addons/point_of_sale/static/src/app/screens/payment_screen/numpad/numpad.scss +++ /dev/null @@ -1,15 +0,0 @@ -.payment-numpad .numpad button { - font-size: clamp(map-get($font-sizes, 6), 3vw, 36px); -} - -.payment-numpad .numpad button:nth-child(16) img { - width: 35%; - max-width: 64px; - height: auto; -} - -@include media-breakpoint-down(md) { - .payment-numpad .numpad button:nth-child(16) img { - max-width: 48px; - } -} diff --git a/addons/point_of_sale/static/src/app/screens/payment_screen/numpad/numpad.xml b/addons/point_of_sale/static/src/app/screens/payment_screen/numpad/numpad.xml deleted file mode 100644 index 7a3b2b63b86..00000000000 --- a/addons/point_of_sale/static/src/app/screens/payment_screen/numpad/numpad.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - -
- - - - - - - - - - - - - - - - - Backspace - -
-
- -
diff --git a/addons/point_of_sale/static/src/app/screens/payment_screen/numpad/numpad_button/numpad_button.js b/addons/point_of_sale/static/src/app/screens/payment_screen/numpad/numpad_button/numpad_button.js deleted file mode 100644 index 2cbdbf58aa3..00000000000 --- a/addons/point_of_sale/static/src/app/screens/payment_screen/numpad/numpad_button/numpad_button.js +++ /dev/null @@ -1,16 +0,0 @@ -/** @odoo-module */ - -import { Component } from "@odoo/owl"; -import { useService } from "@web/core/utils/hooks"; - -export class PSNumpadInputButton extends Component { - static template = "point_of_sale.PSNumpadInputButton"; - - setup() { - this.numberBuffer = useService("number_buffer"); - } - - get _class() { - return this.props.changeClassTo || "input-button number-char"; - } -} diff --git a/addons/point_of_sale/static/src/app/screens/payment_screen/numpad/numpad_button/numpad_button.xml b/addons/point_of_sale/static/src/app/screens/payment_screen/numpad/numpad_button/numpad_button.xml deleted file mode 100644 index f492b91516a..00000000000 --- a/addons/point_of_sale/static/src/app/screens/payment_screen/numpad/numpad_button/numpad_button.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - diff --git a/addons/point_of_sale/static/src/app/screens/payment_screen/payment_screen.js b/addons/point_of_sale/static/src/app/screens/payment_screen/payment_screen.js index f0c7ee20649..2ec3c5acf98 100644 --- a/addons/point_of_sale/static/src/app/screens/payment_screen/payment_screen.js +++ b/addons/point_of_sale/static/src/app/screens/payment_screen/payment_screen.js @@ -13,17 +13,17 @@ import { DatePickerPopup } from "@point_of_sale/app/utils/date_picker_popup/date import { ConfirmPopup } from "@point_of_sale/app/utils/confirm_popup/confirm_popup"; import { ConnectionLostError } from "@web/core/network/rpc_service"; -import { PaymentScreenNumpad } from "@point_of_sale/app/screens/payment_screen/numpad/numpad"; import { PaymentScreenPaymentLines } from "@point_of_sale/app/screens/payment_screen/payment_lines/payment_lines"; import { PaymentScreenStatus } from "@point_of_sale/app/screens/payment_screen/payment_status/payment_status"; import { usePos } from "@point_of_sale/app/store/pos_hook"; import { Component, useState, useRef } from "@odoo/owl"; import { renderToElement } from "@web/core/utils/render"; +import { Numpad } from "@point_of_sale/app/generic_components/numpad/numpad"; export class PaymentScreen extends Component { static template = "point_of_sale.PaymentScreen"; static components = { - PaymentScreenNumpad, + Numpad, PaymentScreenPaymentLines, PaymentScreenStatus, }; @@ -47,6 +47,26 @@ export class PaymentScreen extends Component { this.error = false; this.validateOrder = useAsyncLockedMethod(this.validateOrder); } + getNumpadButtons() { + return [ + { value: "1" }, + { value: "2" }, + { value: "3" }, + { value: "+10" }, + { value: "4" }, + { value: "5" }, + { value: "6" }, + { value: "+20" }, + { value: "7" }, + { value: "8" }, + { value: "9" }, + { value: "+50" }, + { value: "-", text: "+/-" }, + { value: "0" }, + { value: this.env.services.localization.decimalPoint }, + { value: "Backspace", text: "⌫" }, + ]; + } showMaxValueError() { this.popup.add(ErrorPopup, { diff --git a/addons/point_of_sale/static/src/app/screens/payment_screen/payment_screen.xml b/addons/point_of_sale/static/src/app/screens/payment_screen/payment_screen.xml index a3014974359..340300fc18b 100644 --- a/addons/point_of_sale/static/src/app/screens/payment_screen/payment_screen.xml +++ b/addons/point_of_sale/static/src/app/screens/payment_screen/payment_screen.xml @@ -20,9 +20,7 @@
-
- -
+
@@ -55,7 +53,8 @@
- 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 a9b1697bba2..e6495f4728c 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 @@ -12,12 +12,12 @@ import { ConfirmPopup } from "@point_of_sale/app/utils/confirm_popup/confirm_pop import { ActionpadWidget } from "@point_of_sale/app/screens/product_screen/action_pad/action_pad"; import { InvoiceButton } from "@point_of_sale/app/screens/ticket_screen/invoice_button/invoice_button"; -import { NumpadWidget } from "@point_of_sale/app/screens/product_screen/numpad/numpad"; import { OrderDetails } from "@point_of_sale/app/screens/ticket_screen/order_details/order_details"; import { ReprintReceiptButton } from "@point_of_sale/app/screens/ticket_screen/reprint_receipt_button/reprint_receipt_button"; import { SearchBar } from "@point_of_sale/app/screens/ticket_screen/search_bar/search_bar"; import { usePos } from "@point_of_sale/app/store/pos_hook"; import { Component, onMounted, useState } from "@odoo/owl"; +import { Numpad } from "@point_of_sale/app/generic_components/numpad/numpad"; const { DateTime } = luxon; @@ -27,10 +27,10 @@ export class TicketScreen extends Component { static components = { ActionpadWidget, InvoiceButton, - NumpadWidget, OrderDetails, ReprintReceiptButton, SearchBar, + Numpad, }; static defaultProps = { destinationOrder: null, @@ -85,6 +85,26 @@ export class TicketScreen extends Component { await this._fetchSyncedOrders(); } } + getNumpadButtons() { + return [ + { value: "1" }, + { value: "2" }, + { value: "3" }, + { value: "quantity", text: "Qty", class: "active border-primary" }, + { value: "4" }, + { value: "5" }, + { value: "6" }, + { value: "discount", text: "% Disc", disabled: true }, + { value: "7" }, + { value: "8" }, + { value: "9" }, + { value: "price", text: "Price", disabled: true }, + { value: "-", text: "+/-", disabled: true }, + { value: "0" }, + { value: this.env.services.localization.decimalPoint }, + { value: "Backspace", text: "⌫" }, + ]; + } async onSearch(search) { Object.assign(this._state.ui.searchDetails, search); if (this._state.ui.filter == "SYNCED") { 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 4e04302a4fe..bbb4a911217 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 @@ -135,11 +135,7 @@ actionType="'refund'" actionToTrigger.bind="onDoRefund" isActionButtonHighlighted="getHasItemsToRefund()" /> - + diff --git a/addons/point_of_sale/static/src/app/utils/input_popups/number_popup.js b/addons/point_of_sale/static/src/app/utils/input_popups/number_popup.js index ea32ce67566..d3888ed0bc0 100644 --- a/addons/point_of_sale/static/src/app/utils/input_popups/number_popup.js +++ b/addons/point_of_sale/static/src/app/utils/input_popups/number_popup.js @@ -4,9 +4,11 @@ import { _t } from "@web/core/l10n/translation"; import { AbstractAwaitablePopup } from "@point_of_sale/app/popup/abstract_awaitable_popup"; import { useService } from "@web/core/utils/hooks"; import { useState, useRef, onMounted } from "@odoo/owl"; +import { Numpad } from "@point_of_sale/app/generic_components/numpad/numpad"; export class NumberPopup extends AbstractAwaitablePopup { static template = "point_of_sale.NumberPopup"; + static components = { Numpad }; static defaultProps = { confirmText: _t("Confirm"), cancelText: _t("Discard"), @@ -33,7 +35,6 @@ export class NumberPopup extends AbstractAwaitablePopup { */ setup() { super.setup(); - this.localization = useService("localization"); let startingBuffer = ""; let startingPayload = null; if (typeof this.props.startingValue === "number" && this.props.startingValue > 0) { @@ -62,8 +63,26 @@ export class NumberPopup extends AbstractAwaitablePopup { this.inputRef.el.focus(); } } - get decimalSeparator() { - return this.localization.decimalPoint; + getNumpadButtons() { + const { isPassword, cheap } = this.props; + return [ + { value: "1" }, + { value: "2" }, + { value: "3" }, + ...(!isPassword ? [{ value: cheap ? "+1" : "+10" }] : []), + { value: "4" }, + { value: "5" }, + { value: "6" }, + ...(!isPassword ? [{ value: cheap ? "+2" : "+20" }] : []), + { value: "7" }, + { value: "8" }, + { value: "9" }, + ...(!isPassword ? [{ value: "-" }] : []), + { value: "Delete", text: "C" }, + { value: "0" }, + ...(!isPassword ? [{ value: this.env.services.localization.decimalPoint }] : []), + { value: "Backspace", text: "⌫" }, + ]; } get inputBuffer() { if (this.state.buffer === null) { @@ -80,9 +99,6 @@ export class NumberPopup extends AbstractAwaitablePopup { super.confirm(); } } - sendInput(key) { - this.numberBuffer.sendKey(key); - } getPayload() { let startingPayload = null; if (typeof this.props.startingValue === "number" && this.props.startingValue > 0) { diff --git a/addons/point_of_sale/static/src/app/utils/input_popups/number_popup.scss b/addons/point_of_sale/static/src/app/utils/input_popups/number_popup.scss deleted file mode 100644 index 238dc9864e2..00000000000 --- a/addons/point_of_sale/static/src/app/utils/input_popups/number_popup.scss +++ /dev/null @@ -1,5 +0,0 @@ -.popup-numpad .input-button, -.popup-numpad .mode-button { - height: 50px; - width: 50px; -} diff --git a/addons/point_of_sale/static/src/app/utils/input_popups/number_popup.xml b/addons/point_of_sale/static/src/app/utils/input_popups/number_popup.xml index 965c9bfa54b..01756d7214f 100644 --- a/addons/point_of_sale/static/src/app/utils/input_popups/number_popup.xml +++ b/addons/point_of_sale/static/src/app/utils/input_popups/number_popup.xml @@ -13,48 +13,7 @@ - +