From 3fb24aa05e5e06fa4d78c81fe6dbf182d9796d82 Mon Sep 17 00:00:00 2001 From: Samuel Degueldre Date: Tue, 9 May 2023 11:02:32 +0000 Subject: [PATCH] [REF] pos*: use fine grained reactivity instead of deep renders *: l10n_ae_pos, l10n_co_pos, l10n_fr_pos_cert, l10n_gcc_pos, l10n_in_pos, point_of_sale, pos_discount, pos_hr, pos_loyalty, pos_mercury, pos_restaurant, pos_sale, pos_six The code of the pos was one of the first adopters of owl 1, as such, the code was not initially written to take full advantage of the owl reactivity system that would eventually make its way into owl 2. In order to convert the code quickly when migrating to owl 2, a big shortcut was taken: whenever something in the state of the pos changed, the entire UI would be rerendered. While this works decently well in practice, it can create confusing situations because the mental model needed to understand how components work in the pos is different from the rest of the code base. This commit changes the existing code to use the typical fine-grained reactivity model used everywhere else: components individually subscribe to the pieces of state that they use and will rerender on their own when this state changes. In order to achieve this, the pos global state has been removed from the environment and should now be access through the use of the custom hook `usePos` which will subscribe the component to the state that it reads. This also has some minor performance benefits as we only render the parts of the UI that actually need to update whenever there is a state mutation, instead of the entire UI which can be expensive in some cases (eg, the product screen will filter all products during rendering to find only the products that match the search, which is expensive when there are a lot of loaded products) closes odoo/odoo#120992 Related: odoo/enterprise#40873 Signed-off-by: Joseph Caburnay (jcb) --- .../Screens/ReceiptScreen/OrderReceipt.xml | 2 +- .../static/src/js/PaymentScreen.js | 2 +- .../l10n_fr_pos_cert/static/src/js/Chrome.js | 7 +- .../static/src/js/PaymentScreen.js | 2 +- .../static/src/xml/Orderline.xml | 2 +- .../static/src/xml/OrderReceipt.xml | 2 +- .../static/src/xml/pos_receipt.xml | 4 +- .../static/src/app/debug/debug_widget.js | 28 ++-- .../static/src/app/navbar/navbar.js | 17 +-- .../static/src/app/navbar/navbar.xml | 2 +- addons/point_of_sale/static/src/js/Chrome.js | 7 +- .../src/js/ChromeWidgets/CashierName.js | 8 +- .../src/js/ChromeWidgets/HeaderButton.js | 4 +- .../src/js/ChromeWidgets/ProxyStatus.js | 2 +- .../src/js/ChromeWidgets/SaleDetailsButton.js | 7 +- .../src/js/ChromeWidgets/SyncNotification.js | 9 +- .../static/src/js/ControlButtonsMixin.js | 6 +- .../static/src/js/Misc/MobileOrderWidget.js | 2 +- .../PartnerListScreen/PartnerDetailsEdit.js | 9 +- .../PartnerListScreen/PartnerListScreen.js | 35 ++--- .../js/Screens/PaymentScreen/PaymentScreen.js | 44 +++---- .../OrderlineCustomerNoteButton.js | 6 +- .../ControlButtons/ProductInfoButton.js | 7 +- .../ControlButtons/RefundButton.js | 6 +- .../ControlButtons/SaveButton.js | 16 ++- .../ControlButtons/SetFiscalPositionButton.js | 9 +- .../ControlButtons/SetPricelistButton.js | 12 +- .../js/Screens/ProductScreen/NumpadWidget.js | 9 +- .../js/Screens/ProductScreen/OrderSummary.js | 6 +- .../js/Screens/ProductScreen/OrderWidget.js | 4 +- .../src/js/Screens/ProductScreen/Orderline.js | 2 +- .../js/Screens/ProductScreen/ProductItem.js | 6 +- .../js/Screens/ProductScreen/ProductScreen.js | 50 ++++---- .../Screens/ProductScreen/ProductsWidget.js | 60 +++++---- .../ProductsWidgetControlPanel.js | 12 +- .../js/Screens/ReceiptScreen/OrderReceipt.js | 2 + .../js/Screens/ReceiptScreen/ReceiptScreen.js | 21 ++- .../src/js/Screens/ScaleScreen/ScaleScreen.js | 21 ++- .../Screens/TicketScreen/OrderlineDetails.js | 12 +- .../TicketScreen/ReprintReceiptScreen.js | 3 +- .../js/Screens/TicketScreen/TicketScreen.js | 120 +++++++++--------- .../xml/ChromeWidgets/SyncNotification.xml | 12 +- .../PartnerListScreen/PartnerDetailsEdit.xml | 14 +- .../Screens/PaymentScreen/PaymentScreen.xml | 6 +- .../xml/Screens/ProductScreen/Orderline.xml | 2 +- .../Screens/ProductScreen/ProductScreen.xml | 2 +- .../ProductsWidgetControlPanel.xml | 4 +- .../Screens/ReceiptScreen/OrderReceipt.xml | 4 +- .../static/src/js/DiscountButton.js | 26 ++-- addons/pos_hr/static/src/app/navbar.xml | 8 +- addons/pos_hr/static/src/js/CashierName.js | 6 +- addons/pos_hr/static/src/js/Chrome.js | 6 +- .../pos_hr/static/src/js/HeaderLockButton.js | 2 +- addons/pos_hr/static/src/js/LoginScreen.js | 4 +- addons/pos_hr/static/src/js/PaymentScreen.js | 2 +- .../static/src/js/SelectCashierMixin.js | 18 +-- .../src/js/ControlButtons/PromoCodeButton.js | 7 +- .../js/ControlButtons/ResetProgramsButton.js | 11 +- .../src/js/ControlButtons/RewardButton.js | 9 +- .../src/js/ControlButtons/eWalletButton.js | 13 +- .../pos_loyalty/static/src/js/OrderSummary.js | 2 +- addons/pos_loyalty/static/src/js/Orderline.js | 6 +- .../pos_loyalty/static/src/js/PartnerLine.js | 7 +- .../static/src/js/PaymentScreen.js | 28 ++-- .../static/src/js/ProductScreen.js | 7 +- .../pos_loyalty/static/src/js/TicketScreen.js | 4 +- .../src/xml/ControlButtons/eWalletButton.xml | 2 +- .../static/src/xml/PartnerLine.xml | 2 +- .../static/src/js/PaymentScreen.js | 58 ++++----- .../src/app/floor_screen/editable_table.js | 25 ++-- .../src/app/floor_screen/editable_table.xml | 2 +- .../src/app/floor_screen/floor_screen.js | 105 +++++++-------- .../src/app/floor_screen/floor_screen.xml | 6 +- .../static/src/app/floor_screen/table.js | 28 ++-- .../src/app/navbar/BackToFloorButton.js | 2 +- .../static/src/app/navbar/navbar.js | 19 +-- .../static/src/js/Screens/PaymentScreen.js | 2 +- .../ControlButtons/OrderlineNoteButton.js | 7 +- .../ControlButtons/PrintBillButton.js | 4 +- .../ControlButtons/SplitBillButton.js | 5 +- .../ControlButtons/TableGuestsButton.js | 9 +- .../ControlButtons/TransferOrderButton.js | 5 +- .../js/Screens/ReceiptScreen/ReceiptScreen.js | 14 +- .../SplitBillScreen/SplitBillScreen.js | 42 +++--- .../static/src/js/Screens/TicketScreen.js | 56 ++++---- .../static/src/js/Screens/TipScreen.js | 18 +-- .../Screens/PaymentScreen/PaymentScreen.xml | 6 +- .../Screens/ReceiptScreen/OrderReceipt.xml | 2 +- .../static/src/xml/Screens/TicketScreen.xml | 4 +- .../static/src/xml/Screens/TipScreen.xml | 2 +- .../SaleOrderManagementControlPanel.js | 5 +- .../SaleOrderManagementScreen.js | 89 +++++++------ addons/pos_six/static/app/navbar.xml | 2 +- addons/pos_six/static/src/js/BalanceButton.js | 6 +- 94 files changed, 684 insertions(+), 638 deletions(-) diff --git a/addons/l10n_ae_pos/static/src/xml/Screens/ReceiptScreen/OrderReceipt.xml b/addons/l10n_ae_pos/static/src/xml/Screens/ReceiptScreen/OrderReceipt.xml index b18b043abac..3ec842972ab 100644 --- a/addons/l10n_ae_pos/static/src/xml/Screens/ReceiptScreen/OrderReceipt.xml +++ b/addons/l10n_ae_pos/static/src/xml/Screens/ReceiptScreen/OrderReceipt.xml @@ -3,7 +3,7 @@
- VAT + VAT Total Taxes
diff --git a/addons/l10n_co_pos/static/src/js/PaymentScreen.js b/addons/l10n_co_pos/static/src/js/PaymentScreen.js index 279d756b0c1..d091c625a55 100644 --- a/addons/l10n_co_pos/static/src/js/PaymentScreen.js +++ b/addons/l10n_co_pos/static/src/js/PaymentScreen.js @@ -7,7 +7,7 @@ patch(PaymentScreen.prototype, "l10n_co_pos.PaymentScreen", { async _postPushOrderResolve(order, order_server_ids) { const _super = this._super; try { - if (this.env.pos.is_colombian_country()) { + if (this.pos.globalState.is_colombian_country()) { const result = await this.orm.searchRead( "pos.order", [["id", "in", order_server_ids]], diff --git a/addons/l10n_fr_pos_cert/static/src/js/Chrome.js b/addons/l10n_fr_pos_cert/static/src/js/Chrome.js index 10a37002fcd..8785c136e80 100644 --- a/addons/l10n_fr_pos_cert/static/src/js/Chrome.js +++ b/addons/l10n_fr_pos_cert/static/src/js/Chrome.js @@ -9,12 +9,13 @@ patch(Chrome.prototype, "l10n_fr_pos_cert.Chrome", { setup() { this._super(...arguments); onMounted(async () => { - if (this.env.pos.is_french_country() && this.env.pos.pos_session.start_at) { + const { globalState } = this.pos; + if (globalState.is_french_country() && globalState.pos_session.start_at) { const now = Date.now(); - const limitDate = new Date(this.env.pos.pos_session.start_at); + const limitDate = new Date(globalState.pos_session.start_at); limitDate.setDate(limitDate.getDate() + 1); if (limitDate.getTime() < now) { - const info = await this.env.pos.getClosePosInfo(); + const info = await globalState.getClosePosInfo(); this.popup.add(ClosePosPopup, { info }); } } diff --git a/addons/l10n_fr_pos_cert/static/src/js/PaymentScreen.js b/addons/l10n_fr_pos_cert/static/src/js/PaymentScreen.js index 1ec6539ca03..a78e3847276 100644 --- a/addons/l10n_fr_pos_cert/static/src/js/PaymentScreen.js +++ b/addons/l10n_fr_pos_cert/static/src/js/PaymentScreen.js @@ -7,7 +7,7 @@ patch(PaymentScreen.prototype, "l10n_fr_pos_cert.PaymentScreen", { async _postPushOrderResolve(order, order_server_ids) { const _super = this._super; try { - if (this.env.pos.is_french_country()) { + if (this.pos.globalState.is_french_country()) { const result = await this.orm.searchRead( "pos.order", [["id", "in", order_server_ids]], diff --git a/addons/l10n_fr_pos_cert/static/src/xml/Orderline.xml b/addons/l10n_fr_pos_cert/static/src/xml/Orderline.xml index 49420409f77..ef790a1be8a 100644 --- a/addons/l10n_fr_pos_cert/static/src/xml/Orderline.xml +++ b/addons/l10n_fr_pos_cert/static/src/xml/Orderline.xml @@ -3,7 +3,7 @@ - +
  • Old unit price: diff --git a/addons/l10n_gcc_pos/static/src/xml/OrderReceipt.xml b/addons/l10n_gcc_pos/static/src/xml/OrderReceipt.xml index 88fa1fbc571..ae30b96d2eb 100644 --- a/addons/l10n_gcc_pos/static/src/xml/OrderReceipt.xml +++ b/addons/l10n_gcc_pos/static/src/xml/OrderReceipt.xml @@ -114,7 +114,7 @@
    - + x diff --git a/addons/l10n_in_pos/static/src/xml/pos_receipt.xml b/addons/l10n_in_pos/static/src/xml/pos_receipt.xml index ea461cc9d7d..3402f545ab7 100644 --- a/addons/l10n_in_pos/static/src/xml/pos_receipt.xml +++ b/addons/l10n_in_pos/static/src/xml/pos_receipt.xml @@ -2,7 +2,7 @@ - +
    @@ -19,7 +19,7 @@ - +
    HSN Code: diff --git a/addons/point_of_sale/static/src/app/debug/debug_widget.js b/addons/point_of_sale/static/src/app/debug/debug_widget.js index ac3b0e03ae8..bcada4e2630 100644 --- a/addons/point_of_sale/static/src/app/debug/debug_widget.js +++ b/addons/point_of_sale/static/src/app/debug/debug_widget.js @@ -8,6 +8,7 @@ import { OrderImportPopup } from "@point_of_sale/js/Popups/OrderImportPopup"; import { useBus, useService } from "@web/core/utils/hooks"; import { useEffect, useRef, useState, Component } from "@odoo/owl"; +import { usePos } from "../pos_hook"; export class DebugWidget extends Component { static components = { Transition }; @@ -15,6 +16,7 @@ export class DebugWidget extends Component { static props = { state: { type: Object, shape: { showWidget: Boolean } } }; setup() { super.setup(); + this.pos = usePos(); this.debug = useService("debug"); this.popup = useService("popup"); this.barcodeReader = useService("barcode_reader"); @@ -29,11 +31,11 @@ export class DebugWidget extends Component { buffer: numberBuffer.get(), }); this.root = useRef("root"); - this.pos = useState({ left: null, top: null }); + this.position = useState({ left: null, top: null }); useEffect( (root) => { - this.pos.left = root?.offsetLeft; - this.pos.top = root?.offsetTop; + this.position.left = root?.offsetLeft; + this.position.top = root?.offsetTop; }, () => [this.root.el] ); @@ -41,12 +43,12 @@ export class DebugWidget extends Component { useMovable({ ref: this.root, onMoveStart: () => { - posBeforeMove = { ...this.pos }; + posBeforeMove = { ...this.position }; }, onMove: ({ dx, dy }) => { const { minX, minY, maxX, maxY } = getLimits(this.root.el, document.body); - this.pos.left = constrain(posBeforeMove.left + dx, minX, maxX); - this.pos.top = constrain(posBeforeMove.top + dy, minY, maxY); + this.position.left = constrain(posBeforeMove.left + dx, minX, maxX); + this.position.top = constrain(posBeforeMove.top + dy, minY, maxY); }, }); @@ -96,8 +98,8 @@ export class DebugWidget extends Component { ), }); if (confirmed) { - this.env.pos.db.remove_all_orders(); - this.env.pos.set_synch("connected", 0); + this.pos.globalState.db.remove_all_orders(); + this.pos.globalState.set_synch("connected", 0); } } async deleteUnpaidOrders() { @@ -108,7 +110,7 @@ export class DebugWidget extends Component { ), }); if (confirmed) { - this.env.pos.db.remove_all_unpaid_orders(); + this.pos.globalState.db.remove_all_unpaid_orders(); window.location = "/"; } } @@ -122,7 +124,7 @@ export class DebugWidget extends Component { // The implementation can be better. preparePaidOrders() { try { - this.paidOrdersBlob = this._createBlob(this.env.pos.export_paid_orders()); + this.paidOrdersBlob = this._createBlob(this.pos.globalState.export_paid_orders()); this.state.isPaidOrdersReady = true; } catch (error) { console.warn(error); @@ -138,7 +140,7 @@ export class DebugWidget extends Component { // FIXME POSREF why is this two steps? prepareUnpaidOrders() { try { - this.unpaidOrdersBlob = this._createBlob(this.env.pos.export_unpaid_orders()); + this.unpaidOrdersBlob = this._createBlob(this.pos.globalState.export_unpaid_orders()); this.state.isUnpaidOrdersReady = true; } catch (error) { console.warn(error); @@ -154,7 +156,7 @@ export class DebugWidget extends Component { async importOrders(event) { const file = event.target.files[0]; if (file) { - const report = this.env.pos.import_orders(await file.text()); + const report = this.pos.globalState.import_orders(await file.text()); await this.popup.add(OrderImportPopup, { report }); } } @@ -168,7 +170,7 @@ export class DebugWidget extends Component { return `"${this.state.buffer}"`; } get style() { - const { left, top } = this.pos; + const { left, top } = this.position; return top === null ? "" : `position: absolute; left: ${left}px; top: ${top}px;`; } } diff --git a/addons/point_of_sale/static/src/app/navbar/navbar.js b/addons/point_of_sale/static/src/app/navbar/navbar.js index 1f5b33e5ff1..00829589067 100644 --- a/addons/point_of_sale/static/src/app/navbar/navbar.js +++ b/addons/point_of_sale/static/src/app/navbar/navbar.js @@ -46,7 +46,7 @@ export class Navbar extends Component { } get customerFacingDisplayButtonIsShown() { - return this.env.pos.config.iface_customer_facing_display; + return this.pos.globalState.config.iface_customer_facing_display; } onCashMoveButtonClick() { @@ -58,14 +58,15 @@ export class Navbar extends Component { this.pos.closeScreen(); } else { if (this._shouldLoadOrders()) { + const { globalState } = this.pos; try { - this.env.pos.setLoadingOrderState(true); - const message = await this.env.pos._syncAllOrdersFromServer(); + globalState.setLoadingOrderState(true); + const message = await globalState._syncAllOrdersFromServer(); if (message) { this.notification.add(message, 5000); } } finally { - this.env.pos.setLoadingOrderState(false); + globalState.setLoadingOrderState(false); this.pos.showScreen("TicketScreen"); } } else { @@ -75,7 +76,7 @@ export class Navbar extends Component { } _shouldLoadOrders() { - return this.env.pos.config.trusted_config_ids.length > 0; + return this.pos.globalState.config.trusted_config_ids.length > 0; } get isTicketScreenShown() { @@ -83,11 +84,7 @@ export class Navbar extends Component { } get orderCount() { - // FIXME POSREF: can this condition ever be false? - if (this.env.pos) { - return this.env.pos.get_order_list().length; - } - return 0; + return this.pos.globalState.get_order_list().length; } isBurgerMenuClosed() { diff --git a/addons/point_of_sale/static/src/app/navbar/navbar.xml b/addons/point_of_sale/static/src/app/navbar/navbar.xml index 5c692b92ba7..2fad487fa80 100644 --- a/addons/point_of_sale/static/src/app/navbar/navbar.xml +++ b/addons/point_of_sale/static/src/app/navbar/navbar.xml @@ -11,7 +11,7 @@
    - +
    diff --git a/addons/point_of_sale/static/src/js/Chrome.js b/addons/point_of_sale/static/src/js/Chrome.js index dce34977ad0..ab1854ecf13 100644 --- a/addons/point_of_sale/static/src/js/Chrome.js +++ b/addons/point_of_sale/static/src/js/Chrome.js @@ -1,7 +1,6 @@ /** @odoo-module */ import { useService } from "@web/core/utils/hooks"; -import { batched } from "@point_of_sale/js/utils"; import { throttleForAnimation } from "@web/core/utils/timing"; import { Transition } from "@web/core/transition"; import { MainComponentsContainer } from "@web/core/main_components_container"; @@ -36,16 +35,12 @@ export class Chrome extends Component { get isMobile() { return window.innerWidth <= 768; }, - pos: reactive( - reactivePos, - batched(() => this.render(true)) // FIXME POSREF remove render(true) - ), }); let currentIsMobile = this.env.isMobile; const updateUI = throttleForAnimation(() => { if (this.env.isMobile !== currentIsMobile) { currentIsMobile = this.env.isMobile; - // FIXME POSREF + // FIXME POSREF use reactive mobile instead this.render(true); } }); diff --git a/addons/point_of_sale/static/src/js/ChromeWidgets/CashierName.js b/addons/point_of_sale/static/src/js/ChromeWidgets/CashierName.js index 78345988cdf..c3e1d36f349 100644 --- a/addons/point_of_sale/static/src/js/ChromeWidgets/CashierName.js +++ b/addons/point_of_sale/static/src/js/ChromeWidgets/CashierName.js @@ -1,17 +1,21 @@ /** @odoo-module */ import { Component } from "@odoo/owl"; +import { usePos } from "@point_of_sale/app/pos_hook"; // Previously UsernameWidget export class CashierName extends Component { static template = "CashierName"; + setup() { + this.pos = usePos(); + } get username() { - const { name } = this.env.pos.get_cashier(); + const { name } = this.pos.globalState.get_cashier(); return name ? name : ""; } get avatar() { - const user_id = this.env.pos.get_cashier_user_id(); + const user_id = this.pos.globalState.get_cashier_user_id(); const id = user_id ? user_id : -1; return `/web/image/res.users/${id}/avatar_128`; } diff --git a/addons/point_of_sale/static/src/js/ChromeWidgets/HeaderButton.js b/addons/point_of_sale/static/src/js/ChromeWidgets/HeaderButton.js index 73374baad11..bdb6847a43f 100644 --- a/addons/point_of_sale/static/src/js/ChromeWidgets/HeaderButton.js +++ b/addons/point_of_sale/static/src/js/ChromeWidgets/HeaderButton.js @@ -3,6 +3,7 @@ import { useService } from "@web/core/utils/hooks"; import { ClosePosPopup } from "@point_of_sale/js/Popups/ClosePosPopup"; import { Component } from "@odoo/owl"; +import { usePos } from "@point_of_sale/app/pos_hook"; // Previously HeaderButtonWidget // This is the close session button @@ -11,11 +12,12 @@ export class HeaderButton extends Component { setup() { super.setup(...arguments); + this.pos = usePos(); this.popup = useService("popup"); } async onClick() { - const info = await this.env.pos.getClosePosInfo(); + const info = await this.pos.globalState.getClosePosInfo(); this.popup.add(ClosePosPopup, { info: info, keepBehind: true }); } } diff --git a/addons/point_of_sale/static/src/js/ChromeWidgets/ProxyStatus.js b/addons/point_of_sale/static/src/js/ChromeWidgets/ProxyStatus.js index bd84357755e..6c76b4bfed9 100644 --- a/addons/point_of_sale/static/src/js/ChromeWidgets/ProxyStatus.js +++ b/addons/point_of_sale/static/src/js/ChromeWidgets/ProxyStatus.js @@ -24,7 +24,7 @@ export class ProxyStatus extends Component { iface_print_via_proxy, iface_cashdrawer, iface_electronic_scale, - } = this.env.pos.config; + } = this.pos.globalState.config; const devices = [ { name: _t("Scanner"), diff --git a/addons/point_of_sale/static/src/js/ChromeWidgets/SaleDetailsButton.js b/addons/point_of_sale/static/src/js/ChromeWidgets/SaleDetailsButton.js index fee2b50d0b6..fa7c571b149 100644 --- a/addons/point_of_sale/static/src/js/ChromeWidgets/SaleDetailsButton.js +++ b/addons/point_of_sale/static/src/js/ChromeWidgets/SaleDetailsButton.js @@ -4,31 +4,34 @@ import { useService } from "@web/core/utils/hooks"; import { renderToElement } from "@web/core/utils/render"; import { ErrorPopup } from "../Popups/ErrorPopup"; import { Component } from "@odoo/owl"; +import { usePos } from "@point_of_sale/app/pos_hook"; export class SaleDetailsButton extends Component { static template = "SaleDetailsButton"; setup() { super.setup(...arguments); + this.pos = usePos(); this.popup = useService("popup"); this.orm = useService("orm"); this.hardwareProxy = useService("hardware_proxy"); } async onClick() { + const { globalState } = this.pos; // IMPROVEMENT: Perhaps put this logic in a parent component // so that for unit testing, we can check if this simple // component correctly triggers an event. const saleDetails = await this.orm.call( "report.point_of_sale.report_saledetails", "get_sale_details", - [false, false, false, [this.env.pos.pos_session.id]] + [false, false, false, [globalState.pos_session.id]] ); const report = renderToElement( "SaleDetailsReport", Object.assign({}, saleDetails, { date: new Date().toLocaleString(), - pos: this.env.pos, + pos: globalState, formatCurrency: this.env.utils.formatCurrency, }) ); diff --git a/addons/point_of_sale/static/src/js/ChromeWidgets/SyncNotification.js b/addons/point_of_sale/static/src/js/ChromeWidgets/SyncNotification.js index 3ad8a8a46c4..739b7e8a301 100644 --- a/addons/point_of_sale/static/src/js/ChromeWidgets/SyncNotification.js +++ b/addons/point_of_sale/static/src/js/ChromeWidgets/SyncNotification.js @@ -1,11 +1,18 @@ /** @odoo-module */ import { Component } from "@odoo/owl"; +import { usePos } from "@point_of_sale/app/pos_hook"; export class SyncNotification extends Component { static template = "SyncNotification"; + setup() { + this.pos = usePos(); + } + get sync() { + return this.pos.globalState.synch; + } onClick() { - this.env.pos.push_orders({ show_error: true }); + this.pos.globalState.push_orders({ show_error: true }); } } diff --git a/addons/point_of_sale/static/src/js/ControlButtonsMixin.js b/addons/point_of_sale/static/src/js/ControlButtonsMixin.js index 17dc38cbd25..7afbdb3e43b 100644 --- a/addons/point_of_sale/static/src/js/ControlButtonsMixin.js +++ b/addons/point_of_sale/static/src/js/ControlButtonsMixin.js @@ -27,9 +27,11 @@ export const ControlButtonsMixin = (x) => { * @param {Object} controlButton * @param {new (...args: any[]) => Component} controlButton.component the * component class + * FIXME POSREF: maybe just pass the pos explicitly to allow for arrow functions? + * Should probably refactor this so that it's not a mixin anymore. * @param {Function} controlButton.condition zero argument function that is bound - * to the instance of ProductScreen, such that `this.env.pos` can be used - * inside the function. + * to the instance of ProductScreen. This gives the condition acces to + * the pos store and related object which it may need. * @param {Array} [controlButton.position] array of two elements * [locator, relativeTo] * locator: string -> any of ('before', 'after', 'replace') diff --git a/addons/point_of_sale/static/src/js/Misc/MobileOrderWidget.js b/addons/point_of_sale/static/src/js/Misc/MobileOrderWidget.js index 38d617b8d67..cd5410da5e2 100644 --- a/addons/point_of_sale/static/src/js/Misc/MobileOrderWidget.js +++ b/addons/point_of_sale/static/src/js/Misc/MobileOrderWidget.js @@ -11,7 +11,7 @@ export class MobileOrderWidget extends Component { this.pos = usePos(); } get order() { - return this.env.pos.get_order(); + return this.pos.globalState.get_order(); } get total() { const _total = this.order ? this.order.get_total_with_tax() : 0; diff --git a/addons/point_of_sale/static/src/js/Screens/PartnerListScreen/PartnerDetailsEdit.js b/addons/point_of_sale/static/src/js/Screens/PartnerListScreen/PartnerDetailsEdit.js index 5e04369a380..c06106c8b88 100644 --- a/addons/point_of_sale/static/src/js/Screens/PartnerListScreen/PartnerDetailsEdit.js +++ b/addons/point_of_sale/static/src/js/Screens/PartnerListScreen/PartnerDetailsEdit.js @@ -5,6 +5,7 @@ import { getDataURLFromFile } from "@web/core/utils/urls"; import { ErrorPopup } from "@point_of_sale/js/Popups/ErrorPopup"; import { useService } from "@web/core/utils/hooks"; import { Component } from "@odoo/owl"; +import { usePos } from "@point_of_sale/app/pos_hook"; export class PartnerDetailsEdit extends Component { static template = "PartnerDetailsEdit"; @@ -12,6 +13,7 @@ export class PartnerDetailsEdit extends Component { setup() { super.setup(); this.popup = useService("popup"); + this.pos = usePos(); this.intFields = ["country_id", "state_id", "property_product_pricelist"]; const partner = this.props.partner; this.changes = { @@ -23,13 +25,12 @@ export class PartnerDetailsEdit extends Component { save: () => this.saveChanges(), }); } + // FIXME POSREF naming setDefaultPricelist(partner) { if (partner.property_product_pricelist) { return partner.property_product_pricelist[0]; - } else if (this.env.pos.default_pricelist) { - return this.env.pos.default_pricelist.id; } - return false; + return this.pos.globalState.default_pricelist?.id ?? false; } get partnerImageUrl() { @@ -82,8 +83,6 @@ export class PartnerDetailsEdit extends Component { if (loadedImage) { const resizedImage = await this._resizeImage(loadedImage, 800, 600); this.changes.image_1920 = resizedImage.toDataURL(); - // Rerender to reflect the changes in the screen - this.render(true); } } } diff --git a/addons/point_of_sale/static/src/js/Screens/PartnerListScreen/PartnerListScreen.js b/addons/point_of_sale/static/src/js/Screens/PartnerListScreen/PartnerListScreen.js index 8910d2b57b5..9a02a4cbea7 100644 --- a/addons/point_of_sale/static/src/js/Screens/PartnerListScreen/PartnerListScreen.js +++ b/addons/point_of_sale/static/src/js/Screens/PartnerListScreen/PartnerListScreen.js @@ -7,7 +7,7 @@ import { useService } from "@web/core/utils/hooks"; import { PartnerLine } from "./PartnerLine"; import { PartnerDetailsEdit } from "./PartnerDetailsEdit"; import { usePos } from "@point_of_sale/app/pos_hook"; -import { Component, onWillUnmount, useRef } from "@odoo/owl"; +import { Component, onWillUnmount, useRef, useState } from "@odoo/owl"; import { sprintf } from "@web/core/utils/strings"; /** @@ -36,12 +36,7 @@ export class PartnerListScreen extends Component { this.notification = useService("pos_notification"); this.searchWordInputRef = useRef("search-word-input-partner"); - // We are not using useState here because the object - // passed to useState converts the object and its contents - // to Observer proxy. Not sure of the side-effects of making - // a persistent object, such as pos, into Observer. But it - // is better to be safe. - this.state = { + this.state = useState({ query: null, selectedPartner: this.props.partner, detailIsShown: false, @@ -50,7 +45,7 @@ export class PartnerListScreen extends Component { }, previousQuery: "", currentOffset: 0, - }; + }); this.updatePartnerList = debounce(this.updatePartnerList, 70); onWillUnmount(this.updatePartnerList.cancel); this.partnerEditor = {}; // create an imperative handle for PartnerDetailsEdit @@ -59,7 +54,6 @@ export class PartnerListScreen extends Component { back() { if (this.state.detailIsShown) { this.state.detailIsShown = false; - this.render(true); } else { this.props.resolve({ confirmed: false, payload: false }); this.pos.closeTempScreen(); @@ -71,20 +65,19 @@ export class PartnerListScreen extends Component { } activateEditMode() { this.state.detailIsShown = true; - this.render(true); } // Getters get currentOrder() { - return this.env.pos.get_order(); + return this.pos.globalState.get_order(); } get partners() { let res; if (this.state.query && this.state.query.trim() !== "") { - res = this.env.pos.db.search_partner(this.state.query.trim()); + res = this.pos.globalState.db.search_partner(this.state.query.trim()); } else { - res = this.env.pos.db.get_partners_sorted(1000); + res = this.pos.globalState.db.get_partners_sorted(1000); } res.sort(function (a, b) { return (a.name || "").localeCompare(b.name || ""); @@ -134,13 +127,11 @@ export class PartnerListScreen extends Component { _clearSearch() { this.searchWordInputRef.el.value = ""; this.state.query = ""; - this.render(true); } // We declare this event handler as a debounce function in // order to lower its trigger rate. async updatePartnerList(event) { this.state.query = event.target.value; - this.render(true); } clickPartner(partner) { if (this.state.selectedPartner && this.state.selectedPartner.id === partner.id) { @@ -156,16 +147,15 @@ export class PartnerListScreen extends Component { } createPartner() { // initialize the edit screen with default details about country & state - this.state.editModeProps.partner = { - country_id: this.env.pos.company.country_id, - state_id: this.env.pos.company.state_id, - }; + const { country_id, state_id } = this.pos.globalState.company; + this.state.editModeProps.partner = { country_id, state_id }; this.activateEditMode(); } async saveChanges(processedChanges) { + const { globalState } = this.pos; const partnerId = await this.orm.call("res.partner", "create_from_ui", [processedChanges]); - await this.env.pos.load_new_partners(); - this.state.selectedPartner = this.env.pos.db.get_partner_by_id(partnerId); + await globalState.load_new_partners(); + this.state.selectedPartner = globalState.db.get_partner_by_id(partnerId); this.confirm(); } async searchPartner() { @@ -173,8 +163,7 @@ export class PartnerListScreen extends Component { this.state.currentOffset = 0; } const result = await this.getNewPartners(); - this.env.pos.addPartners(result); - this.render(true); + this.pos.globalState.addPartners(result); if (this.state.previousQuery == this.state.query) { this.state.currentOffset += result.length; } else { diff --git a/addons/point_of_sale/static/src/js/Screens/PaymentScreen/PaymentScreen.js b/addons/point_of_sale/static/src/js/Screens/PaymentScreen/PaymentScreen.js index 75daffd1d6a..11d12140883 100644 --- a/addons/point_of_sale/static/src/js/Screens/PaymentScreen/PaymentScreen.js +++ b/addons/point_of_sale/static/src/js/Screens/PaymentScreen/PaymentScreen.js @@ -34,8 +34,8 @@ export class PaymentScreen extends Component { this.report = useService("report"); this.notification = useService("pos_notification"); this.hardwareProxy = useService("hardware_proxy"); - this.payment_methods_from_config = this.env.pos.payment_methods.filter((method) => - this.env.pos.config.payment_method_ids.includes(method.id) + this.payment_methods_from_config = this.pos.globalState.payment_methods.filter((method) => + this.pos.globalState.config.payment_method_ids.includes(method.id) ); this.numberBuffer = useService("number_buffer"); this.numberBuffer.use(this._getNumberBufferConfig); @@ -71,7 +71,7 @@ export class PaymentScreen extends Component { return config; } get currentOrder() { - return this.env.pos.get_order(); + return this.pos.globalState.get_order(); } get paymentLines() { return this.currentOrder.get_paymentlines(); @@ -130,9 +130,7 @@ export class PaymentScreen extends Component { } } toggleIsToInvoice() { - // click_invoice this.currentOrder.set_to_invoice(!this.currentOrder.is_to_invoice()); - this.render(true); } openCashbox() { this.hardwareProxy.printer.openCashbox(); @@ -147,7 +145,7 @@ export class PaymentScreen extends Component { title: tip ? this.env._t("Change Tip") : this.env._t("Add Tip"), startingValue: value, isInputSelected: true, - inputSuffix: this.env.pos.currency.symbol, + inputSuffix: this.pos.globalState.currency.symbol, }); if (confirmed) { @@ -167,7 +165,6 @@ export class PaymentScreen extends Component { } } deletePaymentLine(cid) { - var self = this; const line = this.paymentLines.find((line) => line.cid === cid); // If a paymentline with a payment terminal linked to // it is removed, the terminal should get a cancel @@ -176,27 +173,24 @@ export class PaymentScreen extends Component { line.set_payment_status("waitingCancel"); line.payment_method.payment_terminal .send_payment_cancel(this.currentOrder, cid) - .then(function () { - self.currentOrder.remove_paymentline(line); + .then(() => { + this.currentOrder.remove_paymentline(line); this.numberBuffer.reset(); - self.render(true); }); } else if (line.get_payment_status() !== "waitingCancel") { this.currentOrder.remove_paymentline(line); this.numberBuffer.reset(); - this.render(true); } } selectPaymentLine(cid) { const line = this.paymentLines.find((line) => line.cid === cid); this.currentOrder.select_paymentline(line); this.numberBuffer.reset(); - this.render(true); } async validateOrder(isForceValidate) { this.numberBuffer.capture(); - if (this.env.pos.config.cash_rounding) { - if (!this.env.pos.get_order().check_paymentlines_rounding()) { + if (this.pos.globalState.config.cash_rounding) { + if (!this.pos.globalState.get_order().check_paymentlines_rounding()) { this.popup.add(ErrorPopup, { title: this.env._t("Rounding error in payment lines"), body: this.env._t( @@ -217,9 +211,10 @@ export class PaymentScreen extends Component { } } async _finalizeValidation() { + const { globalState } = this.pos; if ( (this.currentOrder.is_paid_with_cash() || this.currentOrder.get_change()) && - this.env.pos.config.iface_cashdrawer + globalState.config.iface_cashdrawer ) { this.hardwareProxy.printer.openCashbox(); } @@ -231,7 +226,7 @@ export class PaymentScreen extends Component { try { // 1. Save order to server. - syncOrderResult = await this.env.pos.push_single_order(this.currentOrder); + syncOrderResult = await globalState.push_single_order(this.currentOrder); // 2. Invoice. if (this.currentOrder.is_to_invoice()) { @@ -283,10 +278,10 @@ export class PaymentScreen extends Component { this.pos.showScreen(this.nextScreen); // Remove the order from the local storage so that when we refresh the page, the order // won't be there - this.env.pos.db.remove_unpaid_order(this.currentOrder); + globalState.db.remove_unpaid_order(this.currentOrder); // Ask the user to sync the remaining unsynced orders. - if (!hasError && syncOrderResult && this.env.pos.db.get_orders().length) { + if (!hasError && syncOrderResult && globalState.db.get_orders().length) { const { confirmed } = await this.popup.add(ConfirmPopup, { title: this.env._t("Remaining unsynced orders"), body: this.env._t( @@ -297,7 +292,7 @@ export class PaymentScreen extends Component { // NOTE: Not yet sure if this should be awaited or not. // If awaited, some operations like changing screen // might not work. - this.env.pos.push_orders(); + globalState.push_orders(); } } } @@ -404,11 +399,7 @@ export class PaymentScreen extends Component { this.currentOrder.get_rounding_applied() ) > 0.00001 ) { - var cash = false; - for (var i = 0; i < this.env.pos.payment_methods.length; i++) { - cash = cash || this.env.pos.payment_methods[i].is_cash_count; - } - if (!cash) { + if (!this.pos.globalState.payment_methods.some((pm) => pm.is_cash_count)) { this.popup.add(ErrorPopup, { title: this.env._t("Cannot return change without a cash payment method"), body: this.env._t( @@ -472,10 +463,11 @@ export class PaymentScreen extends Component { line.can_be_reversed = payment_terminal.supports_reversals; // Automatically validate the order when after an electronic payment, // the current order is fully paid and due is zero. + const { config, currency } = this.pos.globalState; if ( this.currentOrder.is_paid() && - floatIsZero(this.currentOrder.get_due(), this.env.pos.currency.decimal_places) && - this.env.pos.config.auto_validate_terminal_payment + floatIsZero(this.currentOrder.get_due(), currency.decimal_places) && + config.auto_validate_terminal_payment ) { this.validateOrder(false); } diff --git a/addons/point_of_sale/static/src/js/Screens/ProductScreen/ControlButtons/OrderlineCustomerNoteButton.js b/addons/point_of_sale/static/src/js/Screens/ProductScreen/ControlButtons/OrderlineCustomerNoteButton.js index f435e22be44..b5473e84ab2 100644 --- a/addons/point_of_sale/static/src/js/Screens/ProductScreen/ControlButtons/OrderlineCustomerNoteButton.js +++ b/addons/point_of_sale/static/src/js/Screens/ProductScreen/ControlButtons/OrderlineCustomerNoteButton.js @@ -4,16 +4,18 @@ import { ProductScreen } from "@point_of_sale/js/Screens/ProductScreen/ProductSc import { useService } from "@web/core/utils/hooks"; import { TextAreaPopup } from "@point_of_sale/js/Popups/TextAreaPopup"; import { Component } from "@odoo/owl"; +import { usePos } from "@point_of_sale/app/pos_hook"; export class OrderlineCustomerNoteButton extends Component { static template = "OrderlineCustomerNoteButton"; setup() { - super.setup(); + this.pos = usePos(); this.popup = useService("popup"); } async onClick() { - const selectedOrderline = this.env.pos.get_order().get_selected_orderline(); + const selectedOrderline = this.pos.globalState.get_order().get_selected_orderline(); + // FIXME POSREF can this happen? Shouldn't the orderline just be a prop? if (!selectedOrderline) { return; } diff --git a/addons/point_of_sale/static/src/js/Screens/ProductScreen/ControlButtons/ProductInfoButton.js b/addons/point_of_sale/static/src/js/Screens/ProductScreen/ControlButtons/ProductInfoButton.js index 5cd793e867a..5e5eec04b89 100644 --- a/addons/point_of_sale/static/src/js/Screens/ProductScreen/ControlButtons/ProductInfoButton.js +++ b/addons/point_of_sale/static/src/js/Screens/ProductScreen/ControlButtons/ProductInfoButton.js @@ -4,20 +4,21 @@ import { ProductScreen } from "@point_of_sale/js/Screens/ProductScreen/ProductSc import { useService } from "@web/core/utils/hooks"; import { ProductInfoPopup } from "@point_of_sale/js/Popups/ProductInfoPopup"; import { Component } from "@odoo/owl"; +import { usePos } from "@point_of_sale/app/pos_hook"; export class ProductInfoButton extends Component { static template = "ProductInfoButton"; setup() { - super.setup(); + this.pos = usePos(); this.popup = useService("popup"); } async click() { - const orderline = this.env.pos.get_order().get_selected_orderline(); + const orderline = this.pos.globalState.get_order().get_selected_orderline(); if (orderline) { const product = orderline.get_product(); const quantity = orderline.get_quantity(); - const info = await this.env.pos.getProductInfo(product, quantity); + const info = await this.pos.globalState.getProductInfo(product, quantity); this.popup.add(ProductInfoPopup, { info: info, product: product }); } } diff --git a/addons/point_of_sale/static/src/js/Screens/ProductScreen/ControlButtons/RefundButton.js b/addons/point_of_sale/static/src/js/Screens/ProductScreen/ControlButtons/RefundButton.js index 516d0768b8d..45a42ffcd0d 100644 --- a/addons/point_of_sale/static/src/js/Screens/ProductScreen/ControlButtons/RefundButton.js +++ b/addons/point_of_sale/static/src/js/Screens/ProductScreen/ControlButtons/RefundButton.js @@ -8,15 +8,15 @@ export class RefundButton extends Component { static template = "point_of_sale.RefundButton"; setup() { - super.setup(); this.pos = usePos(); } click() { - const partner = this.env.pos.get_order().get_partner(); + const order = this.pos.globalState.get_order(); + const partner = order.get_partner(); const searchDetails = partner ? { fieldName: "PARTNER", searchTerm: partner.name } : {}; this.pos.showScreen("TicketScreen", { ui: { filter: "SYNCED", searchDetails }, - destinationOrder: this.env.pos.get_order(), + destinationOrder: order, }); } } diff --git a/addons/point_of_sale/static/src/js/Screens/ProductScreen/ControlButtons/SaveButton.js b/addons/point_of_sale/static/src/js/Screens/ProductScreen/ControlButtons/SaveButton.js index dc472d66420..72efd32fc22 100644 --- a/addons/point_of_sale/static/src/js/Screens/ProductScreen/ControlButtons/SaveButton.js +++ b/addons/point_of_sale/static/src/js/Screens/ProductScreen/ControlButtons/SaveButton.js @@ -1,6 +1,7 @@ /** @odoo-module */ import { Component } from "@odoo/owl"; +import { usePos } from "@point_of_sale/app/pos_hook"; import { ProductScreen } from "@point_of_sale/js/Screens/ProductScreen/ProductScreen"; import { useService } from "@web/core/utils/hooks"; @@ -8,11 +9,11 @@ export class SaveButton extends Component { static template = "point_of_sale.SaveButton"; setup() { - super.setup(); + this.pos = usePos(); this.notification = useService("pos_notification"); } onClick() { - const orderline = this.env.pos.get_order().get_selected_orderline(); + const orderline = this.pos.globalState.get_order().get_selected_orderline(); if (!orderline) { this.notification.add(this.env._t("You cannot save an empty order"), 3000); return; @@ -21,13 +22,14 @@ export class SaveButton extends Component { this.notification.add(this.env._t("Order saved for later"), 3000); } _selectEmptyOrder() { - const orders = this.env.pos.get_order_list(); + const { globalState } = this.pos; + const orders = globalState.get_order_list(); const emptyOrders = orders.filter((order) => order.is_empty()); if (emptyOrders.length > 0) { - this.env.pos.sendDraftToServer(); - this.env.pos.set_order(emptyOrders[0]); + globalState.sendDraftToServer(); + globalState.set_order(emptyOrders[0]); } else { - this.env.pos.add_new_order(); + globalState.add_new_order(); } } } @@ -35,6 +37,6 @@ export class SaveButton extends Component { ProductScreen.addControlButton({ component: SaveButton, condition: function () { - return this.env.pos.config.trusted_config_ids.length > 0; + return this.pos.globalState.config.trusted_config_ids.length > 0; }, }); diff --git a/addons/point_of_sale/static/src/js/Screens/ProductScreen/ControlButtons/SetFiscalPositionButton.js b/addons/point_of_sale/static/src/js/Screens/ProductScreen/ControlButtons/SetFiscalPositionButton.js index b7525feb1de..ccd69d8cbc1 100644 --- a/addons/point_of_sale/static/src/js/Screens/ProductScreen/ControlButtons/SetFiscalPositionButton.js +++ b/addons/point_of_sale/static/src/js/Screens/ProductScreen/ControlButtons/SetFiscalPositionButton.js @@ -4,16 +4,17 @@ import { ProductScreen } from "@point_of_sale/js/Screens/ProductScreen/ProductSc import { useService } from "@web/core/utils/hooks"; import { SelectionPopup } from "@point_of_sale/js/Popups/SelectionPopup"; import { Component } from "@odoo/owl"; +import { usePos } from "@point_of_sale/app/pos_hook"; export class SetFiscalPositionButton extends Component { static template = "SetFiscalPositionButton"; setup() { - super.setup(); + this.pos = usePos(); this.popup = useService("popup"); } get currentOrder() { - return this.env.pos.get_order(); + return this.pos.globalState.get_order(); } get currentFiscalPositionName() { return this.currentOrder && this.currentOrder.fiscal_position @@ -29,7 +30,7 @@ export class SetFiscalPositionButton extends Component { isSelected: !currentFiscalPosition, }, ]; - for (const fiscalPos of this.env.pos.fiscal_positions) { + for (const fiscalPos of this.pos.globalState.fiscal_positions) { fiscalPosList.push({ id: fiscalPos.id, label: fiscalPos.name, @@ -60,7 +61,7 @@ export class SetFiscalPositionButton extends Component { ProductScreen.addControlButton({ component: SetFiscalPositionButton, condition: function () { - return this.env.pos.fiscal_positions.length > 0; + return this.pos.globalState.fiscal_positions.length > 0; }, position: ["before", "SetPricelistButton"], }); diff --git a/addons/point_of_sale/static/src/js/Screens/ProductScreen/ControlButtons/SetPricelistButton.js b/addons/point_of_sale/static/src/js/Screens/ProductScreen/ControlButtons/SetPricelistButton.js index 86ff979bd68..212aad7af0c 100644 --- a/addons/point_of_sale/static/src/js/Screens/ProductScreen/ControlButtons/SetPricelistButton.js +++ b/addons/point_of_sale/static/src/js/Screens/ProductScreen/ControlButtons/SetPricelistButton.js @@ -4,16 +4,17 @@ import { ProductScreen } from "@point_of_sale/js/Screens/ProductScreen/ProductSc import { useService } from "@web/core/utils/hooks"; import { SelectionPopup } from "@point_of_sale/js/Popups/SelectionPopup"; import { Component } from "@odoo/owl"; +import { usePos } from "@point_of_sale/app/pos_hook"; export class SetPricelistButton extends Component { static template = "SetPricelistButton"; setup() { - super.setup(); + this.pos = usePos(); this.popup = useService("popup"); } get currentOrder() { - return this.env.pos.get_order(); + return this.pos.globalState.get_order(); } get currentPricelistName() { const order = this.currentOrder; @@ -23,7 +24,7 @@ export class SetPricelistButton extends Component { // Create the list to be passed to the SelectionPopup. // Pricelist object is passed as item in the list because it // is the object that will be returned when the popup is confirmed. - const selectionList = this.env.pos.pricelists.map((pricelist) => ({ + const selectionList = this.pos.globalState.pricelists.map((pricelist) => ({ id: pricelist.id, label: pricelist.name, isSelected: @@ -31,7 +32,7 @@ export class SetPricelistButton extends Component { item: pricelist, })); - if (!this.env.pos.default_pricelist) { + if (!this.pos.globalState.default_pricelist) { selectionList.push({ id: null, label: this.env._t("Default Price"), @@ -54,6 +55,7 @@ export class SetPricelistButton extends Component { ProductScreen.addControlButton({ component: SetPricelistButton, condition: function () { - return this.env.pos.config.use_pricelist && this.env.pos.pricelists.length > 0; + const { config, pricelists } = this.pos.globalState; + return config.use_pricelist && pricelists.length > 0; }, }); diff --git a/addons/point_of_sale/static/src/js/Screens/ProductScreen/NumpadWidget.js b/addons/point_of_sale/static/src/js/Screens/ProductScreen/NumpadWidget.js index 2e5cabc793d..91c72b7653f 100644 --- a/addons/point_of_sale/static/src/js/Screens/ProductScreen/NumpadWidget.js +++ b/addons/point_of_sale/static/src/js/Screens/ProductScreen/NumpadWidget.js @@ -2,6 +2,7 @@ import { useService } from "@web/core/utils/hooks"; import { Component } from "@odoo/owl"; +import { usePos } from "@point_of_sale/app/pos_hook"; /** * @prop {'quantity' | 'price' | 'discount'} activeMode @@ -15,18 +16,20 @@ export class NumpadWidget extends Component { disableSign: false, }; setup() { + this.pos = usePos(); this.numberBuffer = useService("number_buffer"); this.localization = useService("localization"); } get hasPriceControlRights() { return ( - this.env.pos.cashierHasPriceControlRights() && + this.pos.globalState.cashierHasPriceControlRights() && !this.props.disabledModes.includes("price") ); } get hasManualDiscount() { return ( - this.env.pos.config.manual_discount && !this.props.disabledModes.includes("discount") + this.pos.globalState.config.manual_discount && + !this.props.disabledModes.includes("discount") ); } changeMode(mode) { @@ -38,7 +41,7 @@ export class NumpadWidget extends Component { } this.numberBuffer.capture(); this.numberBuffer.reset(); - this.env.pos.numpadMode = mode; + this.pos.globalState.numpadMode = mode; } sendInput(key) { this.numberBuffer.sendKey(key); diff --git a/addons/point_of_sale/static/src/js/Screens/ProductScreen/OrderSummary.js b/addons/point_of_sale/static/src/js/Screens/ProductScreen/OrderSummary.js index dbf5a7f2011..2fb46ee7a38 100644 --- a/addons/point_of_sale/static/src/js/Screens/ProductScreen/OrderSummary.js +++ b/addons/point_of_sale/static/src/js/Screens/ProductScreen/OrderSummary.js @@ -1,11 +1,15 @@ /** @odoo-module */ import { Component } from "@odoo/owl"; +import { usePos } from "@point_of_sale/app/pos_hook"; import { floatIsZero } from "@web/core/utils/numbers"; export class OrderSummary extends Component { static template = "OrderSummary"; + setup() { + this.pos = usePos(); + } getTotal() { return this.env.utils.formatCurrency(this.props.order.get_total_with_tax()); } @@ -14,7 +18,7 @@ export class OrderSummary extends Component { const totalWithoutTax = this.props.order.get_total_without_tax(); const taxAmount = total - totalWithoutTax; return { - hasTax: !floatIsZero(taxAmount, this.env.pos.currency.decimal_places), + hasTax: !floatIsZero(taxAmount, this.pos.globalState.currency.decimal_places), displayAmount: this.env.utils.formatCurrency(taxAmount), }; } diff --git a/addons/point_of_sale/static/src/js/Screens/ProductScreen/OrderWidget.js b/addons/point_of_sale/static/src/js/Screens/ProductScreen/OrderWidget.js index 604692fc88a..6cefca19bb6 100644 --- a/addons/point_of_sale/static/src/js/Screens/ProductScreen/OrderWidget.js +++ b/addons/point_of_sale/static/src/js/Screens/ProductScreen/OrderWidget.js @@ -6,6 +6,7 @@ import { EditListPopup } from "@point_of_sale/js/Popups/EditListPopup"; import { Orderline } from "./Orderline"; import { OrderSummary } from "./OrderSummary"; import { Component, useEffect, useRef } from "@odoo/owl"; +import { usePos } from "@point_of_sale/app/pos_hook"; export class OrderWidget extends Component { static components = { Orderline, OrderSummary }; @@ -13,6 +14,7 @@ export class OrderWidget extends Component { setup() { super.setup(); + this.pos = usePos(); this.popup = useService("popup"); this.numberBuffer = useService("number_buffer"); this.scrollableRef = useRef("scrollable"); @@ -29,7 +31,7 @@ export class OrderWidget extends Component { ); } get order() { - return this.env.pos.get_order(); + return this.pos.globalState.get_order(); } get orderlinesArray() { return this.order ? this.order.get_orderlines() : []; diff --git a/addons/point_of_sale/static/src/js/Screens/ProductScreen/Orderline.js b/addons/point_of_sale/static/src/js/Screens/ProductScreen/Orderline.js index 1554c4c977f..d1391274170 100644 --- a/addons/point_of_sale/static/src/js/Screens/ProductScreen/Orderline.js +++ b/addons/point_of_sale/static/src/js/Screens/ProductScreen/Orderline.js @@ -18,7 +18,7 @@ export class Orderline extends Component { selectLine() { const line = this.props.line; // the orderline - if (this.env.pos.get_order().selected_orderline.id !== line.id) { + if (this.pos.globalState.get_order().selected_orderline.id !== line.id) { this.mp_dbclk_time = new Date().getTime(); } else if (!this.mp_dbclk_time) { this.mp_dbclk_time = new Date().getTime(); diff --git a/addons/point_of_sale/static/src/js/Screens/ProductScreen/ProductItem.js b/addons/point_of_sale/static/src/js/Screens/ProductScreen/ProductItem.js index eefccbc7748..74fcee1645f 100644 --- a/addons/point_of_sale/static/src/js/Screens/ProductScreen/ProductItem.js +++ b/addons/point_of_sale/static/src/js/Screens/ProductScreen/ProductItem.js @@ -25,11 +25,11 @@ export class ProductItem extends Component { return `/web/image?model=product.product&field=image_128&id=${product.id}&unique=${product.write_date}`; } get pricelist() { - const current_order = this.env.pos.get_order(); + const current_order = this.pos.globalState.get_order(); if (current_order) { return current_order.pricelist; } - return this.env.pos.default_pricelist; + return this.pos.globalState.default_pricelist; } get price() { const formattedUnitPrice = this.env.utils.formatCurrency( @@ -37,7 +37,7 @@ export class ProductItem extends Component { ); if (this.props.product.to_weight) { return `${formattedUnitPrice}/${ - this.env.pos.units_by_id[this.props.product.uom_id[0]].name + this.pos.globalState.units_by_id[this.props.product.uom_id[0]].name }`; } else { return formattedUnitPrice; diff --git a/addons/point_of_sale/static/src/js/Screens/ProductScreen/ProductScreen.js b/addons/point_of_sale/static/src/js/Screens/ProductScreen/ProductScreen.js index a8cb02ad496..d4c2aae9e35 100644 --- a/addons/point_of_sale/static/src/js/Screens/ProductScreen/ProductScreen.js +++ b/addons/point_of_sale/static/src/js/Screens/ProductScreen/ProductScreen.js @@ -76,21 +76,19 @@ export class ProductScreen extends ControlButtonsMixin(Component) { return this.currentOrder ? this.currentOrder.get_partner() : null; } get currentOrder() { - return this.env.pos.get_order(); + return this.pos.globalState.get_order(); } async updateSelectedOrderline({ buffer, key }) { - if (this.env.pos.numpadMode === "quantity" && this.env.pos.disallowLineQuantityChange()) { - const order = this.env.pos.get_order(); + const { globalState } = this.pos; + if (globalState.numpadMode === "quantity" && globalState.disallowLineQuantityChange()) { + const order = globalState.get_order(); if (!order.orderlines.length) { return; } const selectedLine = order.get_selected_orderline(); const orderlines = order.orderlines; const lastId = orderlines.length !== 0 && orderlines.at(orderlines.length - 1).cid; - const currentQuantity = this.env.pos - .get_order() - .get_selected_orderline() - .get_quantity(); + const currentQuantity = globalState.get_order().get_selected_orderline().get_quantity(); if (selectedLine.noDecrease) { this.popup.add(ErrorPopup, { @@ -112,20 +110,21 @@ export class ProductScreen extends ControlButtonsMixin(Component) { this._setValue(val); if (val == "remove") { this.numberBuffer.reset(); - this.env.pos.numpadMode = "quantity"; + globalState.numpadMode = "quantity"; } } } _setValue(val) { + const { numpadMode } = this.pos.globalState; if (this.currentOrder.get_selected_orderline()) { - if (this.env.pos.numpadMode === "quantity") { + if (numpadMode === "quantity") { const result = this.currentOrder.get_selected_orderline().set_quantity(val); if (!result) { this.numberBuffer.reset(); } - } else if (this.env.pos.numpadMode === "discount") { + } else if (numpadMode === "discount") { this.currentOrder.get_selected_orderline().set_discount(val); - } else if (this.env.pos.numpadMode === "price") { + } else if (numpadMode === "price") { var selected_orderline = this.currentOrder.get_selected_orderline(); selected_orderline.price_manually_set = true; selected_orderline.set_unit_price(val); @@ -133,7 +132,8 @@ export class ProductScreen extends ControlButtonsMixin(Component) { } } async _barcodeProductAction(code) { - let product = this.env.pos.db.get_product_by_barcode(code.base_code); + const { globalState } = this.pos; + let product = globalState.db.get_product_by_barcode(code.base_code); if (!product) { // find the barcode in the backend let foundProductIds = []; @@ -141,9 +141,9 @@ export class ProductScreen extends ControlButtonsMixin(Component) { ["barcode", "=", code.base_code], ]); if (foundProductIds.length) { - await this.env.pos._addProducts(foundProductIds); + await globalState._addProducts(foundProductIds); // assume that the result is unique. - product = this.env.pos.db.get_product_by_id(foundProductIds[0]); + product = globalState.db.get_product_by_id(foundProductIds[0]); } else { return this.popup.add(ErrorBarcodePopup, { code: code.base_code }); } @@ -178,7 +178,7 @@ export class ProductScreen extends ControlButtonsMixin(Component) { this.numberBuffer.reset(); } _barcodePartnerAction(code) { - const partner = this.env.pos.db.get_partner_by_barcode(code.code); + const partner = this.pos.globalState.db.get_partner_by_barcode(code.code); if (partner) { if (this.currentOrder.get_partner() !== partner) { this.currentOrder.set_partner(partner); @@ -207,8 +207,8 @@ export class ProductScreen extends ControlButtonsMixin(Component) { }); const newQuantity = inputNumber && inputNumber !== "" ? parseFloat(inputNumber) : null; if (confirmed && newQuantity !== null) { - const order = this.env.pos.get_order(); - const selectedLine = this.env.pos.get_order().get_selected_orderline(); + const order = this.pos.globalState.get_order(); + const selectedLine = order.get_selected_orderline(); const currentQuantity = selectedLine.get_quantity(); if (newQuantity >= currentQuantity) { selectedLine.set_quantity(newQuantity); @@ -230,22 +230,23 @@ export class ProductScreen extends ControlButtonsMixin(Component) { } } async onClickPay() { - if (this.env.pos.get_order().server_id) { + const { globalState } = this.pos; + if (globalState.get_order().server_id) { try { const isPaid = await this.orm.call("pos.order", "is_already_paid", [ - this.env.pos.get_order().server_id, + globalState.get_order().server_id, ]); if (isPaid) { const searchDetails = { fieldName: "RECEIPT_NUMBER", - searchTerm: this.env.pos.get_order().uid, + searchTerm: globalState.get_order().uid, }; this.pos.showScreen("TicketScreen", { ui: { filter: "SYNCED", searchDetails }, }); this.notification.add(this.env._t("The order has been already paid."), 3000); - this.env.pos.removeOrder(this.env.pos.get_order(), false); - this.env.pos.add_new_order(); + globalState.removeOrder(globalState.get_order(), false); + globalState.add_new_order(); return; } } catch (error) { @@ -257,14 +258,13 @@ export class ProductScreen extends ControlButtonsMixin(Component) { } } if ( - this.env.pos + globalState .get_order() .orderlines.some( (line) => line.get_product().tracking !== "none" && !line.has_valid_product_lot() ) && - (this.env.pos.picking_type.use_create_lots || - this.env.pos.picking_type.use_existing_lots) + (globalState.picking_type.use_create_lots || globalState.picking_type.use_existing_lots) ) { const { confirmed } = await this.popup.add(ConfirmPopup, { title: this.env._t("Some Serial/Lot Numbers are missing"), diff --git a/addons/point_of_sale/static/src/js/Screens/ProductScreen/ProductsWidget.js b/addons/point_of_sale/static/src/js/Screens/ProductScreen/ProductsWidget.js index a2257e9f470..04319154e9e 100644 --- a/addons/point_of_sale/static/src/js/Screens/ProductScreen/ProductsWidget.js +++ b/addons/point_of_sale/static/src/js/Screens/ProductScreen/ProductsWidget.js @@ -35,63 +35,63 @@ export class ProductsWidget extends Component { return Object.keys(this.pos.globalState.db.product_by_id).length > 0; } get selectedCategoryId() { - return this.env.pos.selectedCategoryId; + return this.pos.globalState.selectedCategoryId; } get searchWord() { - return this.env.pos.searchProductWord.trim(); + return this.pos.globalState.searchProductWord.trim(); } get productsToDisplay() { + const { db } = this.pos.globalState; let list = []; if (this.searchWord !== "") { - list = this.env.pos.db.search_product_in_category( - this.selectedCategoryId, - this.searchWord - ); + list = db.search_product_in_category(this.selectedCategoryId, this.searchWord); } else { - list = this.env.pos.db.get_product_by_category(this.selectedCategoryId); + list = db.get_product_by_category(this.selectedCategoryId); } return list.sort(function (a, b) { return a.display_name.localeCompare(b.display_name); }); } get subcategories() { - return this.env.pos.db + const { db } = this.pos.globalState; + return db .get_category_childs_ids(this.selectedCategoryId) - .map((id) => this.env.pos.db.get_category_by_id(id)); + .map((id) => db.get_category_by_id(id)); } get breadcrumbs() { - if (this.selectedCategoryId === this.env.pos.db.root_category_id) { + const { db } = this.pos.globalState; + if (this.selectedCategoryId === db.root_category_id) { return []; } return [ - ...this.env.pos.db.get_category_ancestors_ids(this.selectedCategoryId).slice(1), + ...db.get_category_ancestors_ids(this.selectedCategoryId).slice(1), this.selectedCategoryId, - ].map((id) => this.env.pos.db.get_category_by_id(id)); + ].map((id) => db.get_category_by_id(id)); } get hasNoCategories() { - return this.env.pos.db.get_category_childs_ids(0).length === 0; + return this.pos.globalState.db.get_category_childs_ids(0).length === 0; } get shouldShowButton() { return this.productsToDisplay.length === 0 && this.searchWord; } switchCategory(categoryId) { - this.env.pos.setSelectedCategoryId(categoryId); + this.pos.globalState.setSelectedCategoryId(categoryId); } updateSearch(searchWord) { - this.env.pos.searchProductWord = searchWord; + this.pos.globalState.searchProductWord = searchWord; } clearSearch() { - this.env.pos.searchProductWord = ""; + this.pos.globalState.searchProductWord = ""; } updateProductList(event) { - this.render(true); this.switchCategory(0); } async onPressEnterKey() { - if (!this.env.pos.searchProductWord) { + const { searchProductWord } = this.pos.globalState; + if (!searchProductWord) { return; } - if (this.state.previousSearchWord != this.env.pos.searchProductWord) { + if (this.state.previousSearchWord !== searchProductWord) { this.state.currentOffset = 0; } const result = await this.loadProductFromDB(); @@ -100,28 +100,26 @@ export class ProductsWidget extends Component { sprintf( this.env._t('%s product(s) found for "%s".'), result.length, - this.env.pos.searchProductWord + searchProductWord ), 3000 ); } else { this.notification.add( - sprintf( - this.env._t('No more product found for "%s".'), - this.env.pos.searchProductWord - ), + sprintf(this.env._t('No more product found for "%s".'), searchProductWord), 3000 ); } - if (this.state.previousSearchWord == this.env.pos.searchProductWord) { + if (this.state.previousSearchWord === searchProductWord) { this.state.currentOffset += result.length; } else { - this.state.previousSearchWord = this.env.pos.searchProductWord; + this.state.previousSearchWord = searchProductWord; this.state.currentOffset = result.length; } } async loadProductFromDB() { - if (!this.env.pos.searchProductWord) { + const { searchProductWord } = this.pos.globalState; + if (!searchProductWord) { return; } @@ -136,9 +134,9 @@ export class ProductsWidget extends Component { ["available_in_pos", "=", true], "|", "|", - ["name", "ilike", this.env.pos.searchProductWord], - ["default_code", "ilike", this.env.pos.searchProductWord], - ["barcode", "ilike", this.env.pos.searchProductWord], + ["name", "ilike", searchProductWord], + ["default_code", "ilike", searchProductWord], + ["barcode", "ilike", searchProductWord], ], ], { @@ -147,7 +145,7 @@ export class ProductsWidget extends Component { } ); if (ProductIds.length) { - await this.env.pos._addProducts(ProductIds, false); + await this.pos.globalState._addProducts(ProductIds, false); } this.updateProductList(); return ProductIds; diff --git a/addons/point_of_sale/static/src/js/Screens/ProductScreen/ProductsWidgetControlPanel.js b/addons/point_of_sale/static/src/js/Screens/ProductScreen/ProductsWidgetControlPanel.js index 5580a6c556c..9cddb336802 100644 --- a/addons/point_of_sale/static/src/js/Screens/ProductScreen/ProductsWidgetControlPanel.js +++ b/addons/point_of_sale/static/src/js/Screens/ProductScreen/ProductsWidgetControlPanel.js @@ -24,26 +24,26 @@ export class ProductsWidgetControlPanel extends Component { this.state.mobileSearchBarIsShown = !this.state.mobileSearchBarIsShown; } _clearSearch() { - this.env.pos.searchProductWord = ""; + this.pos.globalState.searchProductWord = ""; this.props.clearSearch(); } get displayCategImages() { return ( - Object.values(this.env.pos.db.category_by_id).some((categ) => categ.has_image) && - !this.env.isMobile + !this.env.isMobile && + Object.values(this.pos.globalState.db.category_by_id).some((categ) => categ.has_image) ); } updateSearch(event) { - this.props.updateSearch(this.env.pos.searchProductWord); + this.props.updateSearch(this.pos.globalState.searchProductWord); } async _onPressEnterKey() { - if (!this.env.pos.searchProductWord) { + if (!this.pos.globalState.searchProductWord) { return; } this.props.loadProductFromServer(); } searchProductFromInfo(productName) { - this.env.pos.searchProductWord = productName; + this.pos.globalState.searchProductWord = productName; this.props.switchCategory(0); this.props.updateSearch(productName); } diff --git a/addons/point_of_sale/static/src/js/Screens/ReceiptScreen/OrderReceipt.js b/addons/point_of_sale/static/src/js/Screens/ReceiptScreen/OrderReceipt.js index b911c366bac..c84efd8f570 100644 --- a/addons/point_of_sale/static/src/js/Screens/ReceiptScreen/OrderReceipt.js +++ b/addons/point_of_sale/static/src/js/Screens/ReceiptScreen/OrderReceipt.js @@ -1,5 +1,6 @@ /** @odoo-module */ +import { usePos } from "@point_of_sale/app/pos_hook"; import { WrappedProductNameLines } from "./WrappedProductNameLines"; import { Component, onWillUpdateProps } from "@odoo/owl"; @@ -9,6 +10,7 @@ export class OrderReceipt extends Component { setup() { super.setup(); + this.pos = usePos(); this._receiptEnv = this.props.order.getOrderReceiptEnv(); onWillUpdateProps((nextProps) => { diff --git a/addons/point_of_sale/static/src/js/Screens/ReceiptScreen/ReceiptScreen.js b/addons/point_of_sale/static/src/js/Screens/ReceiptScreen/ReceiptScreen.js index 672180e42f6..514d75e3703 100644 --- a/addons/point_of_sale/static/src/js/Screens/ReceiptScreen/ReceiptScreen.js +++ b/addons/point_of_sale/static/src/js/Screens/ReceiptScreen/ReceiptScreen.js @@ -22,7 +22,7 @@ export class ReceiptScreen extends AbstractReceiptScreen { this.orderReceipt = useRef("order-receipt"); this.buttonMailReceipt = useRef("order-mail-receipt-button"); this.buttonPrintReceipt = useRef("order-print-receipt-button"); - this.currentOrder = this.env.pos.get_order(); + this.currentOrder = this.pos.globalState.get_order(); const partner = this.currentOrder.get_partner(); this.orderUiState = this.currentOrder.uiState.ReceiptScreen; this.orderUiState.inputEmail = @@ -52,7 +52,7 @@ export class ReceiptScreen extends AbstractReceiptScreen { }); } _addNewOrder() { - this.env.pos.add_new_order(); + this.pos.globalState.add_new_order(); } onSendEmail() { if (this.buttonMailReceipt.el.classList.contains("fa-spin")) { @@ -92,8 +92,7 @@ export class ReceiptScreen extends AbstractReceiptScreen { get orderAmountPlusTip() { const order = this.currentOrder; const orderTotalAmount = order.get_total_with_tax(); - const tip_product_id = - this.env.pos.config.tip_product_id && this.env.pos.config.tip_product_id[0]; + const tip_product_id = this.pos.globalState.config.tip_product_id?.[0]; const tipLine = order .get_orderlines() .find((line) => tip_product_id && line.product.id === tip_product_id); @@ -134,19 +133,19 @@ export class ReceiptScreen extends AbstractReceiptScreen { } } orderDone() { - this.env.pos.removeOrder(this.currentOrder); + this.pos.globalState.removeOrder(this.currentOrder); this._addNewOrder(); const { name, props } = this.nextScreen; this.pos.showScreen(name, props); } resumeOrder() { - this.env.pos.removeOrder(this.currentOrder); - this.env.pos.selectNextOrder(); + this.pos.globalState.removeOrder(this.currentOrder); + this.pos.globalState.selectNextOrder(); const { name, props } = this.ticketScreen; this.pos.showScreen(name, props); } isResumeVisible() { - return this.env.pos.get_order_list().length > 1; + return this.pos.globalState.get_order_list().length > 1; } async printReceipt() { this.buttonPrintReceipt.el.className = "fa fa-fw fa-spin fa-circle-o-notch"; @@ -160,7 +159,7 @@ export class ReceiptScreen extends AbstractReceiptScreen { this.buttonPrintReceipt.el.className = "fa fa-print"; } _shouldAutoPrint() { - return this.env.pos.config.iface_print_auto && !this.currentOrder._printed; + return this.pos.globalState.config.iface_print_auto && !this.currentOrder._printed; } _shouldCloseImmediately() { var invoiced_finalized = this.currentOrder.is_to_invoice() @@ -168,7 +167,7 @@ export class ReceiptScreen extends AbstractReceiptScreen { : true; return ( this.hardwareProxy.printer && - this.env.pos.config.iface_print_skip_screen && + this.pos.globalState.config.iface_print_skip_screen && invoiced_finalized ); } @@ -183,7 +182,7 @@ export class ReceiptScreen extends AbstractReceiptScreen { email: this.orderUiState.inputEmail, name: partner ? partner.name : this.orderUiState.inputEmail, }; - const order_server_id = this.env.pos.validated_orders_name_server_id_map[orderName]; + const order_server_id = this.pos.globalState.validated_orders_name_server_id_map[orderName]; if (!order_server_id) { this.popup.add(OfflineErrorPopup, { title: this.env._t("Unsynced order"), diff --git a/addons/point_of_sale/static/src/js/Screens/ScaleScreen/ScaleScreen.js b/addons/point_of_sale/static/src/js/Screens/ScaleScreen/ScaleScreen.js index 368fba28c8c..de57faf59b9 100644 --- a/addons/point_of_sale/static/src/js/Screens/ScaleScreen/ScaleScreen.js +++ b/addons/point_of_sale/static/src/js/Screens/ScaleScreen/ScaleScreen.js @@ -14,7 +14,7 @@ export class ScaleScreen extends Component { * @param {Object} props.product The product to weight. */ setup() { - super.setup(); + this.pos = usePos(); this.hardwareProxy = useService("hardware_proxy"); useExternalListener(document, "keyup", this._onHotkeys); this.state = useState({ weight: 0 }); @@ -60,8 +60,8 @@ export class ScaleScreen extends Component { setTimeout(() => this._setWeight(), 500); } get _activePricelist() { - const current_order = this.env.pos.get_order(); - let current_pricelist = this.env.pos.default_pricelist; + const current_order = this.pos.globalState.get_order(); + let current_pricelist = this.pos.globalState.default_pricelist; if (current_order) { current_pricelist = current_order.pricelist; } @@ -69,14 +69,14 @@ export class ScaleScreen extends Component { } get productWeightString() { const defaultstr = (this.state.weight || 0).toFixed(3) + " Kg"; - if (!this.props.product || !this.env.pos) { + if (!this.props.product) { return defaultstr; } const unit_id = this.props.product.uom_id; if (!unit_id) { return defaultstr; } - const unit = this.env.pos.units_by_id[unit_id[0]]; + const unit = this.pos.globalState.units_by_id[unit_id[0]]; const weight = round_pr(this.state.weight || 0, unit.rounding); let weightstr = weight.toFixed(Math.ceil(Math.log(1.0 / unit.rounding) / Math.log(10))); weightstr += " " + unit.name; @@ -90,14 +90,13 @@ export class ScaleScreen extends Component { return (product ? product.get_price(this._activePricelist, this.state.weight) : 0) || 0; } get productName() { - return ( - (this.props.product ? this.props.product.display_name : undefined) || "Unnamed Product" - ); + return this.props.product?.display_name || "Unnamed Product"; } get productUom() { - return this.props.product - ? this.env.pos.units_by_id[this.props.product.uom_id[0]].name - : ""; + if (!this.props.product) { + return ""; + } + return this.pos.globalState.units_by_id[this.props.product.uom_id[0]].name; } } diff --git a/addons/point_of_sale/static/src/js/Screens/TicketScreen/OrderlineDetails.js b/addons/point_of_sale/static/src/js/Screens/TicketScreen/OrderlineDetails.js index 036302cd65b..b4125297e3e 100644 --- a/addons/point_of_sale/static/src/js/Screens/TicketScreen/OrderlineDetails.js +++ b/addons/point_of_sale/static/src/js/Screens/TicketScreen/OrderlineDetails.js @@ -4,6 +4,7 @@ import { Component } from "@odoo/owl"; import { sprintf } from "@web/core/utils/strings"; import { formatFloat } from "@web/views/fields/formatters"; import { roundPrecision as round_pr } from "@web/core/utils/numbers"; +import { usePos } from "@point_of_sale/app/pos_hook"; /** * @props {pos.order.line} line @@ -11,12 +12,15 @@ import { roundPrecision as round_pr } from "@web/core/utils/numbers"; export class OrderlineDetails extends Component { static template = "OrderlineDetails"; + setup() { + this.pos = usePos(); + } get line() { const line = this.props.line; const formatQty = (line) => { const quantity = line.get_quantity(); const unit = line.get_unit(); - const decimals = this.env.pos.dp["Product Unit of Measure"]; + const decimals = this.pos.globalState.dp["Product Unit of Measure"]; const rounding = Math.max(unit.rounding, Math.pow(10, -decimals)); const roundedQuantity = round_pr(quantity, rounding); return formatFloat(roundedQuantity, { digits: [69, decimals] }); @@ -51,17 +55,17 @@ export class OrderlineDetails extends Component { return this.props.line.get_customer_note(); } getToRefundDetail() { - return this.env.pos.toRefundLines[this.props.line.id]; + return this.pos.globalState.toRefundLines[this.props.line.id]; } hasRefundedQty() { - return !this.env.pos.isProductQtyZero(this.props.line.refunded_qty); + return !this.pos.globalState.isProductQtyZero(this.props.line.refunded_qty); } getFormattedRefundedQty() { return this.env.utils.formatProductQty(this.props.line.refunded_qty); } hasToRefundQty() { const toRefundDetail = this.getToRefundDetail(); - return !this.env.pos.isProductQtyZero(toRefundDetail && toRefundDetail.qty); + return !this.pos.globalState.isProductQtyZero(toRefundDetail && toRefundDetail.qty); } getFormattedToRefundQty() { const toRefundDetail = this.getToRefundDetail(); diff --git a/addons/point_of_sale/static/src/js/Screens/TicketScreen/ReprintReceiptScreen.js b/addons/point_of_sale/static/src/js/Screens/TicketScreen/ReprintReceiptScreen.js index 0407b211f3b..7d7d7d27d72 100644 --- a/addons/point_of_sale/static/src/js/Screens/TicketScreen/ReprintReceiptScreen.js +++ b/addons/point_of_sale/static/src/js/Screens/TicketScreen/ReprintReceiptScreen.js @@ -21,7 +21,8 @@ export class ReprintReceiptScreen extends AbstractReceiptScreen { this.pos.showScreen("TicketScreen", { reuseSavedUIState: true }); } async printReceipt() { - if (this.hardwareProxy.printer && this.env.pos.config.iface_print_skip_screen) { + const { iface_print_skip_screen } = this.pos.globalState.config; + if (this.hardwareProxy.printer && iface_print_skip_screen) { const result = await this._printReceipt(); if (result) { this.pos.showScreen("TicketScreen", { reuseSavedUIState: true }); diff --git a/addons/point_of_sale/static/src/js/Screens/TicketScreen/TicketScreen.js b/addons/point_of_sale/static/src/js/Screens/TicketScreen/TicketScreen.js index eb2142a149b..b4d78da85e5 100644 --- a/addons/point_of_sale/static/src/js/Screens/TicketScreen/TicketScreen.js +++ b/addons/point_of_sale/static/src/js/Screens/TicketScreen/TicketScreen.js @@ -54,7 +54,7 @@ export class TicketScreen extends IndependentToOrderScreen { this.numberBuffer.use({ triggerAtInput: (event) => this._onUpdateSelectedOrderline(event), }); - this._state = this.env.pos.TICKET_SCREEN_STATE; + this._state = this.pos.globalState.TICKET_SCREEN_STATE; this.state = useState({ showSearchBar: !this.env.isMobile, }); @@ -62,7 +62,7 @@ export class TicketScreen extends IndependentToOrderScreen { ? this._state.ui : { selectedSyncedOrderId: null, - searchDetails: this.env.pos.getDefaultSearchDetails(), + searchDetails: this.pos.globalState.getDefaultSearchDetails(), filter: null, selectedOrderlineIds: {}, }; @@ -115,13 +115,13 @@ export class TicketScreen extends IndependentToOrderScreen { } } onCreateNewOrder() { - this.env.pos.add_new_order(); + this.pos.globalState.add_new_order(); this.pos.showScreen("ProductScreen"); } _selectNextOrder(currentOrder) { const currentOrderIndex = this._getOrderList().indexOf(currentOrder); const orderList = this._getOrderList(); - this.env.pos.set_order( + this.pos.globalState.set_order( orderList[currentOrderIndex + 1] || orderList[currentOrderIndex - 1] ); } @@ -145,14 +145,15 @@ export class TicketScreen extends IndependentToOrderScreen { return; } } + const { globalState } = this.pos; if (order && (await this._onBeforeDeleteOrder(order))) { - if (order === this.env.pos.get_order()) { + if (order === globalState.get_order()) { this._selectNextOrder(order); } - this.env.pos.removeOrder(order); + globalState.removeOrder(order); } - if (this.env.pos.isOpenOrderShareable()) { - this.env.pos._removeOrdersFromServer(); + if (globalState.isOpenOrderShareable()) { + globalState._removeOrdersFromServer(); } } async onNextPage() { @@ -168,7 +169,7 @@ export class TicketScreen extends IndependentToOrderScreen { } } async onInvoiceOrder(orderId) { - this.env.pos._invalidateSyncedOrdersCache([orderId]); + this.pos.globalState._invalidateSyncedOrdersCache([orderId]); await this._fetchSyncedOrders(); } onClickOrderline(orderline) { @@ -178,7 +179,7 @@ export class TicketScreen extends IndependentToOrderScreen { } onClickRefundOrderUid(orderUid) { // Open the refund order. - const refundOrder = this.env.pos.orders.find((order) => order.uid == orderUid); + const refundOrder = this.pos.globalState.orders.find((order) => order.uid == orderUid); if (refundOrder) { this._setOrder(refundOrder); } @@ -258,9 +259,10 @@ export class TicketScreen extends IndependentToOrderScreen { ? this.props.destinationOrder : this._getEmptyOrder(partner); + const { globalState } = this.pos; // Add orderline for each toRefundDetail to the destinationOrder. for (const refundDetail of allToRefundDetails) { - const product = this.env.pos.db.get_product_by_id(refundDetail.orderline.productId); + const product = globalState.db.get_product_by_id(refundDetail.orderline.productId); const options = this._prepareRefundOrderlineOptions(refundDetail); await destinationOrder.add_product(product, options); refundDetail.destinationOrderUid = destinationOrder.uid; @@ -272,8 +274,8 @@ export class TicketScreen extends IndependentToOrderScreen { destinationOrder.updatePricelist(partner); } - if (this.env.pos.get_order().cid !== destinationOrder.cid) { - this.env.pos.set_order(destinationOrder); + if (globalState.get_order().cid !== destinationOrder.cid) { + globalState.set_order(destinationOrder); } this.onCloseScreen(); @@ -361,7 +363,7 @@ export class TicketScreen extends IndependentToOrderScreen { const productScreenStatus = this._getScreenToStatusMap().ProductScreen; return ( order.get_orderlines().length === 0 && - this.env.pos.get_order_list().length === 1 && + this.pos.globalState.get_order_list().length === 1 && status === productScreenStatus && order.get_paymentlines().length === 0 ); @@ -385,12 +387,12 @@ export class TicketScreen extends IndependentToOrderScreen { const selectedOrder = this.getSelectedSyncedOrder(); return selectedOrder ? order.backendId == selectedOrder.backendId : false; } else { - const activeOrder = this.env.pos.get_order(); + const activeOrder = this.pos.globalState.get_order(); return activeOrder ? activeOrder.uid == order.uid : false; } } showCardholderName() { - return this.env.pos.payment_methods.some((method) => method.use_payment_terminal); + return this.pos.globalState.payment_methods.some((method) => method.use_payment_terminal); } getSearchBarConfig() { return { @@ -424,7 +426,7 @@ export class TicketScreen extends IndependentToOrderScreen { if (this._doesOrderHaveSoleItem(order)) { return true; } - const total = Object.values(this.env.pos.toRefundLines) + const total = Object.values(this.pos.globalState.toRefundLines) .filter( (toRefundDetail) => toRefundDetail.orderline.orderUid === order.uid && @@ -432,7 +434,7 @@ export class TicketScreen extends IndependentToOrderScreen { ) .map((toRefundDetail) => toRefundDetail.qty) .reduce((acc, val) => acc + val, 0); - return !this.env.pos.isProductQtyZero(total); + return !this.pos.globalState.isProductQtyZero(total); } //#endregion //#region PRIVATE METHODS @@ -447,7 +449,7 @@ export class TicketScreen extends IndependentToOrderScreen { _getEmptyOrder(partner) { let emptyOrderForPartner = null; let emptyOrder = null; - for (const order of this.env.pos.orders) { + for (const order of this.pos.globalState.orders) { if (order.get_orderlines().length === 0 && order.get_paymentlines().length === 0) { if (order.get_partner() === partner) { emptyOrderForPartner = order; @@ -458,7 +460,7 @@ export class TicketScreen extends IndependentToOrderScreen { } } } - return emptyOrderForPartner || emptyOrder || this.env.pos.add_new_order(); + return emptyOrderForPartner || emptyOrder || this.pos.globalState.add_new_order(); } _doesOrderHaveSoleItem(order) { const orderlines = order.get_orderlines(); @@ -467,7 +469,7 @@ export class TicketScreen extends IndependentToOrderScreen { } const theOrderline = orderlines[0]; const refundableQty = theOrderline.get_quantity() - theOrderline.refunded_qty; - return this.env.pos.isProductQtyZero(refundableQty - 1); + return this.pos.globalState.isProductQtyZero(refundableQty - 1); } _prepareAutoRefundOnOrder(order) { const selectedOrderlineId = this.getSelectedOrderlineId(); @@ -478,7 +480,7 @@ export class TicketScreen extends IndependentToOrderScreen { const toRefundDetail = this._getToRefundDetail(orderline); const refundableQty = orderline.get_quantity() - orderline.refunded_qty; - if (this.env.pos.isProductQtyZero(refundableQty - 1) && toRefundDetail.qty === 0) { + if (this.pos.globalState.isProductQtyZero(refundableQty - 1) && toRefundDetail.qty === 0) { toRefundDetail.qty = 1; } return true; @@ -491,30 +493,30 @@ export class TicketScreen extends IndependentToOrderScreen { * @returns */ _getToRefundDetail(orderline) { - if (orderline.id in this.env.pos.toRefundLines) { - return this.env.pos.toRefundLines[orderline.id]; - } else { - const partner = orderline.order.get_partner(); - const orderPartnerId = partner ? partner.id : false; - const newToRefundDetail = { - qty: 0, - orderline: { - id: orderline.id, - productId: orderline.product.id, - price: orderline.price, - qty: orderline.quantity, - refundedQty: orderline.refunded_qty, - orderUid: orderline.order.uid, - orderBackendId: orderline.order.backendId, - orderPartnerId, - tax_ids: orderline.get_taxes().map((tax) => tax.id), - discount: orderline.discount, - }, - destinationOrderUid: false, - }; - this.env.pos.toRefundLines[orderline.id] = newToRefundDetail; - return newToRefundDetail; + const { toRefundLines } = this.pos.globalState; + if (orderline.id in toRefundLines) { + return toRefundLines[orderline.id]; } + const partner = orderline.order.get_partner(); + const orderPartnerId = partner ? partner.id : false; + const newToRefundDetail = { + qty: 0, + orderline: { + id: orderline.id, + productId: orderline.product.id, + price: orderline.price, + qty: orderline.quantity, + refundedQty: orderline.refunded_qty, + orderUid: orderline.order.uid, + orderBackendId: orderline.order.backendId, + orderPartnerId, + tax_ids: orderline.get_taxes().map((tax) => tax.id), + discount: orderline.discount, + }, + destinationOrderUid: false, + }; + toRefundLines[orderline.id] = newToRefundDetail; + return newToRefundDetail; } /** * Select the lines from toRefundLines, as they can come from different orders. @@ -527,9 +529,9 @@ export class TicketScreen extends IndependentToOrderScreen { * @returns {Array} refundableDetails */ _getRefundableDetails(partner) { - return Object.values(this.env.pos.toRefundLines).filter( + return Object.values(this.pos.globalState.toRefundLines).filter( ({ qty, orderline, destinationOrderUid }) => - !this.env.pos.isProductQtyZero(qty) && + !this.pos.globalState.isProductQtyZero(qty) && (partner ? orderline.orderPartnerId == partner.id : true) && !destinationOrderUid ); @@ -553,14 +555,15 @@ export class TicketScreen extends IndependentToOrderScreen { }; } _setOrder(order) { - if (this.env.pos.isOpenOrderShareable()) { - this.env.pos.sendDraftToServer(); + const { globalState } = this.pos; + if (globalState.isOpenOrderShareable()) { + globalState.sendDraftToServer(); } - this.env.pos.set_order(order); + globalState.set_order(order); this.close(); } _getOrderList() { - return this.env.pos.get_order_list(); + return this.pos.globalState.get_order_list(); } _getFilterOptions() { const orderStates = this._getOrderStates(); @@ -659,20 +662,17 @@ export class TicketScreen extends IndependentToOrderScreen { * order is not fetched anymore, instead, we use info from cache. */ async _fetchSyncedOrders() { + const { globalState } = this.pos; const domain = this._computeSyncedOrdersDomain(); const limit = this._state.syncedOrders.nPerPage; const offset = (this._state.syncedOrders.currentPage - 1) * this._state.syncedOrders.nPerPage; + const config_id = globalState.config.id; const { ordersInfo, totalCount } = await this.orm.call( "pos.order", "search_paid_order_ids", [], - { - config_id: this.env.pos.config.id, - domain, - limit, - offset, - } + { config_id, domain, limit, offset } ); const idsNotInCache = ordersInfo.filter( (orderInfo) => !(orderInfo[0] in this._state.syncedOrders.cache) @@ -686,14 +686,14 @@ export class TicketScreen extends IndependentToOrderScreen { if (idsToLoad.length > 0) { const fetchedOrders = await this.orm.call("pos.order", "export_for_ui", [idsToLoad]); // Check for missing products and partners and load them in the PoS - await this.env.pos._loadMissingProducts(fetchedOrders); - await this.env.pos._loadMissingPartners(fetchedOrders); + await globalState._loadMissingProducts(fetchedOrders); + await globalState._loadMissingPartners(fetchedOrders); // Cache these fetched orders so that next time, no need to fetch // them again, unless invalidated. See `_onInvoiceOrder`. fetchedOrders.forEach((order) => { this._state.syncedOrders.cache[order.id] = new Order( {}, - { pos: this.env.pos, json: order } + { pos: globalState, json: order } ); }); //Update the datetime indicator of the cache refresh diff --git a/addons/point_of_sale/static/src/xml/ChromeWidgets/SyncNotification.xml b/addons/point_of_sale/static/src/xml/ChromeWidgets/SyncNotification.xml index 89ecf5d5930..dabfda0276d 100644 --- a/addons/point_of_sale/static/src/xml/ChromeWidgets/SyncNotification.xml +++ b/addons/point_of_sale/static/src/xml/ChromeWidgets/SyncNotification.xml @@ -3,23 +3,23 @@
    - - + + -
    +
    -
    +
    -
    +
    -
    +
    diff --git a/addons/point_of_sale/static/src/xml/Screens/PartnerListScreen/PartnerDetailsEdit.xml b/addons/point_of_sale/static/src/xml/Screens/PartnerListScreen/PartnerDetailsEdit.xml index 5348218207b..a042c9284e5 100644 --- a/addons/point_of_sale/static/src/xml/Screens/PartnerListScreen/PartnerDetailsEdit.xml +++ b/addons/point_of_sale/static/src/xml/Screens/PartnerListScreen/PartnerDetailsEdit.xml @@ -40,7 +40,7 @@ - +
    -
    +
    Pricelist - + +
    diff --git a/addons/point_of_sale/static/src/xml/Screens/ReceiptScreen/OrderReceipt.xml b/addons/point_of_sale/static/src/xml/Screens/ReceiptScreen/OrderReceipt.xml index 0c8c9ce1865..a3af3e91579 100644 --- a/addons/point_of_sale/static/src/xml/Screens/ReceiptScreen/OrderReceipt.xml +++ b/addons/point_of_sale/static/src/xml/Screens/ReceiptScreen/OrderReceipt.xml @@ -197,7 +197,7 @@
    - + @@ -211,7 +211,7 @@
    - + x diff --git a/addons/pos_discount/static/src/js/DiscountButton.js b/addons/pos_discount/static/src/js/DiscountButton.js index 531aef87e42..5b58cf95ec4 100644 --- a/addons/pos_discount/static/src/js/DiscountButton.js +++ b/addons/pos_discount/static/src/js/DiscountButton.js @@ -6,19 +6,20 @@ import { NumberPopup } from "@point_of_sale/js/Popups/NumberPopup"; import { ErrorPopup } from "@point_of_sale/js/Popups/ErrorPopup"; import { Component } from "@odoo/owl"; import { sprintf } from "@web/core/utils/strings"; +import { usePos } from "@point_of_sale/app/pos_hook"; export class DiscountButton extends Component { static template = "DiscountButton"; setup() { - super.setup(); + this.pos = usePos(); this.popup = useService("popup"); } async click() { var self = this; const { confirmed, payload } = await this.popup.add(NumberPopup, { title: this.env._t("Discount Percentage"), - startingValue: this.env.pos.config.discount_pc, + startingValue: this.pos.globalState.config.discount_pc, isInputSelected: true, }); if (confirmed) { @@ -28,9 +29,10 @@ export class DiscountButton extends Component { } async apply_discount(pc) { - var order = this.env.pos.get_order(); - var lines = order.get_orderlines(); - var product = this.env.pos.db.get_product_by_id(this.env.pos.config.discount_product_id[0]); + const { globalState } = this.pos; + const order = globalState.get_order(); + const lines = order.get_orderlines(); + const product = globalState.db.get_product_by_id(globalState.config.discount_product_id[0]); if (product === undefined) { await this.popup.add(ErrorPopup, { title: this.env._t("No discount product found"), @@ -56,7 +58,14 @@ export class DiscountButton extends Component { .filter((id) => id !== "") .map((id) => Number(id)); - const baseToDiscount = order.calculate_base_amount(tax_ids_array, lines.filter((line) => !this.env.pos.config.tip_product_id || line.product.id !== this.env.pos.config.tip_product_id[0])); + const baseToDiscount = order.calculate_base_amount( + tax_ids_array, + lines.filter( + (line) => + !globalState.config.tip_product_id || + line.product.id !== globalState.config.tip_product_id[0] + ) + ); // We add the price as manually set to avoid recomputation when changing customer. const discount = (-pc / 100.0) * baseToDiscount; @@ -72,7 +81,7 @@ export class DiscountButton extends Component { ? sprintf( this.env._t("Tax: %s"), tax_ids_array - .map((taxId) => this.env.pos.taxes_by_id[taxId].amount + "%") + .map((taxId) => globalState.taxes_by_id[taxId].amount + "%") .join(", ") ) : this.env._t("No tax")), @@ -88,6 +97,7 @@ export class DiscountButton extends Component { ProductScreen.addControlButton({ component: DiscountButton, condition: function () { - return this.env.pos.config.module_pos_discount && this.env.pos.config.discount_product_id; + const { module_pos_discount, discount_product_id } = this.pos.globalState.config; + return module_pos_discount && discount_product_id; }, }); diff --git a/addons/pos_hr/static/src/app/navbar.xml b/addons/pos_hr/static/src/app/navbar.xml index afa366f7e35..f792a4c1c1b 100644 --- a/addons/pos_hr/static/src/app/navbar.xml +++ b/addons/pos_hr/static/src/app/navbar.xml @@ -4,10 +4,10 @@
    - - - -
    + + + +
    diff --git a/addons/pos_hr/static/src/js/CashierName.js b/addons/pos_hr/static/src/js/CashierName.js index 9fa6e9a1d0f..3767338cd12 100644 --- a/addons/pos_hr/static/src/js/CashierName.js +++ b/addons/pos_hr/static/src/js/CashierName.js @@ -11,15 +11,15 @@ patch(CashierName.prototype, "pos_hr.CashierName", { }, //@Override get avatar() { - if (this.env.pos.config.module_pos_hr) { - const cashier = this.env.pos.get_cashier(); + if (this.pos.globalState.config.module_pos_hr) { + const cashier = this.pos.globalState.get_cashier(); return `/web/image/hr.employee/${cashier.id}/avatar_128`; } return this._super(...arguments); }, //@Override get cssClass() { - if (this.env.pos.config.module_pos_hr) { + if (this.pos.globalState.config.module_pos_hr) { return { oe_status: true }; } return this._super(...arguments); diff --git a/addons/pos_hr/static/src/js/Chrome.js b/addons/pos_hr/static/src/js/Chrome.js index a4ed3088905..b26ba2191d2 100644 --- a/addons/pos_hr/static/src/js/Chrome.js +++ b/addons/pos_hr/static/src/js/Chrome.js @@ -5,9 +5,7 @@ import { patch } from "@web/core/utils/patch"; patch(Chrome.prototype, "pos_hr.Chrome", { get showCashMoveButton() { - return ( - this._super(...arguments) && - (!this.env.pos.cashier || this.env.pos.cashier.role == "manager") - ); + const { cashier } = this.pos.globalState; + return this._super(...arguments) && (!cashier || cashier.role == "manager"); }, }); diff --git a/addons/pos_hr/static/src/js/HeaderLockButton.js b/addons/pos_hr/static/src/js/HeaderLockButton.js index 1dd8371fb1b..5a947f53b68 100644 --- a/addons/pos_hr/static/src/js/HeaderLockButton.js +++ b/addons/pos_hr/static/src/js/HeaderLockButton.js @@ -11,7 +11,7 @@ export class HeaderLockButton extends Component { this.pos = usePos(); } async showLoginScreen() { - this.env.pos.reset_cashier(); + this.pos.globalState.reset_cashier(); await this.pos.showTempScreen("LoginScreen"); } } diff --git a/addons/pos_hr/static/src/js/LoginScreen.js b/addons/pos_hr/static/src/js/LoginScreen.js index c9cdc47b259..4f29ad8aa15 100644 --- a/addons/pos_hr/static/src/js/LoginScreen.js +++ b/addons/pos_hr/static/src/js/LoginScreen.js @@ -19,12 +19,12 @@ export class LoginScreen extends Component { back() { this.props.resolve({ confirmed: false, payload: false }); this.pos.closeTempScreen(); - this.env.pos.hasLoggedIn = true; + this.pos.globalState.hasLoggedIn = true; this.pos.openCashControl(); } get shopName() { - return this.env.pos.config.name; + return this.pos.globalState.config.name; } } diff --git a/addons/pos_hr/static/src/js/PaymentScreen.js b/addons/pos_hr/static/src/js/PaymentScreen.js index de88ea8677e..1c30569a260 100644 --- a/addons/pos_hr/static/src/js/PaymentScreen.js +++ b/addons/pos_hr/static/src/js/PaymentScreen.js @@ -5,7 +5,7 @@ import { patch } from "@web/core/utils/patch"; patch(PaymentScreen.prototype, "pos_hr.PaymentScreen", { async _finalizeValidation() { - this.currentOrder.cashier = this.env.pos.get_cashier(); + this.currentOrder.cashier = this.pos.globalState.get_cashier(); await this._super(...arguments); }, }); diff --git a/addons/pos_hr/static/src/js/SelectCashierMixin.js b/addons/pos_hr/static/src/js/SelectCashierMixin.js index 41d2e41175d..8c15498ad09 100644 --- a/addons/pos_hr/static/src/js/SelectCashierMixin.js +++ b/addons/pos_hr/static/src/js/SelectCashierMixin.js @@ -7,26 +7,26 @@ import { NumberPopup } from "@point_of_sale/js/Popups/NumberPopup"; import { SelectionPopup } from "@point_of_sale/js/Popups/SelectionPopup"; import { ErrorPopup } from "@point_of_sale/js/Popups/ErrorPopup"; import { useService } from "@web/core/utils/hooks"; -import { useEnv } from "@odoo/owl"; import { useBarcodeReader } from "@point_of_sale/app/barcode_reader_hook"; +import { usePos } from "@point_of_sale/app/pos_hook"; export function useCashierSelector( { onCashierChanged, exclusive } = { onCashierChanged: () => {}, exclusive: false } ) { const popup = useService("popup"); - const env = useEnv(); + const { globalState } = usePos(); useBarcodeReader( { async cashier(code) { - const employee = env.pos.employees.find( + const employee = globalState.employees.find( (emp) => emp.barcode === Sha1.hash(code.code) ); if ( employee && - employee !== env.pos.get_cashier() && + employee !== globalState.get_cashier() && (!employee.pin || (await checkPin(employee))) ) { - env.pos.set_cashier(employee); + globalState.set_cashier(employee); if (onCashierChanged) { onCashierChanged(); } @@ -60,9 +60,9 @@ export function useCashierSelector( * Select a cashier, the returning value will either be an object or nothing (undefined) */ return async function selectCashier() { - if (env.pos.config.module_pos_hr) { - const employeesList = env.pos.employees - .filter((employee) => employee.id !== env.pos.get_cashier().id) + if (globalState.config.module_pos_hr) { + const employeesList = globalState.employees + .filter((employee) => employee.id !== globalState.get_cashier().id) .map((employee) => { return { id: employee.id, @@ -80,7 +80,7 @@ export function useCashierSelector( return; } - env.pos.set_cashier(employee); + globalState.set_cashier(employee); if (onCashierChanged) { onCashierChanged(); } diff --git a/addons/pos_loyalty/static/src/js/ControlButtons/PromoCodeButton.js b/addons/pos_loyalty/static/src/js/ControlButtons/PromoCodeButton.js index 84dca1bdd14..e33e38cbed2 100644 --- a/addons/pos_loyalty/static/src/js/ControlButtons/PromoCodeButton.js +++ b/addons/pos_loyalty/static/src/js/ControlButtons/PromoCodeButton.js @@ -4,12 +4,13 @@ import { ProductScreen } from "@point_of_sale/js/Screens/ProductScreen/ProductSc import { useService } from "@web/core/utils/hooks"; import { TextInputPopup } from "@point_of_sale/js/Popups/TextInputPopup"; import { Component } from "@odoo/owl"; +import { usePos } from "@point_of_sale/app/pos_hook"; export class PromoCodeButton extends Component { static template = "PromoCodeButton"; setup() { - super.setup(); + this.pos = usePos(); this.popup = useService("popup"); } @@ -22,7 +23,7 @@ export class PromoCodeButton extends Component { if (confirmed) { code = code.trim(); if (code !== "") { - this.env.pos.get_order().activateCode(code); + this.pos.globalState.get_order().activateCode(code); } } } @@ -31,7 +32,7 @@ export class PromoCodeButton extends Component { ProductScreen.addControlButton({ component: PromoCodeButton, condition: function () { - return this.env.pos.programs.some((p) => + return this.pos.globalState.programs.some((p) => ["coupons", "promotion", "gift_card", "promo_code"].includes(p.program_type) ); }, diff --git a/addons/pos_loyalty/static/src/js/ControlButtons/ResetProgramsButton.js b/addons/pos_loyalty/static/src/js/ControlButtons/ResetProgramsButton.js index 38efd9899d3..5d67469dc82 100644 --- a/addons/pos_loyalty/static/src/js/ControlButtons/ResetProgramsButton.js +++ b/addons/pos_loyalty/static/src/js/ControlButtons/ResetProgramsButton.js @@ -2,24 +2,27 @@ import { ProductScreen } from "@point_of_sale/js/Screens/ProductScreen/ProductScreen"; import { Component } from "@odoo/owl"; +import { usePos } from "@point_of_sale/app/pos_hook"; export class ResetProgramsButton extends Component { static template = "ResetProgramsButton"; setup() { - super.setup(); + this.pos = usePos(); } _isDisabled() { - return !this.env.pos.get_order().isProgramsResettable(); + return !this.pos.globalState.get_order().isProgramsResettable(); } click() { - this.env.pos.get_order()._resetPrograms(); + this.pos.globalState.get_order()._resetPrograms(); } } ProductScreen.addControlButton({ component: ResetProgramsButton, condition: function () { - return this.env.pos.programs.some((p) => ["coupons", "promotion"].includes(p.program_type)); + return this.pos.globalState.programs.some((p) => + ["coupons", "promotion"].includes(p.program_type) + ); }, }); diff --git a/addons/pos_loyalty/static/src/js/ControlButtons/RewardButton.js b/addons/pos_loyalty/static/src/js/ControlButtons/RewardButton.js index a9a8c15f34f..70faf91e5e6 100644 --- a/addons/pos_loyalty/static/src/js/ControlButtons/RewardButton.js +++ b/addons/pos_loyalty/static/src/js/ControlButtons/RewardButton.js @@ -10,7 +10,6 @@ export class RewardButton extends Component { static template = "RewardButton"; setup() { - super.setup(); this.popup = useService("popup"); this.pos = usePos(); this.notification = useService("pos_notification"); @@ -31,7 +30,7 @@ export class RewardButton extends Component { } _getPotentialRewards() { - const order = this.env.pos.get_order(); + const order = this.pos.globalState.get_order(); // Claimable rewards excluding those from eWallet programs. // eWallet rewards are handled in the eWalletButton. let rewards = []; @@ -62,14 +61,14 @@ export class RewardButton extends Component { * @param {Integer} coupon_id */ async _applyReward(reward, coupon_id, potentialQty) { - const order = this.env.pos.get_order(); + const order = this.pos.globalState.get_order(); order.disabledRewards.delete(reward.id); const args = {}; if (reward.reward_type === "product" && reward.multi_product) { const productsList = reward.reward_product_ids.map((product_id) => ({ id: product_id, - label: this.env.pos.db.get_product_by_id(product_id).display_name, + label: this.pos.globalState.db.get_product_by_id(product_id).display_name, item: product_id, })); const { confirmed, payload: selectedProduct } = await this.popup.add(SelectionPopup, { @@ -126,6 +125,6 @@ export class RewardButton extends Component { ProductScreen.addControlButton({ component: RewardButton, condition: function () { - return this.env.pos.programs.length > 0; + return this.pos.globalState.programs.length > 0; }, }); diff --git a/addons/pos_loyalty/static/src/js/ControlButtons/eWalletButton.js b/addons/pos_loyalty/static/src/js/ControlButtons/eWalletButton.js index 9925ae7549f..2e2e823bc3d 100644 --- a/addons/pos_loyalty/static/src/js/ControlButtons/eWalletButton.js +++ b/addons/pos_loyalty/static/src/js/ControlButtons/eWalletButton.js @@ -11,7 +11,6 @@ export class eWalletButton extends Component { static template = "point_of_sale.eWalletButton"; setup() { - super.setup(...arguments); this.popup = useService("popup"); this.pos = usePos(); } @@ -24,11 +23,13 @@ export class eWalletButton extends Component { return eWalletRewards; } _getEWalletPrograms() { - return this.env.pos.programs.filter((p) => p.program_type == "ewallet"); + return this.pos.globalState.programs.filter((p) => p.program_type == "ewallet"); } async _onClickWalletButton() { - const order = this.env.pos.get_order(); - const eWalletPrograms = this.env.pos.programs.filter((p) => p.program_type == "ewallet"); + const order = this.pos.globalState.get_order(); + const eWalletPrograms = this.pos.globalState.programs.filter( + (p) => p.program_type == "ewallet" + ); const orderTotal = order.get_total_with_tax(); const eWalletRewards = this._getEWalletRewards(order); if (orderTotal < 0 && eWalletPrograms.length >= 1) { @@ -49,7 +50,7 @@ export class eWalletButton extends Component { } } if (selectedProgram) { - const eWalletProduct = this.env.pos.db.get_product_by_id( + const eWalletProduct = this.pos.globalState.db.get_product_by_id( selectedProgram.trigger_product_ids[0] ); this.pos.addProductFromUi(eWalletProduct, { @@ -109,6 +110,6 @@ export class eWalletButton extends Component { ProductScreen.addControlButton({ component: eWalletButton, condition: function () { - return this.env.pos.programs.filter((p) => p.program_type == "ewallet").length > 0; + return this.pos.globalState.programs.filter((p) => p.program_type == "ewallet").length > 0; }, }); diff --git a/addons/pos_loyalty/static/src/js/OrderSummary.js b/addons/pos_loyalty/static/src/js/OrderSummary.js index 78084e72760..eaca8e3685b 100644 --- a/addons/pos_loyalty/static/src/js/OrderSummary.js +++ b/addons/pos_loyalty/static/src/js/OrderSummary.js @@ -5,7 +5,7 @@ import { patch } from "@web/core/utils/patch"; patch(OrderSummary.prototype, "pos_loyalty.OrderSummary", { getLoyaltyPoints() { - const order = this.env.pos.get_order(); + const order = this.pos.globalState.get_order(); return order.getLoyaltyPoints(); }, }); diff --git a/addons/pos_loyalty/static/src/js/Orderline.js b/addons/pos_loyalty/static/src/js/Orderline.js index 3653a8a84a0..6bac2acbd3f 100644 --- a/addons/pos_loyalty/static/src/js/Orderline.js +++ b/addons/pos_loyalty/static/src/js/Orderline.js @@ -11,9 +11,9 @@ patch(Orderline.prototype, "pos_loyalty.Orderline", { ); }, _isGiftCardOrEWalletReward() { - const coupon = this.env.pos.couponCache[this.props.line.coupon_id]; + const coupon = this.pos.globalState.couponCache[this.props.line.coupon_id]; if (coupon) { - const program = this.env.pos.program_by_id[coupon.program_id]; + const program = this.pos.globalState.program_by_id[coupon.program_id]; return ( ["ewallet", "gift_card"].includes(program.program_type) && this.props.line.is_reward_line @@ -22,7 +22,7 @@ patch(Orderline.prototype, "pos_loyalty.Orderline", { return false; }, _getGiftCardOrEWalletBalance() { - const coupon = this.env.pos.couponCache[this.props.line.coupon_id]; + const coupon = this.pos.globalState.couponCache[this.props.line.coupon_id]; if (coupon) { return this.env.utils.formatCurrency(coupon.balance); } diff --git a/addons/pos_loyalty/static/src/js/PartnerLine.js b/addons/pos_loyalty/static/src/js/PartnerLine.js index a9d5a6cb957..5f27d8edde8 100644 --- a/addons/pos_loyalty/static/src/js/PartnerLine.js +++ b/addons/pos_loyalty/static/src/js/PartnerLine.js @@ -1,13 +1,18 @@ /** @odoo-module */ +import { usePos } from "@point_of_sale/app/pos_hook"; import { PartnerLine } from "@point_of_sale/js/Screens/PartnerListScreen/PartnerLine"; import { patch } from "@web/core/utils/patch"; import { sprintf } from "@web/core/utils/strings"; import { formatFloat } from "@web/views/fields/formatters"; patch(PartnerLine.prototype, "pos_loyalty.PartnerLine", { + setup() { + this._super(...arguments); + this.pos = usePos(); + }, _getLoyaltyPointsRepr(loyaltyCard) { - const program = this.env.pos.program_by_id[loyaltyCard.program_id]; + const program = this.pos.globalState.program_by_id[loyaltyCard.program_id]; if (program.program_type === "ewallet") { return `${program.name}: ${this.env.utils.formatCurrency(loyaltyCard.balance)}`; } diff --git a/addons/pos_loyalty/static/src/js/PaymentScreen.js b/addons/pos_loyalty/static/src/js/PaymentScreen.js index 0801a0c72f0..17e9d353e05 100644 --- a/addons/pos_loyalty/static/src/js/PaymentScreen.js +++ b/addons/pos_loyalty/static/src/js/PaymentScreen.js @@ -41,17 +41,18 @@ patch(PaymentScreen.prototype, "pos_loyalty.PaymentScreen", { [[], pointChanges, newCodes] ); // Payload may contain the points of the concerned coupons to be updated in case of error. (So that rewards can be corrected) + const { couponCache } = this.pos.globalState; if (payload && payload.updated_points) { for (const pointChange of Object.entries(payload.updated_points)) { - if (this.env.pos.couponCache[pointChange[0]]) { - this.env.pos.couponCache[pointChange[0]].balance = pointChange[1]; + if (couponCache[pointChange[0]]) { + couponCache[pointChange[0]].balance = pointChange[1]; } } } if (payload && payload.removed_coupons) { for (const couponId of payload.removed_coupons) { - if (this.env.pos.couponCache[couponId]) { - delete this.env.pos.couponCache[couponId]; + if (couponCache[couponId]) { + delete couponCache[couponId]; } } this.currentOrder.codeActivatedCoupons = @@ -79,22 +80,21 @@ patch(PaymentScreen.prototype, "pos_loyalty.PaymentScreen", { async _postPushOrderResolve(order, server_ids) { // Compile data for our function const _super = this._super; + const { program_by_id, reward_by_id, couponCache } = this.pos.globalState; const rewardLines = order._get_reward_lines(); const partner = order.get_partner(); let couponData = Object.values(order.couponPointChanges).reduce((agg, pe) => { agg[pe.coupon_id] = Object.assign({}, pe, { - points: - pe.points - - order._getPointsCorrection(this.env.pos.program_by_id[pe.program_id]), + points: pe.points - order._getPointsCorrection(program_by_id[pe.program_id]), }); - const program = this.env.pos.program_by_id[pe.program_id]; + const program = program_by_id[pe.program_id]; if (program.is_nominative && partner) { agg[pe.coupon_id].partner_id = partner.id; } return agg; }, {}); for (const line of rewardLines) { - const reward = this.env.pos.reward_by_id[line.reward_id]; + const reward = reward_by_id[line.reward_id]; if (!couponData[line.coupon_id]) { couponData[line.coupon_id] = { points: 0, @@ -114,7 +114,7 @@ patch(PaymentScreen.prototype, "pos_loyalty.PaymentScreen", { // We actually do not care about coupons for 'current' programs that did not claim any reward, they will be lost if not validated couponData = Object.fromEntries( Object.entries(couponData).filter(([key, value]) => { - const program = this.env.pos.program_by_id[value.program_id]; + const program = program_by_id[value.program_id]; if (program.applies_on === "current") { return value.line_codes && value.line_codes.length; } @@ -128,7 +128,7 @@ patch(PaymentScreen.prototype, "pos_loyalty.PaymentScreen", { ]); if (payload.coupon_updates) { for (const couponUpdate of payload.coupon_updates) { - let dbCoupon = this.env.pos.couponCache[couponUpdate.old_id]; + let dbCoupon = couponCache[couponUpdate.old_id]; if (dbCoupon) { dbCoupon.id = couponUpdate.id; dbCoupon.balance = couponUpdate.points; @@ -142,14 +142,14 @@ patch(PaymentScreen.prototype, "pos_loyalty.PaymentScreen", { couponUpdate.points ); } - delete this.env.pos.couponCache[couponUpdate.old_id]; - this.env.pos.couponCache[couponUpdate.id] = dbCoupon; + delete couponCache[couponUpdate.old_id]; + couponCache[couponUpdate.id] = dbCoupon; } } // Update the usage count since it is checked based on local data if (payload.program_updates) { for (const programUpdate of payload.program_updates) { - const program = this.env.pos.program_by_id[programUpdate.program_id]; + const program = program_by_id[programUpdate.program_id]; if (program) { program.total_order_count = programUpdate.usages; } diff --git a/addons/pos_loyalty/static/src/js/ProductScreen.js b/addons/pos_loyalty/static/src/js/ProductScreen.js index 8ba36e56a31..5e6c45986cf 100644 --- a/addons/pos_loyalty/static/src/js/ProductScreen.js +++ b/addons/pos_loyalty/static/src/js/ProductScreen.js @@ -41,7 +41,7 @@ patch(ProductScreen.prototype, "pos_loyalty.ProductScreen", { !selectedLine.manual_reward && (key === "Backspace" || key === "Delete") ) { - const reward = this.env.pos.reward_by_id[selectedLine.reward_id]; + const reward = this.pos.globalState.reward_by_id[selectedLine.reward_id]; const { confirmed } = await this.popup.add(ConfirmPopup, { title: this.env._t("Deactivating reward"), body: sprintf( @@ -87,13 +87,14 @@ patch(ProductScreen.prototype, "pos_loyalty.ProductScreen", { } if (selectedLine.is_reward_line && val === "remove") { this.currentOrder.disabledRewards.add(selectedLine.reward_id); - const coupon = this.env.pos.couponCache[selectedLine.coupon_id]; + const { couponCache } = this.pos.globalState; + const coupon = couponCache[selectedLine.coupon_id]; if ( coupon && coupon.id > 0 && this.currentOrder.codeActivatedCoupons.find((c) => c.code === coupon.code) ) { - delete this.env.pos.couponCache[selectedLine.coupon_id]; + delete couponCache[selectedLine.coupon_id]; this.currentOrder.codeActivatedCoupons.splice( this.currentOrder.codeActivatedCoupons.findIndex((coupon) => { return coupon.id === selectedLine.coupon_id; diff --git a/addons/pos_loyalty/static/src/js/TicketScreen.js b/addons/pos_loyalty/static/src/js/TicketScreen.js index dcd094d81db..3648ff462e8 100644 --- a/addons/pos_loyalty/static/src/js/TicketScreen.js +++ b/addons/pos_loyalty/static/src/js/TicketScreen.js @@ -43,12 +43,12 @@ patch(TicketScreen.prototype, "pos_loyalty.TicketScreen", { ); }, _isEWalletGiftCard(orderline) { - const linkedProgramIds = this.env.pos.productId2ProgramIds[orderline.product.id]; + const linkedProgramIds = this.pos.globalState.productId2ProgramIds[orderline.product.id]; if (linkedProgramIds) { return linkedProgramIds.length > 0; } if (orderline.is_reward_line) { - const reward = this.env.pos.reward_by_id[orderline.reward_id]; + const reward = this.pos.globalState.reward_by_id[orderline.reward_id]; const program = reward && reward.program_id; if (program && ["gift_card", "ewallet"].includes(program.program_type)) { return true; diff --git a/addons/pos_loyalty/static/src/xml/ControlButtons/eWalletButton.xml b/addons/pos_loyalty/static/src/xml/ControlButtons/eWalletButton.xml index 8a9574439d5..477b5b9b643 100644 --- a/addons/pos_loyalty/static/src/xml/ControlButtons/eWalletButton.xml +++ b/addons/pos_loyalty/static/src/xml/ControlButtons/eWalletButton.xml @@ -2,7 +2,7 @@ - + diff --git a/addons/pos_loyalty/static/src/xml/PartnerLine.xml b/addons/pos_loyalty/static/src/xml/PartnerLine.xml index b1618b80b51..c4e1c2b1c74 100644 --- a/addons/pos_loyalty/static/src/xml/PartnerLine.xml +++ b/addons/pos_loyalty/static/src/xml/PartnerLine.xml @@ -3,7 +3,7 @@ - +
    diff --git a/addons/pos_mercury/static/src/js/PaymentScreen.js b/addons/pos_mercury/static/src/js/PaymentScreen.js index b7927f6c193..9d364dbf7c2 100644 --- a/addons/pos_mercury/static/src/js/PaymentScreen.js +++ b/addons/pos_mercury/static/src/js/PaymentScreen.js @@ -96,7 +96,7 @@ const lookUpCodeTransaction = { patch(PaymentScreen.prototype, "pos_mercury.PaymentScreen", { setup() { this._super(...arguments); - if (this.env.pos.getOnlinePaymentMethods().length !== 0) { + if (this.pos.globalState.getOnlinePaymentMethods().length !== 0) { useBarcodeReader({ credit: this.credit_code_action, }); @@ -123,7 +123,7 @@ patch(PaymentScreen.prototype, "pos_mercury.PaymentScreen", { }, _get_swipe_pending_line() { var i = 0; - var lines = this.env.pos.get_order().get_paymentlines(); + var lines = this.pos.globalState.get_order().get_paymentlines(); for (i = 0; i < lines.length; i++) { if (lines[i].mercury_swipe_pending) { @@ -135,7 +135,7 @@ patch(PaymentScreen.prototype, "pos_mercury.PaymentScreen", { }, _does_credit_payment_line_exist(amount, card_number, card_brand, card_owner_name) { var i = 0; - var lines = this.env.pos.get_order().get_paymentlines(); + var lines = this.pos.globalState.get_order().get_paymentlines(); for (i = 0; i < lines.length; i++) { if ( @@ -191,7 +191,8 @@ patch(PaymentScreen.prototype, "pos_mercury.PaymentScreen", { }, // Handler to manage the card reader string credit_code_transaction(parsed_result, old_deferred, retry_nr) { - var order = this.env.pos.get_order(); + const { globalState } = this.pos.globalState; + const order = globalState.get_order(); if (order.get_due(order.selected_paymentline) < 0) { this.popup.add(ErrorPopup, { title: this.env._t("Refunds not supported"), @@ -202,12 +203,11 @@ patch(PaymentScreen.prototype, "pos_mercury.PaymentScreen", { return; } - if (this.env.pos.getOnlinePaymentMethods().length === 0) { + if (globalState.getOnlinePaymentMethods().length === 0) { return; } - var self = this; - var decodedMagtek = self.env.pos.decodeMagtek(parsed_result.code); + var decodedMagtek = globalState.decodeMagtek(parsed_result.code); if (!decodedMagtek) { this.popup.add(ErrorPopup, { @@ -219,13 +219,13 @@ patch(PaymentScreen.prototype, "pos_mercury.PaymentScreen", { return; } - var swipe_pending_line = self._get_swipe_pending_line(); + var swipe_pending_line = this._get_swipe_pending_line(); var purchase_amount = 0; if (swipe_pending_line) { purchase_amount = swipe_pending_line.get_amount(); } else { - purchase_amount = self.env.pos.get_order().get_due(); + purchase_amount = globalState.get_order().get_due(); } var transaction = { @@ -233,7 +233,7 @@ patch(PaymentScreen.prototype, "pos_mercury.PaymentScreen", { encrypted_block: decodedMagtek["encrypted_block"], transaction_type: "Credit", transaction_code: "Sale", - invoice_no: self.env.pos.get_order().uid.replace(/-/g, ""), + invoice_no: globalState.get_order().uid.replace(/-/g, ""), purchase: purchase_amount, payment_method_id: parsed_result.payment_method_id, }; @@ -255,15 +255,15 @@ patch(PaymentScreen.prototype, "pos_mercury.PaymentScreen", { // FIXME POSREF timeout this.orm .call("pos_mercury.mercury_transaction", "do_payment", [transaction]) - .then(function (data) { + .then((data) => { // if not receiving a response from Vantiv, we should retry if (data === "timeout") { - self.retry_mercury_transaction( + this.retry_mercury_transaction( def, null, retry_nr, true, - self.credit_code_transaction, + this.credit_code_transaction, [parsed_result, def, retry_nr + 1] ); return; @@ -271,26 +271,26 @@ patch(PaymentScreen.prototype, "pos_mercury.PaymentScreen", { if (data === "not setup") { def.resolve({ - message: self.env._t("Please setup your Vantiv merchant account."), + message: this.env._t("Please setup your Vantiv merchant account."), }); return; } if (data === "internal error") { def.resolve({ - message: self.env._t("Odoo error while processing transaction."), + message: this.env._t("Odoo error while processing transaction."), }); return; } - var response = self.env.pos.decodeMercuryResponse(data); + var response = globalState.decodeMercuryResponse(data); response.payment_method_id = parsed_result.payment_method_id; if (response.status === "Approved") { // AP* indicates a duplicate request, so don't add anything for those if ( response.message === "AP*" && - self._does_credit_payment_line_exist( + this._does_credit_payment_line_exist( response.authorize, decodedMagtek["number"], response.card_type, @@ -303,13 +303,13 @@ patch(PaymentScreen.prototype, "pos_mercury.PaymentScreen", { }); } else { // If the payment is approved, add a payment line - var order = self.env.pos.get_order(); + var order = globalState.get_order(); if (swipe_pending_line) { order.select_paymentline(swipe_pending_line); } else { order.add_paymentline( - self.payment_methods_by_id[parsed_result.payment_method_id] + this.payment_methods_by_id[parsed_result.payment_method_id] ); } @@ -331,7 +331,7 @@ patch(PaymentScreen.prototype, "pos_mercury.PaymentScreen", { if (response.message === "PARTIAL AP") { def.resolve({ - message: self.env._t("Partially approved"), + message: this.env._t("Partially approved"), auto_close: false, }); } else { @@ -347,12 +347,12 @@ patch(PaymentScreen.prototype, "pos_mercury.PaymentScreen", { else { if (lookUpCodeTransaction["TimeoutError"][response.error]) { // recoverable error - self.retry_mercury_transaction( + this.retry_mercury_transaction( def, response, retry_nr, true, - self.credit_code_transaction, + this.credit_code_transaction, [parsed_result, def, retry_nr + 1] ); } else { @@ -364,13 +364,13 @@ patch(PaymentScreen.prototype, "pos_mercury.PaymentScreen", { } } }) - .catch(function () { - self.retry_mercury_transaction( + .catch(() => { + this.retry_mercury_transaction( def, null, retry_nr, false, - self.credit_code_transaction, + this.credit_code_transaction, [parsed_result, def, retry_nr + 1] ); }); @@ -379,7 +379,7 @@ patch(PaymentScreen.prototype, "pos_mercury.PaymentScreen", { return; }, credit_code_action(parsed_result) { - var online_payment_methods = this.env.pos.getOnlinePaymentMethods(); + var online_payment_methods = this.pos.globalState.getOnlinePaymentMethods(); if (online_payment_methods.length === 1) { parsed_result.payment_method_id = online_payment_methods[0].item; @@ -408,7 +408,7 @@ patch(PaymentScreen.prototype, "pos_mercury.PaymentScreen", { } }, remove_paymentline_by_ref(line) { - this.env.pos.get_order().remove_paymentline(line); + this.pos.globalState.get_order().remove_paymentline(line); this.numberBuffer.reset(); }, do_reversal(line, is_voidsale, old_deferred, retry_nr) { @@ -467,7 +467,7 @@ patch(PaymentScreen.prototype, "pos_mercury.PaymentScreen", { return; } - var response = self.env.pos.decodeMercuryResponse(data); + var response = self.pos.globalState.decodeMercuryResponse(data); if (!is_voidsale) { if (response.status != "Approved" || response.message != "REVERSED") { @@ -520,7 +520,7 @@ patch(PaymentScreen.prototype, "pos_mercury.PaymentScreen", { * @override */ addNewPaymentLine(paymentMethod) { - const order = this.env.pos.get_order(); + const order = this.pos.globalState.get_order(); const res = this._super(...arguments); if (res && paymentMethod.pos_mercury_config_id) { order.selected_paymentline.mercury_swipe_pending = true; diff --git a/addons/pos_restaurant/static/src/app/floor_screen/editable_table.js b/addons/pos_restaurant/static/src/app/floor_screen/editable_table.js index 0be5da3525b..fd3dded8c86 100644 --- a/addons/pos_restaurant/static/src/app/floor_screen/editable_table.js +++ b/addons/pos_restaurant/static/src/app/floor_screen/editable_table.js @@ -3,6 +3,7 @@ import { getLimits, useMovable, constrain } from "@point_of_sale/app/movable_hook"; import { onWillUnmount, useEffect, useRef, Component } from "@odoo/owl"; import { Table } from "./table"; +import { usePos } from "@point_of_sale/app/pos_hook"; const MIN_TABLE_SIZE = 30; // px @@ -16,7 +17,7 @@ export class EditableTable extends Component { }; setup() { - super.setup(); + this.pos = usePos(); useEffect(this._setElementStyle.bind(this)); this.root = useRef("root"); this.handles = { @@ -43,7 +44,7 @@ export class EditableTable extends Component { } onMoveStart() { - if (this.env.pos.floorPlanStyle == 'kanban') { + if (this.pos.globalState.floorPlanStyle == "kanban") { return; } this.startTable = { ...this.props.table }; @@ -59,7 +60,7 @@ export class EditableTable extends Component { } onMove({ dx, dy }) { - if (this.env.pos.floorPlanStyle == 'kanban') { + if (this.pos.globalState.floorPlanStyle == "kanban") { return; } const { minX, minY, maxX, maxY } = getLimits(this.root.el, this.props.limit.el); @@ -70,12 +71,12 @@ export class EditableTable extends Component { this.props.selectedTables[index].position_h = constrain(position_h + dx, minX, maxX); this.props.selectedTables[index].position_v = constrain(position_v + dy, minY, maxY); } - + this._setElementStyle(); } onResizeHandleMove([moveX, moveY], { dx, dy }) { - if (this.env.pos.floorPlanStyle == 'kanban') { + if (this.pos.globalState.floorPlanStyle == "kanban") { return; } // Working with min/max x and y makes constraints much easier to apply uniformly @@ -127,14 +128,18 @@ export class EditableTable extends Component { _setElementStyle() { const table = this.props.table; - if (this.env.pos.floorPlanStyle == 'kanban') { + if (this.pos.globalState.floorPlanStyle == "kanban") { const floor = table.floor; const index = floor.tables.indexOf(table); const minWidth = 100 + 20; const nbrHorizontal = Math.floor(window.innerWidth / minWidth); - const widthTable = (window.innerWidth - nbrHorizontal*10) / nbrHorizontal; - const position_h = widthTable * (index % nbrHorizontal) + 5 + (index % nbrHorizontal) * 10; - const position_v = widthTable * Math.floor(index / nbrHorizontal) + 5 + Math.floor(index / nbrHorizontal) * 10; + const widthTable = (window.innerWidth - nbrHorizontal * 10) / nbrHorizontal; + const position_h = + widthTable * (index % nbrHorizontal) + 5 + (index % nbrHorizontal) * 10; + const position_v = + widthTable * Math.floor(index / nbrHorizontal) + + 5 + + Math.floor(index / nbrHorizontal) * 10; Object.assign(this.root.el.style, { left: `${position_h}px`, @@ -145,7 +150,7 @@ export class EditableTable extends Component { "line-height": `${widthTable}px`, "border-radius": table.shape === "round" ? "1000px" : "3px", "font-size": widthTable >= 150 ? "32px" : "16px", - "opacity": "0.7", + opacity: "0.7", }); return; } diff --git a/addons/pos_restaurant/static/src/app/floor_screen/editable_table.xml b/addons/pos_restaurant/static/src/app/floor_screen/editable_table.xml index 6c38ba00c77..779b2ec4b3a 100644 --- a/addons/pos_restaurant/static/src/app/floor_screen/editable_table.xml +++ b/addons/pos_restaurant/static/src/app/floor_screen/editable_table.xml @@ -9,7 +9,7 @@ - +
    diff --git a/addons/pos_restaurant/static/src/app/floor_screen/floor_screen.js b/addons/pos_restaurant/static/src/app/floor_screen/floor_screen.js index 51a692a8a34..d65bf59e261 100644 --- a/addons/pos_restaurant/static/src/app/floor_screen/floor_screen.js +++ b/addons/pos_restaurant/static/src/app/floor_screen/floor_screen.js @@ -28,7 +28,7 @@ export class FloorScreen extends Component { this.pos = usePos(); this.popup = useService("popup"); this.orm = useService("orm"); - const floor = this.props.floor ? this.props.floor : this.env.pos.floors[0]; + const floor = this.props.floor || this.pos.globalState.floors[0]; this.state = useState({ selectedFloorId: floor ? floor.id : null, selectedTableIds: [], @@ -36,11 +36,11 @@ export class FloorScreen extends Component { floorMapScrollTop: 0, isColorPicker: false, }); - if (!this.env.pos.floorPlanStyle) { + if (!this.pos.globalState.floorPlanStyle) { if (this.env.isMobile) { - this.env.pos.floorPlanStyle = "kanban"; + this.pos.globalState.floorPlanStyle = "kanban"; } else { - this.env.pos.floorPlanStyle = "default"; + this.pos.globalState.floorPlanStyle = "default"; } } this.floorMapRef = useRef("floor-map-ref"); @@ -53,7 +53,7 @@ export class FloorScreen extends Component { onPatched() { this.floorMapRef.el.style.background = this.state.floorBackground; this.addFloorRef.el.style.background = this.state.floorBackground; - if (!this.env.pos.isEditMode && this.env.pos.floors.length > 0) { + if (!this.pos.globalState.isEditMode && this.pos.globalState.floors.length > 0) { this.addFloorRef.el.style.display = "none"; } else { this.addFloorRef.el.style.display = "initial"; @@ -64,7 +64,7 @@ export class FloorScreen extends Component { this.pos.openCashControl(); this.floorMapRef.el.style.background = this.state.floorBackground; this.addFloorRef.el.style.background = this.state.floorBackground; - if (!this.env.pos.isEditMode && this.env.pos.floors.length > 0) { + if (!this.pos.globalState.isEditMode && this.pos.globalState.floors.length > 0) { this.addFloorRef.el.style.display = "none"; } else { this.addFloorRef.el.style.display = "initial"; @@ -249,20 +249,21 @@ export class FloorScreen extends Component { delete tableCopy.floor; const tableId = await this.orm.call("restaurant.table", "create_from_ui", [tableCopy]); table.id = tableId; - this.env.pos.tables_by_id[tableId] = table; + this.pos.globalState.tables_by_id[tableId] = table; } async _renameFloor(floorId, newName) { await this.orm.call("restaurant.floor", "rename_floor", [floorId, newName]); } async _tableLongpolling() { - if (this.env.pos.isEditMode) { + const { globalState } = this.pos; + if (globalState.isEditMode) { return; } const result = await this.orm.call("pos.config", "get_tables_order_count", [ - this.env.pos.config.id, + globalState.config.id, ]); for (const table of result) { - if (!(table.id in this.env.pos.tables_by_id)) { + if (!(table.id in globalState.tables_by_id)) { //We enter this condition if, after loading our PoS, a table is deleted on a PoS and not on another. //This will lead in receiving information on orders from a table that we do not have. //If we do not have a table in the PoS but still receive information about it, we reload the tables @@ -270,13 +271,13 @@ export class FloorScreen extends Component { const result = await this.orm.call("pos.session", "get_pos_ui_restaurant_floor", [ [odoo.pos_session_id], ]); - if (this.env.pos.config.module_pos_restaurant) { - this.env.pos.floors = result; - this.env.pos.loadRestaurantFloor(); + if (globalState.config.module_pos_restaurant) { + globalState.floors = result; + globalState.loadRestaurantFloor(); } } - const table_obj = this.env.pos.tables_by_id[table.id]; - const unsynced_orders = this.env.pos.getTableOrders(table_obj.id).filter( + const table_obj = globalState.tables_by_id[table.id]; + const unsynced_orders = globalState.getTableOrders(table_obj.id).filter( (o) => o.server_id === undefined && (o.orderlines.length !== 0 || o.paymentlines.length !== 0) && @@ -288,7 +289,7 @@ export class FloorScreen extends Component { } get activeFloor() { return this.state.selectedFloorId - ? this.env.pos.floors_by_id[this.state.selectedFloorId] + ? this.pos.globalState.floors_by_id[this.state.selectedFloorId] : null; } get activeTables() { @@ -300,12 +301,12 @@ export class FloorScreen extends Component { get selectedTables() { const tables = []; this.state.selectedTableIds.forEach((id) => { - tables.push(this.env.pos.tables_by_id[id]); + tables.push(this.pos.globalState.tables_by_id[id]); }); return tables; } get nbrFloors() { - return this.env.pos.floors.length; + return this.pos.globalState.floors.length; } movePinch(hypot) { const delta = hypot / this.scalehypot; @@ -333,8 +334,8 @@ export class FloorScreen extends Component { this.state.selectedTableIds = []; } toggleEditMode() { - this.env.pos.toggleEditMode(); - if (!this.env.pos.isEditMode && this.env.pos.floors.length > 0) { + this.pos.globalState.toggleEditMode(); + if (!this.pos.globalState.isEditMode && this.pos.globalState.floors.length > 0) { this.addFloorRef.el.style.display = "none"; } else { this.addFloorRef.el.style.display = "initial"; @@ -342,7 +343,8 @@ export class FloorScreen extends Component { this.state.selectedTableIds = []; } async onSelectTable(table, ev) { - if (this.env.pos.isEditMode) { + const { globalState } = this.pos; + if (globalState.isEditMode) { if (ev.ctrlKey || ev.metaKey) { this.state.selectedTableIds.push(table.id); } else { @@ -350,11 +352,11 @@ export class FloorScreen extends Component { this.state.selectedTableIds.push(table.id); } } else { - if (this.env.pos.orderToTransfer) { - await this.env.pos.transferTable(table); + if (globalState.orderToTransfer) { + await globalState.transferTable(table); } else { try { - await this.env.pos.setTable(table); + await globalState.setTable(table); } catch (e) { if (!(e.message instanceof ConnectionLostError)) { throw e; @@ -363,7 +365,7 @@ export class FloorScreen extends Component { Promise.reject(e); } } - const order = this.env.pos.get_order(); + const order = globalState.get_order(); this.pos.showScreen(order.get_screen_data().name); } } @@ -377,15 +379,16 @@ export class FloorScreen extends Component { if (!confirmed) { return; } + const { globalState } = this.pos; const floor = await this.orm.call("restaurant.floor", "create_from_ui", [ newName, "#ACADAD", - this.env.pos.config.id, + globalState.config.id, ]); - this.env.pos.floors_by_id[floor.id] = floor; - this.env.pos.floors.push(floor); + globalState.floors_by_id[floor.id] = floor; + globalState.floors.push(floor); this.selectFloor(floor); - this.env.pos.isEditMode = true; + globalState.isEditMode = true; } async createTable() { const newTable = await this._createTableHelper(); @@ -396,16 +399,17 @@ export class FloorScreen extends Component { } async duplicateTableOrFloor() { if (this.selectedTables.length == 0) { + const { globalState } = this.pos; const floor = this.activeFloor; const tables = this.activeFloor.tables; const newFloorName = floor.name + " (copy)"; const newFloor = await this.orm.call("restaurant.floor", "create_from_ui", [ newFloorName, floor.background_color, - this.env.pos.config.id, + globalState.config.id, ]); - this.env.pos.floors_by_id[newFloor.id] = newFloor; - this.env.pos.floors.push(newFloor); + globalState.floors_by_id[newFloor.id] = newFloor; + globalState.floors.push(newFloor); this.selectFloor(newFloor); for (const table of tables) { await this._createTableHelper(table, true); @@ -491,7 +495,6 @@ export class FloorScreen extends Component { selectedTable.shape = form; await this._save(selectedTable); }); - this.render(); } async setTableColor(color) { const selectedTables = this.selectedTables; @@ -499,7 +502,6 @@ export class FloorScreen extends Component { selectedTable.color = color; await this._save(selectedTable); }); - this.render(); this.state.isColorPicker = false; } async setFloorColor(color) { @@ -514,6 +516,7 @@ export class FloorScreen extends Component { this.state.isColorPicker = !this.state.isColorPicker; } async deleteFloorOrTable() { + const { globalState } = this.pos; if (this.selectedTables.length == 0) { const { confirmed } = await this.popup.add(ConfirmPopup, { title: `Removing floor ${this.activeFloor.name}`, @@ -528,28 +531,28 @@ export class FloorScreen extends Component { const originalSelectedFloorId = this.activeFloor.id; await this.orm.call("restaurant.floor", "deactivate_floor", [ originalSelectedFloorId, - this.env.pos.pos_session.id, + globalState.pos_session.id, ]); - const floor = this.env.pos.floors_by_id[originalSelectedFloorId]; - const orderList = [...this.env.pos.get_order_list()]; + const floor = globalState.floors_by_id[originalSelectedFloorId]; + const orderList = [...globalState.get_order_list()]; for (const order of orderList) { if (floor.table_ids.includes(order.tableId)) { - this.env.pos.removeOrder(order, false); + globalState.removeOrder(order, false); } } floor.table_ids.forEach((tableId) => { - delete this.env.pos.tables_by_id[tableId]; + delete globalState.tables_by_id[tableId]; }); - delete this.env.pos.floors_by_id[originalSelectedFloorId]; - this.env.pos.floors = this.env.pos.floors.filter( + delete globalState.floors_by_id[originalSelectedFloorId]; + globalState.floors = globalState.floors.filter( (floor) => floor.id != originalSelectedFloorId ); - this.env.pos.TICKET_SCREEN_STATE.syncedOrders.cache = {}; - if (this.env.pos.floors.length > 0) { - this.selectFloor(this.env.pos.floors[0]); + globalState.TICKET_SCREEN_STATE.syncedOrders.cache = {}; + if (globalState.floors.length > 0) { + this.selectFloor(globalState.floors[0]); } else { - this.env.pos.isEditMode = false; - this.env.pos.floorPlanStyle = "default"; + globalState.isEditMode = false; + globalState.floorPlanStyle = "default"; this.state.floorBackground = null; } return; @@ -568,17 +571,17 @@ export class FloorScreen extends Component { ]); if (!response) { //remove order not send to server - for (const order of this.env.pos.get_order_list()) { + for (const order of globalState.get_order_list()) { if (order.tableId == id) { - this.env.pos.removeOrder(order, false); + globalState.removeOrder(order, false); } } - this.env.pos.tables_by_id[id].active = false; + globalState.tables_by_id[id].active = false; await this.orm.call("restaurant.table", "create_from_ui", [ { active: false, id: id }, ]); this.activeFloor.tables = this.activeTables.filter((table) => table.id !== id); - delete this.env.pos.tables_by_id[id]; + delete globalState.tables_by_id[id]; } else { await this.popup.add(ErrorPopup, { title: this.env._t("Delete Error"), @@ -600,7 +603,7 @@ export class FloorScreen extends Component { if (equalsCheck(this.state.selectedTableIds, originalSelectedTableIds)) { this.state.selectedTableIds = []; } - this.env.pos.TICKET_SCREEN_STATE.syncedOrders.cache = {}; + globalState.TICKET_SCREEN_STATE.syncedOrders.cache = {}; } } diff --git a/addons/pos_restaurant/static/src/app/floor_screen/floor_screen.xml b/addons/pos_restaurant/static/src/app/floor_screen/floor_screen.xml index 5823efc6c2e..4a9130b477a 100644 --- a/addons/pos_restaurant/static/src/app/floor_screen/floor_screen.xml +++ b/addons/pos_restaurant/static/src/app/floor_screen/floor_screen.xml @@ -3,7 +3,7 @@
    -
    - + @@ -29,7 +29,7 @@ class="floor-map" t-ref="floor-map-ref" > - +
    No tables available,
    ADD your first table
    diff --git a/addons/pos_restaurant/static/src/app/floor_screen/table.js b/addons/pos_restaurant/static/src/app/floor_screen/table.js index 9d3f0298ff2..4ea3d3a9644 100644 --- a/addons/pos_restaurant/static/src/app/floor_screen/table.js +++ b/addons/pos_restaurant/static/src/app/floor_screen/table.js @@ -1,6 +1,7 @@ /** @odoo-module */ import { Component } from "@odoo/owl"; +import { usePos } from "@point_of_sale/app/pos_hook"; export class Table extends Component { static template = "pos_restaurant.Table"; @@ -22,17 +23,24 @@ export class Table extends Component { }, }; + setup() { + this.pos = usePos(); + } get style() { const table = this.props.table; - if (this.env.pos.floorPlanStyle == "kanban") { + if (this.pos.globalState.floorPlanStyle == "kanban") { const floor = table.floor; const index = floor.tables.indexOf(table); const minWidth = 100 + 20; const nbrHorizontal = Math.floor(window.innerWidth / minWidth); - const widthTable = (window.innerWidth - nbrHorizontal*10) / nbrHorizontal; - const position_h = widthTable * (index % nbrHorizontal) + 5 + (index % nbrHorizontal) * 10; - const position_v = widthTable * Math.floor(index / nbrHorizontal) + 5 + Math.floor(index / nbrHorizontal) * 10; + const widthTable = (window.innerWidth - nbrHorizontal * 10) / nbrHorizontal; + const position_h = + widthTable * (index % nbrHorizontal) + 5 + (index % nbrHorizontal) * 10; + const position_v = + widthTable * Math.floor(index / nbrHorizontal) + + 5 + + Math.floor(index / nbrHorizontal) * 10; return ` width: ${widthTable}px; height: ${widthTable}px; @@ -57,20 +65,20 @@ export class Table extends Component { } } get fill() { - const customerCount = this.env.pos.getCustomerCount(this.props.table.id); + const customerCount = this.pos.globalState.getCustomerCount(this.props.table.id); return Math.min(1, Math.max(0, customerCount / this.props.table.seats)); } get orderCount() { const table = this.props.table; return table.order_count !== undefined ? table.order_count - : this.env.pos + : this.pos.globalState .getTableOrders(table.id) .filter((o) => o.orderlines.length !== 0 || o.paymentlines.length !== 0).length; } get orderCountClass() { const countClass = { "order-count": true }; - if (this.env.pos.orderPreparationCategories.size) { + if (this.pos.globalState.orderPreparationCategories.size) { const notifications = this._getNotifications(); countClass["notify-printing"] = notifications.printing; countClass["notify-skipped"] = notifications.skipped; @@ -78,10 +86,12 @@ export class Table extends Component { return countClass; } get customerCountDisplay() { - return `${this.env.pos.getCustomerCount(this.props.table.id)}/${this.props.table.seats}`; + return `${this.pos.globalState.getCustomerCount(this.props.table.id)}/${ + this.props.table.seats + }`; } _getNotifications() { - const orders = this.env.pos.getTableOrders(this.props.table.id); + const orders = this.pos.globalState.getTableOrders(this.props.table.id); let hasChangesCount = 0; let hasSkippedCount = 0; diff --git a/addons/pos_restaurant/static/src/app/navbar/BackToFloorButton.js b/addons/pos_restaurant/static/src/app/navbar/BackToFloorButton.js index 85d93ae11ff..27e0d4f97a1 100644 --- a/addons/pos_restaurant/static/src/app/navbar/BackToFloorButton.js +++ b/addons/pos_restaurant/static/src/app/navbar/BackToFloorButton.js @@ -11,7 +11,7 @@ export class BackToFloorButton extends Component { this.pos = usePos(); } get table() { - return this.env.pos.table; + return this.pos.globalState.table; } get floor() { return this.table ? this.table.floor : null; diff --git a/addons/pos_restaurant/static/src/app/navbar/navbar.js b/addons/pos_restaurant/static/src/app/navbar/navbar.js index 80d3810247f..08df6c27b74 100644 --- a/addons/pos_restaurant/static/src/app/navbar/navbar.js +++ b/addons/pos_restaurant/static/src/app/navbar/navbar.js @@ -11,22 +11,23 @@ patch(Navbar.prototype, "pos_restaurant.Navbar", { * is floor screen, then the order count should be based on all the orders. */ get orderCount() { - if (!this.env.pos || !this.env.pos.config) { - return 0; - } - if (this.env.pos.config.module_pos_restaurant && this.env.pos.table) { - return this.env.pos.getTableOrders(this.env.pos.table.id).length; + const { globalState } = this.pos; + if (globalState.config.module_pos_restaurant && globalState.table) { + return globalState.getTableOrders(globalState.table.id).length; } return this._super(...arguments); }, _shouldLoadOrders() { - return this._super() || (this.env.pos.config.module_pos_restaurant && !this.env.pos.table); + return ( + this._super() || + (this.pos.globalState.config.module_pos_restaurant && !this.pos.globalState.table) + ); }, onSwitchButtonClick() { - this.env.pos.floorPlanStyle = - this.env.pos.floorPlanStyle == "kanban" ? "default" : "kanban"; + this.pos.globalState.floorPlanStyle = + this.pos.globalState.floorPlanStyle == "kanban" ? "default" : "kanban"; }, toggleEditMode() { - this.env.pos.toggleEditMode(); + this.pos.globalState.toggleEditMode(); }, }); diff --git a/addons/pos_restaurant/static/src/js/Screens/PaymentScreen.js b/addons/pos_restaurant/static/src/js/Screens/PaymentScreen.js index 91388055ab6..abcf22510af 100644 --- a/addons/pos_restaurant/static/src/js/Screens/PaymentScreen.js +++ b/addons/pos_restaurant/static/src/js/Screens/PaymentScreen.js @@ -13,7 +13,7 @@ patch(PaymentScreen.prototype, "pos_restaurant.PaymentScreen", { }, get nextScreen() { const order = this.currentOrder; - if (!this.env.pos.config.set_tip_after_payment || order.is_tipped) { + if (!this.pos.globalState.config.set_tip_after_payment || order.is_tipped) { return this._super(...arguments); } // Take the first payment method as the main payment. diff --git a/addons/pos_restaurant/static/src/js/Screens/ProductScreen/ControlButtons/OrderlineNoteButton.js b/addons/pos_restaurant/static/src/js/Screens/ProductScreen/ControlButtons/OrderlineNoteButton.js index 0409f576dfe..64f9bb7bcf3 100644 --- a/addons/pos_restaurant/static/src/js/Screens/ProductScreen/ControlButtons/OrderlineNoteButton.js +++ b/addons/pos_restaurant/static/src/js/Screens/ProductScreen/ControlButtons/OrderlineNoteButton.js @@ -4,16 +4,17 @@ import { ProductScreen } from "@point_of_sale/js/Screens/ProductScreen/ProductSc import { useService } from "@web/core/utils/hooks"; import { TextAreaPopup } from "@point_of_sale/js/Popups/TextAreaPopup"; import { Component } from "@odoo/owl"; +import { usePos } from "@point_of_sale/app/pos_hook"; export class OrderlineNoteButton extends Component { static template = "OrderlineNoteButton"; setup() { - super.setup(); + this.pos = usePos(); this.popup = useService("popup"); } get selectedOrderline() { - return this.env.pos.get_order().get_selected_orderline(); + return this.pos.globalState.get_order().get_selected_orderline(); } async click() { if (!this.selectedOrderline) { @@ -34,6 +35,6 @@ export class OrderlineNoteButton extends Component { ProductScreen.addControlButton({ component: OrderlineNoteButton, condition: function () { - return this.env.pos.config.iface_orderline_notes; + return this.pos.globalState.config.iface_orderline_notes; }, }); diff --git a/addons/pos_restaurant/static/src/js/Screens/ProductScreen/ControlButtons/PrintBillButton.js b/addons/pos_restaurant/static/src/js/Screens/ProductScreen/ControlButtons/PrintBillButton.js index 1c84e45b4f3..3ab74a31efe 100644 --- a/addons/pos_restaurant/static/src/js/Screens/ProductScreen/ControlButtons/PrintBillButton.js +++ b/addons/pos_restaurant/static/src/js/Screens/ProductScreen/ControlButtons/PrintBillButton.js @@ -12,7 +12,7 @@ export class PrintBillButton extends Component { this.pos = usePos(); } _isDisabled() { - const order = this.env.pos.get_order(); + const order = this.pos.globalState.get_order(); return order.get_orderlines().length === 0; } click() { @@ -23,6 +23,6 @@ export class PrintBillButton extends Component { ProductScreen.addControlButton({ component: PrintBillButton, condition: function () { - return this.env.pos.config.iface_printbill; + return this.pos.globalState.config.iface_printbill; }, }); diff --git a/addons/pos_restaurant/static/src/js/Screens/ProductScreen/ControlButtons/SplitBillButton.js b/addons/pos_restaurant/static/src/js/Screens/ProductScreen/ControlButtons/SplitBillButton.js index 177b85f34f6..90bdb93b9f4 100644 --- a/addons/pos_restaurant/static/src/js/Screens/ProductScreen/ControlButtons/SplitBillButton.js +++ b/addons/pos_restaurant/static/src/js/Screens/ProductScreen/ControlButtons/SplitBillButton.js @@ -8,11 +8,10 @@ export class SplitBillButton extends Component { static template = "SplitBillButton"; setup() { - super.setup(); this.pos = usePos(); } _isDisabled() { - const order = this.env.pos.get_order(); + const order = this.pos.globalState.get_order(); return ( order .get_orderlines() @@ -27,6 +26,6 @@ export class SplitBillButton extends Component { ProductScreen.addControlButton({ component: SplitBillButton, condition: function () { - return this.env.pos.config.iface_splitbill; + return this.pos.globalState.config.iface_splitbill; }, }); diff --git a/addons/pos_restaurant/static/src/js/Screens/ProductScreen/ControlButtons/TableGuestsButton.js b/addons/pos_restaurant/static/src/js/Screens/ProductScreen/ControlButtons/TableGuestsButton.js index e93ef0de357..cf4279cc258 100644 --- a/addons/pos_restaurant/static/src/js/Screens/ProductScreen/ControlButtons/TableGuestsButton.js +++ b/addons/pos_restaurant/static/src/js/Screens/ProductScreen/ControlButtons/TableGuestsButton.js @@ -6,16 +6,17 @@ import { NumberPopup } from "@point_of_sale/js/Popups/NumberPopup"; import { ErrorPopup } from "@point_of_sale/js/Popups/ErrorPopup"; import { Component } from "@odoo/owl"; import { sprintf } from "@web/core/utils/strings"; +import { usePos } from "@point_of_sale/app/pos_hook"; export class TableGuestsButton extends Component { static template = "TableGuestsButton"; setup() { - super.setup(); + this.pos = usePos(); this.popup = useService("popup"); } get currentOrder() { - return this.env.pos.get_order(); + return this.pos.globalState.get_order(); } get nGuests() { return this.currentOrder ? this.currentOrder.getCustomerCount() : 0; @@ -42,7 +43,7 @@ export class TableGuestsButton extends Component { }); return; } - this.env.pos.get_order().setCustomerCount(guestCount); + this.currentOrder.setCustomerCount(guestCount); } } } @@ -50,6 +51,6 @@ export class TableGuestsButton extends Component { ProductScreen.addControlButton({ component: TableGuestsButton, condition: function () { - return this.env.pos.config.module_pos_restaurant; + return this.pos.globalState.config.module_pos_restaurant; }, }); diff --git a/addons/pos_restaurant/static/src/js/Screens/ProductScreen/ControlButtons/TransferOrderButton.js b/addons/pos_restaurant/static/src/js/Screens/ProductScreen/ControlButtons/TransferOrderButton.js index 204837a4b23..960896763a7 100644 --- a/addons/pos_restaurant/static/src/js/Screens/ProductScreen/ControlButtons/TransferOrderButton.js +++ b/addons/pos_restaurant/static/src/js/Screens/ProductScreen/ControlButtons/TransferOrderButton.js @@ -8,11 +8,10 @@ export class TransferOrderButton extends Component { static template = "TransferOrderButton"; setup() { - super.setup(); this.pos = usePos(); } async click() { - this.env.pos.setCurrentOrderToTransfer(); + this.pos.globalState.setCurrentOrderToTransfer(); this.pos.showScreen("FloorScreen"); } } @@ -20,6 +19,6 @@ export class TransferOrderButton extends Component { ProductScreen.addControlButton({ component: TransferOrderButton, condition: function () { - return this.env.pos.config.module_pos_restaurant; + return this.pos.globalState.config.module_pos_restaurant; }, }); diff --git a/addons/pos_restaurant/static/src/js/Screens/ReceiptScreen/ReceiptScreen.js b/addons/pos_restaurant/static/src/js/Screens/ReceiptScreen/ReceiptScreen.js index 2b0164e2831..7399f461fc6 100644 --- a/addons/pos_restaurant/static/src/js/Screens/ReceiptScreen/ReceiptScreen.js +++ b/addons/pos_restaurant/static/src/js/Screens/ReceiptScreen/ReceiptScreen.js @@ -1,7 +1,6 @@ /** @odoo-module */ import { ReceiptScreen } from "@point_of_sale/js/Screens/ReceiptScreen/ReceiptScreen"; -import { usePos } from "@point_of_sale/app/pos_hook"; import { patch } from "@web/core/utils/patch"; import { onWillUnmount } from "@odoo/owl"; import { FloorScreen } from "@pos_restaurant/app/floor_screen/floor_screen"; @@ -13,30 +12,29 @@ patch(ReceiptScreen, "pos_restaurant.ReceiptScreen", { patch(ReceiptScreen.prototype, "pos_restaurant.ReceiptScreen", { setup() { this._super(...arguments); - this.pos = usePos(); onWillUnmount(() => { // When leaving the receipt screen to the floor screen the order is paid and can be removed if (this.pos.mainScreen.component === FloorScreen) { - this.env.pos.removeOrder(this.currentOrder); + this.pos.globalState.removeOrder(this.currentOrder); } }); }, //@override _addNewOrder() { - if (!this.env.pos.config.module_pos_restaurant) { + if (!this.pos.globalState.config.module_pos_restaurant) { this._super(...arguments); } }, isResumeVisible() { - if (this.env.pos.config.module_pos_restaurant && this.env.pos.table) { - return this.env.pos.getTableOrders(this.env.pos.table.id).length > 1; + if (this.pos.globalState.config.module_pos_restaurant && this.pos.globalState.table) { + return this.pos.globalState.getTableOrders(this.pos.globalState.table.id).length > 1; } return this._super(...arguments); }, //@override get nextScreen() { - if (this.env.pos.config.module_pos_restaurant) { - const table = this.env.pos.table; + if (this.pos.globalState.config.module_pos_restaurant) { + const table = this.pos.globalState.table; return { name: "FloorScreen", props: { floor: table ? table.floor : null } }; } else { return this._super(...arguments); diff --git a/addons/pos_restaurant/static/src/js/Screens/SplitBillScreen/SplitBillScreen.js b/addons/pos_restaurant/static/src/js/Screens/SplitBillScreen/SplitBillScreen.js index 41997eb4592..cba35736b4c 100644 --- a/addons/pos_restaurant/static/src/js/Screens/SplitBillScreen/SplitBillScreen.js +++ b/addons/pos_restaurant/static/src/js/Screens/SplitBillScreen/SplitBillScreen.js @@ -5,35 +5,28 @@ import { Order } from "@point_of_sale/js/models"; import { SplitOrderline } from "./SplitOrderline"; import { registry } from "@web/core/registry"; import { usePos } from "@point_of_sale/app/pos_hook"; -import { Component, useState, onMounted } from "@odoo/owl"; +import { Component, useState } from "@odoo/owl"; export class SplitBillScreen extends Component { static template = "SplitBillScreen"; static components = { SplitOrderline }; setup() { - super.setup(); this.pos = usePos(); - this.splitlines = useState(this._initSplitLines(this.env.pos.get_order())); + this.splitlines = useState(this._initSplitLines(this.pos.globalState.get_order())); this.newOrderLines = {}; this.newOrder = undefined; this._isFinal = false; - onMounted(() => { - // Should create the new order outside of the constructor because - // sequence_number of pos_session is modified. which will trigger - // rerendering which will rerender this screen and will be infinite loop. - this.newOrder = new Order( - {}, - { - pos: this.env.pos, - temporary: true, - } - ); - this.render(); - }); + this.newOrder = new Order( + {}, + { + pos: this.pos.globalState, + temporary: true, + } + ); } get currentOrder() { - return this.env.pos.get_order(); + return this.pos.globalState.get_order(); } get orderlines() { return this.currentOrder.get_orderlines(); @@ -59,13 +52,14 @@ export class SplitBillScreen extends Component { this.newOrder.set_screen_data({ name: "PaymentScreen" }); + const { globalState } = this.pos; // for the kitchen printer we assume that everything // has already been sent to the kitchen before splitting // the bill. So we save all changes both for the old // order and for the new one. This is not entirely correct // but avoids flooding the kitchen with unnecessary orders. // Not sure what to do in this case. - if (this.env.pos.orderPreparationCategories.size) { + if (globalState.orderPreparationCategories.size) { this.currentOrder.updateLastOrderChange(); this.newOrder.updateLastOrderChange(); } @@ -75,9 +69,9 @@ export class SplitBillScreen extends Component { this.currentOrder.setCustomerCount(newCustomerCount || 1); this.currentOrder.set_screen_data({ name: "ProductScreen" }); - const reactiveNewOrder = this.env.pos.makeOrderReactive(this.newOrder); - this.env.pos.orders.add(reactiveNewOrder); - this.env.pos.selectedOrder = reactiveNewOrder; + const reactiveNewOrder = globalState.makeOrderReactive(this.newOrder); + globalState.orders.add(reactiveNewOrder); + globalState.selectedOrder = reactiveNewOrder; } this.pos.showScreen("PaymentScreen"); } @@ -97,7 +91,7 @@ export class SplitBillScreen extends Component { let totalQuantity = 0; - this.env.pos + this.pos.globalState .get_order() .get_orderlines() .forEach(function (orderLine) { @@ -143,7 +137,7 @@ export class SplitBillScreen extends Component { } } _isFullPayOrder() { - const order = this.env.pos.get_order(); + const order = this.pos.globalState.get_order(); let full = true; const splitlines = this.splitlines; const groupedLines = _.groupBy(order.get_orderlines(), (line) => line.get_product().id); @@ -167,7 +161,7 @@ export class SplitBillScreen extends Component { return full; } _setQuantityOnCurrentOrder() { - const order = this.env.pos.get_order(); + const order = this.pos.globalState.get_order(); for (var id in this.splitlines) { var split = this.splitlines[id]; var line = this.currentOrder.get_orderline(parseInt(id)); diff --git a/addons/pos_restaurant/static/src/js/Screens/TicketScreen.js b/addons/pos_restaurant/static/src/js/Screens/TicketScreen.js index 324921cbf33..f8c3d2a3ce1 100644 --- a/addons/pos_restaurant/static/src/js/Screens/TicketScreen.js +++ b/addons/pos_restaurant/static/src/js/Screens/TicketScreen.js @@ -9,7 +9,7 @@ import { Component, useState } from "@odoo/owl"; patch(TicketScreen.prototype, "pos_restaurant.TicketScreen", { _getScreenToStatusMap() { return Object.assign(this._super(...arguments), { - PaymentScreen: this.env.pos.config.set_tip_after_payment + PaymentScreen: this.pos.globalState.config.set_tip_after_payment ? "OPEN" : this._super(...arguments).PaymentScreen, TipScreen: "TIPPING", @@ -22,7 +22,7 @@ patch(TicketScreen.prototype, "pos_restaurant.TicketScreen", { }, //@override _getSearchFields() { - if (!this.env.pos.config.module_pos_restaurant) { + if (!this.pos.globalState.config.module_pos_restaurant) { return this._super(...arguments); } return Object.assign({}, this._super(...arguments), { @@ -34,23 +34,23 @@ patch(TicketScreen.prototype, "pos_restaurant.TicketScreen", { }); }, async _setOrder(order) { - if (!this.env.pos.config.module_pos_restaurant || this.env.pos.table) { - this._super(order); - } else { - // we came from the FloorScreen - const orderTable = order.getTable(); - await this.env.pos.setTable(orderTable, order.uid); - this.close(); + const { globalState } = this.pos; + if (!globalState.config.module_pos_restaurant || globalState.table) { + return this._super(...arguments); } + // we came from the FloorScreen + const orderTable = order.getTable(); + await globalState.setTable(orderTable, order.uid); + this.close(); }, get allowNewOrders() { - return this.env.pos.config.module_pos_restaurant - ? Boolean(this.env.pos.table) + return this.pos.globalState.config.module_pos_restaurant + ? Boolean(this.pos.globalState.table) : this._super(...arguments); }, _getOrderList() { - if (this.env.pos.table) { - return this.env.pos.getTableOrders(this.env.pos.table.id); + if (this.pos.globalState.table) { + return this.pos.globalState.getTableOrders(this.pos.globalState.table.id); } return this._super(...arguments); }, @@ -58,7 +58,7 @@ patch(TicketScreen.prototype, "pos_restaurant.TicketScreen", { // set tip in each order for (const order of this.getFilteredOrderList()) { const tipAmount = parseFloat(order.uiState.TipScreen.inputTipAmount || "0"); - const serverId = this.env.pos.validated_orders_name_server_id_map[order.name]; + const serverId = this.pos.globalState.validated_orders_name_server_id_map[order.name]; if (!serverId) { console.warn( `${order.name} is not yet sync. Sync it to server before setting a tip.` @@ -73,27 +73,29 @@ patch(TicketScreen.prototype, "pos_restaurant.TicketScreen", { }, //@override _selectNextOrder(currentOrder) { - if (this.env.pos.config.module_pos_restaurant && this.env.pos.table) { + if (this.pos.globalState.config.module_pos_restaurant && this.pos.globalState.table) { return this._super(...arguments); } }, //@override async onDeleteOrder(order) { const _super = this._super; - if (this.env.pos.config.module_pos_restaurant) { - this.env.pos.setOrderToRemove(order); - if (!this.env.pos.table) { - await this.env.pos._removeOrdersFromServer(); + const { globalState } = this.pos; + if (globalState.config.module_pos_restaurant) { + globalState.setOrderToRemove(order); + if (!globalState.table) { + await globalState._removeOrdersFromServer(); } } await _super(...arguments); }, async setTip(order, serverId, amount) { + const { globalState } = this.pos; try { const paymentline = order.get_paymentlines()[0]; if (paymentline.payment_method.payment_terminal) { paymentline.amount += amount; - this.env.pos.set_order(order, { silent: true }); + globalState.set_order(order, { silent: true }); await paymentline.payment_method.payment_terminal.send_payment_adjust( paymentline.cid ); @@ -108,10 +110,10 @@ patch(TicketScreen.prototype, "pos_restaurant.TicketScreen", { const tip_line = order.selected_orderline; await this.orm.call("pos.order", "set_tip", [serverId, tip_line.export_as_JSON()]); } - if (order === this.env.pos.get_order()) { + if (order === globalState.get_order()) { this._selectNextOrder(order); } - this.env.pos.removeOrder(order); + globalState.removeOrder(order); return true; } catch { const { confirmed } = await this.popup.add(ConfirmPopup, { @@ -126,7 +128,7 @@ patch(TicketScreen.prototype, "pos_restaurant.TicketScreen", { }, _getOrderStates() { const result = this._super(...arguments); - if (this.env.pos.config.set_tip_after_payment) { + if (this.pos.globalState.config.set_tip_after_payment) { result.delete("PAYMENT"); result.set("OPEN", { text: this.env._t("Open"), indented: true }); result.set("TIPPING", { text: this.env._t("Tipping"), indented: true }); @@ -135,15 +137,15 @@ patch(TicketScreen.prototype, "pos_restaurant.TicketScreen", { }, async onDoRefund() { const order = this.getSelectedSyncedOrder(); - if (this.env.pos.config.module_pos_restaurant && order) { - this.env.pos.setTable( - order.table ? order.table : Object.values(this.env.pos.tables_by_id)[0] + if (this.pos.globalState.config.module_pos_restaurant && order) { + this.pos.globalState.setTable( + order.table ? order.table : Object.values(this.pos.globalState.tables_by_id)[0] ); } this._super(...arguments); }, isDefaultOrderEmpty(order) { - if (this.env.pos.config.module_pos_restaurant) { + if (this.pos.globalState.config.module_pos_restaurant) { return false; } return this._super(...arguments); diff --git a/addons/pos_restaurant/static/src/js/Screens/TipScreen.js b/addons/pos_restaurant/static/src/js/Screens/TipScreen.js index b6316d68194..c07d83d11f3 100644 --- a/addons/pos_restaurant/static/src/js/Screens/TipScreen.js +++ b/addons/pos_restaurant/static/src/js/Screens/TipScreen.js @@ -37,7 +37,7 @@ export class TipScreen extends Component { return this._totalAmount; } get currentOrder() { - return this.env.pos.get_order(); + return this.pos.globalState.get_order(); } get percentageTips() { return [ @@ -48,8 +48,8 @@ export class TipScreen extends Component { } async validateTip() { const amount = parseFloat(this.state.inputTipAmount) || 0; - const order = this.env.pos.get_order(); - const serverId = this.env.pos.validated_orders_name_server_id_map[order.name]; + const order = this.pos.globalState.get_order(); + const serverId = this.pos.globalState.validated_orders_name_server_id_map[order.name]; if (!serverId) { this.popup.add(ErrorPopup, { @@ -84,7 +84,7 @@ export class TipScreen extends Component { order.set_tip(amount); order.finalized = true; - const paymentline = this.env.pos.get_order().get_paymentlines()[0]; + const paymentline = this.pos.globalState.get_order().get_paymentlines()[0]; if (paymentline.payment_method.payment_terminal) { paymentline.amount += amount; await paymentline.payment_method.payment_terminal.send_payment_adjust(paymentline.cid); @@ -96,16 +96,16 @@ export class TipScreen extends Component { this.goNextScreen(); } goNextScreen() { - this.env.pos.removeOrder(this.currentOrder); - if (!this.env.pos.config.module_pos_restaurant) { - this.env.pos.add_new_order(); + this.pos.globalState.removeOrder(this.currentOrder); + if (!this.pos.globalState.config.module_pos_restaurant) { + this.pos.globalState.add_new_order(); } const { name, props } = this.nextScreen; this.pos.showScreen(name, props); } get nextScreen() { - if (this.env.pos.config.module_pos_restaurant) { - const table = this.env.pos.table; + if (this.pos.globalState.config.module_pos_restaurant) { + const table = this.pos.globalState.table; return { name: "FloorScreen", props: { floor: table ? table.floor : null } }; } else { return { name: "ProductScreen" }; diff --git a/addons/pos_restaurant/static/src/xml/Screens/PaymentScreen/PaymentScreen.xml b/addons/pos_restaurant/static/src/xml/Screens/PaymentScreen/PaymentScreen.xml index 7a460e5ed9b..9e3d0d23342 100644 --- a/addons/pos_restaurant/static/src/xml/Screens/PaymentScreen/PaymentScreen.xml +++ b/addons/pos_restaurant/static/src/xml/Screens/PaymentScreen/PaymentScreen.xml @@ -3,18 +3,18 @@ - env.pos.config.set_tip_after_payment and !currentOrder.is_paid() + pos.globalState.config.set_tip_after_payment and !currentOrder.is_paid() - + Keep Open $0 - + Close Tab $0 diff --git a/addons/pos_restaurant/static/src/xml/Screens/ReceiptScreen/OrderReceipt.xml b/addons/pos_restaurant/static/src/xml/Screens/ReceiptScreen/OrderReceipt.xml index 93d8250f359..47f2ce1a25d 100644 --- a/addons/pos_restaurant/static/src/xml/Screens/ReceiptScreen/OrderReceipt.xml +++ b/addons/pos_restaurant/static/src/xml/Screens/ReceiptScreen/OrderReceipt.xml @@ -19,7 +19,7 @@ - +
    For convenience, we are providing the following gratuity calculations:
    diff --git a/addons/pos_restaurant/static/src/xml/Screens/TicketScreen.xml b/addons/pos_restaurant/static/src/xml/Screens/TicketScreen.xml index 2c4a4f1024d..bfeac51a083 100644 --- a/addons/pos_restaurant/static/src/xml/Screens/TicketScreen.xml +++ b/addons/pos_restaurant/static/src/xml/Screens/TicketScreen.xml @@ -3,11 +3,11 @@ -
    Table
    +
    Table
    Tip
    -
    +
    Table
    diff --git a/addons/pos_restaurant/static/src/xml/Screens/TipScreen.xml b/addons/pos_restaurant/static/src/xml/Screens/TipScreen.xml index f4b22b73691..c99d94e7f30 100644 --- a/addons/pos_restaurant/static/src/xml/Screens/TipScreen.xml +++ b/addons/pos_restaurant/static/src/xml/Screens/TipScreen.xml @@ -48,7 +48,7 @@
    - +
    diff --git a/addons/pos_sale/static/src/js/OrderManagementScreen/SaleOrderManagementControlPanel.js b/addons/pos_sale/static/src/js/OrderManagementScreen/SaleOrderManagementControlPanel.js index 688f301ea6c..92d08161235 100644 --- a/addons/pos_sale/static/src/js/OrderManagementScreen/SaleOrderManagementControlPanel.js +++ b/addons/pos_sale/static/src/js/OrderManagementScreen/SaleOrderManagementControlPanel.js @@ -3,6 +3,7 @@ import { useAutofocus, useService } from "@web/core/utils/hooks"; import { orderManagement } from "@point_of_sale/js/PosContext"; import { Component, useState } from "@odoo/owl"; +import { usePos } from "@point_of_sale/app/pos_hook"; // NOTE: These are constants so that they are only instantiated once // and they can be used efficiently by the OrderManagementControlPanel. @@ -23,12 +24,12 @@ export class SaleOrderManagementControlPanel extends Component { static template = "SaleOrderManagementControlPanel"; setup() { - super.setup(); + this.pos = usePos(); this.saleOrderFetcher = useService("sale_order_fetcher"); this.orderManagementContext = useState(orderManagement); useAutofocus(); - const currentPartner = this.env.pos.get_order().get_partner(); + const currentPartner = this.pos.globalState.get_order().get_partner(); if (currentPartner) { this.orderManagementContext.searchString = currentPartner.name; } diff --git a/addons/pos_sale/static/src/js/OrderManagementScreen/SaleOrderManagementScreen.js b/addons/pos_sale/static/src/js/OrderManagementScreen/SaleOrderManagementScreen.js index cb1ce4b77e2..3ed23a814d3 100644 --- a/addons/pos_sale/static/src/js/OrderManagementScreen/SaleOrderManagementScreen.js +++ b/addons/pos_sale/static/src/js/OrderManagementScreen/SaleOrderManagementScreen.js @@ -17,6 +17,7 @@ import { NumberPopup } from "@point_of_sale/js/Popups/NumberPopup"; import { SaleOrderList } from "./SaleOrderList"; import { SaleOrderManagementControlPanel } from "./SaleOrderManagementControlPanel"; import { onMounted, useRef, useState } from "@odoo/owl"; +import { usePos } from "@point_of_sale/app/pos_hook"; /** * ID getter to take into account falsy many2one value. @@ -33,6 +34,7 @@ export class SaleOrderManagementScreen extends ControlButtonsMixin(IndependentTo setup() { super.setup(); + this.pos = usePos(); this.popup = useService("popup"); this.orm = useService("orm"); this.root = useRef("root"); @@ -59,10 +61,10 @@ export class SaleOrderManagementScreen extends ControlButtonsMixin(IndependentTo this.saleOrderFetcher.setNPerPage(val); this.saleOrderFetcher.fetch(); } - _getSaleOrderOrigin(order) { + _getSaleOrderOrigin(order) { for (const line of order.get_orderlines()) { if (line.sale_order_origin_id) { - return line.sale_order_origin_id + return line.sale_order_origin_id; } } return false; @@ -91,6 +93,7 @@ export class SaleOrderManagementScreen extends ControlButtonsMixin(IndependentTo this.saleOrderFetcher.fetch(); } async onClickSaleOrder(clickedOrder) { + const { globalState } = this.pos; const { confirmed, payload: selectedOption } = await this.popup.add(SelectionPopup, { title: this.env._t("What do you want to do?"), list: [ @@ -109,7 +112,7 @@ export class SaleOrderManagementScreen extends ControlButtonsMixin(IndependentTo }); if (confirmed) { - let currentPOSOrder = this.env.pos.get_order(); + let currentPOSOrder = globalState.get_order(); const sale_order = await this._getSaleOrder(clickedOrder.id); clickedOrder.shipping_date = sale_order.shipping_date; @@ -123,22 +126,22 @@ export class SaleOrderManagementScreen extends ControlButtonsMixin(IndependentTo getId(linkedSO.partner_invoice_id) !== getId(sale_order.partner_invoice_id) || getId(linkedSO.partner_shipping_id) !== getId(sale_order.partner_shipping_id) ) { - currentPOSOrder = this.env.pos.add_new_order(); + currentPOSOrder = globalState.add_new_order(); this.notification.add(this.env._t("A new order has been created."), 4000); } } try { - await this.env.pos.load_new_partners(); + await globalState.load_new_partners(); } catch { // FIXME Universal catch seems ill advised } - const order_partner = this.env.pos.db.get_partner_by_id(sale_order.partner_id[0]); + const order_partner = globalState.db.get_partner_by_id(sale_order.partner_id[0]); if (order_partner) { currentPOSOrder.set_partner(order_partner); } else { try { - await this.env.pos._loadPartners([sale_order.partner_id[0]]); + await globalState._loadPartners([sale_order.partner_id[0]]); } catch { const title = this.env._t("Customer loading error"); const body = sprintf( @@ -148,11 +151,11 @@ export class SaleOrderManagementScreen extends ControlButtonsMixin(IndependentTo await this.popup.add(ErrorPopup, { title, body }); } currentPOSOrder.set_partner( - this.env.pos.db.get_partner_by_id(sale_order.partner_id[0]) + globalState.db.get_partner_by_id(sale_order.partner_id[0]) ); } const orderFiscalPos = sale_order.fiscal_position_id - ? this.env.pos.fiscal_positions.find( + ? globalState.fiscal_positions.find( (position) => position.id === sale_order.fiscal_position_id[0] ) : false; @@ -160,7 +163,7 @@ export class SaleOrderManagementScreen extends ControlButtonsMixin(IndependentTo currentPOSOrder.fiscal_position = orderFiscalPos; } const orderPricelist = sale_order.pricelist_id - ? this.env.pos.pricelists.find( + ? globalState.pricelists.find( (pricelist) => pricelist.id === sale_order.pricelist_id[0] ) : false; @@ -172,7 +175,7 @@ export class SaleOrderManagementScreen extends ControlButtonsMixin(IndependentTo // settle the order const lines = sale_order.order_line; const product_to_add_in_pos = lines - .filter((line) => !this.env.pos.db.get_product_by_id(line.product_id[0])) + .filter((line) => !globalState.db.get_product_by_id(line.product_id[0])) .map((line) => line.product_id[0]); if (product_to_add_in_pos.length) { const { confirmed } = await this.popup.add(ConfirmPopup, { @@ -184,7 +187,7 @@ export class SaleOrderManagementScreen extends ControlButtonsMixin(IndependentTo cancelText: this.env._t("No"), }); if (confirmed) { - await this.env.pos._addProducts(product_to_add_in_pos); + await globalState._addProducts(product_to_add_in_pos); } } @@ -202,16 +205,16 @@ export class SaleOrderManagementScreen extends ControlButtonsMixin(IndependentTo for (var i = 0; i < lines.length; i++) { const line = lines[i]; - if (!this.env.pos.db.get_product_by_id(line.product_id[0])) { + if (!globalState.db.get_product_by_id(line.product_id[0])) { continue; } const new_line = new Orderline( {}, { - pos: this.env.pos, - order: this.env.pos.get_order(), - product: this.env.pos.db.get_product_by_id(line.product_id[0]), + pos: globalState, + order: globalState.get_order(), + product: globalState.db.get_product_by_id(line.product_id[0]), description: line.name, price: line.price_unit, tax_ids: orderFiscalPos ? undefined : line.tax_id, @@ -224,8 +227,8 @@ export class SaleOrderManagementScreen extends ControlButtonsMixin(IndependentTo if ( new_line.get_product().tracking !== "none" && - (this.env.pos.picking_type.use_create_lots || - this.env.pos.picking_type.use_existing_lots) && + (globalState.picking_type.use_create_lots || + globalState.picking_type.use_existing_lots) && line.lot_names.length > 0 ) { // Ask once when `useLoadedLots` is undefined, then reuse it's value on the succeeding lines. @@ -253,39 +256,33 @@ export class SaleOrderManagementScreen extends ControlButtonsMixin(IndependentTo new_line.setQuantityFromSOL(line); new_line.set_unit_price(line.price_unit); new_line.set_discount(line.discount); - this.env.pos.get_order().add_orderline(new_line); + globalState.get_order().add_orderline(new_line); } } else { // apply a downpayment - if (this.env.pos.config.down_payment_product_id) { - let lines = sale_order.order_line; - const tab = []; - lines = lines.filter((line) => { - return ( - line.product_id[0] !== this.env.pos.config.down_payment_product_id[0] - ); + if (globalState.config.down_payment_product_id) { + const lines = sale_order.order_line.filter((line) => { + return line.product_id[0] !== globalState.config.down_payment_product_id[0]; }); - for (let i = 0; i < lines.length; i++) { - tab[i] = { - product_name: lines[i].product_id[1], - product_uom_qty: lines[i].product_uom_qty, - price_unit: lines[i].price_unit, - total: lines[i].price_total, - }; - } - let down_payment_product = this.env.pos.db.get_product_by_id( - this.env.pos.config.down_payment_product_id[0] + const tab = lines.map((line) => ({ + product_name: line.product_id[1], + product_uom_qty: line.product_uom_qty, + price_unit: line.price_unit, + total: line.price_total, + })); + let down_payment_product = globalState.db.get_product_by_id( + globalState.config.down_payment_product_id[0] ); if (!down_payment_product) { - await this.env.pos._addProducts([ - this.env.pos.config.down_payment_product_id[0], + await globalState._addProducts([ + globalState.config.down_payment_product_id[0], ]); - down_payment_product = this.env.pos.db.get_product_by_id( - this.env.pos.config.down_payment_product_id[0] + down_payment_product = globalState.db.get_product_by_id( + globalState.config.down_payment_product_id[0] ); } const down_payment_tax = - this.env.pos.taxes_by_id[down_payment_product.taxes_id] || false; + globalState.taxes_by_id[down_payment_product.taxes_id] || false; let down_payment; if (down_payment_tax) { down_payment = down_payment_tax.price_include @@ -302,7 +299,7 @@ export class SaleOrderManagementScreen extends ControlButtonsMixin(IndependentTo const popupSubtitle = this.env._t("Due balance: %s"); if (selectedOption == "dpAmount") { popupTitle = this.env._t("Down Payment"); - popupInputSuffix = this.env.pos.currency.symbol; + popupInputSuffix = globalState.currency.symbol; } else { popupTitle = this.env._t("Down Payment"); popupInputSuffix = "%"; @@ -361,8 +358,8 @@ export class SaleOrderManagementScreen extends ControlButtonsMixin(IndependentTo const new_line = new Orderline( {}, { - pos: this.env.pos, - order: this.env.pos.get_order(), + pos: globalState, + order: globalState.get_order(), product: down_payment_product, price: down_payment, price_automatically_set: true, @@ -371,7 +368,7 @@ export class SaleOrderManagementScreen extends ControlButtonsMixin(IndependentTo } ); new_line.set_unit_price(down_payment); - this.env.pos.get_order().add_orderline(new_line); + globalState.get_order().add_orderline(new_line); } else { const title = this.env._t("No down payment product"); const body = this.env._t( @@ -400,7 +397,7 @@ export class SaleOrderManagementScreen extends ControlButtonsMixin(IndependentTo "amount_unpaid", "picking_ids", "partner_shipping_id", - "partner_invoice_id" + "partner_invoice_id", ] ); diff --git a/addons/pos_six/static/app/navbar.xml b/addons/pos_six/static/app/navbar.xml index a469fb37320..5154f5682c3 100644 --- a/addons/pos_six/static/app/navbar.xml +++ b/addons/pos_six/static/app/navbar.xml @@ -3,7 +3,7 @@ - + diff --git a/addons/pos_six/static/src/js/BalanceButton.js b/addons/pos_six/static/src/js/BalanceButton.js index fb5937521ed..4949de911a2 100644 --- a/addons/pos_six/static/src/js/BalanceButton.js +++ b/addons/pos_six/static/src/js/BalanceButton.js @@ -1,12 +1,16 @@ /** @odoo-module */ import { Component } from "@odoo/owl"; +import { usePos } from "@point_of_sale/app/pos_hook"; export class BalanceButton extends Component { static template = "BalanceButton"; + setup() { + this.pos = usePos(); + } sendBalance() { - this.env.pos.payment_methods.map((pm) => { + this.pos.globalState.payment_methods.forEach((pm) => { if (pm.use_payment_terminal === "six") { pm.payment_terminal.send_balance(); }