From b795fe45f6b3800b7d9b4ccadda37a0987df79df Mon Sep 17 00:00:00 2001 From: Samuel Degueldre Date: Thu, 2 Mar 2023 08:10:31 +0000 Subject: [PATCH] [FIX] point_of_sale: fix crash when closing session with draft orders In odoo/odoo#112219 we removed the usage of useListener for cross-component communication, one such use was to close the pos from the closing popup. The closeSession method was moved from the closing popup to the store but the corresponding error handling method wasnt. It appears that the closeSession method doesn't need to be on the store at all, only the closePos method. This commit moves the closeSession method back to the closing popup, so that it has access to the handleClosingError method again. closes odoo/odoo#114127 Signed-off-by: Trinh Jacky (trj) --- .../point_of_sale/static/src/app/pos_store.js | 69 ------------- addons/point_of_sale/static/src/js/Chrome.js | 14 +-- .../static/src/js/Popups/ClosePosPopup.js | 96 ++++++++++++++----- .../static/src/xml/Popups/ClosePosPopup.xml | 2 +- 4 files changed, 77 insertions(+), 104 deletions(-) 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 af27060386f..2ca20834d74 100644 --- a/addons/point_of_sale/static/src/app/pos_store.js +++ b/addons/point_of_sale/static/src/app/pos_store.js @@ -7,8 +7,6 @@ import { registry } from "@web/core/registry"; import { ConfirmPopup } from "@point_of_sale/js/Popups/ConfirmPopup"; import { reactive, markRaw } from "@odoo/owl"; import { Reactive } from "@point_of_sale/utils"; -import { identifyError } from "@point_of_sale/app/error_handlers/error_handlers"; -import { ConnectionLostError } from "@web/core/network/rpc_service"; import { ErrorPopup } from "@point_of_sale/js/Popups/ErrorPopup"; import { _t } from "@web/core/l10n/translation"; @@ -130,73 +128,6 @@ export class PosStore extends Reactive { } } } - async closeSession(defaultCashCounted, notes, otherPaymentMethods, payments) { - let response; - - if (this.globalState.config.cashControl) { - response = await this.orm.call( - "pos.session", - "post_closing_cash_details"[this.globalState.pos_session.id], - { - counted_cash: defaultCashCounted, - } - ); - - if (!response.successful) { - return this.handleClosingError(response); - } - } - - try { - await this.orm.call("pos.session", "update_closing_control_state_session", [ - this.globalState.pos_session.id, - notes, - ]); - } catch (error) { - // We have to handle the error manually otherwise the validation check stops the script. - // In case of "rescue session", we want to display the next popup with "handleClosingError". - // FIXME - if ( - !error.message && - !error.message.data && - error.message.data.message !== "This session is already closed." - ) { - throw error; - } - } - - try { - const bankPaymentMethodDiffPairs = otherPaymentMethods - .filter((pm) => pm.type == "bank") - .map((pm) => [pm.id, payments[pm.id].difference]); - response = await this.orm.call("pos.session", "close_session_from_ui", [ - this.globalState.pos_session.id, - bankPaymentMethodDiffPairs, - ]); - if (!response.successful) { - return this.handleClosingError(response); - } - window.location = "/web#action=point_of_sale.action_client_pos_menu"; - } catch (error) { - if (identifyError(error) instanceof ConnectionLostError) { - // Cannot redirect to backend when offline, let error handlers show the offline popup - // FIXME POSREF: doing this means closing again when online will redo the beginning of the method - // although it's impossible to close again because this.closeSessionClicked isn't reset to false - // The application state is corrupted. - throw error; - } else { - // FIXME POSREF: why are we catching errors here but not anywhere else in this method? - await this.popup.add(ErrorPopup, { - title: _t("Closing session error"), - body: _t( - "An error has occurred when trying to close the session.\n" + - "You will be redirected to the back-end to manually close the session." - ), - }); - window.location = "/web#action=point_of_sale.action_client_pos_menu"; - } - } - } async selectPartner() { // FIXME, find order to refund when we are in the ticketscreen. const currentOrder = this.globalState.get_order(); diff --git a/addons/point_of_sale/static/src/js/Chrome.js b/addons/point_of_sale/static/src/js/Chrome.js index d76696e4a31..2f63e03e426 100644 --- a/addons/point_of_sale/static/src/js/Chrome.js +++ b/addons/point_of_sale/static/src/js/Chrome.js @@ -57,18 +57,8 @@ export class Chrome extends Component { window.posmodel = this.pos.globalState.debug ? reactivePos : this.pos.globalState; this.wowlEnv = this.env; - for (const service of [ - "pos", - "sound", - "debug", - "pos_notification", - "number_buffer", - "popup", - "sale_order_fetcher", - ]) { - env.services[service] = this.wowlEnv.services[service]; - } - + // FIXME POSREF: make wowl services available in legacy env + Object.setPrototypeOf(env.services, this.wowlEnv.services); this.env = env; this.__owl__.childEnv = env; useSubEnv({ diff --git a/addons/point_of_sale/static/src/js/Popups/ClosePosPopup.js b/addons/point_of_sale/static/src/js/Popups/ClosePosPopup.js index a969276b159..4b0b600412d 100644 --- a/addons/point_of_sale/static/src/js/Popups/ClosePosPopup.js +++ b/addons/point_of_sale/static/src/js/Popups/ClosePosPopup.js @@ -3,11 +3,14 @@ import { AbstractAwaitablePopup } from "@point_of_sale/js/Popups/AbstractAwaitablePopup"; import { SaleDetailsButton } from "../ChromeWidgets/SaleDetailsButton"; import { ConfirmPopup } from "./ConfirmPopup"; -import { ErrorPopup } from "./ErrorPopup"; import { MoneyDetailsPopup } from "./MoneyDetailsPopup"; -import { AlertPopup } from "./AlertPopup"; import { useService } from "@web/core/utils/hooks"; +import { AlertPopup } from "./AlertPopup"; +import { ErrorPopup } from "./ErrorPopup"; import { useState } from "@odoo/owl"; +import { ConnectionLostError } from "@web/core/network/rpc_service"; +import { identifyError } from "@point_of_sale/app/error_handlers/error_handlers"; +import { _t } from "@web/core/l10n/translation"; export class ClosePosPopup extends AbstractAwaitablePopup { static components = { SaleDetailsButton }; @@ -17,6 +20,7 @@ export class ClosePosPopup extends AbstractAwaitablePopup { super.setup(); this.popup = useService("popup"); this.pos = useService("pos"); + this.orm = useService("orm"); this.manualInputCashCount = false; this.cashControl = this.env.pos.config.cash_control; this.closeSessionClicked = false; @@ -120,39 +124,87 @@ export class ClosePosPopup extends AbstractAwaitablePopup { canCancel() { return true; } - closePos() { - this.pos.closePos(); - } async closeSession() { if (!this.closeSessionClicked) { this.closeSessionClicked = true; - const defaultCashCounted = this.env.pos.config.cashControl - ? this.state.payments[this.defaultCashDetails.id].counted - : 0; - this.pos.closeSession( - defaultCashCounted, - this.state.notes, - this.otherPaymentMethods, - this.state.payments - ); + if (this.env.pos.config.cashControl) { + const response = await this.orm.call( + "pos.session", + "post_closing_cash_details"[this.env.pos.pos_session.id], + { + counted_cash: this.env.pos.config.cashControl + ? this.state.payments[this.defaultCashDetails.id].counted + : 0, + } + ); + + if (!response.successful) { + return this.handleClosingError(response); + } + } + + try { + await this.orm.call("pos.session", "update_closing_control_state_session", [ + this.env.pos.pos_session.id, + this.state.notes, + ]); + } catch (error) { + // We have to handle the error manually otherwise the validation check stops the script. + // In case of "rescue session", we want to display the next popup with "handleClosingError". + // FIXME + if ( + !error.message && + !error.message.data && + error.message.data.message !== "This session is already closed." + ) { + throw error; + } + } + + try { + const bankPaymentMethodDiffPairs = this.otherPaymentMethods + .filter((pm) => pm.type == "bank") + .map((pm) => [pm.id, this.state.payments[pm.id].difference]); + const response = await this.orm.call("pos.session", "close_session_from_ui", [ + this.env.pos.pos_session.id, + bankPaymentMethodDiffPairs, + ]); + if (!response.successful) { + return this.handleClosingError(response); + } + window.location = "/web#action=point_of_sale.action_client_pos_menu"; + } catch (error) { + if (identifyError(error) instanceof ConnectionLostError) { + // Cannot redirect to backend when offline, let error handlers show the offline popup + // FIXME POSREF: doing this means closing again when online will redo the beginning of the method + // although it's impossible to close again because this.closeSessionClicked isn't reset to false + // The application state is corrupted. + throw error; + } else { + // FIXME POSREF: why are we catching errors here but not anywhere else in this method? + await this.popup.add(ErrorPopup, { + title: _t("Closing session error"), + body: _t( + "An error has occurred when trying to close the session.\n" + + "You will be redirected to the back-end to manually close the session." + ), + }); + window.location = "/web#action=point_of_sale.action_client_pos_menu"; + } + } } this.closeSessionClicked = false; } async handleClosingError(response) { - let popupType = ""; - let title = ""; - + const body = response.message; if (response.type == "alert") { - popupType = AlertPopup; - title = response.title ? response.title : ""; + await this.popup.add(AlertPopup, { title: response.title || "", body }); } else { - popupType = ErrorPopup; - title = "Error"; + await this.popup.add(ErrorPopup, { title: "Error", body }); } - await this.popup.add(popupType, { title: title, body: response.message }); if (response.redirect) { window.location = "/web#action=point_of_sale.action_client_pos_menu"; } diff --git a/addons/point_of_sale/static/src/xml/Popups/ClosePosPopup.xml b/addons/point_of_sale/static/src/xml/Popups/ClosePosPopup.xml index 147a29a2a56..5fe74463d83 100644 --- a/addons/point_of_sale/static/src/xml/Popups/ClosePosPopup.xml +++ b/addons/point_of_sale/static/src/xml/Popups/ClosePosPopup.xml @@ -80,7 +80,7 @@