diff --git a/addons/pos_hr_restaurant/models/pos_order.py b/addons/pos_hr_restaurant/models/pos_order.py index 25ace8545f1..e9128b50161 100644 --- a/addons/pos_hr_restaurant/models/pos_order.py +++ b/addons/pos_hr_restaurant/models/pos_order.py @@ -13,8 +13,8 @@ class PosOrder(models.Model): return fields @api.model - def get_table_draft_orders(self, table_id): - table_orders = super().get_table_draft_orders(table_id) + def get_table_draft_orders(self, table_ids): + table_orders = super().get_table_draft_orders(table_ids) for order in table_orders: if order['employee_id']: order['employee_id'] = order['employee_id'][0] if order['employee_id'] else False diff --git a/addons/pos_restaurant/models/pos_order.py b/addons/pos_restaurant/models/pos_order.py index 22b0f9802b4..ec262bc2ebc 100644 --- a/addons/pos_restaurant/models/pos_order.py +++ b/addons/pos_restaurant/models/pos_order.py @@ -149,7 +149,7 @@ class PosOrder(models.Model): ] @api.model - def get_table_draft_orders(self, table_id): + def get_table_draft_orders(self, table_ids): """Generate an object of all draft orders for the given table. Generate and return an JSON object with all draft orders for the given table, to send to the @@ -160,7 +160,7 @@ class PosOrder(models.Model): :returns: list -- list of dict representing the table orders """ table_orders = self.search_read( - domain=[('state', '=', 'draft'), ('table_id', '=', table_id)], + domain=[('state', '=', 'draft'), ('table_id', 'in', table_ids)], fields=self._get_fields_for_draft_order()) self._get_order_lines(table_orders) diff --git a/addons/pos_restaurant/static/src/js/ChromeWidgets/TicketButton.js b/addons/pos_restaurant/static/src/js/ChromeWidgets/TicketButton.js index 31c6f5ba346..8d71d3a845e 100644 --- a/addons/pos_restaurant/static/src/js/ChromeWidgets/TicketButton.js +++ b/addons/pos_restaurant/static/src/js/ChromeWidgets/TicketButton.js @@ -3,9 +3,35 @@ odoo.define('pos_restaurant.TicketButton', function (require) { const TicketButton = require('point_of_sale.TicketButton'); const Registries = require('point_of_sale.Registries'); + const { isConnectionError } = require('point_of_sale.utils'); const PosResTicketButton = (TicketButton) => class extends TicketButton { + async onClick() { + if (this.env.pos.config.iface_floorplan && !this.props.isTicketScreenShown && !this.env.pos.table) { + try { + this.env.pos.setLoadingOrderState(true); + await this.env.pos._syncAllOrdersFromServer(); + } catch (error) { + if (isConnectionError(error)) { + await this.showPopup('OfflineErrorPopup', { + title: this.env._t('Offline'), + body: this.env._t('Due to a connection error, the orders are not synchronized.'), + }); + } else { + this.showPopup('ErrorPopup', { + title: this.env._t('Unknown error'), + body: error.message, + }); + } + } finally { + this.env.pos.setLoadingOrderState(false); + this.showScreen('TicketScreen'); + } + } else { + super.onClick(); + } + } /** * If no table is set to pos, which means the current main screen * is floor screen, then the order count should be based on all the orders. diff --git a/addons/pos_restaurant/static/src/js/models.js b/addons/pos_restaurant/static/src/js/models.js index db1bc1b9138..cc0e70ddad7 100644 --- a/addons/pos_restaurant/static/src/js/models.js +++ b/addons/pos_restaurant/static/src/js/models.js @@ -105,13 +105,13 @@ const PosRestaurantPosGlobalState = (PosGlobalState) => class PosRestaurantPosGl } this.config.iface_printers = !!this.unwatched.printers.length; } - async _getTableOrdersFromServer(tableId) { + async _getTableOrdersFromServer(tableIds) { this.set_synch('connecting', 1); try { const orders = await this.env.services.rpc({ model: 'pos.order', method: 'get_table_draft_orders', - args: [tableId], + args: [tableIds], }, { timeout: TIMEOUT, shadow: true, @@ -199,21 +199,31 @@ const PosRestaurantPosGlobalState = (PosGlobalState) => class PosRestaurantPosGl */ async _syncTableOrdersFromServer(tableId) { await this._removeOrdersFromServer(); // in case we were offline and we deleted orders in the mean time - const ordersJsons = await this._getTableOrdersFromServer(tableId); + const ordersJsons = await this._getTableOrdersFromServer([tableId]); const tableOrders = this.getTableOrders(tableId); - - tableOrders.forEach(order => { + this._replaceOrders(tableOrders, ordersJsons); + } + async _syncAllOrdersFromServer() { + await this._removeOrdersFromServer(); // in case we were offline and we deleted orders in the mean time + const tableIds = [].concat(...this.floors.map(floor => floor.tables.map(table => table.id))); + const ordersJsons = await this._getTableOrdersFromServer(tableIds); // get all orders + await this._syncTableOrdersToServer(); // to prevent losing the transferred orders + const allOrders = [...this.get_order_list()]; + this._replaceOrders(allOrders, ordersJsons); + } + _replaceOrders(ordersToReplace, newOrdersJsons) { + ordersToReplace.forEach(order => { // We don't remove the validated orders because we still want to see them in the ticket screen. // Orders in 'ReceiptScreen' or 'TipScreen' are validated orders. if (order.server_id && !order.finalized && !this.transferredOrdersSet.has(order)){ this.removeOrder(order, false); } }); - ordersJsons.forEach(json => { + newOrdersJsons.forEach(json => { // Because of the offline feature, some draft orders fetched from the backend will appear // to belong in different table, but in fact they are already moved. const transferredOrder = [...this.transferredOrdersSet].find(order => order.uid === json.uid) - const isSameTable = transferredOrder && transferredOrder.tableId === tableId; + const isSameTable = transferredOrder && transferredOrder.tableId === json.tableId; if (isSameTable) { // this means we transferred back to the original table, we'll prioritize the server state this.removeOrder(transferredOrder, false); @@ -224,6 +234,9 @@ const PosRestaurantPosGlobalState = (PosGlobalState) => class PosRestaurantPosGl } }); } + setLoadingOrderState(bool) { + this.loadingOrderState = bool; + } loadRestaurantFloor() { // we do this in the front end due to the circular/recursive reference needed // Ignore floorplan features if no floor specified. diff --git a/addons/pos_restaurant/static/src/xml/Screens/TicketScreen.xml b/addons/pos_restaurant/static/src/xml/Screens/TicketScreen.xml index e8124699c5a..cdd675952e7 100644 --- a/addons/pos_restaurant/static/src/xml/Screens/TicketScreen.xml +++ b/addons/pos_restaurant/static/src/xml/Screens/TicketScreen.xml @@ -8,7 +8,7 @@
- +
Table
diff --git a/addons/pos_restaurant/static/tests/tours/TipScreen.tour.js b/addons/pos_restaurant/static/tests/tours/TipScreen.tour.js index 2257ebda1c0..b7fac64952a 100644 --- a/addons/pos_restaurant/static/tests/tours/TipScreen.tour.js +++ b/addons/pos_restaurant/static/tests/tours/TipScreen.tour.js @@ -56,7 +56,7 @@ odoo.define('pos_restaurant.tour.TipScreen', function (require) { Chrome.do.backToFloor(); FloorScreen.check.orderCountSyncedInTableIs('T5', '1'); Chrome.do.clickTicketButton(); - TicketScreen.check.nthRowContains('4', 'Tipping'); + TicketScreen.check.nthRowContains('3', 'Tipping'); // Tip 20% on order1 TicketScreen.do.selectOrder('-0001');