diff --git a/addons/point_of_sale/__manifest__.py b/addons/point_of_sale/__manifest__.py index 0e42a7cb1ea..b413c6ca03e 100644 --- a/addons/point_of_sale/__manifest__.py +++ b/addons/point_of_sale/__manifest__.py @@ -125,6 +125,7 @@ 'point_of_sale/static/src/js/**/*.js', 'web/static/lib/zxing-library/zxing-library.js', 'point_of_sale/static/src/xml/**/*.xml', + 'point_of_sale/static/src/utils.js', 'point_of_sale/static/src/app/**/*', ], # This bundle contains the code responsible for starting the POS UI. diff --git a/addons/point_of_sale/static/src/app/debug/debug_service.js b/addons/point_of_sale/static/src/app/debug/debug_service.js new file mode 100644 index 00000000000..1035c35644e --- /dev/null +++ b/addons/point_of_sale/static/src/app/debug/debug_service.js @@ -0,0 +1,34 @@ +/** @odoo-module */ + +import { reactive } from "@odoo/owl"; +import { registry } from "@web/core/registry"; +import { DebugWidget } from "./debug_widget"; +import { withComputedProperties } from "@point_of_sale/utils"; + +const debugService = { + dependencies: ["pos"], + /** + * @param {{ debug: string }} env + * @param {object} deps + * @param {import("@point_of_sale/app/pos_store").PosStore} deps.pos + */ + start(env, { pos }) { + const internalState = reactive({ widgetOpen: true }); + const state = withComputedProperties(reactive({}), [internalState, pos], { + showWidget(internalState, pos) { + return env.debug && pos.uiState === "READY" && internalState.widgetOpen; + }, + }); + registry.category("main_components").add("DebugWidget", { + Component: DebugWidget, + props: { state }, + }); + return { + toggleWidget() { + internalState.widgetOpen = !internalState.widgetOpen; + }, + }; + }, +}; + +registry.category("services").add("debug", debugService); diff --git a/addons/point_of_sale/static/src/app/debug_widget/debug_widget.js b/addons/point_of_sale/static/src/app/debug/debug_widget.js similarity index 95% rename from addons/point_of_sale/static/src/app/debug_widget/debug_widget.js rename to addons/point_of_sale/static/src/app/debug/debug_widget.js index 378e34bf120..7b39a553da1 100644 --- a/addons/point_of_sale/static/src/app/debug_widget/debug_widget.js +++ b/addons/point_of_sale/static/src/app/debug/debug_widget.js @@ -3,21 +3,20 @@ import { parse } from "web.field_utils"; import { numberBuffer } from "@point_of_sale/js/Misc/NumberBuffer"; import { PosComponent } from "@point_of_sale/js/PosComponent"; -import { usePos } from "@point_of_sale/app/pos_store"; -import { registry } from "@web/core/registry"; import { Transition } from "@web/core/transition"; import { Draggable } from "@point_of_sale/js/Misc/Draggable"; import { ConfirmPopup } from "@point_of_sale/js/Popups/ConfirmPopup"; import { OrderImportPopup } from "@point_of_sale/js/Popups/OrderImportPopup"; +import { useService } from "@web/core/utils/hooks"; -const { onMounted, onWillUnmount, useRef, useState } = owl; +import { onMounted, onWillUnmount, useRef, useState } from "@odoo/owl"; export class DebugWidget extends PosComponent { static components = { Transition, Draggable }; static template = "point_of_sale.DebugWidget"; setup() { super.setup(); - this.pos = usePos(); + this.debug = useService("debug"); this.state = useState({ barcodeInput: "", weightInput: "", @@ -162,5 +161,3 @@ export class DebugWidget extends PosComponent { return `"${this.state.buffer}"`; } } - -registry.category("main_components").add("DebugWidget", { Component: DebugWidget }); diff --git a/addons/point_of_sale/static/src/app/debug_widget/debug_widget.scss b/addons/point_of_sale/static/src/app/debug/debug_widget.scss similarity index 100% rename from addons/point_of_sale/static/src/app/debug_widget/debug_widget.scss rename to addons/point_of_sale/static/src/app/debug/debug_widget.scss diff --git a/addons/point_of_sale/static/src/app/debug_widget/debug_widget.xml b/addons/point_of_sale/static/src/app/debug/debug_widget.xml similarity index 94% rename from addons/point_of_sale/static/src/app/debug_widget/debug_widget.xml rename to addons/point_of_sale/static/src/app/debug/debug_widget.xml index 4cac0c1568a..f41876ef80f 100644 --- a/addons/point_of_sale/static/src/app/debug_widget/debug_widget.xml +++ b/addons/point_of_sale/static/src/app/debug/debug_widget.xml @@ -2,13 +2,13 @@ - +

Debug Window

-

Electronic Scale

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 a90c56327f6..3ab31a7ad2b 100644 --- a/addons/point_of_sale/static/src/app/navbar/navbar.js +++ b/addons/point_of_sale/static/src/app/navbar/navbar.js @@ -2,6 +2,7 @@ import { PosComponent } from "@point_of_sale/js/PosComponent"; import { usePos } from "@point_of_sale/app/pos_store"; +import { useService } from "@web/core/utils/hooks"; import { CashierName } from "@point_of_sale/js/ChromeWidgets/CashierName"; import { CashMoveButton } from "@point_of_sale/js/ChromeWidgets/CashMoveButton"; @@ -30,6 +31,7 @@ export class Navbar extends PosComponent { }; setup() { this.pos = usePos(); + this.debug = useService("debug"); } get customerFacingDisplayButtonIsShown() { return this.env.pos.config.iface_customer_facing_display; 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 cdf9e7a3d85..397c3de6d5f 100644 --- a/addons/point_of_sale/static/src/app/navbar/navbar.xml +++ b/addons/point_of_sale/static/src/app/navbar/navbar.xml @@ -5,7 +5,7 @@
- +
diff --git a/addons/point_of_sale/static/src/app/notification/notification.scss b/addons/point_of_sale/static/src/app/notification/notification.scss new file mode 100644 index 00000000000..5f4a172f7dd --- /dev/null +++ b/addons/point_of_sale/static/src/app/notification/notification.scss @@ -0,0 +1,25 @@ +.o_pos_notification_manager { + position: fixed; + top: 0; + bottom: 0; + left: 0; + right: 0; + display: flex; + flex-direction: column; + padding: 2rem; + justify-content: end; + align-items: center; + pointer-events: none; +} + +.o_notification { + pointer-events: auto; + width: 350px; + background-color: #333333AA; + color: #fff; + text-align: center; + border-radius: 2px; + padding: 16px; + margin: .5rem; + font-size: 1rem; +} diff --git a/addons/point_of_sale/static/src/app/notification/notification.xml b/addons/point_of_sale/static/src/app/notification/notification.xml new file mode 100644 index 00000000000..f76d88f9d6f --- /dev/null +++ b/addons/point_of_sale/static/src/app/notification/notification.xml @@ -0,0 +1,20 @@ + + + + +
+ +
+
+ + +
+ + + + + +
+
+ +
diff --git a/addons/point_of_sale/static/src/app/notification/notification_service.js b/addons/point_of_sale/static/src/app/notification/notification_service.js new file mode 100644 index 00000000000..476ee01d36c --- /dev/null +++ b/addons/point_of_sale/static/src/app/notification/notification_service.js @@ -0,0 +1,50 @@ +/** @odoo-module */ + +import { reactive, Component } from "@odoo/owl"; +import { registry } from "@web/core/registry"; +import { Transition } from "@web/core/transition"; + +const TRANSITION_LEAVE_DURATION = 200; // ms + +class Notification extends Component { + static template = "point_of_sale.Notification"; + static props = { message: String, close: Function, className: String }; +} + +class NotificationContainer extends Component { + static template = "point_of_sale.NotificationContainer"; + static components = { Transition, Notification }; + static props = { + notifications: Object, + }; + leaveDuration = TRANSITION_LEAVE_DURATION; +} +// FIXME: probably should use the main notification service from web long term. +export const notificationService = { + start() { + const notifications = reactive({}); + let notifId = 0; + registry.category("main_components").add("PosNotificationContainer", { + Component: NotificationContainer, + props: { notifications }, + }); + return { + add(message, duration = 2000) { + const id = ++notifId; + notifications[id] = { + message, + visible: true, + close() { + notifications[id].visible = false; + }, + delete() { + delete notifications[id]; + }, + }; + setTimeout(() => notifications?.[id]?.close(), duration); + }, + }; + }, +}; + +registry.category("services").add("pos_notification", notificationService); diff --git a/addons/point_of_sale/static/src/app/pos_store.js b/addons/point_of_sale/static/src/app/pos_store.js index b961d23c138..13c3f006d8d 100644 --- a/addons/point_of_sale/static/src/app/pos_store.js +++ b/addons/point_of_sale/static/src/app/pos_store.js @@ -1,32 +1,27 @@ /** @odoo-module */ +import { PosGlobalState } from "@point_of_sale/js/models"; +import { pos_env as legacyEnv } from "@point_of_sale/js/pos_env"; + import { registry } from "@web/core/registry"; import { useService } from "@web/core/utils/hooks"; -import { debounce } from "@web/core/utils/timing"; -import { reactive, useState, toRaw } from "@odoo/owl"; +import { reactive, useState, markRaw } from "@odoo/owl"; export class PosStore { /** @type {'LOADING' | 'READY' | 'CLOSING'} */ uiState = "LOADING"; - debugWidgetIsShown = true; hasBigScrollBars = false; - notification = { - isShown: false, - message: "", - duration: 2000, - }; loadingSkipButtonIsShown = false; - // not using an arrow function here because we need the correct `this` - toggleDebugWidget = debounce(function toggleDebugWidget() { - this.debugWidgetIsShown = !toRaw(this).debugWidgetIsShown; - }, 100); mainScreen = { name: null, component: null }; tempScreen = null; + legacyEnv = legacyEnv; constructor() { this.setup(); } - // to allow other modules to add things to the store. - setup() {} + // use setup instead of constructor because setup can be patched. + setup() { + this.globalState = new PosGlobalState({ env: markRaw(legacyEnv) }); + } } export const posService = { @@ -37,6 +32,9 @@ export const posService = { registry.category("services").add("pos", posService); +/** + * @returns {PosStore} + */ export function usePos() { return useState(useService("pos")); } diff --git a/addons/point_of_sale/static/src/js/Chrome.js b/addons/point_of_sale/static/src/js/Chrome.js index dc47b4409e1..846a8714b87 100644 --- a/addons/point_of_sale/static/src/js/Chrome.js +++ b/addons/point_of_sale/static/src/js/Chrome.js @@ -15,13 +15,10 @@ import { Navbar } from "@point_of_sale/app/navbar/navbar"; // ChromeAdapter imports import { ProductScreen } from "@point_of_sale/js/Screens/ProductScreen/ProductScreen"; -import { PosGlobalState } from "@point_of_sale/js/models"; import { configureGui } from "@point_of_sale/js/Gui"; import { registry } from "@web/core/registry"; import { pos_env as env } from "@point_of_sale/js/pos_env"; -import { Notification } from "./Notification"; -import { PosPopupController } from "./Popups/PosPopupController"; import { ErrorTracebackPopup } from "./Popups/ErrorTracebackPopup"; import { CashOpeningPopup } from "./Popups/CashOpeningPopup"; import { ConfirmPopup } from "./Popups/ConfirmPopup"; @@ -32,7 +29,6 @@ import { useExternalListener, useSubEnv, reactive, - markRaw, onWillUnmount, } from "@odoo/owl"; import { usePos } from "@point_of_sale/app/pos_store"; @@ -43,18 +39,15 @@ import { usePos } from "@point_of_sale/app/pos_store"; export class Chrome extends PosComponent { static template = "Chrome"; // FIXME POSREF namespace templates setup() { + this.pos = usePos(); // BEGIN ChromeAdapter ProductScreen.sortControlButtons(); const legacyActionManager = useService("legacy_action_manager"); - // Instantiate PosGlobalState here to ensure that every extension - // (or class overloads) is taken into consideration. - const pos = new PosGlobalState({ env: markRaw(env) }); - this.batchedCustomerDisplayRender = batched(() => { reactivePos.send_current_order_to_customer_facing_display(); }); - const reactivePos = reactive(pos, this.batchedCustomerDisplayRender); + const reactivePos = reactive(this.pos.globalState, this.batchedCustomerDisplayRender); env.pos = reactivePos; env.legacyActionManager = legacyActionManager; @@ -63,12 +56,13 @@ export class Chrome extends PosComponent { // TODO: Should we continue on exposing posmodel as global variable? // Expose only the reactive version of `pos` when in debug mode. - window.posmodel = pos.debug ? reactivePos : pos; + window.posmodel = this.pos.globalState.debug ? reactivePos : this.pos.globalState; this.wowlEnv = this.env; - env.services.pos = this.wowlEnv.services.pos; - env.services.sound = this.wowlEnv.services.sound; - window.sound = env.services.sound; + for (const service of ["pos", "sound", "debug", "pos_notification"]) { + env.services[service] = this.wowlEnv.services[service]; + } + this.env = env; this.__owl__.childEnv = env; useSubEnv({ @@ -94,20 +88,11 @@ export class Chrome extends PosComponent { useListener("close-temp-screen", this.__closeTempScreen); useListener("close-pos", this._closePos); useListener("loading-skip-callback", () => this.env.proxy.stop_searching()); - const sound = useService("sound"); - useListener("play-sound", ({ detail: name }) => sound.play(name)); useListener("set-sync-status", this._onSetSyncStatus); - useListener("show-notification", this._onShowNotification); - useListener("close-notification", this._onCloseNotification); useListener("connect-to-proxy", this.connect_to_proxy); useBus(this.env.posbus, "start-cash-control", this.openCashControl); numberBuffer.activate(); - this.state = usePos(); - - this.mainScreen = this.state.mainScreen; - this.mainScreenProps = {}; - useSubEnv({ pos: reactive( this.env.pos, @@ -145,9 +130,9 @@ export class Chrome extends PosComponent { * NOTE: Wait for pos data to be completed before calling this getter. */ get startScreen() { - if (this.state.uiState !== "READY") { + if (this.pos.uiState !== "READY") { console.warn( - `Accessing startScreen of Chrome component before 'state.uiState' to be 'READY' is not recommended.` + `Accessing startScreen of Chrome component before 'pos.uiState' to be 'READY' is not recommended.` ); } return { name: "ProductScreen" }; @@ -184,7 +169,7 @@ export class Chrome extends PosComponent { this.env.pos.config.start_category && this.env.pos.config.iface_start_categ_id ? this.env.pos.config.iface_start_categ_id[0] : 0; - this.state.uiState = "READY"; + this.pos.uiState = "READY"; this._showStartScreen(); setTimeout(() => this._runBackgroundTasks()); } catch (error) { @@ -267,7 +252,7 @@ export class Chrome extends PosComponent { connect_to_proxy() { return new Promise((resolve, reject) => { this.env.barcode_reader.disconnect_from_proxy(); - this.state.loadingSkipButtonIsShown = true; + this.pos.loadingSkipButtonIsShown = true; this.env.proxy .autoconnect({ force_ip: this.env.pos.config.proxy_ip || undefined, @@ -326,21 +311,19 @@ export class Chrome extends PosComponent { } __showTempScreen(event) { const { name, props, resolve } = event.detail; - this.state.tempScreen = { + this.pos.tempScreen = { name, component: registry.category("pos_screens").get(name), props: { ...props, resolve }, }; } __closeTempScreen() { - this.state.tempScreen = null; + this.pos.tempScreen = null; } __showScreen({ detail: { name, props = {} } }) { const component = registry.category("pos_screens").get(name); // 1. Set the information of the screen to display. - this.mainScreen.name = name; - this.mainScreen.component = component; - this.mainScreenProps = props; + this.pos.mainScreen = { name, component, props }; // 2. Save the screen to the order. // - This screen is shown when the order is selected. @@ -402,8 +385,8 @@ export class Chrome extends PosComponent { }); if (confirmed) { // FIXME POSREF setting the location prevents the next render, the loading screen never shows - this.state.uiState = "CLOSING"; - this.state.loadingSkipButtonIsShown = false; + this.pos.uiState = "CLOSING"; + this.pos.loadingSkipButtonIsShown = false; window.location = "/web#action=point_of_sale.action_client_pos_menu"; } } @@ -413,14 +396,6 @@ export class Chrome extends PosComponent { this.env.pos.synch.status = status; this.env.pos.synch.pending = pending; } - _onShowNotification({ detail: { message, duration } }) { - this.state.notification.isShown = true; - this.state.notification.message = message; - this.state.notification.duration = duration; - } - _onCloseNotification() { - this.state.notification.isShown = false; - } /** * Save `env.pos.toRefundLines` in localStorage on beforeunload - closing the * browser, reloading or going to other page. @@ -458,7 +433,7 @@ export class Chrome extends PosComponent { } if (this.env.pos.config.iface_big_scrollbars) { - this.state.hasBigScrollBars = true; + this.pos.hasBigScrollBars = true; } this._disableBackspaceBack(); @@ -507,8 +482,6 @@ Object.defineProperty(Chrome, "components", { MainComponentsContainer, WithEnv, Navbar, - PosPopupController, - Notification, }, PosComponent.components ); diff --git a/addons/point_of_sale/static/src/js/Notification.js b/addons/point_of_sale/static/src/js/Notification.js deleted file mode 100644 index 9f029b2f40c..00000000000 --- a/addons/point_of_sale/static/src/js/Notification.js +++ /dev/null @@ -1,21 +0,0 @@ -/** @odoo-module */ - -import { useListener } from "@web/core/utils/hooks"; -import { PosComponent } from "@point_of_sale/js/PosComponent"; - -const { onMounted } = owl; - -export class Notification extends PosComponent { - static template = "Notification"; - - setup() { - super.setup(); - useListener("click", this.closeNotification); - - onMounted(() => { - setTimeout(() => { - this.closeNotification(); - }, this.props.duration); - }); - } -} diff --git a/addons/point_of_sale/static/src/js/Popups/PosPopupController.js b/addons/point_of_sale/static/src/js/Popups/PosPopupController.js index 6dc72e4edde..70e76618f5a 100644 --- a/addons/point_of_sale/static/src/js/Popups/PosPopupController.js +++ b/addons/point_of_sale/static/src/js/Popups/PosPopupController.js @@ -2,6 +2,9 @@ import { PosComponent } from "@point_of_sale/js/PosComponent"; import { useBus } from "@web/core/utils/hooks"; +import { registry } from "@web/core/registry"; +import { usePos } from "@point_of_sale/app/pos_store"; +import { useExternalListener, useState } from "@odoo/owl"; /** * This component is responsible in controlling the popups. It does so @@ -29,11 +32,15 @@ export class PosPopupController extends PosComponent { static components = {}; setup() { + this.pos = usePos(); + // FIXME POSREF stop overwriting env + this.env = this.pos.legacyEnv; + this.__owl__.childEnv = this.env; super.setup(); useBus(this.env.posbus, "show-popup", this._showPopup); useBus(this.env.posbus, "close-popup", this._closePopup); - owl.useExternalListener(window, "keyup", this._onWindowKeyup); - this.popups = owl.useState([]); + useExternalListener(window, "keyup", this._onWindowKeyup); + this.popups = useState([]); } /** * A popup can be cancelled/confirmed with 'Escape'/'Enter' key by default. @@ -109,3 +116,7 @@ export class PosPopupController extends PosComponent { return this.topPopup === popup || popup.props.keepBehind; } } + +registry.category("main_components").add("PosPopupController", { + Component: PosPopupController, +}); diff --git a/addons/point_of_sale/static/src/js/PosComponent.js b/addons/point_of_sale/static/src/js/PosComponent.js index 1eba2538564..8d0af987c86 100644 --- a/addons/point_of_sale/static/src/js/PosComponent.js +++ b/addons/point_of_sale/static/src/js/PosComponent.js @@ -1,11 +1,16 @@ /** @odoo-module */ +import { useService } from "@web/core/utils/hooks"; import { LegacyComponent } from "@web/legacy/legacy_component"; let nextId = 0; export class PosComponent extends LegacyComponent { static components = {}; + setup() { + this.notification = useService("pos_notification"); + this.sound = useService("sound"); + } /** * This function is available to all Components that inherit this class. * The goal of this function is to show an awaitable dialog (popup) that @@ -42,7 +47,7 @@ export class PosComponent extends LegacyComponent { * @param {String} name 'bell' | 'error' */ playSound(name) { - this.trigger("play-sound", name); + this.sound.play(name); } /** * Control the SyncNotification component. @@ -52,10 +57,7 @@ export class PosComponent extends LegacyComponent { setSyncStatus(status, pending) { this.trigger("set-sync-status", { status, pending }); } - showNotification(message, duration = 2000) { - this.trigger("show-notification", { message, duration }); - } - closeNotification() { - this.trigger("close-notification"); + showNotification(message, duration) { + this.notification.add(message, duration); } } diff --git a/addons/point_of_sale/static/src/scss/pos.scss b/addons/point_of_sale/static/src/scss/pos.scss index b7a5f0812fb..e79d0530c2e 100644 --- a/addons/point_of_sale/static/src/scss/pos.scss +++ b/addons/point_of_sale/static/src/scss/pos.scss @@ -3676,24 +3676,6 @@ td { } } -/** - * Notification - */ - - .pos .notification { - width: 350px; - background-color: #333333AA; - color: #fff; - text-align: center; - border-radius: 2px; - padding: 16px; - position: fixed; - z-index: 1; - left: calc((100% - 350px - 32px)/2); - bottom: 5%; - font-size: 17px; -} - .pos .pos-topheader .status-buttons > div:not(.not-clickable):hover { background: rgba(0, 0, 0, .08); } diff --git a/addons/point_of_sale/static/src/utils.js b/addons/point_of_sale/static/src/utils.js new file mode 100644 index 00000000000..dffb1556cfe --- /dev/null +++ b/addons/point_of_sale/static/src/utils.js @@ -0,0 +1,43 @@ +/** @odoo-module */ + +import { reactive } from "@odoo/owl"; + +/** + * Creates a side-effect that runs based on the content of reactive objects. + * + * @template {object[]} T + * @param {(...args: [...T]) => void} cb callback for the effect + * @param {[...T]} deps the reactive objects that the effect depends on + */ +export function effect(cb, deps) { + const reactiveDeps = reactive(deps, () => { + cb(...reactiveDeps); + }); + cb(...reactiveDeps); +} + +/** + * Adds computed properties to a reactive object derived from multiples sources. + * + * @template {object} T + * @template {object[]} U + * @template {{[key: string]: (this: T, ...rest: [...U]) => unknown}} V + * @param {T} obj the reactive object on which to add the computed + * properties + * @param {[...U]} sources the reactive objects which are needed to compute + * the properties + * @param {V} descriptor the object containing methods to compute the + * properties + * @returns {T & {[key in keyof V]: ReturnType}} + */ +export function withComputedProperties(obj, sources, descriptor) { + for (const [key, compute] of Object.entries(descriptor)) { + effect( + (obj, sources) => { + obj[key] = compute.call(obj, ...sources); + }, + [obj, sources] + ); + } + return obj; +} diff --git a/addons/point_of_sale/static/src/xml/Chrome.xml b/addons/point_of_sale/static/src/xml/Chrome.xml index a12fa990fc0..ad4f76e0bfa 100644 --- a/addons/point_of_sale/static/src/xml/Chrome.xml +++ b/addons/point_of_sale/static/src/xml/Chrome.xml @@ -2,19 +2,19 @@ -
+
- +
- - + +
@@ -22,12 +22,12 @@
- +
- +

Connecting to devices

- - - - - - - -
diff --git a/addons/point_of_sale/static/src/xml/Notification.xml b/addons/point_of_sale/static/src/xml/Notification.xml deleted file mode 100644 index cf5d2de92d8..00000000000 --- a/addons/point_of_sale/static/src/xml/Notification.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - -
- - - -
-
- -
diff --git a/addons/point_of_sale/static/tests/unit/test_PosPopupController.js b/addons/point_of_sale/static/tests/unit/test_PosPopupController.js index 18ac4601d23..5cc8d2c96fe 100644 --- a/addons/point_of_sale/static/tests/unit/test_PosPopupController.js +++ b/addons/point_of_sale/static/tests/unit/test_PosPopupController.js @@ -6,6 +6,8 @@ import { PosComponent } from "@point_of_sale/js/PosComponent"; import makeTestEnvironment from "web.test_env"; import testUtils from "web.test_utils"; import { mount } from "@web/../tests/helpers/utils"; +import { makeTestEnv } from "@web/../tests/helpers/mock_env"; +import { registry } from "@web/core/registry"; const { EventBus, useSubEnv, xml } = owl; @@ -35,29 +37,46 @@ CustomPopup2.template = xml/* html */ `
`; -QUnit.module("unit tests for PosPopupController"); +let env; +QUnit.module("unit tests for PosPopupController", { + async beforeEach() { + const posbus = new EventBus(); + const makeService = (obj) => ({ + start() { + return obj; + }, + }); + const legacyEnv = makeTestEnvironment(); + registry.category("services").add("pos_notification", makeService({ add() {} })); + registry.category("services").add("sound", makeService({ play() {} })); + registry.category("services").add("pos", makeService({ legacyEnv })); + env = await makeTestEnv(); + for (const service of ["pos", "pos_notification", "sound"]) { + legacyEnv.services[service] = env.services[service]; + } + env.posbus = posbus; + legacyEnv.posbus = posbus; + }, +}); QUnit.test("allow multiple popups at the same time", async function (assert) { assert.expect(12); - class Root extends PosComponent { static components = { PosPopupController }; setup() { super.setup(); useSubEnv({ isDebug: () => false, - posbus: new EventBus(), }); } } - Root.env = makeTestEnvironment(); Root.template = xml/* html */ `
`; - const root = await mount(Root, testUtils.prepareTarget()); + const root = await mount(Root, testUtils.prepareTarget(), { env }); // Check 1 popup let popup1Promise = root.showPopup(CustomPopup1, {}); @@ -117,18 +136,16 @@ QUnit.test("pressing cancel/confirm key should only close the top popup", async super.setup(); useSubEnv({ isDebug: () => false, - posbus: new EventBus(), }); } } - Root.env = makeTestEnvironment(); Root.template = xml/* html */ `
`; - const root = await mount(Root, testUtils.prepareTarget()); + const root = await mount(Root, testUtils.prepareTarget(), { env }); const popup1Promise = root.showPopup(CustomPopup1, { confirmKey: "Enter", diff --git a/addons/pos_hr_restaurant/static/src/js/Chrome.js b/addons/pos_hr_restaurant/static/src/js/Chrome.js index 2382a2fab15..673c17d2aa4 100644 --- a/addons/pos_hr_restaurant/static/src/js/Chrome.js +++ b/addons/pos_hr_restaurant/static/src/js/Chrome.js @@ -1,11 +1,11 @@ /* @odoo-module alias=pos_restaurant_hr.chrome */ -import { Chrome } from '@point_of_sale/js/Chrome'; +import { Chrome } from "@point_of_sale/js/Chrome"; import { patch } from "@web/core/utils/patch"; patch(Chrome.prototype, "pos_hr_restaurant.Chrome", { //@override _shouldResetIdleTimer() { - return this._super() && this.state.tempScreen?.name !== 'LoginScreen'; - } + return this._super() && this.pos.tempScreen?.name !== "LoginScreen"; + }, }); diff --git a/addons/pos_restaurant/static/src/js/Chrome.js b/addons/pos_restaurant/static/src/js/Chrome.js index 7d531055dec..02d4a324cc9 100644 --- a/addons/pos_restaurant/static/src/js/Chrome.js +++ b/addons/pos_restaurant/static/src/js/Chrome.js @@ -58,7 +58,7 @@ patch(Chrome.prototype, "pos_restaurant.Chrome", { this.env.posbus.trigger("close-popups-but-error", { resolve }) ); if (isPopupClosed) { - if (this.state.tempScreen) { + if (this.pos.tempScreen) { this.trigger("close-temp-screen"); } const table = this.env.pos.table; @@ -73,12 +73,12 @@ patch(Chrome.prototype, "pos_restaurant.Chrome", { }, _shouldResetIdleTimer() { const stayPaymentScreen = - this.mainScreen.name === "PaymentScreen" && + this.pos.mainScreen.name === "PaymentScreen" && this.env.pos.get_order().paymentlines.length > 0; return ( this.env.pos.config.iface_floorplan && !stayPaymentScreen && - this.mainScreen.name !== "FloorScreen" + this.pos.mainScreen.name !== "FloorScreen" ); }, __showScreen() {