diff options
| author | Joseph Caburnay <jcb@odoo.com> | 2020-07-09 12:07:14 +0000 |
|---|---|---|
| committer | Joseph Caburnay <jcb@odoo.com> | 2020-08-05 13:35:08 +0000 |
| commit | 9ea0aca6ea30fe42e1a7e0a4eaeb79f92a521152 (patch) | |
| tree | b3c969ef00f0bbc637d94c124202a96887df450a /addons/pos_restaurant/static | |
| parent | 71f719a61ea34252abdc9f1b2fb2caf8e62c7917 (diff) | |
[IMP] point_of_sale,pos_*: top bar improvements and ticket list
The following changes are made in this task:
1. Remove order tabs and replace with ticket list.
2. Top bar color change.
3. Search bar in the product screen is moved in the top bar.
4. List of sub-categories are now in the same line as the category
breadcrumbs.
closes odoo/odoo#55100
Task-id: 2276678
Signed-off-by: pimodoo <pimodoo@users.noreply.github.com>
Diffstat (limited to 'addons/pos_restaurant/static')
18 files changed, 329 insertions, 307 deletions
diff --git a/addons/pos_restaurant/static/src/js/ChromeWidgets/BackToFloorButton.js b/addons/pos_restaurant/static/src/js/ChromeWidgets/BackToFloorButton.js index dbd21c5fd32..c2b623500c8 100644 --- a/addons/pos_restaurant/static/src/js/ChromeWidgets/BackToFloorButton.js +++ b/addons/pos_restaurant/static/src/js/ChromeWidgets/BackToFloorButton.js @@ -1,22 +1,28 @@ -odoo.define('pos_restaurant.BackToFloorButton', function(require) { +odoo.define('pos_restaurant.BackToFloorButton', function (require) { 'use strict'; const PosComponent = require('point_of_sale.PosComponent'); - const { useListener } = require('web.custom_hooks'); const Registries = require('point_of_sale.Registries'); + const { posbus } = require('point_of_sale.utils'); class BackToFloorButton extends PosComponent { - constructor() { - super(...arguments); - useListener('click', this._backToFloorScreen); + mounted() { + posbus.on('table-set', this, this.render); + } + willUnmount() { + posbus.on('table-set', this); } get table() { - return this.props.table; + return (this.env.pos && this.env.pos.table) || null; } get floor() { - return this.props.table.floor; + const table = this.table; + return table ? table.floor : null; + } + get hasTable() { + return this.table !== null; } - async _backToFloorScreen() { + backToFloorScreen() { this.showScreen('FloorScreen', { floor: this.floor }); } } diff --git a/addons/pos_restaurant/static/src/js/ChromeWidgets/OrderSelector.js b/addons/pos_restaurant/static/src/js/ChromeWidgets/OrderSelector.js deleted file mode 100644 index 255b84db073..00000000000 --- a/addons/pos_restaurant/static/src/js/ChromeWidgets/OrderSelector.js +++ /dev/null @@ -1,20 +0,0 @@ -odoo.define('pos_restaurant.OrderSelector', function(require) { - 'use strict'; - - const OrderSelector = require('point_of_sale.OrderSelector'); - const Registries = require('point_of_sale.Registries'); - - const PosResOrderSelector = OrderSelector => - class extends OrderSelector { - get currentTable() { - return this.env.pos.table; - } - get backToFloorButtonIsShown() { - return this.env.pos.config.iface_floorplan && this.currentTable; - } - }; - - Registries.Component.extend(OrderSelector, PosResOrderSelector); - - return OrderSelector; -}); diff --git a/addons/pos_restaurant/static/src/js/ChromeWidgets/TicketButton.js b/addons/pos_restaurant/static/src/js/ChromeWidgets/TicketButton.js new file mode 100644 index 00000000000..1e66bf91352 --- /dev/null +++ b/addons/pos_restaurant/static/src/js/ChromeWidgets/TicketButton.js @@ -0,0 +1,33 @@ +odoo.define('pos_restaurant.TicketButton', function (require) { + 'use strict'; + + const TicketButton = require('point_of_sale.TicketButton'); + const Registries = require('point_of_sale.Registries'); + const { posbus } = require('point_of_sale.utils'); + + const PosResTicketButton = (TicketButton) => + class extends TicketButton { + mounted() { + posbus.on('table-set', this, this.render); + } + willUnmount() { + posbus.off('table-set', this); + } + /** + * 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. + */ + get count() { + if (!this.env.pos || !this.env.pos.config) return 0; + if (this.env.pos.config.iface_floorplan && !this.env.pos.table) { + return this.env.pos.get('orders').models.length; + } else { + return super.count; + } + } + }; + + Registries.Component.extend(TicketButton, PosResTicketButton); + + return TicketButton; +}); diff --git a/addons/pos_restaurant/static/src/js/Screens/FloorScreen/FloorScreen.js b/addons/pos_restaurant/static/src/js/Screens/FloorScreen/FloorScreen.js index 276663cf57c..1bf06c838f5 100644 --- a/addons/pos_restaurant/static/src/js/Screens/FloorScreen/FloorScreen.js +++ b/addons/pos_restaurant/static/src/js/Screens/FloorScreen/FloorScreen.js @@ -171,12 +171,12 @@ odoo.define('pos_restaurant.FloorScreen', function (require) { } } } - async _onSelectTable(event) { + _onSelectTable(event) { const table = event.detail; if (this.state.isEditMode) { this.state.selectedTableId = table.id; } else { - await this.env.pos.set_table(table); + this.env.pos.set_table(table); } } _onDeselectTable() { diff --git a/addons/pos_restaurant/static/src/js/Screens/OrderManagementScreen/OrderManagementScreen.js b/addons/pos_restaurant/static/src/js/Screens/OrderManagementScreen/OrderManagementScreen.js index e2a1ce65dce..8753be25753 100644 --- a/addons/pos_restaurant/static/src/js/Screens/OrderManagementScreen/OrderManagementScreen.js +++ b/addons/pos_restaurant/static/src/js/Screens/OrderManagementScreen/OrderManagementScreen.js @@ -12,10 +12,9 @@ odoo.define('pos_restaurant.OrderManagementScreen', function (require) { _setOrder(order) { if (this.env.pos.config.module_pos_restaurant) { const currentOrder = this.env.pos.get_order(); + this.env.pos.set_table(order.table, order); if (currentOrder && currentOrder.uid === order.uid) { this.close(); - } else { - this.env.pos.set_table(order.table, order); } } else { super._setOrder(order); 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 689c3bf40ca..5909292e0db 100644 --- a/addons/pos_restaurant/static/src/js/Screens/ReceiptScreen/ReceiptScreen.js +++ b/addons/pos_restaurant/static/src/js/Screens/ReceiptScreen/ReceiptScreen.js @@ -20,6 +20,18 @@ odoo.define('pos_restaurant.ReceiptScreen', function(require) { return super.nextScreen; } } + /** + * If this order is synced to/from the server, then the draft needs to be deleted + * after the order is paid and the receipt screen is exited via 'Next Order' button. + * Thus, we set this order to be removed from server. Note that only the draft version + * is deleted if we trace the algorithm. + */ + orderDone() { + if (this.env.pos.config.iface_floorplan) { + this.env.pos.db.set_order_to_remove_from_server(this.currentOrder); + } + super.orderDone(); + } }; Registries.Component.extend(ReceiptScreen, PosResReceiptScreen); 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 2390e35f7c4..f44af5bff7a 100644 --- a/addons/pos_restaurant/static/src/js/Screens/SplitBillScreen/SplitBillScreen.js +++ b/addons/pos_restaurant/static/src/js/Screens/SplitBillScreen/SplitBillScreen.js @@ -55,7 +55,7 @@ odoo.define('pos_restaurant.SplitBillScreen', function(require) { } else { this._setQuantityOnCurrentOrder(); - this.newOrder.set_screen_data('screen', { name: 'PaymentScreen' }); + this.newOrder.set_screen_data({ name: 'PaymentScreen' }); // for the kitchen printer we assume that everything // has already been sent to the kitchen before splitting @@ -72,7 +72,7 @@ odoo.define('pos_restaurant.SplitBillScreen', function(require) { this.newOrder.set_customer_count(1); const newCustomerCount = this.currentOrder.get_customer_count() - 1; this.currentOrder.set_customer_count(newCustomerCount || 1); - this.currentOrder.set_screen_data('screen', { name: 'ProductScreen' }); + this.currentOrder.set_screen_data({ name: 'ProductScreen' }); this.env.pos.get('orders').add(this.newOrder); this.env.pos.set('selectedOrder', this.newOrder); diff --git a/addons/pos_restaurant/static/src/js/Screens/TicketScreen.js b/addons/pos_restaurant/static/src/js/Screens/TicketScreen.js new file mode 100644 index 00000000000..2d5c3e004b2 --- /dev/null +++ b/addons/pos_restaurant/static/src/js/Screens/TicketScreen.js @@ -0,0 +1,54 @@ +odoo.define('pos_restaurant.TicketScreen', function (require) { + 'use strict'; + + const TicketScreen = require('point_of_sale.TicketScreen'); + const Registries = require('point_of_sale.Registries'); + const { posbus } = require('point_of_sale.utils'); + + const PosResTicketScreen = (TicketScreen) => + class extends TicketScreen { + close() { + super.close(); + if (!this.env.pos.config.iface_floorplan) { + // Make sure the 'table-set' event is triggered + // to properly rerender the components that listens to it. + posbus.trigger('table-set'); + } + } + getTable(order) { + return `${order.table.floor.name} (${order.table.name})`; + } + get _searchFields() { + if (!this.env.pos.config.iface_floorplan) { + return super._searchFields; + } + return Object.assign({}, super._searchFields, { + Table: (order) => `${order.table.floor.name} (${order.table.name})`, + }); + } + _setOrder(order) { + if (!this.env.pos.config.iface_floorplan) { + super._setOrder(order); + } else if (order !== this.env.pos.get_order()) { + // Only call set_table if the order is not the same as the current order. + // This is to prevent syncing to the server because syncing is only intended + // when going back to the floorscreen or opening a table. + this.env.pos.set_table(order.table, order); + } + } + get showNewTicketButton() { + return this.env.pos.config.iface_floorplan ? Boolean(this.env.pos.table) : super.showNewTicketButton; + } + get orderList() { + if (this.env.pos.table) { + return super.orderList; + } else { + return this.env.pos.get('orders').models; + } + } + }; + + Registries.Component.extend(TicketScreen, PosResTicketScreen); + + return TicketScreen; +}); diff --git a/addons/pos_restaurant/static/src/js/floors.js b/addons/pos_restaurant/static/src/js/floors.js index b6614c07ebe..51ded242c63 100644 --- a/addons/pos_restaurant/static/src/js/floors.js +++ b/addons/pos_restaurant/static/src/js/floors.js @@ -2,6 +2,8 @@ odoo.define('pos_restaurant.floors', function (require) { "use strict"; var models = require('point_of_sale.models'); +const { Gui } = require('point_of_sale.Gui'); +const { posbus } = require('point_of_sale.utils'); // At POS Startup, load the floors, and add them to the pos model models.load_models({ @@ -213,7 +215,12 @@ models.PosModel = models.PosModel.extend({ this._get_from_server(table.id).then(function (server_orders) { var orders = self.get_order_list(); orders.forEach(function(order){ - if (order.server_id){ + const screen = order.get_screen_data(); + // Only remove the 'Receipt' status order when 'Next Order' + // from the receipt screen is clicked. We are bypassing the + // removal of paid order here to make sure those orders are + // still in the tickets list. + if (order.server_id && screen.name !== 'ReceiptScreen'){ self.get("orders").remove(order); order.destroy(); } @@ -257,6 +264,7 @@ models.PosModel = models.PosModel.extend({ if(!table){ this.sync_from_server(table, this.get_order_list(), this.get_order_with_uid()); this.set_order(null); + this.table = null; } else if (this.order_to_transfer_to_different_table) { var order_ids = this.get_order_with_uid(); @@ -269,6 +277,7 @@ models.PosModel = models.PosModel.extend({ this.table = table; this.sync_to_server(table, order); } + posbus.trigger('table-set'); }, // if we have tables, we do not load a default order, as the default order will be @@ -284,9 +293,12 @@ models.PosModel = models.PosModel.extend({ add_new_order: function() { if (this.config.iface_floorplan) { if (this.table) { - return _super_posmodel.add_new_order.call(this); + return _super_posmodel.add_new_order.apply(this, arguments); } else { - console.warn("WARNING: orders cannot be created when there is no active table in restaurant mode"); + Gui.showPopup('ConfirmPopup', { + title: 'Unable to create order', + body: 'Orders cannot be created when there is no active table in restaurant mode', + }); return undefined; } } else { @@ -298,7 +310,7 @@ models.PosModel = models.PosModel.extend({ // get the list of unpaid orders (associated to the current table) get_order_list: function() { var orders = _super_posmodel.get_order_list.call(this); - if (!this.config.iface_floorplan) { + if (!(this.config && this.config.iface_floorplan)) { return orders; } else if (!this.table) { return []; @@ -345,7 +357,7 @@ models.PosModel = models.PosModel.extend({ this.db.set_order_to_remove_from_server(removed_order); } if( (reason === 'abandon' || removed_order.temporary) && order_list.length > 0){ - this.set_order(order_list[index] || order_list[order_list.length -1]); + this.set_order(order_list[index] || order_list[order_list.length - 1], { silent: true }); } else if (order_list.length === 0) { this.set_order(null); } diff --git a/addons/pos_restaurant/static/src/xml/Chrome.xml b/addons/pos_restaurant/static/src/xml/Chrome.xml new file mode 100644 index 00000000000..86032c07017 --- /dev/null +++ b/addons/pos_restaurant/static/src/xml/Chrome.xml @@ -0,0 +1,10 @@ +<?xml version="1.0" encoding="UTF-8"?> +<templates id="template" xml:space="preserve"> + + <t t-name="Chrome" t-inherit="point_of_sale.Chrome" t-inherit-mode="extension" owl="1"> + <xpath expr="//div[hasclass('search-bar-portal')]" position="before"> + <BackToFloorButton /> + </xpath> + </t> + +</templates> diff --git a/addons/pos_restaurant/static/src/xml/ChromeWidgets/BackToFloorButton.xml b/addons/pos_restaurant/static/src/xml/ChromeWidgets/BackToFloorButton.xml index 1f36d2763f3..2b5c865ca18 100644 --- a/addons/pos_restaurant/static/src/xml/ChromeWidgets/BackToFloorButton.xml +++ b/addons/pos_restaurant/static/src/xml/ChromeWidgets/BackToFloorButton.xml @@ -2,7 +2,7 @@ <templates id="template" xml:space="preserve"> <t t-name="BackToFloorButton" owl="1"> - <span class="order-button floor-button"> + <span t-if="hasTable" class="order-button floor-button" t-on-click="backToFloorScreen"> <i class="fa fa-angle-double-left" role="img" aria-label="Back to floor" title="Back to floor" /> <span> </span> <span t-esc="floor.name" /> @@ -13,6 +13,7 @@ <span> )</span> </span> </span> + <span t-else=""></span> </t> </templates> diff --git a/addons/pos_restaurant/static/src/xml/ChromeWidgets/OrderSelector.xml b/addons/pos_restaurant/static/src/xml/ChromeWidgets/OrderSelector.xml deleted file mode 100644 index 824ff26bcee..00000000000 --- a/addons/pos_restaurant/static/src/xml/ChromeWidgets/OrderSelector.xml +++ /dev/null @@ -1,20 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<templates id="template" xml:space="preserve"> - - <t t-name="OrderSelector" t-inherit="point_of_sale.OrderSelector" t-inherit-mode="extension" owl="1"> - <xpath expr="//div[hasclass('order-selector')]//span[hasclass('orders')]//t" position="before"> - <BackToFloorButton t-if="backToFloorButtonIsShown" table="currentTable" /> - </xpath> - <xpath expr="//span[hasclass('order-sequence')]" position="replace"> - <span class="order-sequence"> - <t t-if="order.server_id and env.pos.pos_session.login_number != order.uid.split('-')[1]"> - <t t-esc="order.uid.substring(order.uid.indexOf('-') +1)" /> - </t> - <t t-else=""> - <t t-esc="order.sequence_number" /> - </t> - </span> - </xpath> - </t> - -</templates> diff --git a/addons/pos_restaurant/static/src/xml/Screens/TicketScreen.xml b/addons/pos_restaurant/static/src/xml/Screens/TicketScreen.xml new file mode 100644 index 00000000000..7430ee1a6b7 --- /dev/null +++ b/addons/pos_restaurant/static/src/xml/Screens/TicketScreen.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<templates id="template" xml:space="preserve"> + + <t t-name="TicketScreen" t-inherit="point_of_sale.TicketScreen" t-inherit-mode="extension" owl="1"> + <xpath expr="//div[hasclass('header-row')]//div[@name='delete']" position="before"> + <div t-if="env.pos.config.iface_floorplan" class="col start" name="table">Table</div> + </xpath> + <xpath expr="//div[hasclass('order-row')]//div[@name='delete']" position="before"> + <div t-if="env.pos.config.iface_floorplan" class="col start" name="table"> + <t t-esc="getTable(order)"></t> + </div> + </xpath> + </t> + +</templates> diff --git a/addons/pos_restaurant/static/tests/tours/OrderManagementScreen.tour.js b/addons/pos_restaurant/static/tests/tours/OrderManagementScreen.tour.js index 2a198c9e7ab..5cedaba0a14 100644 --- a/addons/pos_restaurant/static/tests/tours/OrderManagementScreen.tour.js +++ b/addons/pos_restaurant/static/tests/tours/OrderManagementScreen.tour.js @@ -11,6 +11,7 @@ odoo.define('pos_restaurant.tour.OrderManagementScreen', function (require) { } = require('point_of_sale.tour.OrderManagementScreenTourMethods'); const { FloorScreen } = require('pos_restaurant.tour.FloorScreenTourMethods'); const { ProductScreen } = require('pos_restaurant.tour.ProductScreenTourMethods'); + const { TicketScreen } = require('point_of_sale.tour.TicketScreenTourMethods'); const { getSteps, startSteps } = require('point_of_sale.tour.utils'); var Tour = require('web_tour.tour'); @@ -36,7 +37,8 @@ odoo.define('pos_restaurant.tour.OrderManagementScreen', function (require) { ['Water', '3', '4'], ['Minute Maid', '5', '6'] ); - Chrome.do.newOrder(); + Chrome.do.clickTicketButton(); + TicketScreen.do.clickNewTicket(); ProductScreen.exec.addMultiOrderlines(['Coca-Cola', '1', '2'], ['Minute Maid', '5', '6']); Chrome.do.backToFloor(); @@ -47,7 +49,8 @@ odoo.define('pos_restaurant.tour.OrderManagementScreen', function (require) { ['Water', '9', '10'], ['Minute Maid', '11', '12'] ); - Chrome.do.newOrder(); + Chrome.do.clickTicketButton(); + TicketScreen.do.clickNewTicket(); ProductScreen.exec.addMultiOrderlines(['Coca-Cola', '13', '14'], ['Minute Maid', '15', '16']); Chrome.do.backToFloor(); diff --git a/addons/pos_restaurant/static/tests/tours/SplitBillScreen.tour.js b/addons/pos_restaurant/static/tests/tours/SplitBillScreen.tour.js index 82e783dbcc7..9eb138bbb9b 100644 --- a/addons/pos_restaurant/static/tests/tours/SplitBillScreen.tour.js +++ b/addons/pos_restaurant/static/tests/tours/SplitBillScreen.tour.js @@ -6,6 +6,7 @@ odoo.define('pos_restaurant.tour.SplitBillScreen', function (require) { const { FloorScreen } = require('pos_restaurant.tour.FloorScreenTourMethods'); const { ProductScreen } = require('pos_restaurant.tour.ProductScreenTourMethods'); const { SplitBillScreen } = require('pos_restaurant.tour.SplitBillScreenTourMethods'); + const { TicketScreen } = require('point_of_sale.tour.TicketScreenTourMethods'); const { getSteps, startSteps } = require('point_of_sale.tour.utils'); var Tour = require('web_tour.tour'); @@ -42,7 +43,8 @@ odoo.define('pos_restaurant.tour.SplitBillScreen', function (require) { ProductScreen.do.clickOrderline('Coca-Cola', '1.0') // go back to the original order and see if the order is changed - Chrome.do.selectOrder('1'); + Chrome.do.clickTicketButton(); + TicketScreen.do.selectOrder('-0001'); ProductScreen.do.clickOrderline('Water', '2.0') ProductScreen.do.clickOrderline('Minute Maid', '3.0') diff --git a/addons/pos_restaurant/static/tests/tours/TicketScreen.tour.js b/addons/pos_restaurant/static/tests/tours/TicketScreen.tour.js new file mode 100644 index 00000000000..790ae060777 --- /dev/null +++ b/addons/pos_restaurant/static/tests/tours/TicketScreen.tour.js @@ -0,0 +1,44 @@ +odoo.define('pos_restaurant.tour.TicketScreen', function (require) { + 'use strict'; + + const { ProductScreen } = require('point_of_sale.tour.ProductScreenTourMethods'); + const { FloorScreen } = require('pos_restaurant.tour.FloorScreenTourMethods'); + const { TicketScreen } = require('point_of_sale.tour.TicketScreenTourMethods'); + const { Chrome } = require('pos_restaurant.tour.ChromeTourMethods'); + const { getSteps, startSteps } = require('point_of_sale.tour.utils'); + var Tour = require('web_tour.tour'); + + startSteps(); + + // New Ticket button should not be in the ticket screen if no table is selected. + Chrome.do.clickTicketButton(); + TicketScreen.check.noNewTicketButton(); + TicketScreen.do.clickDiscard(); + + // Deleting the last order in the table brings back to floorscreen + FloorScreen.do.clickTable('T4'); + Chrome.do.clickTicketButton(); + TicketScreen.check.nthRowContains(2, '-0001'); + TicketScreen.do.deleteOrder('-0001'); + FloorScreen.check.isShown(); + + // Create 2 items in a table. From floorscreen, delete 1 item. Then select the other item. + // Correct order and screen should be displayed and the BackToFloorButton is shown. + FloorScreen.do.clickTable('T2'); + ProductScreen.exec.addOrderline('Minute Maid', '1', '2'); + ProductScreen.check.totalAmountIs('2.0'); + Chrome.do.clickTicketButton(); + TicketScreen.do.clickNewTicket(); + ProductScreen.exec.addOrderline('Coca-Cola', '2', '2'); + ProductScreen.check.totalAmountIs('4.0'); + Chrome.do.backToFloor(); + FloorScreen.check.orderCountSyncedInTableIs('T2', '2'); + Chrome.do.clickTicketButton(); + TicketScreen.do.deleteOrder('-0003'); + Chrome.do.confirmPopup(); + TicketScreen.do.selectOrder('-0002'); + ProductScreen.check.totalAmountIs('2.0'); + Chrome.check.backToFloorTextIs('Main Floor', 'T2'); + + Tour.register('PosResTicketScreenTour', { test: true, url: '/pos/web' }, getSteps()); +}); diff --git a/addons/pos_restaurant/static/tests/tours/helpers/FloorScreenTourMethods.js b/addons/pos_restaurant/static/tests/tours/helpers/FloorScreenTourMethods.js index 6895dc3e257..b6e614357f0 100644 --- a/addons/pos_restaurant/static/tests/tours/helpers/FloorScreenTourMethods.js +++ b/addons/pos_restaurant/static/tests/tours/helpers/FloorScreenTourMethods.js @@ -72,9 +72,7 @@ odoo.define('pos_restaurant.tour.FloorScreenTourMethods', function (require) { return [ { content: `change shape to '${shape}'`, - trigger: `.edit-button .button-option${ - shape === 'round' ? '.square' : '.round' - }`, + trigger: `.edit-button .button-option${shape === 'round' ? '.square' : '.round'}`, }, ]; } @@ -122,6 +120,23 @@ odoo.define('pos_restaurant.tour.FloorScreenTourMethods', function (require) { { content: `number of seats in table '${table}' is '${val}'`, trigger: `.floor-map .tables .table .label:contains("${table}") ~ .table-seats:contains("${val}")`, + run: function () {}, + }, + ]; + } + orderCountSyncedInTableIs(table, count) { + return [ + { + trigger: `.floor-map .table .order-count:contains("${count}") ~ .label:contains("${table}")`, + run: function () {}, + }, + ]; + } + isShown() { + return [ + { + trigger: '.floor-map', + run: function () {}, }, ]; } diff --git a/addons/pos_restaurant/static/tests/tours/pos_restaurant.js b/addons/pos_restaurant/static/tests/tours/pos_restaurant.js index 8d5e8f0a80d..252e9834e63 100644 --- a/addons/pos_restaurant/static/tests/tours/pos_restaurant.js +++ b/addons/pos_restaurant/static/tests/tours/pos_restaurant.js @@ -1,252 +1,108 @@ odoo.define('pos_reataurant.tour.synchronized_table_management', function (require) { - "use strict"; - - var Tour = require("web_tour.tour"); - - function verify_order_total(total_str) { - return [{ - content: 'order total contains ' + total_str, - trigger: '.order .total .value:contains("' + total_str + '")', - run: function () {}, // it's a check - }]; - } - - function verify_orders_synced(order_count) { - return [{ - content: "check synced", - trigger: ".order-sequence", - run: function() { - var orders = $('.order-sequence'); - if (orders.length === order_count) { - return - } else { - throw `sync failed 'there should be ${order_count} orders, however, ${orders.length} orders are displayed' `; - } - }, - }]; - } - - function add_product_to_order(product_name) { - return [{ - content: 'buy ' + product_name, - trigger: '.product-list .product-name:contains("' + product_name + '")', - }, { - content: 'the ' + product_name + ' have been added to the order', - trigger: '.order .product-name:contains("' + product_name + '")', - run: function () {}, // it's a check - }]; - } - - function generate_keypad_steps(amount_str, keypad_selector) { - var i, steps = [], current_char; - for (i = 0; i < amount_str.length; ++i) { - current_char = amount_str[i]; - steps.push({ - content: 'press ' + current_char + ' on payment keypad', - trigger: keypad_selector + ' .input-button:contains("' + current_char + '"):visible' - }); - } - - return steps; - } - - function generate_payment_screen_keypad_steps(amount_str) { - return generate_keypad_steps(amount_str, '.payment-numpad'); - } - - function generate_product_screen_keypad_steps(amount_str) { - return generate_keypad_steps(amount_str, '.numpad'); - } - - function goto_payment_screen_and_select_payment_method() { - return [{ - content: "go to payment screen", - trigger: '.button.pay', - }, { - content: "pay with cash", - trigger: '.paymentmethod:contains("Cash")', - }]; - } - - function open_table(table_id, order_count) { - order_count = order_count || null; - var steps = [{ - content: 'open table ' + table_id, - trigger: '.label:contains(' + table_id +')', - run: 'click', - }]; - if (order_count !== null){ - steps = steps.concat(verify_orders_synced(order_count)); - } - return steps; - } - - function transfer_order_to_table(table_id, order_uid) { - return [{ - content: 'Click transfer button', - trigger: '.control-button:contains("Transfer")', - run: 'click', - }, { - content: 'Transfer order to table ' + table_id, - trigger: '.label:contains(' + table_id +')', - run: 'click', - }, { - content: 'Check if order ' + order_uid + ' is open after transfer', - trigger: '.order-button.selected .order-sequence:contains("' + order_uid + '")', - run: function(){} // Check - }]; - } - - function finish_order() { - var steps = [{ - content: "validate the order", - trigger: '.payment-screen .button.next:visible', - }]; - steps = steps.concat([{ - content: "next order", - trigger: '.receipt-screen .button.next:visible', - }]); - return steps; - } - - /* pos_restaurant_sync - * - * Run on new session. - */ - var steps = [{ - content: 'waiting for loading to finish', - trigger: 'body:not(:has(.loader))', - run: function () {}, - }] - - - steps = steps.concat(open_table('T5')); - - steps = steps.concat(add_product_to_order('Coca-Cola')); - steps = steps.concat(add_product_to_order('Water')); - steps = steps.concat(verify_order_total('4.40')); - steps = steps.concat([{ - content: 'start new order', - trigger: '.neworder-button', - run: 'click', - }]); - steps = steps.concat(add_product_to_order('Coca-Cola')); - steps = steps.concat(add_product_to_order('Minute Maid')); - steps = steps.concat(verify_order_total('4.40')); - steps = steps.concat(goto_payment_screen_and_select_payment_method()); - steps = steps.concat(generate_payment_screen_keypad_steps('6.05')); - steps = steps.concat(finish_order()); - steps = steps.concat(open_table('T5', 1)); - steps = steps.concat(verify_order_total('4.40')); - steps = steps.concat([{ - content: 'start new order', - trigger: '.neworder-button', - run: 'click', - }]); - steps = steps.concat(add_product_to_order('Coca-Cola')); - steps = steps.concat(add_product_to_order('Minute Maid')); - steps = steps.concat([{ - content: 'back to floor', - trigger: '.floor-button', - run: 'click', - }]); - steps = steps.concat(open_table('T5', 2)); - steps = steps.concat([{ - content: 'delete order', - trigger: '.deleteorder-button', - run: 'click', - }, { - content: 'confirm delete', - trigger: '.button.confirm', - run: 'click', - }, { - content: 'back to floor', - trigger: '.floor-button', - run: 'click', - }, { - content: 'back to floor', - trigger: '.oe_status .js_connected', - run: function() {}, - }]); - steps = steps.concat(open_table('T5', 1)); - - Tour.register('pos_restaurant_sync', { test: true, url: '/pos/web' }, steps); - + 'use strict'; + + const { PaymentScreen } = require('point_of_sale.tour.PaymentScreenTourMethods'); + const { ReceiptScreen } = require('point_of_sale.tour.ReceiptScreenTourMethods'); + const { Chrome } = require('pos_restaurant.tour.ChromeTourMethods'); + const { FloorScreen } = require('pos_restaurant.tour.FloorScreenTourMethods'); + const { ProductScreen } = require('pos_restaurant.tour.ProductScreenTourMethods'); + const { TicketScreen } = require('point_of_sale.tour.TicketScreenTourMethods'); + const { getSteps, startSteps } = require('point_of_sale.tour.utils'); + const Tour = require('web_tour.tour'); + + startSteps(); + + FloorScreen.do.clickTable('T5'); + + // Create first order + ProductScreen.do.clickDisplayedProduct('Coca-Cola'); + ProductScreen.check.selectedOrderlineHas('Coca-Cola'); + ProductScreen.do.clickDisplayedProduct('Water'); + ProductScreen.check.selectedOrderlineHas('Water'); + ProductScreen.check.totalAmountIs('4.40'); + + // Create 2nd order (paid) + Chrome.do.clickTicketButton(); + TicketScreen.do.clickNewTicket(); + ProductScreen.do.clickDisplayedProduct('Coca-Cola'); + ProductScreen.check.selectedOrderlineHas('Coca-Cola'); + ProductScreen.do.clickDisplayedProduct('Minute Maid'); + ProductScreen.check.selectedOrderlineHas('Minute Maid'); + ProductScreen.check.totalAmountIs('4.40'); + ProductScreen.do.clickPayButton(); + PaymentScreen.do.clickPaymentMethod('Cash'); + PaymentScreen.do.clickValidate(); + ReceiptScreen.do.clickNextOrder(); + + // After clicking next order, floor screen is shown. + // It should have 1 as number of draft synced order. + FloorScreen.check.orderCountSyncedInTableIs('T5', '1'); + FloorScreen.do.clickTable('T5'); + ProductScreen.check.totalAmountIs('4.40'); + + // Create another draft order and go back to floor + Chrome.do.clickTicketButton(); + TicketScreen.do.clickNewTicket(); + ProductScreen.do.clickDisplayedProduct('Coca-Cola'); + ProductScreen.check.selectedOrderlineHas('Coca-Cola'); + ProductScreen.do.clickDisplayedProduct('Minute Maid'); + ProductScreen.check.selectedOrderlineHas('Minute Maid'); + Chrome.do.backToFloor(); + + // At floor screen, there should be 2 synced draft orders + FloorScreen.check.orderCountSyncedInTableIs('T5', '2'); + + // Delete the first order then go back to floor + FloorScreen.do.clickTable('T5'); + ProductScreen.check.isShown(); + Chrome.do.clickTicketButton(); + TicketScreen.do.deleteOrder('-0001'); + Chrome.do.confirmPopup(); + TicketScreen.do.selectOrder('-0003'); + Chrome.do.backToFloor(); + + // There should be 1 synced draft order. + FloorScreen.check.orderCountSyncedInTableIs('T5', '1'); + + Tour.register('pos_restaurant_sync', { test: true, url: '/pos/web' }, getSteps()); + + startSteps(); /* pos_restaurant_sync_second_login * * This tour should be run after the first tour is done. */ - var steps = [{ - content: 'waiting for loading to finish', - trigger: 'body:not(:has(.loader))', - run: function () {}, - }]; - steps = steps.concat(open_table('T5', 1)); - steps = steps.concat(verify_order_total('4.40')); + + // There is one draft synced order from the previous tour + FloorScreen.check.orderCountSyncedInTableIs('T5', '1'); + FloorScreen.do.clickTable('T5'); + ProductScreen.check.totalAmountIs('4.40'); // Test transfering an order - steps = steps.concat(transfer_order_to_table('T4', '002-0001')); + ProductScreen.do.clickTransferButton(); + FloorScreen.do.clickTable('T4'); // Test if products still get merged after transfering the order - steps = steps.concat(add_product_to_order('Coca-Cola')); - steps = steps.concat({ - content: 'check the order-line for Coca-Cola has 2 Units', - trigger: '.orderlines:has(.orderline .product-name:contains("Coca-Cola")) .info-list:contains("2.000")', - run: function () {}, - }) - steps = steps.concat(generate_product_screen_keypad_steps('1')); - - steps = steps.concat(goto_payment_screen_and_select_payment_method()); - steps = steps.concat(generate_payment_screen_keypad_steps('4.4')); - steps = steps.concat(finish_order()); - steps = steps.concat(open_table('T2')); - - // Test transfering an empty order - steps = steps.concat(transfer_order_to_table('T4', '2')); - - steps = steps.concat(add_product_to_order('Coca-Cola')); - steps = steps.concat(verify_order_total('2.20')); - - // Take a synced order with products, remove the products - // and check if the order is still available in the front-end - steps = steps.concat([{ - content: 'back to floor', - trigger: '.floor-button', - run: 'click', - }]); - steps = steps.concat(open_table('T4', 1)); - steps = steps.concat([{ - content: 'click backspace to set quantity to 0', - trigger: '.numpad-backspace', - run: 'click', - }, { - content: 'click backspace to remove line', - trigger: '.numpad-backspace', - run: 'click', - }]); - steps = steps.concat([{ - content: 'back to floor', - trigger: '.floor-button', - run: 'click', - }]); - steps = steps.concat(open_table('T4', 1)); - steps = steps.concat(add_product_to_order('Coca-Cola')); - steps = steps.concat(verify_order_total('2.20')); - steps = steps.concat([{ - content: 'back to floor', - trigger: '.floor-button', - run: 'click', - }, { - content: 'check if in floor screen', - trigger: '.pos-content .floor-screen', - run: function() {}, - }, { - content: 'wait for sync to finish', - trigger: '.oe_status .js_connected', - run: function() {}, - }]); - - Tour.register('pos_restaurant_sync_second_login', { test: true, url: '/pos/web' }, steps); - + ProductScreen.do.clickDisplayedProduct('Coca-Cola'); + ProductScreen.check.selectedOrderlineHas('Coca-Cola', '2.0'); + ProductScreen.check.totalAmountIs('6.60'); + ProductScreen.do.pressNumpad('1'); + ProductScreen.check.totalAmountIs('4.40'); + ProductScreen.do.clickPayButton(); + PaymentScreen.do.clickPaymentMethod('Cash'); + PaymentScreen.do.clickValidate(); + ReceiptScreen.do.clickNextOrder(); + // At this point, there are no draft orders. + + FloorScreen.do.clickTable('T2'); + ProductScreen.check.isShown(); + ProductScreen.check.orderIsEmpty(); + ProductScreen.do.clickTransferButton(); + FloorScreen.do.clickTable('T4'); + ProductScreen.do.clickDisplayedProduct('Coca-Cola'); + ProductScreen.check.totalAmountIs('2.20'); + Chrome.do.backToFloor(); + FloorScreen.check.orderCountSyncedInTableIs('T4', '1'); + + Tour.register('pos_restaurant_sync_second_login', { test: true, url: '/pos/web' }, getSteps()); }); |
