mirror of
https://github.com/bringout/oca-ocb-pos.git
synced 2026-04-24 01:22:04 +02:00
19.0 vanilla
This commit is contained in:
parent
6e54c1af6c
commit
3ca647e428
1087 changed files with 132065 additions and 108499 deletions
|
|
@ -1,62 +0,0 @@
|
|||
odoo.define('pos_restaurant.tour.ControlButtons', function (require) {
|
||||
'use strict';
|
||||
|
||||
const { TextAreaPopup } = require('point_of_sale.tour.TextAreaPopupTourMethods');
|
||||
const { NumberPopup } = require('point_of_sale.tour.NumberPopupTourMethods');
|
||||
const { Chrome } = require('pos_restaurant.tour.ChromeTourMethods');
|
||||
const { FloorScreen } = require('pos_restaurant.tour.FloorScreenTourMethods');
|
||||
const { ProductScreen } = require('pos_restaurant.tour.ProductScreenTourMethods');
|
||||
const { SplitBillScreen } = require('pos_restaurant.tour.SplitBillScreenTourMethods');
|
||||
const { BillScreen } = require('pos_restaurant.tour.BillScreenTourMethods');
|
||||
const { getSteps, startSteps } = require('point_of_sale.tour.utils');
|
||||
var Tour = require('web_tour.tour');
|
||||
|
||||
// signal to start generating steps
|
||||
// when finished, steps can be taken from getSteps
|
||||
startSteps();
|
||||
|
||||
// Test TransferOrderButton
|
||||
FloorScreen.do.clickTable('T2');
|
||||
ProductScreen.exec.addOrderline('Water', '5', '2', '10.0');
|
||||
ProductScreen.do.clickTransferButton();
|
||||
FloorScreen.do.clickTable('T4');
|
||||
ProductScreen.do.clickOrderline('Water', '5', '2');
|
||||
Chrome.do.backToFloor();
|
||||
FloorScreen.do.clickTable('T2');
|
||||
ProductScreen.check.orderIsEmpty();
|
||||
Chrome.do.backToFloor();
|
||||
FloorScreen.do.clickTable('T4');
|
||||
ProductScreen.do.clickOrderline('Water', '5', '2');
|
||||
|
||||
// Test SplitBillButton
|
||||
ProductScreen.do.clickSplitBillButton();
|
||||
SplitBillScreen.do.clickBack();
|
||||
|
||||
// Test OrderlineNoteButton
|
||||
ProductScreen.do.clickNoteButton();
|
||||
TextAreaPopup.check.isShown();
|
||||
TextAreaPopup.do.inputText('test note');
|
||||
TextAreaPopup.do.clickConfirm();
|
||||
ProductScreen.check.orderlineHasNote('Water', '5', 'test note');
|
||||
ProductScreen.exec.addOrderline('Water', '8', '1', '8.0');
|
||||
|
||||
// Test PrintBillButton
|
||||
ProductScreen.do.clickPrintBillButton();
|
||||
BillScreen.check.isShown();
|
||||
BillScreen.do.clickOk();
|
||||
|
||||
// Test GuestButton
|
||||
ProductScreen.do.clickGuestButton();
|
||||
NumberPopup.do.pressNumpad('1 5');
|
||||
NumberPopup.check.inputShownIs('15');
|
||||
NumberPopup.do.clickConfirm();
|
||||
ProductScreen.check.guestNumberIs('15')
|
||||
|
||||
ProductScreen.do.clickGuestButton();
|
||||
NumberPopup.do.pressNumpad('5');
|
||||
NumberPopup.check.inputShownIs('5');
|
||||
NumberPopup.do.clickConfirm();
|
||||
ProductScreen.check.guestNumberIs('5')
|
||||
|
||||
Tour.register('ControlButtonsTour', { test: true, url: '/pos/ui' }, getSteps());
|
||||
});
|
||||
|
|
@ -1,118 +0,0 @@
|
|||
odoo.define('pos_restaurant.tour.FloorScreen', function (require) {
|
||||
'use strict';
|
||||
|
||||
const { Chrome } = require('pos_restaurant.tour.ChromeTourMethods');
|
||||
const { FloorScreen } = require('pos_restaurant.tour.FloorScreenTourMethods');
|
||||
const { TextInputPopup } = require('point_of_sale.tour.TextInputPopupTourMethods');
|
||||
const { NumberPopup } = require('point_of_sale.tour.NumberPopupTourMethods');
|
||||
const { ProductScreen } = require('pos_restaurant.tour.ProductScreenTourMethods');
|
||||
const { getSteps, startSteps } = require('point_of_sale.tour.utils');
|
||||
var Tour = require('web_tour.tour');
|
||||
|
||||
// signal to start generating steps
|
||||
// when finished, steps can be taken from getSteps
|
||||
startSteps();
|
||||
|
||||
// check floors if they contain their corresponding tables
|
||||
FloorScreen.check.selectedFloorIs('Main Floor');
|
||||
FloorScreen.check.hasTable('T2');
|
||||
FloorScreen.check.hasTable('T4');
|
||||
FloorScreen.check.hasTable('T5');
|
||||
FloorScreen.do.clickFloor('Second Floor');
|
||||
FloorScreen.check.hasTable('T3');
|
||||
FloorScreen.check.hasTable('T1');
|
||||
|
||||
// clicking table in active mode does not open product screen
|
||||
// instead, table is selected
|
||||
FloorScreen.do.clickEdit();
|
||||
FloorScreen.check.editModeIsActive(true);
|
||||
FloorScreen.do.clickTable('T3');
|
||||
FloorScreen.check.selectedTableIs('T3');
|
||||
FloorScreen.do.clickTable('T1');
|
||||
FloorScreen.check.selectedTableIs('T1');
|
||||
|
||||
// switching floor in edit mode deactivates edit mode
|
||||
FloorScreen.do.clickFloor('Main Floor');
|
||||
FloorScreen.check.editModeIsActive(false);
|
||||
FloorScreen.do.clickEdit();
|
||||
FloorScreen.check.editModeIsActive(true);
|
||||
|
||||
// test add table
|
||||
FloorScreen.do.clickAddTable();
|
||||
FloorScreen.check.selectedTableIs('T1');
|
||||
FloorScreen.do.clickRename();
|
||||
TextInputPopup.check.isShown();
|
||||
TextInputPopup.do.inputText('T100');
|
||||
TextInputPopup.do.clickConfirm();
|
||||
FloorScreen.check.selectedTableIs('T100');
|
||||
|
||||
// test duplicate table
|
||||
FloorScreen.do.clickDuplicate();
|
||||
// new table is already named T101
|
||||
FloorScreen.check.selectedTableIs('T101');
|
||||
FloorScreen.do.clickRename();
|
||||
TextInputPopup.check.isShown();
|
||||
TextInputPopup.do.inputText('T1111');
|
||||
TextInputPopup.do.clickConfirm();
|
||||
FloorScreen.check.selectedTableIs('T1111');
|
||||
|
||||
// switch floor, switch back and check if
|
||||
// the new tables are still there
|
||||
FloorScreen.do.clickFloor('Second Floor');
|
||||
FloorScreen.check.editModeIsActive(false);
|
||||
FloorScreen.check.hasTable('T3');
|
||||
FloorScreen.check.hasTable('T1');
|
||||
|
||||
FloorScreen.do.clickFloor('Main Floor');
|
||||
FloorScreen.check.hasTable('T2');
|
||||
FloorScreen.check.hasTable('T4');
|
||||
FloorScreen.check.hasTable('T5');
|
||||
FloorScreen.check.hasTable('T100');
|
||||
FloorScreen.check.hasTable('T1111');
|
||||
|
||||
// test delete table
|
||||
FloorScreen.do.clickEdit();
|
||||
FloorScreen.check.editModeIsActive(true);
|
||||
FloorScreen.do.clickTable('T2');
|
||||
FloorScreen.check.selectedTableIs('T2');
|
||||
FloorScreen.do.clickTrash();
|
||||
Chrome.do.confirmPopup();
|
||||
|
||||
// change number of seats
|
||||
FloorScreen.do.clickTable('T4');
|
||||
FloorScreen.check.selectedTableIs('T4');
|
||||
FloorScreen.do.clickSeats();
|
||||
NumberPopup.do.pressNumpad('Backspace 9');
|
||||
NumberPopup.check.inputShownIs('9');
|
||||
NumberPopup.do.clickConfirm();
|
||||
FloorScreen.check.tableSeatIs('T4', '9');
|
||||
|
||||
// change number of seat when the input is already selected
|
||||
FloorScreen.do.clickTable('T4');
|
||||
FloorScreen.check.selectedTableIs('T4');
|
||||
FloorScreen.do.clickSeats();
|
||||
NumberPopup.do.pressNumpad('1 5');
|
||||
NumberPopup.check.inputShownIs('15');
|
||||
NumberPopup.do.clickConfirm();
|
||||
FloorScreen.check.tableSeatIs('T4', '15');
|
||||
|
||||
// change shape
|
||||
FloorScreen.do.changeShapeTo('round');
|
||||
|
||||
// Opening product screen in main floor should go back to main floor
|
||||
FloorScreen.do.clickEdit();
|
||||
FloorScreen.check.editModeIsActive(false);
|
||||
FloorScreen.check.tableIsNotSelected('T4');
|
||||
FloorScreen.do.clickTable('T4');
|
||||
ProductScreen.check.isShown();
|
||||
Chrome.check.backToFloorTextIs('Main Floor', 'T4');
|
||||
Chrome.do.backToFloor();
|
||||
|
||||
// Opening product screen in second floor should go back to second floor
|
||||
FloorScreen.do.clickFloor('Second Floor');
|
||||
FloorScreen.check.hasTable('T3');
|
||||
FloorScreen.do.clickTable('T3');
|
||||
Chrome.check.backToFloorTextIs('Second Floor', 'T3');
|
||||
|
||||
Tour.register('FloorScreenTour', { test: true, url: '/pos/ui' }, getSteps());
|
||||
});
|
||||
|
|
@ -1,80 +0,0 @@
|
|||
odoo.define('pos_restaurant.tour.SplitBillScreen', function (require) {
|
||||
'use strict';
|
||||
|
||||
const { PaymentScreen } = require('point_of_sale.tour.PaymentScreenTourMethods');
|
||||
const { Chrome } = require('pos_restaurant.tour.ChromeTourMethods');
|
||||
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');
|
||||
|
||||
// signal to start generating steps
|
||||
// when finished, steps can be taken from getSteps
|
||||
startSteps();
|
||||
|
||||
FloorScreen.do.clickTable('T2');
|
||||
ProductScreen.do.confirmOpeningPopup();
|
||||
ProductScreen.exec.addOrderline('Water', '5', '2', '10.0');
|
||||
ProductScreen.exec.addOrderline('Minute Maid', '3', '2', '6.0');
|
||||
ProductScreen.exec.addOrderline('Coca-Cola', '1', '2', '2.0');
|
||||
ProductScreen.do.clickSplitBillButton();
|
||||
|
||||
// Check if the screen contains all the orderlines
|
||||
SplitBillScreen.check.orderlineHas('Water', '5', '0');
|
||||
SplitBillScreen.check.orderlineHas('Minute Maid', '3', '0');
|
||||
SplitBillScreen.check.orderlineHas('Coca-Cola', '1', '0');
|
||||
|
||||
// split 3 water and 1 coca-cola
|
||||
SplitBillScreen.do.clickOrderline('Water');
|
||||
SplitBillScreen.check.orderlineHas('Water', '5', '1');
|
||||
SplitBillScreen.do.clickOrderline('Water');
|
||||
SplitBillScreen.do.clickOrderline('Water');
|
||||
SplitBillScreen.check.orderlineHas('Water', '5', '3');
|
||||
SplitBillScreen.check.subtotalIs('6.0')
|
||||
SplitBillScreen.do.clickOrderline('Coca-Cola');
|
||||
SplitBillScreen.check.orderlineHas('Coca-Cola', '1', '1');
|
||||
SplitBillScreen.check.subtotalIs('8.0')
|
||||
|
||||
// click pay to split, go back to check the lines
|
||||
SplitBillScreen.do.clickPay();
|
||||
PaymentScreen.do.clickBack();
|
||||
ProductScreen.do.clickOrderline('Water', '3.0')
|
||||
ProductScreen.do.clickOrderline('Coca-Cola', '1.0')
|
||||
|
||||
// go back to the original order and see if the order is changed
|
||||
Chrome.do.clickTicketButton();
|
||||
TicketScreen.do.selectOrder('-0001');
|
||||
ProductScreen.check.isShown()
|
||||
ProductScreen.do.clickOrderline('Water', '2.0')
|
||||
ProductScreen.do.clickOrderline('Minute Maid', '3.0')
|
||||
|
||||
Tour.register('SplitBillScreenTour', { test: true, url: '/pos/ui' }, getSteps());
|
||||
|
||||
startSteps();
|
||||
|
||||
FloorScreen.do.clickTable('T2');
|
||||
ProductScreen.exec.addOrderline('Water', '1', '2.0');
|
||||
ProductScreen.exec.addOrderline('Minute Maid', '1', '2.0');
|
||||
ProductScreen.exec.addOrderline('Coca-Cola', '1', '2.0');
|
||||
Chrome.do.backToFloor();
|
||||
FloorScreen.do.clickTable('T2');
|
||||
ProductScreen.do.clickSplitBillButton();
|
||||
|
||||
SplitBillScreen.do.clickOrderline('Water');
|
||||
SplitBillScreen.do.clickOrderline('Coca-Cola');
|
||||
SplitBillScreen.do.clickPay();
|
||||
PaymentScreen.do.clickBack();
|
||||
Chrome.do.clickTicketButton();
|
||||
TicketScreen.do.selectOrder('-0002');
|
||||
ProductScreen.do.clickOrderline('Water', '1.0');
|
||||
ProductScreen.do.clickOrderline('Coca-Cola', '1.0');
|
||||
ProductScreen.check.totalAmountIs('4.40');
|
||||
Chrome.do.clickTicketButton();
|
||||
TicketScreen.do.selectOrder('-0001');
|
||||
ProductScreen.do.clickOrderline('Minute Maid', '1.0');
|
||||
ProductScreen.check.totalAmountIs('2.20');
|
||||
|
||||
Tour.register('SplitBillScreenTour2', { test: true, url: '/pos/ui' }, getSteps());
|
||||
});
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
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');
|
||||
ProductScreen.do.confirmOpeningPopup();
|
||||
ProductScreen.check.isShown();
|
||||
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.isShown();
|
||||
ProductScreen.check.totalAmountIs('2.0');
|
||||
Chrome.check.backToFloorTextIs('Main Floor', 'T2');
|
||||
Chrome.do.backToFloor();
|
||||
|
||||
// Make sure that order is deleted properly.
|
||||
FloorScreen.do.clickTable('T5');
|
||||
ProductScreen.exec.addOrderline('Minute Maid', '1', '3');
|
||||
ProductScreen.check.totalAmountIs('3.0');
|
||||
Chrome.do.backToFloor();
|
||||
FloorScreen.check.orderCountSyncedInTableIs('T5', '1');
|
||||
Chrome.do.clickTicketButton();
|
||||
TicketScreen.do.deleteOrder('-0004');
|
||||
Chrome.do.confirmPopup();
|
||||
TicketScreen.do.clickDiscard();
|
||||
FloorScreen.check.isShown();
|
||||
FloorScreen.check.orderCountSyncedInTableIs('T5', '0');
|
||||
FloorScreen.do.clickTable('T5');
|
||||
ProductScreen.check.orderIsEmpty();
|
||||
|
||||
Tour.register('PosResTicketScreenTour', { test: true, url: '/pos/ui' }, getSteps());
|
||||
});
|
||||
|
|
@ -1,127 +0,0 @@
|
|||
odoo.define('pos_restaurant.tour.TipScreen', function (require) {
|
||||
'use strict';
|
||||
|
||||
const { ProductScreen } = require('point_of_sale.tour.ProductScreenTourMethods');
|
||||
const { PaymentScreen } = require('point_of_sale.tour.PaymentScreenTourMethods');
|
||||
const { ReceiptScreen } = require('point_of_sale.tour.ReceiptScreenTourMethods');
|
||||
const { FloorScreen } = require('pos_restaurant.tour.FloorScreenTourMethods');
|
||||
const { TicketScreen } = require('point_of_sale.tour.TicketScreenTourMethods');
|
||||
const { TipScreen } = require('pos_restaurant.tour.TipScreenTourMethods');
|
||||
const { NumberPopup } = require('point_of_sale.tour.NumberPopupTourMethods');
|
||||
const { Chrome } = require('pos_restaurant.tour.ChromeTourMethods');
|
||||
const { getSteps, startSteps } = require('point_of_sale.tour.utils');
|
||||
var Tour = require('web_tour.tour');
|
||||
|
||||
startSteps();
|
||||
|
||||
// Create order that is synced when draft.
|
||||
// order 1
|
||||
FloorScreen.do.clickTable('T2');
|
||||
ProductScreen.do.confirmOpeningPopup();
|
||||
ProductScreen.exec.addOrderline('Minute Maid', '1', '2');
|
||||
ProductScreen.check.totalAmountIs('2.0');
|
||||
Chrome.do.backToFloor();
|
||||
FloorScreen.check.orderCountSyncedInTableIs('T2', '1');
|
||||
FloorScreen.do.clickTable('T2');
|
||||
ProductScreen.check.totalAmountIs('2.0');
|
||||
ProductScreen.do.clickPayButton();
|
||||
PaymentScreen.do.clickPaymentMethod('Bank');
|
||||
PaymentScreen.do.clickValidate();
|
||||
TipScreen.check.isShown();
|
||||
Chrome.do.clickTicketButton();
|
||||
TicketScreen.do.clickNewTicket();
|
||||
// order 2
|
||||
ProductScreen.exec.addOrderline('Coca-Cola', '2', '2');
|
||||
ProductScreen.check.totalAmountIs('4.0');
|
||||
Chrome.do.backToFloor();
|
||||
FloorScreen.check.orderCountSyncedInTableIs('T2', '1');
|
||||
Chrome.do.clickTicketButton();
|
||||
TicketScreen.check.nthRowContains('2', 'Tipping');
|
||||
TicketScreen.do.clickDiscard();
|
||||
|
||||
// Create without syncing the draft.
|
||||
// order 3
|
||||
FloorScreen.do.clickTable('T5');
|
||||
ProductScreen.exec.addOrderline('Minute Maid', '3', '2');
|
||||
ProductScreen.check.totalAmountIs('6.0');
|
||||
ProductScreen.do.clickPayButton();
|
||||
PaymentScreen.do.clickPaymentMethod('Bank');
|
||||
PaymentScreen.do.clickValidate();
|
||||
TipScreen.check.isShown();
|
||||
Chrome.do.clickTicketButton();
|
||||
TicketScreen.do.clickNewTicket();
|
||||
// order 4
|
||||
ProductScreen.exec.addOrderline('Coca-Cola', '4', '2');
|
||||
ProductScreen.check.totalAmountIs('8.0');
|
||||
Chrome.do.backToFloor();
|
||||
FloorScreen.check.orderCountSyncedInTableIs('T5', '1');
|
||||
Chrome.do.clickTicketButton();
|
||||
TicketScreen.check.nthRowContains('3', 'Tipping');
|
||||
|
||||
// Tip 20% on order1
|
||||
TicketScreen.do.selectOrder('-0001');
|
||||
TipScreen.check.isShown();
|
||||
TipScreen.check.totalAmountIs('2.0');
|
||||
TipScreen.check.percentAmountIs('15%', '0.30');
|
||||
TipScreen.check.percentAmountIs('20%', '0.40');
|
||||
TipScreen.check.percentAmountIs('25%', '0.50');
|
||||
TipScreen.do.clickPercentTip('20%');
|
||||
TipScreen.check.inputAmountIs('0.40')
|
||||
Chrome.do.backToFloor();
|
||||
FloorScreen.check.isShown();
|
||||
Chrome.do.clickTicketButton();
|
||||
|
||||
// Tip 25% on order3
|
||||
TicketScreen.do.selectOrder('-0003');
|
||||
TipScreen.check.isShown();
|
||||
TipScreen.check.totalAmountIs('6.0');
|
||||
TipScreen.check.percentAmountIs('15%', '0.90');
|
||||
TipScreen.check.percentAmountIs('20%', '1.20');
|
||||
TipScreen.check.percentAmountIs('25%', '1.50');
|
||||
TipScreen.do.clickPercentTip('25%');
|
||||
TipScreen.check.inputAmountIs('1.50');
|
||||
Chrome.do.backToFloor();
|
||||
FloorScreen.check.isShown();
|
||||
Chrome.do.clickTicketButton();
|
||||
|
||||
// finalize order 4 then tip custom amount
|
||||
TicketScreen.do.selectOrder('-0004');
|
||||
ProductScreen.check.isShown();
|
||||
ProductScreen.check.totalAmountIs('8.0');
|
||||
ProductScreen.do.clickPayButton();
|
||||
PaymentScreen.do.clickPaymentMethod('Bank');
|
||||
PaymentScreen.do.clickValidate();
|
||||
TipScreen.check.isShown();
|
||||
TipScreen.check.totalAmountIs('8.0');
|
||||
TipScreen.check.percentAmountIs('15%', '1.20');
|
||||
TipScreen.check.percentAmountIs('20%', '1.60');
|
||||
TipScreen.check.percentAmountIs('25%', '2.00');
|
||||
TipScreen.do.setCustomTip('1.00');
|
||||
TipScreen.check.inputAmountIs('1.00')
|
||||
Chrome.do.backToFloor();
|
||||
FloorScreen.check.isShown();
|
||||
|
||||
// settle tips here
|
||||
Chrome.do.clickTicketButton();
|
||||
TicketScreen.do.selectFilter('Tipping');
|
||||
TicketScreen.check.tipContains('1.00');
|
||||
TicketScreen.do.settleTips();
|
||||
TicketScreen.do.selectFilter('All active orders');
|
||||
TicketScreen.check.nthRowContains(2, 'Ongoing');
|
||||
|
||||
// tip order2 during payment
|
||||
// tip screen should not show after validating payment screen
|
||||
TicketScreen.do.selectOrder('-0002');
|
||||
ProductScreen.check.isShown();
|
||||
ProductScreen.do.clickPayButton();
|
||||
PaymentScreen.do.clickTipButton();
|
||||
NumberPopup.check.isShown();
|
||||
NumberPopup.do.pressNumpad('1');
|
||||
NumberPopup.check.inputShownIs('1');
|
||||
NumberPopup.do.clickConfirm();
|
||||
PaymentScreen.do.clickPaymentMethod('Cash');
|
||||
PaymentScreen.do.clickValidate();
|
||||
ReceiptScreen.check.isShown();
|
||||
|
||||
Tour.register('PosResTipScreenTour', { test: true, url: '/pos/ui' }, getSteps());
|
||||
});
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
import * as Dialog from "@point_of_sale/../tests/generic_helpers/dialog_util";
|
||||
import * as NumberPopup from "@point_of_sale/../tests/generic_helpers/number_popup_util";
|
||||
import * as FloorScreen from "@pos_restaurant/../tests/tours/utils/floor_screen_util";
|
||||
import * as ProductScreenPos from "@point_of_sale/../tests/pos/tours/utils/product_screen_util";
|
||||
import * as ProductScreenResto from "@pos_restaurant/../tests/tours/utils/product_screen_util";
|
||||
const ProductScreen = { ...ProductScreenPos, ...ProductScreenResto };
|
||||
import * as SplitBillScreen from "@pos_restaurant/../tests/tours/utils/split_bill_screen_util";
|
||||
import * as Order from "@point_of_sale/../tests/generic_helpers/order_widget_util";
|
||||
import * as ChromePos from "@point_of_sale/../tests/pos/tours/utils/chrome_util";
|
||||
import * as ChromeRestaurant from "@pos_restaurant/../tests/tours/utils/chrome";
|
||||
const Chrome = { ...ChromePos, ...ChromeRestaurant };
|
||||
import { registry } from "@web/core/registry";
|
||||
import { delay } from "@web/core/utils/concurrency";
|
||||
|
||||
registry.category("web_tour.tours").add("ControlButtonsTour", {
|
||||
steps: () =>
|
||||
[
|
||||
// Test merging table, transfer is already tested in pos_restaurant_sync_second_login.
|
||||
Chrome.startPoS(),
|
||||
Dialog.confirm("Open Register"),
|
||||
FloorScreen.clickTable("2"),
|
||||
ProductScreen.addOrderline("Water", "5", "2", "10.0"),
|
||||
Chrome.clickPlanButton(),
|
||||
FloorScreen.clickTable("4"),
|
||||
ProductScreen.addOrderline("Minute Maid", "3", "2", "6.0"),
|
||||
// Extra line is added to test merging table.
|
||||
// Merging this order to another should also include this extra line.
|
||||
ProductScreen.clickDisplayedProduct("Coca-Cola"),
|
||||
ProductScreen.selectedOrderlineHas("Coca-Cola", "1"),
|
||||
|
||||
ProductScreen.clickControlButton("Transfer"),
|
||||
{
|
||||
trigger: ".table:contains(2)",
|
||||
async run(helpers) {
|
||||
await delay(500);
|
||||
await helpers.click();
|
||||
},
|
||||
},
|
||||
Order.hasLine({ productName: "Water", quantity: "5" }),
|
||||
Order.hasLine({ productName: "Minute Maid", quantity: "3" }),
|
||||
Order.hasLine({ productName: "Coca-Cola", quantity: "1" }),
|
||||
|
||||
// Test SplitBillButton
|
||||
ProductScreen.clickControlButton("Split"),
|
||||
SplitBillScreen.clickBack(),
|
||||
ProductScreen.clickLine("Water", "5"),
|
||||
ProductScreen.addInternalNote("test note", "Note"),
|
||||
Order.hasLine({
|
||||
productName: "Water",
|
||||
quantity: "5",
|
||||
price: "10.0",
|
||||
internalNote: "test note",
|
||||
withClass: ".selected",
|
||||
}),
|
||||
// Check that note is imported if come back to the table
|
||||
Chrome.clickPlanButton(),
|
||||
FloorScreen.clickTable("2"),
|
||||
Order.hasLine({
|
||||
productName: "Water",
|
||||
quantity: "5",
|
||||
price: "10.0",
|
||||
internalNote: "test note",
|
||||
}),
|
||||
|
||||
ProductScreen.addOrderline("Water", "8", "1", "8.0"),
|
||||
|
||||
// Test GuestButton
|
||||
ProductScreen.clickControlButton("Guests"),
|
||||
{
|
||||
content: `click numpad button: 1`,
|
||||
trigger: ".modal div.numpad button:text(1)",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: `click numpad button: 5`,
|
||||
trigger: ".modal div.numpad button:text(5)",
|
||||
run: "click",
|
||||
},
|
||||
NumberPopup.isShown("15"),
|
||||
Dialog.confirm(),
|
||||
ProductScreen.guestNumberIs("15"),
|
||||
{
|
||||
content: `click guests 15 button`,
|
||||
trigger: `.modal .control-buttons button:contains(15Guests)`,
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
content: `click numpad button: 5`,
|
||||
trigger: ".modal div.numpad button:text(5)",
|
||||
run: "click",
|
||||
},
|
||||
NumberPopup.isShown("5"),
|
||||
Dialog.confirm(),
|
||||
ProductScreen.guestNumberIs("5"),
|
||||
|
||||
// Test Cancel Order Button
|
||||
Dialog.cancel(),
|
||||
Order.hasLine({ productName: "Water", quantity: "5" }),
|
||||
ProductScreen.clickControlButton("Cancel Order"),
|
||||
Dialog.confirm(),
|
||||
Order.doesNotHaveLine(),
|
||||
FloorScreen.isShown(),
|
||||
|
||||
// Test moving order to a table on a different floor
|
||||
FloorScreen.clickTable("5"),
|
||||
ProductScreen.addOrderline("Water", "5", "2", "10.0"),
|
||||
ProductScreen.clickControlButton("Transfer"),
|
||||
FloorScreen.clickFloor("Second Floor"),
|
||||
FloorScreen.clickTable("1"),
|
||||
Order.hasLine({ productName: "Water", quantity: "5" }),
|
||||
].flat(),
|
||||
});
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
import * as Dialog from "@point_of_sale/../tests/generic_helpers/dialog_util";
|
||||
import * as ChromePos from "@point_of_sale/../tests/pos/tours/utils/chrome_util";
|
||||
import * as ChromeRestaurant from "@pos_restaurant/../tests/tours/utils/chrome";
|
||||
import * as ProductScreenPos from "@point_of_sale/../tests/pos/tours/utils/product_screen_util";
|
||||
import * as ProductScreenResto from "@pos_restaurant/../tests/tours/utils/product_screen_util";
|
||||
import * as FloorScreen from "@pos_restaurant/../tests/tours/utils/floor_screen_util";
|
||||
import * as DeviceSynchronization from "@pos_restaurant/../tests/tours/utils/devices_synchronization";
|
||||
import * as PaymentScreen from "@point_of_sale/../tests/pos/tours/utils/payment_screen_util";
|
||||
import * as ReceiptScreen from "@point_of_sale/../tests/pos/tours/utils/receipt_screen_util";
|
||||
import * as TicketScreen from "@point_of_sale/../tests/pos/tours/utils/ticket_screen_util";
|
||||
import { registry } from "@web/core/registry";
|
||||
|
||||
const ProductScreen = { ...ProductScreenPos, ...ProductScreenResto };
|
||||
const Chrome = { ...ChromePos, ...ChromeRestaurant };
|
||||
|
||||
registry.category("web_tour.tours").add("test_devices_synchronization", {
|
||||
steps: () =>
|
||||
[
|
||||
Chrome.startPoS(),
|
||||
Dialog.confirm("Open Register"),
|
||||
FloorScreen.clickTable("5"),
|
||||
|
||||
// product_screen
|
||||
// Check if lines created from another devices
|
||||
// correctly appear in the current device
|
||||
ProductScreen.orderlineIsToOrder("Coca-Cola"),
|
||||
DeviceSynchronization.createNewLine("Water", 2),
|
||||
ProductScreen.orderlineIsToOrder("Water"),
|
||||
DeviceSynchronization.changeLineQuantity("Water", 44),
|
||||
ProductScreen.checkTotalAmount(99.0),
|
||||
ProductScreen.clickPartnerButton(),
|
||||
ProductScreen.clickCustomer("Acme Corporation"),
|
||||
Chrome.clickPlanButton(),
|
||||
|
||||
// prpoduct_screen
|
||||
// Check if changing partner form another device
|
||||
// correctly appear in the current device
|
||||
FloorScreen.clickTable("5"),
|
||||
DeviceSynchronization.changePartner("Lumber Inc"),
|
||||
ProductScreen.customerIs("Lumber Inc"),
|
||||
|
||||
// prpoduct_screen
|
||||
// Check if paying from another device
|
||||
// is correctly synchronized
|
||||
DeviceSynchronization.markOrderAsPaid(),
|
||||
ProductScreen.orderIsEmpty(),
|
||||
|
||||
// floor_screen
|
||||
// Check if floor plan is correctly updated
|
||||
// when creating a new order from another device
|
||||
DeviceSynchronization.createNewOrderOnTable("5", [
|
||||
["Coca-Cola", 1],
|
||||
["Water", 2],
|
||||
]),
|
||||
DeviceSynchronization.createNewOrderOnTable("4", [
|
||||
["Coca-Cola", 50],
|
||||
["Water", 30],
|
||||
]),
|
||||
Chrome.clickPlanButton(),
|
||||
FloorScreen.orderCountSyncedInTableIs("5", 3),
|
||||
FloorScreen.orderCountSyncedInTableIs("4", 80),
|
||||
FloorScreen.clickTable("5"),
|
||||
ProductScreen.checkTotalAmount(6.6),
|
||||
ProductScreen.clickPayButton(false),
|
||||
ProductScreen.discardOrderWarningDialog(),
|
||||
PaymentScreen.clickPaymentMethod("Cash"),
|
||||
PaymentScreen.clickValidate(),
|
||||
ReceiptScreen.clickNextOrder(),
|
||||
Chrome.clickPlanButton(),
|
||||
FloorScreen.clickTable("4"),
|
||||
ProductScreen.checkTotalAmount(176.0),
|
||||
ProductScreen.clickPayButton(false),
|
||||
ProductScreen.discardOrderWarningDialog(),
|
||||
PaymentScreen.clickPaymentMethod("Cash"),
|
||||
PaymentScreen.clickValidate(),
|
||||
ReceiptScreen.clickNextOrder(),
|
||||
|
||||
// product_screen
|
||||
// Check if creating an order one same table from two devices
|
||||
// is correctly handlded
|
||||
FloorScreen.clickTable("5"),
|
||||
ProductScreen.clickDisplayedProduct("Coca-Cola"),
|
||||
DeviceSynchronization.createNewOrderOnTable(
|
||||
"5",
|
||||
[
|
||||
["Coca-Cola", 2],
|
||||
["Water", 2],
|
||||
],
|
||||
false
|
||||
),
|
||||
ProductScreen.orderLineHas("Coca-Cola", "2"),
|
||||
ProductScreen.orderLineHas("Water", "2"),
|
||||
ProductScreen.clickDisplayedProduct("Water"),
|
||||
ProductScreen.clickLine("Coca-Cola", 2),
|
||||
ProductScreen.clickLine("Coca-Cola", 1),
|
||||
ProductScreen.clickLine("Water", 3),
|
||||
].flat(),
|
||||
});
|
||||
|
||||
registry.category("web_tour.tours").add("OrderSynchronisationTour", {
|
||||
steps: () =>
|
||||
[
|
||||
Chrome.startPoS(),
|
||||
Dialog.confirm("Open Register"),
|
||||
DeviceSynchronization.createNewOrderOnTable("4", [
|
||||
["Coca-Cola", 50],
|
||||
["Water", 30],
|
||||
]),
|
||||
FloorScreen.clickTable("4"),
|
||||
ProductScreen.orderLineHas("Coca-Cola", "50.0"),
|
||||
DeviceSynchronization.markOrderAsPaid(),
|
||||
ProductScreen.isShown(),
|
||||
Chrome.clickOrders(),
|
||||
TicketScreen.selectFilter("Paid"),
|
||||
TicketScreen.checkStatus("device_sync", "Paid"),
|
||||
TicketScreen.selectOrder("device_sync"),
|
||||
TicketScreen.confirmRefund(),
|
||||
].flat(),
|
||||
});
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
/* global posmodel */
|
||||
|
||||
import { registry } from "@web/core/registry";
|
||||
import * as PaymentScreen from "@point_of_sale/../tests/pos/tours/utils/payment_screen_util";
|
||||
import * as ReceiptScreen from "@point_of_sale/../tests/pos/tours/utils/receipt_screen_util";
|
||||
import * as FloorScreen from "@pos_restaurant/../tests/tours/utils/floor_screen_util";
|
||||
import * as ChromePos from "@point_of_sale/../tests/pos/tours/utils/chrome_util";
|
||||
import * as ChromeRestaurant from "@pos_restaurant/../tests/tours/utils/chrome";
|
||||
import * as ProductScreenPos from "@point_of_sale/../tests/pos/tours/utils/product_screen_util";
|
||||
import * as ProductScreenResto from "@pos_restaurant/../tests/tours/utils/product_screen_util";
|
||||
|
||||
const Chrome = { ...ChromePos, ...ChromeRestaurant };
|
||||
const ProductScreen = { ...ProductScreenPos, ...ProductScreenResto };
|
||||
|
||||
const getRandomTable = () => {
|
||||
const tables = posmodel.currentFloor.table_ids;
|
||||
return tables[Math.floor(Math.random() * tables.length)].table_number;
|
||||
};
|
||||
|
||||
const getRandomTableWithOrder = () => {
|
||||
const tables = posmodel.currentFloor.table_ids.filter(
|
||||
(table) => table.backLink("<-pos.order.table_id").length > 0
|
||||
);
|
||||
return tables[Math.floor(Math.random() * tables.length)].table_number;
|
||||
};
|
||||
|
||||
const getRandomProduct = () => {
|
||||
const products = posmodel.models["product.product"].filter(
|
||||
(p) =>
|
||||
!p.isConfigurable() &&
|
||||
!p.isCombo() &&
|
||||
!p.isTracked() &&
|
||||
p.id !== posmodel.config.tip_product_id?.id &&
|
||||
!posmodel.config._pos_special_products_ids?.includes(p.id)
|
||||
);
|
||||
return products[Math.floor(Math.random() * products.length)].name;
|
||||
};
|
||||
|
||||
registry.category("web_tour.tours").add("PoSFakeTourRestaurant", {
|
||||
steps: () =>
|
||||
[
|
||||
FloorScreen.clickTable(getRandomTable()),
|
||||
ProductScreen.clickDisplayedProduct(getRandomProduct()),
|
||||
ProductScreen.clickDisplayedProduct(getRandomProduct()),
|
||||
ProductScreen.clickDisplayedProduct(getRandomProduct()),
|
||||
Chrome.clickPlanButton(),
|
||||
FloorScreen.clickTable(getRandomTable()),
|
||||
ProductScreen.clickDisplayedProduct(getRandomProduct()),
|
||||
ProductScreen.clickDisplayedProduct(getRandomProduct()),
|
||||
ProductScreen.clickDisplayedProduct(getRandomProduct()),
|
||||
ProductScreen.clickPayButton(),
|
||||
PaymentScreen.clickPaymentMethod("Cash"),
|
||||
PaymentScreen.clickValidate(),
|
||||
ReceiptScreen.clickNextOrder(),
|
||||
].flat(),
|
||||
});
|
||||
|
||||
registry.category("web_tour.tours").add("PoSFakeTourTransferOrder", {
|
||||
steps: () =>
|
||||
[
|
||||
FloorScreen.clickTable(getRandomTableWithOrder()),
|
||||
ProductScreen.clickControlButton("Transfer"),
|
||||
FloorScreen.clickTable(getRandomTable()),
|
||||
ProductScreen.clickDisplayedProduct(getRandomProduct()),
|
||||
Chrome.clickPlanButton(),
|
||||
].flat(),
|
||||
});
|
||||
|
|
@ -0,0 +1,356 @@
|
|||
import * as FloorScreen from "@pos_restaurant/../tests/tours/utils/floor_screen_util";
|
||||
import * as Dialog from "@point_of_sale/../tests/generic_helpers/dialog_util";
|
||||
import * as NumberPopup from "@point_of_sale/../tests/generic_helpers/number_popup_util";
|
||||
import * as ChromePos from "@point_of_sale/../tests/pos/tours/utils/chrome_util";
|
||||
import * as ChromeRestaurant from "@pos_restaurant/../tests/tours/utils/chrome";
|
||||
const Chrome = { ...ChromePos, ...ChromeRestaurant };
|
||||
import * as ProductScreenPos from "@point_of_sale/../tests/pos/tours/utils/product_screen_util";
|
||||
import * as ProductScreenResto from "@pos_restaurant/../tests/tours/utils/product_screen_util";
|
||||
import * as Utils from "@point_of_sale/../tests/generic_helpers/utils";
|
||||
import * as PaymentScreen from "@point_of_sale/../tests/pos/tours/utils/payment_screen_util";
|
||||
import * as ReceiptScreen from "@point_of_sale/../tests/pos/tours/utils/receipt_screen_util";
|
||||
const ProductScreen = { ...ProductScreenPos, ...ProductScreenResto };
|
||||
import * as TicketScreen from "@point_of_sale/../tests/pos/tours/utils/ticket_screen_util";
|
||||
import { registry } from "@web/core/registry";
|
||||
import { inLeftSide } from "@point_of_sale/../tests/pos/tours/utils/common";
|
||||
|
||||
registry.category("web_tour.tours").add("FloorScreenTour", {
|
||||
steps: () =>
|
||||
[
|
||||
// check floors if they contain their corresponding tables
|
||||
Chrome.startPoS(),
|
||||
FloorScreen.selectedFloorIs("Main Floor"),
|
||||
FloorScreen.hasTable("2"),
|
||||
FloorScreen.hasTable("4"),
|
||||
FloorScreen.hasTable("5"),
|
||||
FloorScreen.clickFloor("Second Floor"),
|
||||
FloorScreen.hasTable("3"),
|
||||
FloorScreen.hasTable("1"),
|
||||
|
||||
// clicking table in active mode does not open product screen
|
||||
// instead, table is selected
|
||||
Chrome.clickMenuOption("Edit Plan"),
|
||||
FloorScreen.clickTable("3"),
|
||||
FloorScreen.selectedTableIs("3"),
|
||||
FloorScreen.clickTable("1"),
|
||||
FloorScreen.selectedTableIs("1"),
|
||||
|
||||
//test copy floor
|
||||
FloorScreen.clickFloor("Main Floor"),
|
||||
FloorScreen.clickEditButton("Clone"),
|
||||
FloorScreen.selectedFloorIs("Main Floor (copy)"),
|
||||
FloorScreen.hasTable("2"),
|
||||
FloorScreen.hasTable("4"),
|
||||
FloorScreen.hasTable("5"),
|
||||
Utils.refresh(),
|
||||
Chrome.clickMenuOption("Edit Plan"),
|
||||
FloorScreen.clickFloor("Main Floor (copy)"),
|
||||
FloorScreen.hasTable("2"),
|
||||
FloorScreen.hasTable("4"),
|
||||
FloorScreen.hasTable("5"),
|
||||
FloorScreen.clickEditButton("Delete"),
|
||||
Dialog.confirm(),
|
||||
Utils.refresh(),
|
||||
Chrome.clickMenuOption("Edit Plan"),
|
||||
Utils.elementDoesNotExist(
|
||||
".floor-selector .button-floor:contains('Main Floor (copy)')"
|
||||
),
|
||||
|
||||
// test add table
|
||||
FloorScreen.clickFloor("Main Floor"),
|
||||
{
|
||||
trigger: `.edit-buttons i[aria-label="Add Table"]`,
|
||||
run: "click",
|
||||
},
|
||||
FloorScreen.selectedTableIs("6"),
|
||||
FloorScreen.clickEditButton("Rename"),
|
||||
|
||||
NumberPopup.enterValue("100"),
|
||||
NumberPopup.isShown("100"),
|
||||
Dialog.confirm(),
|
||||
FloorScreen.selectedTableIs("100"),
|
||||
|
||||
// test duplicate table
|
||||
FloorScreen.clickEditButton("Clone"),
|
||||
// the name is the first number available on the floor
|
||||
FloorScreen.selectedTableIs("1"),
|
||||
FloorScreen.clickEditButton("Rename"),
|
||||
|
||||
NumberPopup.enterValue("1111"),
|
||||
NumberPopup.isShown("1111"),
|
||||
Dialog.confirm(),
|
||||
FloorScreen.selectedTableIs("1111"),
|
||||
|
||||
// switch floor, switch back and check if
|
||||
// the new tables are still there
|
||||
FloorScreen.clickFloor("Second Floor"),
|
||||
FloorScreen.hasTable("3"),
|
||||
FloorScreen.hasTable("1"),
|
||||
|
||||
//test duplicate multiple tables
|
||||
FloorScreen.clickTable("1"),
|
||||
FloorScreen.selectedTableIs("1"),
|
||||
FloorScreen.ctrlClickTable("3"),
|
||||
FloorScreen.selectedTableIs("3"),
|
||||
FloorScreen.clickEditButton("Clone"),
|
||||
FloorScreen.selectedTableIs("4"),
|
||||
FloorScreen.selectedTableIs("5"),
|
||||
|
||||
//test delete multiple tables
|
||||
FloorScreen.clickEditButton("Delete"),
|
||||
Dialog.confirm(),
|
||||
|
||||
FloorScreen.clickFloor("Main Floor"),
|
||||
FloorScreen.hasTable("2"),
|
||||
FloorScreen.hasTable("4"),
|
||||
FloorScreen.hasTable("5"),
|
||||
FloorScreen.hasTable("100"),
|
||||
FloorScreen.hasTable("1111"),
|
||||
|
||||
// test delete table
|
||||
FloorScreen.clickTable("1111"),
|
||||
FloorScreen.selectedTableIs("1111"),
|
||||
FloorScreen.clickEditButton("Delete"),
|
||||
Dialog.confirm(),
|
||||
|
||||
// change number of seats
|
||||
FloorScreen.clickTable("4"),
|
||||
FloorScreen.selectedTableIs("4"),
|
||||
FloorScreen.clickEditButton("Seats"),
|
||||
NumberPopup.enterValue("⌫9"),
|
||||
NumberPopup.enterValue("9"),
|
||||
NumberPopup.isShown("9"),
|
||||
Dialog.confirm(),
|
||||
FloorScreen.table({ name: "4" }),
|
||||
|
||||
// change number of seat when the input is already selected
|
||||
FloorScreen.selectedTableIs("4"),
|
||||
FloorScreen.clickEditButton("Seats"),
|
||||
NumberPopup.enterValue("15"),
|
||||
NumberPopup.isShown("15"),
|
||||
Dialog.confirm(),
|
||||
FloorScreen.table({ name: "4" }),
|
||||
|
||||
// change shape
|
||||
FloorScreen.clickEditButton("Make Round"),
|
||||
|
||||
// Opening product screen in main floor should go back to main floor
|
||||
FloorScreen.clickSaveEditButton(),
|
||||
FloorScreen.table({ name: "4", withoutClass: ".selected" }),
|
||||
FloorScreen.clickTable("4"),
|
||||
ProductScreen.isShown(),
|
||||
Chrome.clickPlanButton(),
|
||||
|
||||
// Opening product screen in second floor should go back to second floor
|
||||
FloorScreen.clickFloor("Second Floor"),
|
||||
FloorScreen.hasTable("3"),
|
||||
FloorScreen.clickTable("3"),
|
||||
ProductScreen.isShown(),
|
||||
Chrome.clickPlanButton(),
|
||||
FloorScreen.selectedFloorIs("Second Floor"),
|
||||
].flat(),
|
||||
});
|
||||
registry.category("web_tour.tours").add("TableMergeUnmergeTour", {
|
||||
steps: () =>
|
||||
[
|
||||
Chrome.startPoS(),
|
||||
// Check the linking of tables
|
||||
FloorScreen.clickFloor("Main Floor"),
|
||||
FloorScreen.clickTable("4"),
|
||||
ProductScreen.clickDisplayedProduct("Coca-Cola"),
|
||||
Chrome.clickPlanButton(),
|
||||
FloorScreen.isShown(),
|
||||
FloorScreen.linkTables("5", "4"),
|
||||
FloorScreen.isChildTable("5"),
|
||||
Utils.refresh(),
|
||||
FloorScreen.isChildTable("5"),
|
||||
|
||||
// Check that tables are unlinked automatically when the order is done
|
||||
FloorScreen.clickTable("5"),
|
||||
Chrome.isTabActive("4 & 5"),
|
||||
inLeftSide(ProductScreen.orderLineHas("Coca-Cola", "1")),
|
||||
Chrome.clickPlanButton(),
|
||||
FloorScreen.isShown(),
|
||||
FloorScreen.goTo("5"),
|
||||
Chrome.isTabActive("4 & 5"),
|
||||
inLeftSide(ProductScreen.orderLineHas("Coca-Cola", "1")),
|
||||
ProductScreen.clickPayButton(false),
|
||||
ProductScreen.discardOrderWarningDialog(),
|
||||
PaymentScreen.clickPaymentMethod("Cash"),
|
||||
PaymentScreen.clickValidate(),
|
||||
ReceiptScreen.clickNextOrder(),
|
||||
Utils.negateStep(FloorScreen.isChildTable("5")),
|
||||
|
||||
FloorScreen.linkTables("5", "4"),
|
||||
// Check that the tables are unlinked when the child table is dragged
|
||||
FloorScreen.unlinkTables("5", "4"),
|
||||
Utils.negateStep(FloorScreen.isChildTable("5")),
|
||||
|
||||
// Verify that tables are unlinked and original orders are restored after dragging a child table.
|
||||
FloorScreen.isShown(),
|
||||
FloorScreen.clickTable("4"),
|
||||
ProductScreen.clickDisplayedProduct("Coca-Cola"),
|
||||
Chrome.clickPlanButton(),
|
||||
FloorScreen.isShown(),
|
||||
|
||||
FloorScreen.clickTable("5"),
|
||||
ProductScreen.clickDisplayedProduct("Minute Maid"),
|
||||
Chrome.clickPlanButton(),
|
||||
FloorScreen.isShown(),
|
||||
|
||||
// Link tables 5 and 4
|
||||
FloorScreen.linkTables("5", "4"),
|
||||
FloorScreen.isChildTable("5"),
|
||||
|
||||
// Check merged orders
|
||||
FloorScreen.clickTable("5"),
|
||||
Chrome.isTabActive("4 & 5"),
|
||||
inLeftSide(ProductScreen.orderLineHas("Coca-Cola", "1")),
|
||||
inLeftSide(ProductScreen.orderLineHas("Minute Maid", "1")),
|
||||
Chrome.clickPlanButton(),
|
||||
FloorScreen.isShown(),
|
||||
|
||||
// Unlink tables and verify restoration of original orders
|
||||
FloorScreen.unlinkTables("5", "4"),
|
||||
Utils.negateStep(FloorScreen.isChildTable("5")),
|
||||
|
||||
// Check original orders for table 4
|
||||
FloorScreen.clickTable("4"),
|
||||
inLeftSide(ProductScreen.orderLineHas("Coca-Cola", "1")),
|
||||
ProductScreen.clickOrderButton(),
|
||||
{
|
||||
...Dialog.confirm(),
|
||||
content: "Acknowledge printing error (test does not use a printer).",
|
||||
},
|
||||
ProductScreen.orderlinesHaveNoChange(),
|
||||
Chrome.clickPlanButton(),
|
||||
FloorScreen.isShown(),
|
||||
|
||||
// Check original orders for table 5
|
||||
FloorScreen.clickTable("5"),
|
||||
inLeftSide(ProductScreen.orderLineHas("Minute Maid", "1")),
|
||||
ProductScreen.clickOrderButton(),
|
||||
{
|
||||
...Dialog.confirm(),
|
||||
content: "Acknowledge printing error (test does not use a printer).",
|
||||
},
|
||||
ProductScreen.orderlinesHaveNoChange(),
|
||||
Chrome.clickPlanButton(),
|
||||
FloorScreen.isShown(),
|
||||
|
||||
// Relink tables and verify
|
||||
FloorScreen.linkTables("5", "4"),
|
||||
FloorScreen.clickTable("5"),
|
||||
Chrome.isTabActive("4 & 5"),
|
||||
ProductScreen.orderlinesHaveNoChange(),
|
||||
|
||||
// Add a new product to the merged order
|
||||
ProductScreen.clickDisplayedProduct("Minute Maid"),
|
||||
ProductScreen.orderlineIsToOrder("Minute Maid"),
|
||||
ProductScreen.clickOrderButton(),
|
||||
{
|
||||
...Dialog.confirm(),
|
||||
content: "Acknowledge printing error (test does not use a printer).",
|
||||
},
|
||||
ProductScreen.orderlinesHaveNoChange(),
|
||||
|
||||
// Unlink tables again and verify restoration
|
||||
Chrome.clickPlanButton(),
|
||||
FloorScreen.isShown(),
|
||||
FloorScreen.unlinkTables("5", "4"),
|
||||
Utils.negateStep(FloorScreen.isChildTable("5")),
|
||||
|
||||
// Verify orders after unlinking
|
||||
FloorScreen.clickTable("5"),
|
||||
inLeftSide(ProductScreen.orderLineHas("Minute Maid", "1")),
|
||||
Chrome.clickPlanButton(),
|
||||
FloorScreen.isShown(),
|
||||
FloorScreen.clickTable("4"),
|
||||
inLeftSide(ProductScreen.orderLineHas("Coca-Cola", "1")),
|
||||
Chrome.clickPlanButton(),
|
||||
FloorScreen.isShown(),
|
||||
].flat(),
|
||||
});
|
||||
|
||||
registry.category("web_tour.tours").add("test_create_floor_tour", {
|
||||
steps: () =>
|
||||
[
|
||||
Chrome.startPoS(),
|
||||
Dialog.confirm("Open Register"),
|
||||
Chrome.clickMenuOption("Edit Plan"),
|
||||
FloorScreen.addFloor("AAA"),
|
||||
].flat(),
|
||||
});
|
||||
|
||||
registry.category("web_tour.tours").add("test_tax_in_merge_table_order_line_tour", {
|
||||
steps: () =>
|
||||
[
|
||||
Chrome.startPoS(),
|
||||
Dialog.confirm("Open Register"),
|
||||
FloorScreen.clickFloor("Main Floor"),
|
||||
FloorScreen.clickTable("4"),
|
||||
ProductScreen.clickDisplayedProduct("product_1"),
|
||||
Chrome.clickPlanButton(),
|
||||
FloorScreen.clickFloor("Main Floor"),
|
||||
FloorScreen.clickTable("5"),
|
||||
ProductScreen.clickDisplayedProduct("product_2"),
|
||||
Chrome.clickPlanButton(),
|
||||
FloorScreen.isShown(),
|
||||
FloorScreen.linkTables("5", "4"),
|
||||
FloorScreen.isChildTable("5"),
|
||||
].flat(),
|
||||
});
|
||||
|
||||
registry.category("web_tour.tours").add("no_ghost_floor", {
|
||||
steps: () =>
|
||||
[
|
||||
Chrome.startPoS(),
|
||||
Dialog.confirm("Open Register"),
|
||||
|
||||
// 1. Create new floor along with a table
|
||||
Chrome.clickMenuOption("Edit Plan"),
|
||||
FloorScreen.addFloor("Ghost Floor"),
|
||||
{
|
||||
trigger: `.edit-buttons i[aria-label="Add Table"]`,
|
||||
run: "click",
|
||||
},
|
||||
FloorScreen.selectedTableIs("1"),
|
||||
FloorScreen.clickEditButton("Rename"),
|
||||
|
||||
NumberPopup.enterValue("999"),
|
||||
NumberPopup.isShown("999"),
|
||||
Dialog.confirm(),
|
||||
FloorScreen.selectedTableIs("999"),
|
||||
FloorScreen.clickSaveEditButton(),
|
||||
|
||||
// 2. Create and pay an order on that table
|
||||
FloorScreen.clickFloor("Ghost Floor"),
|
||||
FloorScreen.clickTable("999"),
|
||||
ProductScreen.clickDisplayedProduct("Coca-Cola"),
|
||||
ProductScreen.clickPayButton(false),
|
||||
PaymentScreen.clickPaymentMethod("Cash"),
|
||||
PaymentScreen.clickValidate(),
|
||||
ReceiptScreen.clickNextOrder(),
|
||||
|
||||
// 3. Delete the floor
|
||||
Chrome.clickMenuOption("Edit Plan"),
|
||||
FloorScreen.clickFloor("Ghost Floor"),
|
||||
FloorScreen.clickEditButton("Delete"),
|
||||
Dialog.confirm(),
|
||||
FloorScreen.clickSaveEditButton(),
|
||||
|
||||
// 4. Refund one orderline of the paid order
|
||||
Chrome.clickOrders(),
|
||||
TicketScreen.selectFilter("Active"),
|
||||
TicketScreen.selectFilter("Paid"),
|
||||
TicketScreen.selectOrder("0001"),
|
||||
TicketScreen.confirmRefund(),
|
||||
PaymentScreen.isShown(),
|
||||
PaymentScreen.clickPaymentMethod("Cash"),
|
||||
PaymentScreen.clickValidate(),
|
||||
ReceiptScreen.clickNextOrder(),
|
||||
|
||||
// 5. Floor Plan ===> The floor deleted was reappearing
|
||||
FloorScreen.hasNotFloor("Ghost Floor"),
|
||||
].flat(),
|
||||
});
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
odoo.define('pos_restaurant.tour.BillScreenTourMethods', function (require) {
|
||||
'use strict';
|
||||
|
||||
const { createTourMethods } = require('point_of_sale.tour.utils');
|
||||
|
||||
class Do {
|
||||
clickOk() {
|
||||
return [
|
||||
{
|
||||
content: `go back`,
|
||||
trigger: `.receipt-screen .button.next`,
|
||||
},
|
||||
];
|
||||
}
|
||||
clickBillButton() {
|
||||
return [
|
||||
{
|
||||
content: "click bill button",
|
||||
trigger: '.control-button:contains("Bill")',
|
||||
},
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
class Check {
|
||||
isShown() {
|
||||
return [
|
||||
{
|
||||
content: 'Bill screen is shown',
|
||||
trigger: '.receipt-screen h1:contains("Bill Printing")',
|
||||
run: () => {},
|
||||
},
|
||||
];
|
||||
}
|
||||
isQRCodeShown() {
|
||||
return [
|
||||
{
|
||||
content: "QR codes are shown",
|
||||
trigger: '#posqrcode',
|
||||
run: () => {},
|
||||
},
|
||||
];
|
||||
}
|
||||
isQRCodeNotShown() {
|
||||
return [
|
||||
{
|
||||
content: "QR codes are shown",
|
||||
trigger: 'body:not(:has(#posqrcode))',
|
||||
run: () => {},
|
||||
},
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return createTourMethods('BillScreen', Do, Check);
|
||||
});
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
odoo.define('pos_restaurant.tour.ChromeTourMethods', function (require) {
|
||||
'use strict';
|
||||
|
||||
const { createTourMethods } = require('point_of_sale.tour.utils');
|
||||
const { Do } = require('point_of_sale.tour.ChromeTourMethods');
|
||||
|
||||
class DoExt extends Do {
|
||||
backToFloor() {
|
||||
return [
|
||||
{
|
||||
content: 'back to floor',
|
||||
trigger: '.floor-button',
|
||||
},
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
class Check {
|
||||
backToFloorTextIs(floor, table) {
|
||||
return [
|
||||
{
|
||||
content: `back to floor text is '${floor} ( ${table} )'`,
|
||||
trigger: `.floor-button span:contains("${floor}") ~ .table-name:contains("(${table})")`,
|
||||
run: () => {},
|
||||
},
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
class Execute {}
|
||||
|
||||
return createTourMethods('Chrome', DoExt, Check, Execute);
|
||||
});
|
||||
|
|
@ -1,157 +0,0 @@
|
|||
odoo.define('pos_restaurant.tour.FloorScreenTourMethods', function (require) {
|
||||
'use strict';
|
||||
|
||||
const { createTourMethods } = require('point_of_sale.tour.utils');
|
||||
|
||||
class Do {
|
||||
clickTable(name) {
|
||||
return [
|
||||
{
|
||||
content: `click table '${name}'`,
|
||||
trigger: `.floor-map .table .label:contains("${name}")`,
|
||||
},
|
||||
];
|
||||
}
|
||||
clickFloor(name) {
|
||||
return [
|
||||
{
|
||||
content: `click '${name}' floor`,
|
||||
trigger: `.floor-selector .button-floor:contains("${name}")`,
|
||||
},
|
||||
];
|
||||
}
|
||||
clickEdit() {
|
||||
return [
|
||||
{
|
||||
content: `click edit button`,
|
||||
trigger: `.floor-map .edit-button`,
|
||||
},
|
||||
];
|
||||
}
|
||||
clickAddTable() {
|
||||
return [
|
||||
{
|
||||
content: 'add table',
|
||||
trigger: `.floor-map .edit-button i[aria-label=Add]`,
|
||||
},
|
||||
];
|
||||
}
|
||||
clickDuplicate() {
|
||||
return [
|
||||
{
|
||||
content: 'duplicate table',
|
||||
trigger: `.floor-map .edit-button i[aria-label=Duplicate]`,
|
||||
},
|
||||
];
|
||||
}
|
||||
clickRename() {
|
||||
return [
|
||||
{
|
||||
content: 'rename table',
|
||||
trigger: `.floor-map .edit-button i[aria-label=Rename]`,
|
||||
},
|
||||
];
|
||||
}
|
||||
clickSeats() {
|
||||
return [
|
||||
{
|
||||
content: 'change number of seats',
|
||||
trigger: `.floor-map .edit-button i[aria-label=Seats]`,
|
||||
},
|
||||
];
|
||||
}
|
||||
clickTrash() {
|
||||
return [
|
||||
{
|
||||
content: 'trash table',
|
||||
trigger: `.floor-map .edit-button.trash`,
|
||||
},
|
||||
];
|
||||
}
|
||||
changeShapeTo(shape) {
|
||||
return [
|
||||
{
|
||||
content: `change shape to '${shape}'`,
|
||||
trigger: `.edit-button .button-option${shape === 'round' ? '.square' : '.round'}`,
|
||||
},
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
class Check {
|
||||
selectedFloorIs(name) {
|
||||
return [
|
||||
{
|
||||
content: `selected floor is '${name}'`,
|
||||
trigger: `.floor-selector .button-floor.active:contains("${name}")`,
|
||||
run: () => {},
|
||||
},
|
||||
];
|
||||
}
|
||||
selectedTableIs(name) {
|
||||
return [
|
||||
{
|
||||
content: `selected table is '${name}'`,
|
||||
trigger: `.floor-map .table.selected .label:contains("${name}")`,
|
||||
run: () => {},
|
||||
},
|
||||
];
|
||||
}
|
||||
hasTable(name) {
|
||||
return [
|
||||
{
|
||||
content: `selected floor has '${name}' table`,
|
||||
trigger: `.floor-map .tables .table .label:contains("${name}")`,
|
||||
run: () => {},
|
||||
},
|
||||
];
|
||||
}
|
||||
editModeIsActive(flag) {
|
||||
return [
|
||||
{
|
||||
content: `check if edit mode is ${flag ? 'active' : 'inactive'}`,
|
||||
trigger: `.floor-map .edit-button${flag ? '.active' : ':not(:has(.active))'}`,
|
||||
run: () => {},
|
||||
},
|
||||
];
|
||||
}
|
||||
tableSeatIs(table, val) {
|
||||
return [
|
||||
{
|
||||
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 () {},
|
||||
},
|
||||
];
|
||||
}
|
||||
tableIsNotSelected(name) {
|
||||
return [
|
||||
{
|
||||
content: `table '${name}' is not selected`,
|
||||
trigger: `.floor-map .table:not(.selected) .label:contains("${name}")`,
|
||||
run: function () {},
|
||||
},
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
class Execute {}
|
||||
|
||||
return createTourMethods('FloorScreen', Do, Check, Execute);
|
||||
});
|
||||
|
|
@ -1,87 +0,0 @@
|
|||
odoo.define('pos_restaurant.tour.ProductScreenTourMethods', function (require) {
|
||||
'use strict';
|
||||
|
||||
const { createTourMethods } = require('point_of_sale.tour.utils');
|
||||
const { Do, Check, Execute } = require('point_of_sale.tour.ProductScreenTourMethods');
|
||||
|
||||
class DoExt extends Do {
|
||||
clickSplitBillButton() {
|
||||
return [
|
||||
{
|
||||
content: 'click split bill button',
|
||||
trigger: '.control-buttons .control-button.order-split',
|
||||
},
|
||||
];
|
||||
}
|
||||
clickTransferButton() {
|
||||
return [
|
||||
{
|
||||
content: 'click transfer button',
|
||||
trigger: '.control-buttons .control-button span:contains("Transfer")',
|
||||
},
|
||||
];
|
||||
}
|
||||
clickNoteButton() {
|
||||
return [
|
||||
{
|
||||
content: 'click note button',
|
||||
trigger: '.control-buttons .control-button span:contains("Internal Note")',
|
||||
},
|
||||
];
|
||||
}
|
||||
clickPrintBillButton() {
|
||||
return [
|
||||
{
|
||||
content: 'click print bill button',
|
||||
trigger: '.control-buttons .control-button.order-printbill',
|
||||
},
|
||||
];
|
||||
}
|
||||
clickSubmitButton() {
|
||||
return [
|
||||
{
|
||||
content: 'click print bill button',
|
||||
trigger: '.control-buttons .control-button span:contains("Order")',
|
||||
},
|
||||
];
|
||||
}
|
||||
clickGuestButton() {
|
||||
return [
|
||||
{
|
||||
content: 'click guest button',
|
||||
trigger: '.control-buttons .control-button span:contains("Guests")'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
class CheckExt extends Check {
|
||||
orderlineHasNote(name, quantity, note) {
|
||||
return [
|
||||
{
|
||||
content: `line has ${quantity} quantity`,
|
||||
trigger: `.order .orderline .product-name:contains("${name}") ~ .info-list em:contains("${quantity}")`,
|
||||
run: function () {}, // it's a check
|
||||
},
|
||||
{
|
||||
content: `line has '${note}' note`,
|
||||
trigger: `.order .orderline .info-list .orderline-note:contains("${note}")`,
|
||||
run: function () {}, // it's a check
|
||||
},
|
||||
];
|
||||
}
|
||||
guestNumberIs(numberInString) {
|
||||
return [
|
||||
{
|
||||
content: `guest number is ${numberInString}`,
|
||||
trigger: `.control-buttons .control-button span.control-button-number:contains(${numberInString})`,
|
||||
run: function () {}, // it's a check
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
class ExecuteExt extends Execute {}
|
||||
|
||||
return createTourMethods('ProductScreen', DoExt, CheckExt, ExecuteExt);
|
||||
});
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
odoo.define('pos_restaurant.tour.SplitBillScreenTourMethods', function (require) {
|
||||
'use strict';
|
||||
|
||||
const { createTourMethods } = require('point_of_sale.tour.utils');
|
||||
|
||||
class Do {
|
||||
clickOrderline(name, totalQuantity) {
|
||||
let trigger = `li.orderline .product-name:contains("${name}")`;
|
||||
if (totalQuantity) {
|
||||
trigger += ` ~ .info-list .info:contains("${totalQuantity}")`;
|
||||
}
|
||||
return [
|
||||
{
|
||||
content: `click '${name}' orderline with total quantity of '${totalQuantity}'`,
|
||||
trigger,
|
||||
},
|
||||
];
|
||||
}
|
||||
clickBack() {
|
||||
return [
|
||||
{
|
||||
content: 'click back button',
|
||||
trigger: `.splitbill-screen .button.back`,
|
||||
},
|
||||
];
|
||||
}
|
||||
clickPay() {
|
||||
return [
|
||||
{
|
||||
content: 'click pay button',
|
||||
trigger: `.splitbill-screen .pay-button .button`
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
class Check {
|
||||
orderlineHas(name, totalQuantity, splitQuantity) {
|
||||
return [
|
||||
{
|
||||
content: `'${name}' orderline has total quantity of '${totalQuantity}'`,
|
||||
trigger: `li.orderline .product-name:contains("${name}") ~ .info-list .info:contains("${totalQuantity}")`,
|
||||
run: () => {},
|
||||
},
|
||||
{
|
||||
content: `'${name}' orderline has '${splitQuantity}' quantity to split`,
|
||||
trigger: `li.orderline .product-name:contains("${name}") ~ .info-list .info em:contains("${splitQuantity}")`,
|
||||
run: () => {},
|
||||
},
|
||||
];
|
||||
}
|
||||
subtotalIs(amount) {
|
||||
return [
|
||||
{
|
||||
content: `total amount of split is '${amount}'`,
|
||||
trigger: `.splitbill-screen .order-info .subtotal:contains("${amount}")`,
|
||||
},
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
class Execute {}
|
||||
|
||||
return createTourMethods('SplitBillScreen', Do, Check, Execute);
|
||||
});
|
||||
|
|
@ -1,60 +0,0 @@
|
|||
odoo.define('pos_restaurant.tour.TipScreenTourMethods', function (require) {
|
||||
'use strict';
|
||||
|
||||
const { createTourMethods } = require('point_of_sale.tour.utils');
|
||||
|
||||
class Do {
|
||||
clickPercentTip(percent) {
|
||||
return [
|
||||
{
|
||||
trigger: `.tip-screen .percentage:contains("${percent}")`,
|
||||
},
|
||||
];
|
||||
}
|
||||
setCustomTip(amount) {
|
||||
return [
|
||||
{
|
||||
trigger: `.tip-screen .custom-amount-form input`,
|
||||
run: `text ${amount}`,
|
||||
},
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
class Check {
|
||||
isShown() {
|
||||
return [
|
||||
{
|
||||
trigger: '.pos .tip-screen',
|
||||
run: () => {},
|
||||
},
|
||||
];
|
||||
}
|
||||
totalAmountIs(amount) {
|
||||
return [
|
||||
{
|
||||
trigger: `.tip-screen .total-amount:contains("${amount}")`,
|
||||
run: () => {},
|
||||
},
|
||||
];
|
||||
}
|
||||
percentAmountIs(percent, amount) {
|
||||
return [
|
||||
{
|
||||
trigger: `.tip-screen .percentage:contains("${percent}") ~ .amount:contains("${amount}")`,
|
||||
run: () => {},
|
||||
},
|
||||
];
|
||||
}
|
||||
inputAmountIs(amount) {
|
||||
return [
|
||||
{
|
||||
trigger: `.tip-screen .custom-amount-form input[data-amount="${amount}"]`,
|
||||
run: () => {},
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
return createTourMethods('TipScreen', Do, Check);
|
||||
});
|
||||
|
|
@ -1,126 +0,0 @@
|
|||
odoo.define('pos_reataurant.tour.synchronized_table_management', function (require) {
|
||||
'use strict';
|
||||
|
||||
const { BillScreen } = require('pos_restaurant.tour.BillScreenTourMethods');
|
||||
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.confirmOpeningPopup();
|
||||
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/ui' }, getSteps());
|
||||
|
||||
startSteps();
|
||||
|
||||
/* pos_restaurant_sync_second_login
|
||||
*
|
||||
* This tour should be run after the first tour is done.
|
||||
*/
|
||||
|
||||
// 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
|
||||
ProductScreen.do.clickTransferButton();
|
||||
FloorScreen.do.clickTable('T4');
|
||||
|
||||
// Test if products still get merged after transfering the order
|
||||
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/ui' }, getSteps());
|
||||
|
||||
startSteps();
|
||||
|
||||
ProductScreen.do.confirmOpeningPopup();
|
||||
FloorScreen.do.clickTable("5");
|
||||
ProductScreen.do.clickDisplayedProduct("Coca-Cola");
|
||||
BillScreen.do.clickBillButton();
|
||||
BillScreen.check.isShown();
|
||||
BillScreen.check.isQRCodeNotShown();
|
||||
BillScreen.do.clickOk();
|
||||
ProductScreen.do.clickPayButton();
|
||||
PaymentScreen.do.clickPaymentMethod("Bank");
|
||||
PaymentScreen.do.clickValidate();
|
||||
BillScreen.check.isQRCodeShown();
|
||||
|
||||
Tour.register('BillScreenTour', { test: true, url: '/pos/ui' }, getSteps());
|
||||
});
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,45 +0,0 @@
|
|||
odoo.define('pos_restaurant.tour.Refund', function (require) {
|
||||
'use strict';
|
||||
|
||||
const { PaymentScreen } = require('point_of_sale.tour.PaymentScreenTourMethods');
|
||||
const { FloorScreen } = require('pos_restaurant.tour.FloorScreenTourMethods');
|
||||
const { ProductScreen } = require('pos_restaurant.tour.ProductScreenTourMethods');
|
||||
const { TicketScreen } = require('point_of_sale.tour.TicketScreenTourMethods');
|
||||
const { ReceiptScreen } = require('point_of_sale.tour.ReceiptScreenTourMethods');
|
||||
const { getSteps, startSteps } = require('point_of_sale.tour.utils');
|
||||
var Tour = require('web_tour.tour');
|
||||
|
||||
// signal to start generating steps
|
||||
// when finished, steps can be taken from getSteps
|
||||
startSteps();
|
||||
|
||||
// Create first order and pay it
|
||||
FloorScreen.do.clickTable("T2");
|
||||
ProductScreen.do.confirmOpeningPopup();
|
||||
ProductScreen.do.clickDisplayedProduct("Coca-Cola");
|
||||
ProductScreen.check.selectedOrderlineHas("Coca-Cola");
|
||||
ProductScreen.do.clickDisplayedProduct("Coca-Cola");
|
||||
ProductScreen.check.selectedOrderlineHas("Coca-Cola");
|
||||
ProductScreen.do.clickDisplayedProduct("Water");
|
||||
ProductScreen.check.selectedOrderlineHas("Water");
|
||||
ProductScreen.check.totalAmountIs("6.60");
|
||||
ProductScreen.do.clickPayButton();
|
||||
PaymentScreen.do.clickPaymentMethod("Cash");
|
||||
PaymentScreen.do.clickValidate();
|
||||
ReceiptScreen.do.clickNextOrder();
|
||||
|
||||
// Go to another table and refund one of the product
|
||||
FloorScreen.do.clickTable("T4");
|
||||
ProductScreen.check.orderIsEmpty();
|
||||
ProductScreen.do.clickRefund();
|
||||
TicketScreen.do.selectOrder("-0001");
|
||||
TicketScreen.do.clickOrderline("Coca-Cola");
|
||||
TicketScreen.do.pressNumpad("2");
|
||||
TicketScreen.check.toRefundTextContains("To Refund: 2.00");
|
||||
TicketScreen.do.confirmRefund();
|
||||
ProductScreen.check.isShown();
|
||||
ProductScreen.check.selectedOrderlineHas("Coca-Cola");
|
||||
ProductScreen.check.totalAmountIs("-4.40");
|
||||
|
||||
Tour.register('RefundStayCurrentTableTour', { test: true, url: '/pos/ui' }, getSteps());
|
||||
});
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
import * as ProductScreenPos from "@point_of_sale/../tests/pos/tours/utils/product_screen_util";
|
||||
import * as ProductScreenResto from "@pos_restaurant/../tests/tours/utils/product_screen_util";
|
||||
const ProductScreen = { ...ProductScreenPos, ...ProductScreenResto };
|
||||
import * as Dialog from "@point_of_sale/../tests/generic_helpers/dialog_util";
|
||||
import * as PaymentScreen from "@point_of_sale/../tests/pos/tours/utils/payment_screen_util";
|
||||
import * as ReceiptScreen from "@point_of_sale/../tests/pos/tours/utils/receipt_screen_util";
|
||||
import * as FloorScreen from "@pos_restaurant/../tests/tours/utils/floor_screen_util";
|
||||
import * as TicketScreen from "@point_of_sale/../tests/pos/tours/utils/ticket_screen_util";
|
||||
import * as Chrome from "@point_of_sale/../tests/pos/tours/utils/chrome_util";
|
||||
import * as Order from "@point_of_sale/../tests/generic_helpers/order_widget_util";
|
||||
import { registry } from "@web/core/registry";
|
||||
import { inLeftSide } from "@point_of_sale/../tests/pos/tours/utils/common";
|
||||
|
||||
registry.category("web_tour.tours").add("RefundStayCurrentTableTour", {
|
||||
steps: () =>
|
||||
[
|
||||
Chrome.startPoS(),
|
||||
Dialog.confirm("Open Register"),
|
||||
|
||||
// Create first order and pay it
|
||||
FloorScreen.clickTable("2"),
|
||||
ProductScreen.clickDisplayedProduct("Coca-Cola", true, "1"),
|
||||
ProductScreen.clickDisplayedProduct("Coca-Cola", true, "2"),
|
||||
ProductScreen.clickDisplayedProduct("Water", true, "1"),
|
||||
ProductScreen.totalAmountIs("6.60"),
|
||||
ProductScreen.clickPayButton(false),
|
||||
ProductScreen.discardOrderWarningDialog(),
|
||||
PaymentScreen.clickPaymentMethod("Cash"),
|
||||
PaymentScreen.clickValidate(),
|
||||
ReceiptScreen.clickNextOrder(),
|
||||
|
||||
// Go to another table and refund one of the products
|
||||
FloorScreen.clickTable("4"),
|
||||
ProductScreen.orderIsEmpty(),
|
||||
...ProductScreen.clickRefund(),
|
||||
TicketScreen.selectOrder("001"),
|
||||
Order.hasLine({
|
||||
productName: "Coca-Cola",
|
||||
}),
|
||||
ProductScreen.clickNumpad("2"),
|
||||
TicketScreen.toRefundTextContains("To Refund: 2"),
|
||||
TicketScreen.confirmRefund(),
|
||||
PaymentScreen.isShown(),
|
||||
PaymentScreen.clickBack(),
|
||||
ProductScreen.isShown(),
|
||||
inLeftSide(ProductScreen.orderLineHas("Coca-Cola")),
|
||||
ProductScreen.totalAmountIs("-4.40"),
|
||||
ProductScreen.clickPayButton(),
|
||||
PaymentScreen.clickPaymentMethod("Cash"),
|
||||
PaymentScreen.clickValidate(),
|
||||
ReceiptScreen.isShown(),
|
||||
].flat(),
|
||||
});
|
||||
|
|
@ -0,0 +1,344 @@
|
|||
import * as PaymentScreen from "@point_of_sale/../tests/pos/tours/utils/payment_screen_util";
|
||||
import * as Dialog from "@point_of_sale/../tests/generic_helpers/dialog_util";
|
||||
import * as ReceiptScreen from "@point_of_sale/../tests/pos/tours/utils/receipt_screen_util";
|
||||
import * as ChromePos from "@point_of_sale/../tests/pos/tours/utils/chrome_util";
|
||||
import * as ChromeRestaurant from "@pos_restaurant/../tests/tours/utils/chrome";
|
||||
const Chrome = { ...ChromePos, ...ChromeRestaurant };
|
||||
import * as FloorScreen from "@pos_restaurant/../tests/tours/utils/floor_screen_util";
|
||||
import * as Order from "@point_of_sale/../tests/generic_helpers/order_widget_util";
|
||||
import * as ProductScreenPos from "@point_of_sale/../tests/pos/tours/utils/product_screen_util";
|
||||
import * as ProductScreenResto from "@pos_restaurant/../tests/tours/utils/product_screen_util";
|
||||
const ProductScreen = { ...ProductScreenPos, ...ProductScreenResto };
|
||||
import * as SplitBillScreen from "@pos_restaurant/../tests/tours/utils/split_bill_screen_util";
|
||||
import * as TicketScreen from "@point_of_sale/../tests/pos/tours/utils/ticket_screen_util";
|
||||
import * as combo from "@point_of_sale/../tests/pos/tours/utils/combo_popup_util";
|
||||
import { registry } from "@web/core/registry";
|
||||
|
||||
registry.category("web_tour.tours").add("SplitBillScreenTour", {
|
||||
steps: () =>
|
||||
[
|
||||
Chrome.startPoS(),
|
||||
Dialog.confirm("Open Register"),
|
||||
FloorScreen.clickTable("2"),
|
||||
ProductScreen.addOrderline("Water", "5", "2", "10.0"),
|
||||
ProductScreen.addOrderline("Minute Maid", "3", "2", "6.0"),
|
||||
ProductScreen.addOrderline("Coca-Cola", "1", "2", "2.0"),
|
||||
ProductScreen.clickControlButton("Split"),
|
||||
|
||||
// Check if the screen contains all the orderlines
|
||||
SplitBillScreen.orderlineHas("Water", "5", "0"),
|
||||
SplitBillScreen.orderlineHas("Minute Maid", "3", "0"),
|
||||
SplitBillScreen.orderlineHas("Coca-Cola", "1", "0"),
|
||||
|
||||
// split 3 water and 1 coca-cola
|
||||
SplitBillScreen.clickOrderline("Water"),
|
||||
SplitBillScreen.orderlineHas("Water", "5", "1"),
|
||||
SplitBillScreen.clickOrderline("Water"),
|
||||
SplitBillScreen.clickOrderline("Water"),
|
||||
SplitBillScreen.orderlineHas("Water", "5", "3"),
|
||||
SplitBillScreen.subtotalIs("6.0"),
|
||||
SplitBillScreen.clickOrderline("Coca-Cola"),
|
||||
SplitBillScreen.orderlineHas("Coca-Cola", "1", "1"),
|
||||
SplitBillScreen.subtotalIs("8.0"),
|
||||
|
||||
// click pay to split, go back to check the lines
|
||||
SplitBillScreen.clickButton("Split"),
|
||||
ProductScreen.totalAmountIs("8.0"),
|
||||
ProductScreen.clickOrderline("Water", "3"),
|
||||
ProductScreen.clickOrderline("Coca-Cola", "1"),
|
||||
|
||||
// go back to the original order and see if the order is changed
|
||||
Chrome.clickOrders(),
|
||||
TicketScreen.selectOrder("001"),
|
||||
TicketScreen.loadSelectedOrder(),
|
||||
ProductScreen.isShown(),
|
||||
ProductScreen.clickOrderline("Water", "2"),
|
||||
ProductScreen.clickOrderline("Minute Maid", "3"),
|
||||
|
||||
// Split the order of table 2 again
|
||||
Chrome.clickPlanButton(),
|
||||
FloorScreen.clickTable("2"),
|
||||
ProductScreen.clickControlButton("Split"),
|
||||
|
||||
SplitBillScreen.clickOrderline("Water"),
|
||||
SplitBillScreen.orderlineHas("Water", "2", "1"),
|
||||
SplitBillScreen.subtotalIs("2.0"),
|
||||
SplitBillScreen.clickOrderline("Minute Maid"),
|
||||
SplitBillScreen.orderlineHas("Minute Maid", "3", "1"),
|
||||
SplitBillScreen.subtotalIs("4.0"),
|
||||
|
||||
SplitBillScreen.clickButton("Split"),
|
||||
ProductScreen.totalAmountIs("4.0"),
|
||||
|
||||
// go back to the original order and see if the order is changed
|
||||
Chrome.clickOrders(),
|
||||
TicketScreen.selectOrder("001"),
|
||||
TicketScreen.loadSelectedOrder(),
|
||||
ProductScreen.isShown(),
|
||||
ProductScreen.clickOrderline("Water", "1"),
|
||||
ProductScreen.clickOrderline("Minute Maid", "2"),
|
||||
].flat(),
|
||||
});
|
||||
|
||||
registry.category("web_tour.tours").add("SplitBillScreenTourPay", {
|
||||
steps: () =>
|
||||
[
|
||||
Chrome.startPoS(),
|
||||
//Split pay by selecting products
|
||||
FloorScreen.clickTable("4"),
|
||||
ProductScreen.addOrderline("Water"),
|
||||
ProductScreen.addOrderline("Minute Maid"),
|
||||
ProductScreen.clickControlButton("Split"),
|
||||
SplitBillScreen.clickOrderline("Water"),
|
||||
SplitBillScreen.clickButton("Pay"),
|
||||
PaymentScreen.clickPaymentMethod("Bank"),
|
||||
PaymentScreen.clickValidate(),
|
||||
ReceiptScreen.clickContinueOrder(),
|
||||
SplitBillScreen.clickOrderline("Minute Maid"),
|
||||
SplitBillScreen.clickOrderline("Minute Maid"),
|
||||
SplitBillScreen.clickButton("Pay"),
|
||||
PaymentScreen.clickPaymentMethod("Bank"),
|
||||
PaymentScreen.clickValidate(),
|
||||
ReceiptScreen.clickNextOrder(),
|
||||
].flat(),
|
||||
});
|
||||
|
||||
registry.category("web_tour.tours").add("SplitBillScreenTour2", {
|
||||
steps: () =>
|
||||
[
|
||||
Chrome.startPoS(),
|
||||
Dialog.confirm("Open Register"),
|
||||
FloorScreen.clickTable("2"),
|
||||
ProductScreen.addOrderline("Water", "1", "2.0"),
|
||||
ProductScreen.addOrderline("Minute Maid", "1", "2.0"),
|
||||
ProductScreen.addOrderline("Coca-Cola", "1", "2.0"),
|
||||
Chrome.clickPlanButton(),
|
||||
FloorScreen.clickTable("2"),
|
||||
Chrome.isSynced(),
|
||||
ProductScreen.clickControlButton("Split"),
|
||||
|
||||
SplitBillScreen.clickOrderline("Water"),
|
||||
SplitBillScreen.orderlineHas("Water", "1", "1"),
|
||||
SplitBillScreen.clickOrderline("Coca-Cola"),
|
||||
SplitBillScreen.orderlineHas("Coca-Cola", "1", "1"),
|
||||
SplitBillScreen.clickButton("Split"),
|
||||
ProductScreen.totalAmountIs("4.0"),
|
||||
Chrome.clickOrders(),
|
||||
TicketScreen.selectOrder("2B"),
|
||||
TicketScreen.loadSelectedOrder(),
|
||||
Order.hasLine({ productName: "Coca-Cola", quantity: "1" }),
|
||||
Order.hasLine({ productName: "Water", quantity: "1" }),
|
||||
ProductScreen.totalAmountIs("4.00"),
|
||||
Chrome.clickOrders(),
|
||||
TicketScreen.selectOrder("001"),
|
||||
TicketScreen.loadSelectedOrder(),
|
||||
Order.hasLine({ productName: "Minute Maid", quantity: "1" }),
|
||||
ProductScreen.totalAmountIs("2.00"),
|
||||
].flat(),
|
||||
});
|
||||
|
||||
registry.category("web_tour.tours").add("SplitBillScreenTour3", {
|
||||
steps: () =>
|
||||
[
|
||||
Chrome.startPoS(),
|
||||
Dialog.confirm("Open Register"),
|
||||
FloorScreen.clickTable("2"),
|
||||
ProductScreen.addOrderline("Water", "2", "2", "4.00"),
|
||||
ProductScreen.clickControlButton("Split"),
|
||||
|
||||
// Check if the screen contains all the orderlines
|
||||
SplitBillScreen.orderlineHas("Water", "2", "0"),
|
||||
|
||||
// split 1 water
|
||||
SplitBillScreen.clickOrderline("Water"),
|
||||
SplitBillScreen.orderlineHas("Water", "2", "1"),
|
||||
SplitBillScreen.subtotalIs("2.0"),
|
||||
|
||||
// click pay to split, and pay
|
||||
SplitBillScreen.clickButton("Split"),
|
||||
ProductScreen.totalAmountIs("2.0"),
|
||||
ProductScreen.clickPayButton(),
|
||||
PaymentScreen.clickPaymentMethod("Bank"),
|
||||
PaymentScreen.clickValidate(),
|
||||
ReceiptScreen.clickContinueOrder(),
|
||||
|
||||
// Check if there is still water in the order
|
||||
ProductScreen.isShown(),
|
||||
ProductScreen.orderLineHas("Water", "1.0"),
|
||||
ProductScreen.clickPayButton(),
|
||||
PaymentScreen.clickPaymentMethod("Bank"),
|
||||
PaymentScreen.clickValidate(),
|
||||
// Check if there is no more order to continue
|
||||
ReceiptScreen.clickNextOrder(),
|
||||
].flat(),
|
||||
});
|
||||
|
||||
registry.category("web_tour.tours").add("SplitBillScreenTour4ProductCombo", {
|
||||
steps: () =>
|
||||
[
|
||||
Chrome.startPoS(),
|
||||
Dialog.confirm("Open Register"),
|
||||
FloorScreen.clickTable("2"),
|
||||
ProductScreen.clickDisplayedProduct("Office Combo"),
|
||||
combo.select("Combo Product 3"),
|
||||
combo.select("Combo Product 5"),
|
||||
combo.select("Combo Product 8"),
|
||||
Dialog.confirm(),
|
||||
|
||||
...ProductScreen.clickDisplayedProduct("Office Combo"),
|
||||
combo.select("Combo Product 2"),
|
||||
combo.select("Combo Product 4"),
|
||||
combo.select("Combo Product 7"),
|
||||
Dialog.confirm(),
|
||||
// now we set the qty of this combo combination to 2
|
||||
ProductScreen.clickOrderline("Combo Product 2"),
|
||||
ProductScreen.clickNumpad("2"),
|
||||
ProductScreen.selectedOrderlineHas("Combo Product 2", "2"),
|
||||
|
||||
ProductScreen.addOrderline("Water", "1"),
|
||||
ProductScreen.addOrderline("Minute Maid", "1"),
|
||||
|
||||
// The water, the first combo, and one out of the two items
|
||||
// of the second combo will go in the new splitted order.
|
||||
// we will then check if the rest of the items from the selected
|
||||
// combos are automatically sent to the new order.
|
||||
ProductScreen.clickControlButton("Split"),
|
||||
SplitBillScreen.clickOrderline("Water"),
|
||||
SplitBillScreen.clickOrderline("Combo Product 3"),
|
||||
SplitBillScreen.clickOrderline("Combo Product 2"),
|
||||
// we check that all the lines in the combo are splitted together
|
||||
SplitBillScreen.orderlineHas("Water", "1", "1"),
|
||||
SplitBillScreen.orderlineHas("Office Combo", "1", "1"),
|
||||
SplitBillScreen.orderlineHas("Combo Product 3", "1", "1"),
|
||||
SplitBillScreen.orderlineHas("Combo Product 5", "1", "1"),
|
||||
SplitBillScreen.orderlineHas("Combo Product 8", "1", "1"),
|
||||
SplitBillScreen.orderlineHas("Office Combo", "2", "1"),
|
||||
SplitBillScreen.orderlineHas("Combo Product 2", "2", "0"),
|
||||
SplitBillScreen.orderlineHas("Combo Product 4", "2", "0"),
|
||||
SplitBillScreen.orderlineHas("Combo Product 7", "2", "0"),
|
||||
|
||||
...SplitBillScreen.subtotalIs("97.15"),
|
||||
...SplitBillScreen.clickButton("Split"),
|
||||
ProductScreen.totalAmountIs("97.13"),
|
||||
ProductScreen.clickPayButton(),
|
||||
...PaymentScreen.clickPaymentMethod("Bank"),
|
||||
...PaymentScreen.clickValidate(),
|
||||
...ReceiptScreen.clickContinueOrder(),
|
||||
|
||||
// Check if there is still water in the order
|
||||
...ProductScreen.isShown(),
|
||||
// now we check that all the lines that remained in the order are correct
|
||||
...ProductScreen.orderLineHas("Minute Maid", "1"),
|
||||
...ProductScreen.clickOrderline("Office Combo"),
|
||||
...ProductScreen.selectedOrderlineHas("Office Combo", "1", "43.33"),
|
||||
...ProductScreen.orderLineHas("Combo Product 2", "1"),
|
||||
...ProductScreen.orderLineHas("Combo Product 4", "1"),
|
||||
...ProductScreen.orderLineHas("Combo Product 7", "1"),
|
||||
...ProductScreen.totalAmountIs("45.53"),
|
||||
].flat(),
|
||||
});
|
||||
|
||||
registry.category("web_tour.tours").add("SplitBillScreenTour5Actions", {
|
||||
steps: () =>
|
||||
[
|
||||
Chrome.startPoS(),
|
||||
Dialog.confirm("Open Register"),
|
||||
FloorScreen.clickTable("2"),
|
||||
ProductScreen.addOrderline("Water", "2", "2", "4.00"),
|
||||
ProductScreen.addOrderline("Minute Maid", "1", "3", "3.00"),
|
||||
ProductScreen.clickControlButton("Split"),
|
||||
|
||||
SplitBillScreen.orderlineHas("Water", "2", "0"),
|
||||
SplitBillScreen.clickOrderline("Water"),
|
||||
SplitBillScreen.clickOrderline("Minute Maid"),
|
||||
SplitBillScreen.subtotalIs("5.0"),
|
||||
|
||||
// click transfer button to split and transfer
|
||||
SplitBillScreen.clickButton("Transfer"),
|
||||
FloorScreen.isShown(),
|
||||
FloorScreen.clickTable("5"),
|
||||
|
||||
// check table 5 order and pay
|
||||
ProductScreen.orderLineHas("Water", "1"),
|
||||
ProductScreen.orderLineHas("Minute Maid", "1"),
|
||||
ProductScreen.clickPayButton(),
|
||||
PaymentScreen.clickPaymentMethod("Bank"),
|
||||
PaymentScreen.clickValidate(),
|
||||
ReceiptScreen.clickNextOrder(),
|
||||
|
||||
// Add products in order
|
||||
FloorScreen.clickTable("2"),
|
||||
ProductScreen.orderLineHas("Water", "1"),
|
||||
ProductScreen.addOrderline("Minute Maid", "2", "3", "6.00"),
|
||||
ProductScreen.clickControlButton("Split"),
|
||||
|
||||
SplitBillScreen.clickOrderline("Minute Maid"),
|
||||
SplitBillScreen.clickOrderline("water"),
|
||||
SplitBillScreen.subtotalIs("5.0"),
|
||||
|
||||
// click pay to split, and pay
|
||||
SplitBillScreen.clickButton("Pay"),
|
||||
PaymentScreen.isShown(),
|
||||
PaymentScreen.clickPaymentMethod("Bank"),
|
||||
PaymentScreen.clickValidate(),
|
||||
ReceiptScreen.clickContinueOrder(),
|
||||
|
||||
// Check if redirect to split bill screen of original order
|
||||
SplitBillScreen.orderlineHas("Minute Maid", "1", "0"),
|
||||
SplitBillScreen.clickButton("Pay"),
|
||||
PaymentScreen.isShown(),
|
||||
PaymentScreen.clickPaymentMethod("Bank"),
|
||||
PaymentScreen.clickValidate(),
|
||||
ReceiptScreen.clickNextOrder(),
|
||||
].flat(),
|
||||
});
|
||||
|
||||
registry.category("web_tour.tours").add("SplitBillScreenTourTransfer", {
|
||||
steps: () =>
|
||||
[
|
||||
Chrome.startPoS(),
|
||||
Dialog.confirm("Open Register"),
|
||||
FloorScreen.clickTable("2"),
|
||||
ProductScreen.addOrderline("Water", "5", "2", "10.0"),
|
||||
ProductScreen.addOrderline("Minute Maid", "3", "2", "6.0"),
|
||||
ProductScreen.addOrderline("Coca-Cola", "1", "2", "2.0"),
|
||||
ProductScreen.clickControlButton("Discount"),
|
||||
Dialog.confirm(),
|
||||
ProductScreen.selectedOrderlineHas("discount", 1, "-1.80"),
|
||||
ProductScreen.clickControlButton("Split"),
|
||||
|
||||
// Check if the screen contains all the orderlines
|
||||
SplitBillScreen.orderlineHas("Water", "5", "0"),
|
||||
SplitBillScreen.orderlineHas("Minute Maid", "3", "0"),
|
||||
SplitBillScreen.orderlineHas("Coca-Cola", "1", "0"),
|
||||
Order.doesNotHaveLine({ productName: "Discount" }),
|
||||
|
||||
// split 3 water and 1 coca-cola
|
||||
SplitBillScreen.clickOrderline("Water"),
|
||||
SplitBillScreen.orderlineHas("Water", "5", "1"),
|
||||
SplitBillScreen.clickOrderline("Water"),
|
||||
SplitBillScreen.clickOrderline("Water"),
|
||||
SplitBillScreen.orderlineHas("Water", "5", "3"),
|
||||
SplitBillScreen.subtotalIs("6.0"),
|
||||
SplitBillScreen.clickOrderline("Coca-Cola"),
|
||||
SplitBillScreen.orderlineHas("Coca-Cola", "1", "1"),
|
||||
SplitBillScreen.subtotalIs("8.0"),
|
||||
|
||||
// click pay to split, go back to check the lines
|
||||
SplitBillScreen.clickButton("Transfer"),
|
||||
FloorScreen.clickTable("5"),
|
||||
|
||||
Order.doesNotHaveLine({ productName: "Discount" }),
|
||||
ProductScreen.totalAmountIs("8.0"),
|
||||
ProductScreen.clickOrderline("Water", "3"),
|
||||
ProductScreen.clickOrderline("Coca-Cola", "1"),
|
||||
|
||||
// go back to the original order and see if the order is changed
|
||||
Chrome.clickOrders(),
|
||||
TicketScreen.selectOrder("001"),
|
||||
TicketScreen.loadSelectedOrder(),
|
||||
ProductScreen.isShown(),
|
||||
ProductScreen.clickOrderline("Water", "2"),
|
||||
ProductScreen.clickOrderline("Minute Maid", "3"),
|
||||
].flat(),
|
||||
});
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
import * as ProductScreenPos from "@point_of_sale/../tests/pos/tours/utils/product_screen_util";
|
||||
import * as ProductScreenResto from "@pos_restaurant/../tests/tours/utils/product_screen_util";
|
||||
const ProductScreen = { ...ProductScreenPos, ...ProductScreenResto };
|
||||
import * as Dialog from "@point_of_sale/../tests/generic_helpers/dialog_util";
|
||||
import * as FloorScreen from "@pos_restaurant/../tests/tours/utils/floor_screen_util";
|
||||
import * as TicketScreen from "@point_of_sale/../tests/pos/tours/utils/ticket_screen_util";
|
||||
import * as Chrome from "@point_of_sale/../tests/pos/tours/utils/chrome_util";
|
||||
import { registry } from "@web/core/registry";
|
||||
|
||||
const { DateTime } = luxon;
|
||||
|
||||
registry.category("web_tour.tours").add("PosResTicketScreenTour", {
|
||||
steps: () =>
|
||||
[
|
||||
Chrome.startPoS(),
|
||||
Dialog.confirm("Open Register"),
|
||||
// New Ticket button should not be in the ticket screen if no table is selected.
|
||||
Chrome.clickOrders(),
|
||||
Chrome.clickPlanButton(),
|
||||
|
||||
// Make sure that order is deleted properly.
|
||||
FloorScreen.clickTable("5"),
|
||||
ProductScreen.addOrderline("Minute Maid", "1", "3"),
|
||||
ProductScreen.totalAmountIs("3.0"),
|
||||
Chrome.clickPlanButton(),
|
||||
FloorScreen.orderCountSyncedInTableIs("5", 0),
|
||||
Chrome.clickOrders(),
|
||||
TicketScreen.deleteOrder("001"),
|
||||
Dialog.confirm(),
|
||||
Chrome.clickPlanButton(),
|
||||
FloorScreen.isShown(),
|
||||
FloorScreen.clickTable("5"),
|
||||
ProductScreen.orderIsEmpty(),
|
||||
].flat(),
|
||||
});
|
||||
|
||||
registry.category("web_tour.tours").add("test_cancel_order_from_ui", {
|
||||
steps: () =>
|
||||
[
|
||||
Chrome.startPoS(),
|
||||
Dialog.confirm("Open Register"),
|
||||
FloorScreen.clickTable("5"),
|
||||
ProductScreen.isShown(),
|
||||
ProductScreen.addOrderline("Coca-Cola", "1", "3"),
|
||||
Chrome.clickPlanButton(),
|
||||
Chrome.isSynced(),
|
||||
FloorScreen.isShown(),
|
||||
FloorScreen.clickTable("5"),
|
||||
ProductScreen.clickReview(),
|
||||
ProductScreen.clickControlButton("Cancel Order"),
|
||||
Dialog.confirm(),
|
||||
FloorScreen.isShown(),
|
||||
Chrome.clickOrders(),
|
||||
TicketScreen.noOrderIsThere(),
|
||||
TicketScreen.selectFilter("Paid"),
|
||||
TicketScreen.noOrderIsThere(),
|
||||
Chrome.storedOrderCount(0),
|
||||
].flat(),
|
||||
});
|
||||
|
||||
registry.category("web_tour.tours").add("OrderNumberConflictTour", {
|
||||
steps: () =>
|
||||
[
|
||||
Chrome.startPoS(),
|
||||
FloorScreen.clickTable("3"),
|
||||
ProductScreen.isShown(),
|
||||
ProductScreen.addOrderline("Coca-Cola", "1", "3"),
|
||||
Chrome.clickPlanButton(),
|
||||
Chrome.clickOrders(),
|
||||
TicketScreen.nthRowContains(1, `${String(DateTime.now().year).slice(-2)}0`),
|
||||
TicketScreen.nthRowContains(1, "T 101"),
|
||||
TicketScreen.nthRowContains(2, `${String(DateTime.now().year).slice(-2)}1`),
|
||||
TicketScreen.nthRowContains(2, "T 103"),
|
||||
].flat(),
|
||||
});
|
||||
|
||||
registry.category("web_tour.tours").add("test_sync_lines_qty_update_ticket_screen", {
|
||||
steps: () =>
|
||||
[
|
||||
Chrome.startPoS(),
|
||||
Dialog.confirm("Open Register"),
|
||||
|
||||
Chrome.clickRegister(),
|
||||
ProductScreen.addOrderline("Coca-Cola", "1"),
|
||||
ProductScreen.clickPartnerButton(),
|
||||
ProductScreen.clickCustomer("A powerful Pos man!"),
|
||||
|
||||
Chrome.clickOrders(),
|
||||
TicketScreen.selectOrder("001"),
|
||||
TicketScreen.loadSelectedOrder(),
|
||||
|
||||
ProductScreen.clickOrderline("Coca-Cola", "1"),
|
||||
ProductScreen.clickNumpad("3"),
|
||||
ProductScreen.selectedOrderlineHas("Coca-Cola", "3"),
|
||||
Chrome.clickOrders(),
|
||||
].flat(),
|
||||
});
|
||||
|
|
@ -0,0 +1,210 @@
|
|||
import * as ProductScreenPos from "@point_of_sale/../tests/pos/tours/utils/product_screen_util";
|
||||
import * as ProductScreenResto from "@pos_restaurant/../tests/tours/utils/product_screen_util";
|
||||
const ProductScreen = { ...ProductScreenPos, ...ProductScreenResto };
|
||||
import * as Dialog from "@point_of_sale/../tests/generic_helpers/dialog_util";
|
||||
import * as PaymentScreen from "@point_of_sale/../tests/pos/tours/utils/payment_screen_util";
|
||||
import * as ReceiptScreen from "@point_of_sale/../tests/pos/tours/utils/receipt_screen_util";
|
||||
import * as FloorScreen from "@pos_restaurant/../tests/tours/utils/floor_screen_util";
|
||||
import * as TicketScreen from "@point_of_sale/../tests/pos/tours/utils/ticket_screen_util";
|
||||
import * as TipScreen from "@pos_restaurant/../tests/tours/utils/tip_screen_util";
|
||||
import * as NumberPopup from "@point_of_sale/../tests/generic_helpers/number_popup_util";
|
||||
import * as Chrome from "@point_of_sale/../tests/pos/tours/utils/chrome_util";
|
||||
import { registry } from "@web/core/registry";
|
||||
|
||||
registry.category("web_tour.tours").add("PosResTipScreenTour", {
|
||||
steps: () =>
|
||||
[
|
||||
// Create order that is synced when draft.
|
||||
// order 1
|
||||
Chrome.startPoS(),
|
||||
Dialog.confirm("Open Register"),
|
||||
FloorScreen.clickTable("2"),
|
||||
ProductScreen.addOrderline("Minute Maid", "1", "2"),
|
||||
ProductScreen.totalAmountIs("2.0"),
|
||||
Chrome.clickPlanButton(),
|
||||
FloorScreen.orderCountSyncedInTableIs("2", "1"),
|
||||
FloorScreen.clickTable("2"),
|
||||
ProductScreen.totalAmountIs("2.0"),
|
||||
ProductScreen.clickPayButton(false),
|
||||
ProductScreen.discardOrderWarningDialog(),
|
||||
PaymentScreen.clickPaymentMethod("Bank"),
|
||||
PaymentScreen.clickPaymentMethod("Bank"),
|
||||
PaymentScreen.clickValidate(),
|
||||
TipScreen.isShown(),
|
||||
Chrome.clickPlanButton(),
|
||||
FloorScreen.clickTable("4"),
|
||||
// order 2
|
||||
ProductScreen.addOrderline("Coca-Cola", "2", "2"),
|
||||
ProductScreen.totalAmountIs("4.0"),
|
||||
Chrome.clickPlanButton(),
|
||||
Chrome.clickOrders(),
|
||||
TicketScreen.selectFilter("Active"),
|
||||
{
|
||||
trigger: `.ticket-screen .orders .order-row:contains(Tipping):contains($ 2.00)`,
|
||||
},
|
||||
Chrome.clickPlanButton(),
|
||||
|
||||
// Create without syncing the draft.
|
||||
// order 3
|
||||
FloorScreen.clickTable("5"),
|
||||
ProductScreen.addOrderline("Minute Maid", "3", "2"),
|
||||
ProductScreen.totalAmountIs("6.0"),
|
||||
ProductScreen.clickPayButton(false),
|
||||
ProductScreen.discardOrderWarningDialog(),
|
||||
PaymentScreen.clickPaymentMethod("Bank"),
|
||||
PaymentScreen.clickValidate(),
|
||||
TipScreen.isShown(),
|
||||
Chrome.clickPlanButton(),
|
||||
FloorScreen.clickNewOrder(),
|
||||
// order 4
|
||||
ProductScreen.addOrderline("Coca-Cola", "4", "2"),
|
||||
ProductScreen.totalAmountIs("8.0"),
|
||||
ProductScreen.clickControlButton("Guests"),
|
||||
NumberPopup.enterValue("2"),
|
||||
NumberPopup.isShown("2"),
|
||||
Dialog.confirm(),
|
||||
ProductScreen.guestNumberIs("2"),
|
||||
ProductScreen.clickCloseButton(),
|
||||
ProductScreen.setTab("Test"),
|
||||
Chrome.clickOrders(),
|
||||
TicketScreen.selectFilter("Active"),
|
||||
{
|
||||
trigger: `.ticket-screen .orders .order-row:contains(Tipping):contains($ 6.00)`,
|
||||
},
|
||||
// Tip 20% on order1
|
||||
TicketScreen.selectOrderByPrice("2.0"),
|
||||
TicketScreen.loadSelectedOrder(),
|
||||
TipScreen.isShown(),
|
||||
TipScreen.totalAmountIs("2.0"),
|
||||
TipScreen.percentAmountIs("15%", "0.30"),
|
||||
TipScreen.percentAmountIs("20%", "0.40"),
|
||||
TipScreen.percentAmountIs("25%", "0.50"),
|
||||
TipScreen.clickPercentTip("20%"),
|
||||
TipScreen.inputAmountIs("0.40"),
|
||||
Chrome.clickPlanButton(),
|
||||
FloorScreen.isShown(),
|
||||
Chrome.clickOrders(),
|
||||
TicketScreen.selectFilter("Active"),
|
||||
|
||||
// Tip 25% on order3
|
||||
TicketScreen.selectOrderByPrice("6.0"),
|
||||
TicketScreen.loadSelectedOrder(),
|
||||
TipScreen.isShown(),
|
||||
TipScreen.totalAmountIs("6.0"),
|
||||
TipScreen.percentAmountIs("15%", "0.90"),
|
||||
TipScreen.percentAmountIs("20%", "1.20"),
|
||||
TipScreen.percentAmountIs("25%", "1.50"),
|
||||
TipScreen.clickPercentTip("25%"),
|
||||
TipScreen.inputAmountIs("1.50"),
|
||||
Chrome.clickPlanButton(),
|
||||
FloorScreen.isShown(),
|
||||
Chrome.clickOrders(),
|
||||
|
||||
// finalize order 4 then tip custom amount
|
||||
TicketScreen.selectOrderByPrice("8.0"),
|
||||
TicketScreen.loadSelectedOrder(),
|
||||
ProductScreen.isShown(),
|
||||
ProductScreen.totalAmountIs("8.0"),
|
||||
ProductScreen.guestNumberIs("2"),
|
||||
ProductScreen.clickCloseButton(),
|
||||
ProductScreen.clickPayButton(false),
|
||||
ProductScreen.discardOrderWarningDialog(),
|
||||
PaymentScreen.clickPaymentMethod("Bank"),
|
||||
PaymentScreen.clickValidate(),
|
||||
TipScreen.isShown(),
|
||||
TipScreen.totalAmountIs("8.0"),
|
||||
TipScreen.percentAmountIs("15%", "1.20"),
|
||||
TipScreen.percentAmountIs("20%", "1.60"),
|
||||
TipScreen.percentAmountIs("25%", "2.00"),
|
||||
TipScreen.setCustomTip("1.00"),
|
||||
TipScreen.inputAmountIs("1.00"),
|
||||
Chrome.clickPlanButton(),
|
||||
FloorScreen.isShown(),
|
||||
|
||||
// settle tips here
|
||||
Chrome.clickOrders(),
|
||||
TicketScreen.selectFilter("Tipping"),
|
||||
TicketScreen.tipContains("1.00"),
|
||||
TicketScreen.settleTips(),
|
||||
TicketScreen.selectFilter("Active"),
|
||||
{
|
||||
trigger: `.ticket-screen .orders .order-row:contains(Ongoing):contains($ 4.00)`,
|
||||
},
|
||||
// tip order2 during payment
|
||||
// tip screen should not show after validating payment screen
|
||||
TicketScreen.selectOrderByPrice("4.0"),
|
||||
TicketScreen.loadSelectedOrder(),
|
||||
ProductScreen.clickPayButton(false),
|
||||
ProductScreen.discardOrderWarningDialog(),
|
||||
PaymentScreen.clickTipButton(),
|
||||
|
||||
NumberPopup.enterValue("1"),
|
||||
NumberPopup.isShown("1"),
|
||||
Dialog.confirm(),
|
||||
PaymentScreen.emptyPaymentlines("5.0"),
|
||||
PaymentScreen.clickPaymentMethod("Cash"),
|
||||
PaymentScreen.clickValidate(),
|
||||
ReceiptScreen.isShown(),
|
||||
|
||||
// order 5
|
||||
// Click directly on "settle" without selecting a Tip
|
||||
ReceiptScreen.clickNextOrder(),
|
||||
FloorScreen.clickTable("2"),
|
||||
ProductScreen.addOrderline("Minute Maid", "3", "2"),
|
||||
ProductScreen.totalAmountIs("6.0"),
|
||||
ProductScreen.clickPayButton(false),
|
||||
ProductScreen.discardOrderWarningDialog(),
|
||||
PaymentScreen.clickPaymentMethod("Bank"),
|
||||
PaymentScreen.clickValidate(),
|
||||
TipScreen.isShown(),
|
||||
TipScreen.clickSettle(),
|
||||
ReceiptScreen.isShown(),
|
||||
ReceiptScreen.clickNextOrder(),
|
||||
FloorScreen.isShown(),
|
||||
].flat(),
|
||||
});
|
||||
|
||||
registry.category("web_tour.tours").add("test_tip_after_payment", {
|
||||
steps: () =>
|
||||
[
|
||||
Chrome.startPoS(),
|
||||
Dialog.confirm("Open Register"),
|
||||
FloorScreen.clickTable("2"),
|
||||
ProductScreen.addOrderline("Minute Maid", "1", "3"),
|
||||
ProductScreen.clickPayButton(false),
|
||||
ProductScreen.discardOrderWarningDialog(),
|
||||
// case 1: remaining < 0 => increase PaymentLine amount
|
||||
PaymentScreen.enterPaymentLineAmount("Bank", "1"),
|
||||
PaymentScreen.clickTipButton(),
|
||||
{
|
||||
content: "click numpad button: 1",
|
||||
trigger: ".modal div.numpad button:contains(/^1/)",
|
||||
run: "click",
|
||||
},
|
||||
Dialog.confirm(),
|
||||
PaymentScreen.selectedPaymentlineHas("Bank", "2.00"),
|
||||
// case 2: remaining >= 0 and remaining >= tip => don't change PaymentLine amount
|
||||
PaymentScreen.clickPaymentlineDelButton("Bank", "2.00"),
|
||||
PaymentScreen.enterPaymentLineAmount("Bank", "5"),
|
||||
PaymentScreen.clickTipButton(),
|
||||
{
|
||||
content: "click numpad button: 2",
|
||||
trigger: ".modal div.numpad button:contains(/^2/)",
|
||||
run: "click",
|
||||
},
|
||||
Dialog.confirm(),
|
||||
PaymentScreen.selectedPaymentlineHas("Bank", "5.00"),
|
||||
// case 3: remaining >= 0 and remaining < tip => increase by the difference
|
||||
PaymentScreen.clickPaymentlineDelButton("Bank", "5.00"),
|
||||
PaymentScreen.enterPaymentLineAmount("Bank", "5"),
|
||||
PaymentScreen.clickTipButton(),
|
||||
{
|
||||
content: "click numpad button: 3",
|
||||
trigger: ".modal div.numpad button:contains(/^3/)",
|
||||
run: "click",
|
||||
},
|
||||
Dialog.confirm(),
|
||||
PaymentScreen.selectedPaymentlineHas("Bank", "6.00"),
|
||||
Chrome.endTour(),
|
||||
].flat(),
|
||||
});
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
import * as Dialog from "@point_of_sale/../tests/generic_helpers/dialog_util";
|
||||
|
||||
export function isTabActive(tabText) {
|
||||
return [
|
||||
{
|
||||
content: "Check if the active tab contains the text" + tabText,
|
||||
trigger: `.pos-leftheader span.text-bg-info:contains(${tabText})`,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
export function closePrintingWarning() {
|
||||
return [
|
||||
{
|
||||
...Dialog.confirm(),
|
||||
content: "acknowledge printing error ( because we don't have printer in the test. )",
|
||||
},
|
||||
];
|
||||
}
|
||||
|
|
@ -0,0 +1,175 @@
|
|||
/* global posmodel */
|
||||
|
||||
const getData = ({ lineProductName, productName, partnerName } = {}) => {
|
||||
const order = posmodel.models["pos.order"].find((o) => o.pos_reference.includes("device_sync"));
|
||||
|
||||
let partner = null;
|
||||
if (partnerName) {
|
||||
partner = posmodel.models["res.partner"].find((p) => p.name === partnerName);
|
||||
}
|
||||
|
||||
let line = null;
|
||||
if (lineProductName) {
|
||||
line = order.lines.find((l) => l.product_id.display_name === lineProductName);
|
||||
}
|
||||
|
||||
let product = null;
|
||||
if (productName) {
|
||||
product = posmodel.models["product.product"].find((p) => p.display_name === productName);
|
||||
}
|
||||
|
||||
return { order, line, product, partner };
|
||||
};
|
||||
|
||||
const notify = async () => {
|
||||
const orm = posmodel.env.services.orm;
|
||||
await orm.call("pos.config", "notify_synchronisation", [
|
||||
posmodel.config.id,
|
||||
posmodel.session.id,
|
||||
999,
|
||||
]);
|
||||
};
|
||||
|
||||
const getLineData = (product, order, quantity) => ({
|
||||
name: product.display_name,
|
||||
order_id: order.id,
|
||||
product_id: product.id,
|
||||
price_unit: product.lst_price,
|
||||
price_subtotal: product.lst_price * quantity,
|
||||
price_subtotal_incl: product.lst_price * quantity,
|
||||
discount: 0,
|
||||
qty: quantity,
|
||||
});
|
||||
|
||||
// In the point-of-sale code, we consider that synchronization is necessary
|
||||
// when the write_date of the local order is smaller than that of the server.
|
||||
// To prevent the PoS from ignoring our synchronization.
|
||||
const writeOnOrder = async (order, data) => {
|
||||
const sec = new Date(order.write_date).getMilliseconds() + 1010;
|
||||
const timeout = Math.ceil(sec - new Date().getMilliseconds(), 0);
|
||||
await new Promise((res) => setTimeout(res, timeout));
|
||||
const orm = posmodel.env.services.orm;
|
||||
await orm.write("pos.order", [order.id], data);
|
||||
await notify();
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {string} productName
|
||||
* @param {number} quantity
|
||||
* @returns StepSchema[]
|
||||
*/
|
||||
export function createNewLine(productName, quantity) {
|
||||
return [
|
||||
{
|
||||
trigger: "body",
|
||||
run: async () => {
|
||||
const { order, product } = getData({ productName });
|
||||
await writeOnOrder(order, {
|
||||
lines: [[0, 0, getLineData(product, order, quantity)]],
|
||||
});
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} productName
|
||||
* @param {number} quantity
|
||||
* @returns StepSchema[]
|
||||
*/
|
||||
export function changeLineQuantity(productName, quantity) {
|
||||
return [
|
||||
{
|
||||
trigger: "body",
|
||||
run: async () => {
|
||||
const { order, line } = getData({ lineProductName: productName });
|
||||
await writeOnOrder(order, {
|
||||
lines: [[1, line.id, getLineData(line.product_id, order, quantity)]],
|
||||
});
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} partnerName
|
||||
* @returns StepSchema[]
|
||||
*/
|
||||
export function changePartner(partnerName) {
|
||||
return [
|
||||
{
|
||||
trigger: "body",
|
||||
run: async () => {
|
||||
const { order, partner } = getData({ partnerName });
|
||||
await writeOnOrder(order, {
|
||||
partner_id: partner.id,
|
||||
});
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
export function markOrderAsPaid() {
|
||||
return [
|
||||
{
|
||||
trigger: "body",
|
||||
run: async () => {
|
||||
const { order } = getData({});
|
||||
await writeOnOrder(order, {
|
||||
state: "paid",
|
||||
amount_paid: order.amount_total,
|
||||
amount_return: 0,
|
||||
amount_tax: 0,
|
||||
amount_total: 0,
|
||||
});
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
export function createNewOrderOnTable(tableName, productTuple) {
|
||||
return [
|
||||
{
|
||||
trigger: "body",
|
||||
run: async () => {
|
||||
const orm = posmodel.env.services.orm;
|
||||
const prices = {
|
||||
amount_paid: 0,
|
||||
amount_return: 0,
|
||||
amount_tax: 0,
|
||||
amount_total: 0,
|
||||
};
|
||||
const lines = productTuple.map(([productName, quantity]) => {
|
||||
const product = posmodel.models["product.product"].find(
|
||||
(p) => p.display_name === productName
|
||||
);
|
||||
const lineData = getLineData(product, false, quantity);
|
||||
prices.amount_paid += lineData.price_subtotal;
|
||||
prices.amount_return += lineData.price_subtotal;
|
||||
return [
|
||||
0,
|
||||
0,
|
||||
{
|
||||
...lineData,
|
||||
price_subtotal: lineData.price_subtotal,
|
||||
price_subtotal_incl: lineData.price_subtotal_incl,
|
||||
},
|
||||
];
|
||||
});
|
||||
const table = posmodel.models["restaurant.table"].find(
|
||||
(t) => t.table_number === parseInt(tableName)
|
||||
);
|
||||
await orm.create("pos.order", [
|
||||
{
|
||||
...prices,
|
||||
pos_reference: `device_sync_${Math.floor(Math.random() * 9999)}`,
|
||||
session_id: posmodel.session.id,
|
||||
table_id: table.id,
|
||||
lines,
|
||||
},
|
||||
]);
|
||||
await notify();
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
|
@ -0,0 +1,220 @@
|
|||
import * as Numpad from "@point_of_sale/../tests/generic_helpers/numpad_util";
|
||||
import { negate } from "@point_of_sale/../tests/generic_helpers/utils";
|
||||
|
||||
export function table({ name, withClass = "", withoutClass, run = () => {}, numOfSeats }) {
|
||||
let trigger = `.floor-map .table${withClass}`;
|
||||
if (withoutClass) {
|
||||
trigger += `:not(${withoutClass})`;
|
||||
}
|
||||
if (name) {
|
||||
trigger += `:has(.label:contains("${name}"))`;
|
||||
}
|
||||
return {
|
||||
content: `Check table with attributes: ${JSON.stringify(arguments[0])}`,
|
||||
trigger,
|
||||
run: typeof run === "string" ? run : (helpers) => run(helpers, trigger),
|
||||
};
|
||||
}
|
||||
export const clickTable = (name) => table({ name, run: "click" });
|
||||
export const hasTable = (name) => table({ name });
|
||||
export const selectedTableIs = (name) => table({ name, withClass: ".selected" });
|
||||
export const ctrlClickTable = (name) =>
|
||||
table({
|
||||
name,
|
||||
run: (helpers, trigger) => {
|
||||
helpers
|
||||
.queryOne(trigger)
|
||||
.dispatchEvent(new MouseEvent("click", { bubbles: true, ctrlKey: true }));
|
||||
},
|
||||
});
|
||||
export function clickFloor(name) {
|
||||
return [
|
||||
{
|
||||
content: `click '${name}' floor`,
|
||||
trigger: `.floor-selector .button-floor:contains("${name}")`,
|
||||
run: "click",
|
||||
},
|
||||
];
|
||||
}
|
||||
export function hasFloor(name) {
|
||||
return [
|
||||
{
|
||||
content: `has '${name}' floor`,
|
||||
trigger: `.floor-selector .button-floor:contains("${name}")`,
|
||||
},
|
||||
];
|
||||
}
|
||||
export function hasNotFloor(name) {
|
||||
return [
|
||||
{
|
||||
content: `has not '${name}' floor`,
|
||||
trigger: negate(`.floor-selector .button-floor:contains("${name}")`),
|
||||
},
|
||||
];
|
||||
}
|
||||
export function clickEditButton(button) {
|
||||
return [
|
||||
{
|
||||
content: "add table",
|
||||
trigger: `.edit-buttons i[aria-label="${button}"]`,
|
||||
run: "click",
|
||||
},
|
||||
];
|
||||
}
|
||||
export function clickSaveEditButton() {
|
||||
return [
|
||||
{
|
||||
content: "add table",
|
||||
trigger: '.edit-buttons button:contains("Save")',
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
trigger: negate(".edit-buttons button:contains('Save')"),
|
||||
},
|
||||
];
|
||||
}
|
||||
export function clickTableSelectorButton() {
|
||||
return [
|
||||
{
|
||||
content: "click on table selector button",
|
||||
trigger: ".floor-screen .right-buttons button i.fa-hashtag",
|
||||
run: "click",
|
||||
},
|
||||
];
|
||||
}
|
||||
export function goTo(name) {
|
||||
return [
|
||||
...clickTableSelectorButton(),
|
||||
...Numpad.enterValue(name),
|
||||
{
|
||||
trigger: ".floor-screen .right-buttons .jump-button",
|
||||
run: "click",
|
||||
},
|
||||
];
|
||||
}
|
||||
export function selectedFloorIs(name) {
|
||||
return [
|
||||
{
|
||||
content: `selected floor is '${name}'`,
|
||||
trigger: `.button-floor.active:contains("${name}")`,
|
||||
},
|
||||
];
|
||||
}
|
||||
export function orderCountSyncedInTableIs(table, count) {
|
||||
if (count === 0 || count === "0") {
|
||||
return [
|
||||
{
|
||||
trigger: `.floor-map .table:has(.label:contains("${table}")):not(:has(.order-count))`,
|
||||
},
|
||||
];
|
||||
}
|
||||
return [
|
||||
{
|
||||
trigger: `.floor-map .table:has(.label:contains("${table}")):has(.order-count:contains("${count}"))`,
|
||||
},
|
||||
];
|
||||
}
|
||||
export function isShown() {
|
||||
return [
|
||||
{
|
||||
trigger: ".floor-map",
|
||||
},
|
||||
];
|
||||
}
|
||||
export function linkTables(child, parent) {
|
||||
async function drag_multiple_and_then_drop(helpers, ...drags) {
|
||||
const dragEffectDelay = async () => {
|
||||
console.log(helpers.delay);
|
||||
await new Promise((resolve) => requestAnimationFrame(resolve));
|
||||
await new Promise((resolve) => setTimeout(resolve, helpers.delay));
|
||||
};
|
||||
const element = helpers.anchor;
|
||||
const { drag } = odoo.loader.modules.get("@odoo/hoot-dom");
|
||||
const { drop, moveTo } = await drag(element);
|
||||
await dragEffectDelay();
|
||||
await helpers.hover(element, {
|
||||
position: {
|
||||
top: 20,
|
||||
left: 20,
|
||||
},
|
||||
relative: true,
|
||||
});
|
||||
await dragEffectDelay();
|
||||
for (const [selector, options] of drags) {
|
||||
console.log("Selector", selector, options);
|
||||
const target = await helpers.waitFor(selector, {
|
||||
visible: true,
|
||||
timeout: 500,
|
||||
});
|
||||
await moveTo(target, options);
|
||||
await dragEffectDelay();
|
||||
}
|
||||
await drop();
|
||||
await dragEffectDelay();
|
||||
}
|
||||
return {
|
||||
content: `Drag table ${child} onto table ${parent} in order to link them`,
|
||||
trigger: table({ name: child }).trigger,
|
||||
async run(helpers) {
|
||||
helpers.delay = 500;
|
||||
await drag_multiple_and_then_drop(
|
||||
helpers,
|
||||
[
|
||||
table({ name: parent }).trigger,
|
||||
{
|
||||
position: "top",
|
||||
relative: true,
|
||||
},
|
||||
],
|
||||
[
|
||||
table({ name: parent }).trigger,
|
||||
{
|
||||
position: "center",
|
||||
relative: true,
|
||||
},
|
||||
]
|
||||
);
|
||||
},
|
||||
};
|
||||
}
|
||||
export function unlinkTables(child, parent) {
|
||||
return {
|
||||
content: `Drag table ${child} away from table ${parent} to unlink them`,
|
||||
trigger: table({ name: child }).trigger,
|
||||
async run(helpers) {
|
||||
await helpers.drag_and_drop(`div.floor-map`, {
|
||||
position: {
|
||||
bottom: 0,
|
||||
},
|
||||
relative: true,
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
export function isChildTable(child) {
|
||||
return {
|
||||
content: `Verify that table ${child} is a child table`,
|
||||
trigger: table({ name: child }).trigger + ` .info.opacity-25`,
|
||||
};
|
||||
}
|
||||
export function clickNewOrder() {
|
||||
return { trigger: ".new-order", run: "click" };
|
||||
}
|
||||
|
||||
export function addFloor(floorName) {
|
||||
return [
|
||||
{
|
||||
trigger: ".floor-selector button i[aria-label='Add Floor']",
|
||||
run: "click",
|
||||
},
|
||||
{
|
||||
trigger: ".modal-body textarea",
|
||||
run: `edit ${floorName}`,
|
||||
},
|
||||
{
|
||||
trigger: ".modal-footer button.btn-primary",
|
||||
run: "click",
|
||||
},
|
||||
...selectedFloorIs(floorName),
|
||||
];
|
||||
}
|
||||
|
|
@ -0,0 +1,145 @@
|
|||
import * as Order from "@point_of_sale/../tests/generic_helpers/order_widget_util";
|
||||
import * as ProductScreen from "@point_of_sale/../tests/pos/tours/utils/product_screen_util";
|
||||
import * as TextInputPopup from "@point_of_sale/../tests/generic_helpers/text_input_popup_util";
|
||||
import * as Dialog from "@point_of_sale/../tests/generic_helpers/dialog_util";
|
||||
|
||||
export function clickOrderButton() {
|
||||
return [
|
||||
{
|
||||
content: "click order button",
|
||||
trigger: ".actionpad .submit-order",
|
||||
run: "click",
|
||||
},
|
||||
];
|
||||
}
|
||||
export function orderlinesHaveNoChange() {
|
||||
return Order.doesNotHaveLine({ withClass: ".has-change" });
|
||||
}
|
||||
export function orderlineIsToOrder(name) {
|
||||
return Order.hasLine({
|
||||
productName: name,
|
||||
withClass: ".orderline.has-change",
|
||||
});
|
||||
}
|
||||
export function guestNumberIs(num) {
|
||||
return [
|
||||
...ProductScreen.clickControlButtonMore(),
|
||||
{
|
||||
content: `guest number is ${num}`,
|
||||
trigger: ProductScreen.controlButtonTrigger("Guests") + `:contains(${num})`,
|
||||
},
|
||||
];
|
||||
}
|
||||
export function OrderButtonNotContain(data) {
|
||||
const steps = [
|
||||
{
|
||||
isActive: ["desktop"],
|
||||
content: "check order button not contain data",
|
||||
trigger: `.product-screen .submit-order:not(:contains("${data}"))`,
|
||||
run: function () {}, // it's a check
|
||||
},
|
||||
];
|
||||
return steps;
|
||||
}
|
||||
export function clickCourseButton() {
|
||||
return [
|
||||
{
|
||||
content: "click course button",
|
||||
trigger: `.course-btn`,
|
||||
run: "click",
|
||||
},
|
||||
];
|
||||
}
|
||||
export function selectCourseLine(name) {
|
||||
return [
|
||||
{
|
||||
content: `select course ${name}`,
|
||||
trigger: `.order-course-name:contains(${name})`,
|
||||
run: "click",
|
||||
},
|
||||
];
|
||||
}
|
||||
export function fireCourseButton() {
|
||||
return [
|
||||
{
|
||||
content: "fire course button",
|
||||
trigger: `.actionpad .fire-btn`,
|
||||
run: "click",
|
||||
},
|
||||
];
|
||||
}
|
||||
export function fireCourseButtonHighlighted(courseName) {
|
||||
return [
|
||||
{
|
||||
content: "fire course button highlighted",
|
||||
trigger: `.actionpad .fire-btn.btn-primary:contains('Fire ${courseName}')`,
|
||||
},
|
||||
];
|
||||
}
|
||||
export function payButtonNotHighlighted() {
|
||||
return [
|
||||
{
|
||||
content: "pay button not highlighted",
|
||||
trigger:
|
||||
".actionpad .pay-order-button:not('.highlight'):not('.btn-primary'):contains('Payment')",
|
||||
},
|
||||
];
|
||||
}
|
||||
export function setTab(name) {
|
||||
return [
|
||||
{
|
||||
content: `set tab to ${name}`,
|
||||
trigger: `.product-screen .new-tab`,
|
||||
run: "click",
|
||||
},
|
||||
TextInputPopup.inputText(name),
|
||||
Dialog.confirm(),
|
||||
];
|
||||
}
|
||||
|
||||
export function releaseTable() {
|
||||
return [
|
||||
{
|
||||
content: "release table",
|
||||
trigger: ".product-screen .leftpane .unbook-table",
|
||||
run: "click",
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
export function addCourse() {
|
||||
return {
|
||||
content: `click Course button`,
|
||||
trigger: ProductScreen.controlButtonTrigger("Course"),
|
||||
run: "click",
|
||||
};
|
||||
}
|
||||
|
||||
export function transferCourseTo(destCourse) {
|
||||
return [
|
||||
...ProductScreen.clickControlButton("Transfer course"),
|
||||
{
|
||||
content: `click ${destCourse} from available courses`,
|
||||
trigger: `.modal-body button:contains(${destCourse})`,
|
||||
run: "click",
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
export function discardOrderWarningDialog() {
|
||||
return [
|
||||
{
|
||||
trigger: `.modal-dialog:contains("It seems that the order has not been sent. Would you like to send it to preparation?")`,
|
||||
},
|
||||
Dialog.discard(),
|
||||
];
|
||||
}
|
||||
|
||||
export function confirmOrderWarningDialog() {
|
||||
return [
|
||||
{
|
||||
trigger: `.modal-dialog:contains("It seems that the order has not been sent. Would you like to send it to preparation?")`,
|
||||
},
|
||||
Dialog.confirm(),
|
||||
];
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
import * as Order from "@point_of_sale/../tests/generic_helpers/order_widget_util";
|
||||
|
||||
export function clickOrderline(productName) {
|
||||
return Order.hasLine({ productName, run: "click" });
|
||||
}
|
||||
export function clickBack() {
|
||||
return [
|
||||
{
|
||||
content: "click back button",
|
||||
trigger: `.splitbill-screen .button.back`,
|
||||
run: "click",
|
||||
},
|
||||
];
|
||||
}
|
||||
export function clickButton(name) {
|
||||
return [
|
||||
{
|
||||
content: `click '${name}' button`,
|
||||
trigger: `.splitbill-screen .pay-button button:contains("${name}")`,
|
||||
run: "click",
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
export function orderlineHas(name, totalQuantity, splitQuantity) {
|
||||
return Order.hasLine({
|
||||
productName: name,
|
||||
quantity: splitQuantity != 0 ? `${splitQuantity} / ${totalQuantity}` : totalQuantity,
|
||||
});
|
||||
}
|
||||
export function subtotalIs(amount) {
|
||||
return [
|
||||
{
|
||||
content: `total amount of split is '${amount}'`,
|
||||
trigger: `.splitbill-screen .order-info .subtotal:contains("${amount}")`,
|
||||
run: "click",
|
||||
},
|
||||
];
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
export function clickPercentTip(percent) {
|
||||
return [
|
||||
{
|
||||
trigger: `.tip-screen .percentage:contains("${percent}")`,
|
||||
run: "click",
|
||||
},
|
||||
];
|
||||
}
|
||||
export function setCustomTip(amount) {
|
||||
return [
|
||||
{
|
||||
trigger: `.tip-screen .custom-amount-form input`,
|
||||
run: `edit ${amount}`,
|
||||
},
|
||||
];
|
||||
}
|
||||
export function clickSettle() {
|
||||
return [
|
||||
{
|
||||
trigger: `.button.highlight.next`,
|
||||
run: "click",
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
export function isShown() {
|
||||
return [
|
||||
{
|
||||
trigger: ".pos .tip-screen",
|
||||
},
|
||||
];
|
||||
}
|
||||
export function totalAmountIs(amount) {
|
||||
return [
|
||||
{
|
||||
trigger: `.tip-screen .total-amount:contains("${amount}")`,
|
||||
},
|
||||
];
|
||||
}
|
||||
export function percentAmountIs(percent, amount) {
|
||||
return [
|
||||
{
|
||||
trigger: `.tip-screen .percentage:contains("${percent}") ~ .amount:contains("${amount}")`,
|
||||
},
|
||||
];
|
||||
}
|
||||
export function inputAmountIs(amount) {
|
||||
return [
|
||||
{
|
||||
trigger: `.tip-screen .custom-amount-form input[data-amount="${amount}"]`,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
import { expect, test } from "@odoo/hoot";
|
||||
import { getFilledOrder, setupPosEnv } from "@point_of_sale/../tests/unit/utils";
|
||||
import { mountWithCleanup } from "@web/../tests/web_test_helpers";
|
||||
import { ActionpadWidget } from "@point_of_sale/app/screens/product_screen/action_pad/action_pad";
|
||||
import { definePosModels } from "@point_of_sale/../tests/unit/data/generate_model_definitions";
|
||||
|
||||
definePosModels();
|
||||
|
||||
test("highlightPay", async () => {
|
||||
const store = await setupPosEnv();
|
||||
const order = await getFilledOrder(store);
|
||||
const comp = await mountWithCleanup(ActionpadWidget, {
|
||||
props: {
|
||||
actionName: "Payment",
|
||||
actionToTrigger: () => {},
|
||||
},
|
||||
});
|
||||
|
||||
expect(comp.highlightPay).toBe(false);
|
||||
// simulating order send
|
||||
order.updateLastOrderChange();
|
||||
expect(comp.highlightPay).toBe(true);
|
||||
|
||||
// orderline qty change
|
||||
order.lines[1].qty = 21;
|
||||
expect(comp.highlightPay).toBe(false);
|
||||
order.updateLastOrderChange();
|
||||
expect(comp.highlightPay).toBe(true);
|
||||
|
||||
// orderline note update
|
||||
order.lines[0].note = "Test Orderline Note";
|
||||
expect(comp.highlightPay).toBe(false);
|
||||
order.updateLastOrderChange();
|
||||
expect(comp.highlightPay).toBe(true);
|
||||
|
||||
// general customer note
|
||||
order.general_customer_note = "Test Order Customer Note";
|
||||
expect(comp.highlightPay).toBe(false);
|
||||
order.updateLastOrderChange();
|
||||
expect(comp.highlightPay).toBe(true);
|
||||
|
||||
// internal note
|
||||
order.internal_note = "Test Order Internal Note";
|
||||
expect(comp.highlightPay).toBe(false);
|
||||
order.updateLastOrderChange();
|
||||
expect(comp.highlightPay).toBe(true);
|
||||
});
|
||||
|
|
@ -0,0 +1,133 @@
|
|||
import { test, expect } from "@odoo/hoot";
|
||||
import { setupPosEnv } from "@point_of_sale/../tests/unit/utils";
|
||||
import { mountWithCleanup } from "@web/../tests/web_test_helpers";
|
||||
import { FloorScreen } from "@pos_restaurant/app/screens/floor_screen/floor_screen";
|
||||
import { definePosModels } from "@point_of_sale/../tests/unit/data/generate_model_definitions";
|
||||
|
||||
definePosModels();
|
||||
|
||||
test("getPosTable", async () => {
|
||||
const store = await setupPosEnv();
|
||||
store.currentFloor = store.models["restaurant.floor"].getFirst();
|
||||
const screen = await mountWithCleanup(FloorScreen, {});
|
||||
const renderedComp = await screen.env.services.renderer.toHtml(FloorScreen, {});
|
||||
const table = screen.getPosTable(renderedComp.querySelector(".tableId-2"));
|
||||
expect(table.id).toBe(store.currentFloor.table_ids[0].id);
|
||||
});
|
||||
|
||||
test.tags("desktop");
|
||||
test("computeFloorSize", async () => {
|
||||
const store = await setupPosEnv();
|
||||
const floor = store.models["restaurant.floor"].get(2);
|
||||
store.currentFloor = floor;
|
||||
store.floorPlanStyle = "default";
|
||||
const screen = await mountWithCleanup(FloorScreen, {});
|
||||
screen.floorScrollBox = {
|
||||
el: {
|
||||
clientHeight: 500,
|
||||
offsetWidth: 700,
|
||||
scrollTop: 0,
|
||||
scrollLeft: 0,
|
||||
},
|
||||
};
|
||||
screen.state.floorMapOffset = { x: 0, y: 0 };
|
||||
screen.computeFloorSize();
|
||||
expect(screen.state.floorWidth).toBe("927px");
|
||||
expect(screen.state.floorHeight).toBe("500px");
|
||||
});
|
||||
|
||||
test("resetTable", async () => {
|
||||
const store = await setupPosEnv();
|
||||
const table = store.models["restaurant.table"].get(1);
|
||||
const order = store.addNewOrder({ table_id: table });
|
||||
store.setOrder(order);
|
||||
const screen = await mountWithCleanup(FloorScreen, {});
|
||||
await screen.resetTable();
|
||||
expect(store.getOrder()).toBe(undefined);
|
||||
});
|
||||
|
||||
test("pinch gesture computes scale and sets it", async () => {
|
||||
await setupPosEnv();
|
||||
const screen = await mountWithCleanup(FloorScreen, {});
|
||||
screen.getScale = () => 1;
|
||||
let scaleValue = null;
|
||||
screen.setScale = (value) => {
|
||||
scaleValue = value;
|
||||
};
|
||||
const startEvent = {
|
||||
touches: [
|
||||
{ pageX: 0, pageY: 0 },
|
||||
{ pageX: 0, pageY: 100 },
|
||||
],
|
||||
currentTarget: {
|
||||
style: {
|
||||
setProperty: () => {},
|
||||
},
|
||||
},
|
||||
};
|
||||
screen._onPinchStart(startEvent);
|
||||
const hypotStart = Math.hypot(0 - 0, 0 - 100);
|
||||
expect(screen.scalehypot).toBe(hypotStart);
|
||||
expect(screen.initalScale).toBe(1);
|
||||
const moveEvent = {
|
||||
touches: [
|
||||
{ pageX: 0, pageY: 0 },
|
||||
{ pageX: 0, pageY: 200 },
|
||||
],
|
||||
};
|
||||
screen._computePinchHypo(moveEvent, screen.movePinch.bind(screen));
|
||||
expect(scaleValue).toBeCloseTo(2);
|
||||
});
|
||||
|
||||
test.tags("desktop");
|
||||
test("_createTableHelper", async () => {
|
||||
const store = await setupPosEnv();
|
||||
const floor = store.models["restaurant.floor"].get(2);
|
||||
const screen = await mountWithCleanup(FloorScreen, {});
|
||||
screen.selectFloor(floor);
|
||||
const table = await screen._createTableHelper(null);
|
||||
expect(Boolean(table)).toBe(true);
|
||||
expect(table.floor_id.id).toBe(floor.id);
|
||||
expect(table.table_number).toBe(5);
|
||||
expect(table.height).toBe(table.width);
|
||||
expect(table.position_v >= 0).toBe(true);
|
||||
expect(table.position_h >= 10).toBe(true);
|
||||
});
|
||||
|
||||
test("_getNewTableNumber", async () => {
|
||||
const store = await setupPosEnv();
|
||||
const floor = store.models["restaurant.floor"].getFirst(); // Main Floor (tables 1,2,4)
|
||||
const screen = await mountWithCleanup(FloorScreen, {});
|
||||
screen.selectFloor(floor);
|
||||
const newNumber = screen._getNewTableNumber();
|
||||
expect(newNumber).toBe(5); // max(1,2,4) + 1 = 5
|
||||
});
|
||||
|
||||
test("duplicateTable", async () => {
|
||||
const store = await setupPosEnv();
|
||||
const floor = store.models["restaurant.floor"].getFirst();
|
||||
const screen = await mountWithCleanup(FloorScreen, {});
|
||||
screen.selectFloor(floor);
|
||||
screen.state.selectedTableIds = [floor.table_ids[0].id];
|
||||
await screen.duplicateTable();
|
||||
expect(screen.state.selectedTableIds.length).toBe(1);
|
||||
const newTableId = screen.state.selectedTableIds[0];
|
||||
expect(newTableId).not.toBe(floor.table_ids[0].id);
|
||||
});
|
||||
|
||||
test("_isTableVisible", async () => {
|
||||
const store = await setupPosEnv();
|
||||
const floor = store.models["restaurant.floor"].getFirst();
|
||||
const screen = await mountWithCleanup(FloorScreen, {});
|
||||
screen.selectFloor(floor);
|
||||
screen.floorScrollBox = {
|
||||
el: {
|
||||
scrollTop: 0,
|
||||
scrollLeft: 0,
|
||||
clientHeight: 500,
|
||||
clientWidth: 500,
|
||||
},
|
||||
};
|
||||
const table = store.models["restaurant.table"].get(2);
|
||||
expect(screen._isTableVisible(table)).toBe(true);
|
||||
});
|
||||
|
|
@ -0,0 +1,129 @@
|
|||
import { describe, test, expect } from "@odoo/hoot";
|
||||
import { SplitBillScreen } from "@pos_restaurant/app/screens/split_bill_screen/split_bill_screen";
|
||||
import { setupPosEnv, getFilledOrder } from "@point_of_sale/../tests/unit/utils";
|
||||
import { mountWithCleanup } from "@web/../tests/web_test_helpers";
|
||||
import { definePosModels } from "@point_of_sale/../tests/unit/data/generate_model_definitions";
|
||||
|
||||
definePosModels();
|
||||
|
||||
test("_getSplitOrderName", async () => {
|
||||
const store = await setupPosEnv();
|
||||
const order = await getFilledOrder(store);
|
||||
const screen = await mountWithCleanup(SplitBillScreen, {
|
||||
props: {
|
||||
orderUuid: order.uuid,
|
||||
},
|
||||
});
|
||||
const originalName = "T1";
|
||||
const result = screen._getSplitOrderName(originalName);
|
||||
expect(result).toBe("T1B");
|
||||
});
|
||||
|
||||
describe("onClickLine", () => {
|
||||
test("increments quantity and price tracker on regular line", async () => {
|
||||
const store = await setupPosEnv();
|
||||
const order = await getFilledOrder(store);
|
||||
const screen = await mountWithCleanup(SplitBillScreen, {
|
||||
props: {
|
||||
orderUuid: order.uuid,
|
||||
},
|
||||
});
|
||||
const line = order.getOrderlines()[0];
|
||||
screen.onClickLine(line);
|
||||
expect(screen.qtyTracker[line.uuid]).toBe(1);
|
||||
expect(screen.priceTracker[line.uuid] > 0).toBe(true);
|
||||
screen.onClickLine(line);
|
||||
expect(screen.qtyTracker[line.uuid]).toBe(2);
|
||||
});
|
||||
|
||||
test("handles combo line and its child lines", async () => {
|
||||
const store = await setupPosEnv();
|
||||
const order = store.addNewOrder();
|
||||
const comboTemplate = store.models["product.template"].get(7);
|
||||
const comboItem1 = store.models["product.combo.item"].get(1);
|
||||
const comboItem2 = store.models["product.combo.item"].get(3);
|
||||
const line = await store.addLineToOrder(
|
||||
{
|
||||
product_tmpl_id: comboTemplate,
|
||||
payload: [
|
||||
[
|
||||
{
|
||||
combo_item_id: comboItem1,
|
||||
qty: 1,
|
||||
},
|
||||
{
|
||||
combo_item_id: comboItem2,
|
||||
qty: 1,
|
||||
},
|
||||
],
|
||||
[],
|
||||
],
|
||||
configure: true,
|
||||
},
|
||||
order
|
||||
);
|
||||
expect(order.lines.length).toBe(3);
|
||||
expect(line.product_id.product_tmpl_id).toBe(comboTemplate);
|
||||
expect(line.combo_line_ids.length).toBe(2);
|
||||
expect(line.combo_line_ids[0].product_id.id).toBe(comboItem1.product_id.id);
|
||||
expect(line.combo_line_ids[1].product_id.id).toBe(comboItem2.product_id.id);
|
||||
const screen = await mountWithCleanup(SplitBillScreen, {
|
||||
props: {
|
||||
orderUuid: order.uuid,
|
||||
},
|
||||
});
|
||||
screen.onClickLine(order.lines[0]);
|
||||
expect(screen.qtyTracker[order.lines[0].uuid]).toBe(1);
|
||||
expect(screen.qtyTracker[order.lines[1].uuid]).toBe(1);
|
||||
expect(screen.qtyTracker[order.lines[2].uuid]).toBe(1);
|
||||
});
|
||||
});
|
||||
|
||||
test("_getOrderName", async () => {
|
||||
const store = await setupPosEnv();
|
||||
const order = await getFilledOrder(store);
|
||||
const screen = await mountWithCleanup(SplitBillScreen, {
|
||||
props: {
|
||||
orderUuid: order.uuid,
|
||||
},
|
||||
});
|
||||
expect(screen._getOrderName({ table_id: { table_number: 3 } })).toBe("3");
|
||||
expect(screen._getOrderName({ floatingOrderName: "ToGo" })).toBe("ToGo");
|
||||
expect(screen._getOrderName({})).toBe("");
|
||||
});
|
||||
|
||||
test("setLineQtyStr", async () => {
|
||||
const store = await setupPosEnv();
|
||||
const order = await getFilledOrder(store);
|
||||
const screen = await mountWithCleanup(SplitBillScreen, {
|
||||
props: {
|
||||
orderUuid: order.uuid,
|
||||
},
|
||||
});
|
||||
const line = order.getOrderlines()[0];
|
||||
screen.qtyTracker[line.uuid] = 2;
|
||||
screen.setLineQtyStr(line);
|
||||
expect(line.uiState.splitQty).toBe("2 / 3");
|
||||
});
|
||||
|
||||
test("createSplittedOrder", async () => {
|
||||
const store = await setupPosEnv();
|
||||
const order = await getFilledOrder(store);
|
||||
const table = store.models["restaurant.table"].get(2);
|
||||
order.table_id = table;
|
||||
const screen = await mountWithCleanup(SplitBillScreen, {
|
||||
props: {
|
||||
orderUuid: order.uuid,
|
||||
},
|
||||
});
|
||||
const line = order.getOrderlines()[0];
|
||||
screen.qtyTracker[line.uuid] = 2;
|
||||
const originalUUID = order.uuid;
|
||||
await screen.createSplittedOrder();
|
||||
const currentOrder = store.getOrder();
|
||||
expect(currentOrder.floating_order_name).toBe("1B");
|
||||
expect(currentOrder.uuid).not.toBe(originalUUID);
|
||||
expect(currentOrder.getOrderlines().length).toBe(1);
|
||||
expect(currentOrder.getOrderlines()[0].getQuantity()).toBe(2);
|
||||
expect(order.getOrderlines()[0].getQuantity()).toBe(1);
|
||||
});
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
import { test, expect } from "@odoo/hoot";
|
||||
import { TipScreen } from "@pos_restaurant/app/screens/tip_screen/tip_screen";
|
||||
import { mountWithCleanup, MockServer } from "@web/../tests/web_test_helpers";
|
||||
import { setupPosEnv, getFilledOrder } from "@point_of_sale/../tests/unit/utils";
|
||||
import { definePosModels } from "@point_of_sale/../tests/unit/data/generate_model_definitions";
|
||||
|
||||
definePosModels();
|
||||
|
||||
test("validateTip", async () => {
|
||||
const store = await setupPosEnv();
|
||||
const order = await getFilledOrder(store);
|
||||
const cardPaymentMethod = store.models["pos.payment.method"].get(2);
|
||||
order.addPaymentline(cardPaymentMethod);
|
||||
await store.syncAllOrders();
|
||||
TipScreen.prototype.printTipReceipt = async () => {};
|
||||
const screen = await mountWithCleanup(TipScreen, {
|
||||
props: {
|
||||
orderUuid: order.uuid,
|
||||
},
|
||||
});
|
||||
screen.state.inputTipAmount = "2";
|
||||
await screen.validateTip();
|
||||
expect(order.is_tipped).toBe(true);
|
||||
expect(order.tip_amount).toBe(2);
|
||||
const tipLine = order.lines.find(
|
||||
(line) => line.product_id.id === store.config.tip_product_id.id
|
||||
);
|
||||
store.data.write("pos.order.line", [tipLine.id], {
|
||||
write_date: luxon.DateTime.now(),
|
||||
});
|
||||
MockServer.env["pos.order.line"].write([tipLine.id], {
|
||||
order_id: order.id,
|
||||
write_date: luxon.DateTime.now(),
|
||||
});
|
||||
expect(Boolean(tipLine)).toBe(true);
|
||||
expect(tipLine.price_unit).toBe(2);
|
||||
await store.removeOrder(order);
|
||||
});
|
||||
|
||||
test("overallAmountStr", async () => {
|
||||
const store = await setupPosEnv();
|
||||
const order = await getFilledOrder(store);
|
||||
const cardPaymentMethod = store.models["pos.payment.method"].get(2);
|
||||
order.addPaymentline(cardPaymentMethod);
|
||||
await store.syncAllOrders();
|
||||
TipScreen.prototype.printTipReceipt = async () => {};
|
||||
const screen = await mountWithCleanup(TipScreen, {
|
||||
props: {
|
||||
orderUuid: order.uuid,
|
||||
},
|
||||
});
|
||||
screen.state.inputTipAmount = "2";
|
||||
const result = screen.overallAmountStr;
|
||||
const total = order.priceIncl;
|
||||
const original = screen.env.utils.formatCurrency(total);
|
||||
const tip = screen.env.utils.formatCurrency(2);
|
||||
const overall = screen.env.utils.formatCurrency(total + 2);
|
||||
expect(result).toBe(`${original} + ${tip} tip = ${overall}`);
|
||||
});
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
import { PosConfig } from "@point_of_sale/../tests/unit/data/pos_config.data";
|
||||
|
||||
PosConfig._records = PosConfig._records.map((record) => ({
|
||||
...record,
|
||||
module_pos_restaurant: true,
|
||||
floor_ids: [2, 3],
|
||||
iface_tipproduct: true,
|
||||
tip_product_id: 1,
|
||||
set_tip_after_payment: true,
|
||||
default_screen: "tables",
|
||||
}));
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
import { patch } from "@web/core/utils/patch";
|
||||
import { PosOrderLine } from "@point_of_sale/../tests/unit/data/pos_order_line.data";
|
||||
|
||||
patch(PosOrderLine.prototype, {
|
||||
_load_pos_data_fields() {
|
||||
return [...super._load_pos_data_fields(), "course_id"];
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
import { patch } from "@web/core/utils/patch";
|
||||
import { PosPreset } from "@point_of_sale/../tests/unit/data/pos_preset.data";
|
||||
|
||||
patch(PosPreset.prototype, {
|
||||
_load_pos_data_fields() {
|
||||
return [...super._load_pos_data_fields(), "use_guest"];
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
import { PosSession } from "@point_of_sale/../tests/unit/data/pos_session.data";
|
||||
import { patch } from "@web/core/utils/patch";
|
||||
|
||||
patch(PosSession.prototype, {
|
||||
_load_pos_data_models() {
|
||||
return [
|
||||
...super._load_pos_data_models(),
|
||||
"restaurant.floor",
|
||||
"restaurant.table",
|
||||
"restaurant.order.course",
|
||||
];
|
||||
},
|
||||
});
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
import { patch } from "@web/core/utils/patch";
|
||||
import { hootPosModels } from "@point_of_sale/../tests/unit/data/generate_model_definitions";
|
||||
import { models } from "@web/../tests/web_test_helpers";
|
||||
|
||||
export class RestaurantFloor extends models.ServerModel {
|
||||
_name = "restaurant.floor";
|
||||
|
||||
_load_pos_data_fields() {
|
||||
return [
|
||||
"name",
|
||||
"background_color",
|
||||
"table_ids",
|
||||
"sequence",
|
||||
"pos_config_ids",
|
||||
"floor_background_image",
|
||||
];
|
||||
}
|
||||
|
||||
_records = [
|
||||
{
|
||||
id: 2,
|
||||
name: "Main Floor",
|
||||
background_color: "red",
|
||||
table_ids: [2, 3, 4],
|
||||
sequence: 1,
|
||||
pos_config_ids: [1],
|
||||
floor_background_image: false,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Patio",
|
||||
background_color: "rgb(130, 233, 171)",
|
||||
table_ids: [14, 15, 16],
|
||||
sequence: 1,
|
||||
pos_config_ids: [1],
|
||||
floor_background_image: false,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
patch(hootPosModels, [...hootPosModels, RestaurantFloor]);
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
import { patch } from "@web/core/utils/patch";
|
||||
import { hootPosModels } from "@point_of_sale/../tests/unit/data/generate_model_definitions";
|
||||
import { models } from "@web/../tests/web_test_helpers";
|
||||
|
||||
export class RestaurantOrderCourse extends models.ServerModel {
|
||||
_name = "restaurant.order.course";
|
||||
|
||||
_load_pos_data_fields() {
|
||||
return ["uuid", "fired", "order_id", "line_ids", "index", "write_date"];
|
||||
}
|
||||
}
|
||||
|
||||
patch(hootPosModels, [...hootPosModels, RestaurantOrderCourse]);
|
||||
|
|
@ -0,0 +1,112 @@
|
|||
import { patch } from "@web/core/utils/patch";
|
||||
import { hootPosModels } from "@point_of_sale/../tests/unit/data/generate_model_definitions";
|
||||
import { models } from "@web/../tests/web_test_helpers";
|
||||
|
||||
export class RestaurantTable extends models.ServerModel {
|
||||
_name = "restaurant.table";
|
||||
|
||||
_load_pos_data_fields() {
|
||||
return [
|
||||
"table_number",
|
||||
"width",
|
||||
"height",
|
||||
"position_h",
|
||||
"position_v",
|
||||
"parent_id",
|
||||
"shape",
|
||||
"floor_id",
|
||||
"color",
|
||||
"seats",
|
||||
"active",
|
||||
];
|
||||
}
|
||||
|
||||
_records = [
|
||||
{
|
||||
id: 2,
|
||||
table_number: 1,
|
||||
width: 90,
|
||||
height: 90,
|
||||
position_h: 407,
|
||||
position_v: 88,
|
||||
parent_id: false,
|
||||
shape: "square",
|
||||
floor_id: 2,
|
||||
color: "rgb(53,211,116)",
|
||||
seats: 4,
|
||||
active: true,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
table_number: 2,
|
||||
width: 90,
|
||||
height: 90,
|
||||
position_h: 732,
|
||||
position_v: 221,
|
||||
parent_id: false,
|
||||
shape: "square",
|
||||
floor_id: 2,
|
||||
color: "rgb(53,211,116)",
|
||||
seats: 4,
|
||||
active: true,
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
table_number: 4,
|
||||
width: 165,
|
||||
height: 100,
|
||||
position_h: 762,
|
||||
position_v: 83,
|
||||
parent_id: false,
|
||||
shape: "square",
|
||||
floor_id: 2,
|
||||
color: "rgb(53,211,116)",
|
||||
seats: 4,
|
||||
active: true,
|
||||
},
|
||||
{
|
||||
id: 14,
|
||||
table_number: 101,
|
||||
width: 130,
|
||||
height: 85,
|
||||
position_h: 100,
|
||||
position_v: 50,
|
||||
parent_id: false,
|
||||
shape: "square",
|
||||
floor_id: 3,
|
||||
color: "rgb(53,211,116)",
|
||||
seats: 2,
|
||||
active: true,
|
||||
},
|
||||
{
|
||||
id: 15,
|
||||
table_number: 102,
|
||||
width: 130,
|
||||
height: 85,
|
||||
position_h: 100,
|
||||
position_v: 166,
|
||||
parent_id: false,
|
||||
shape: "square",
|
||||
floor_id: 3,
|
||||
color: "rgb(53,211,116)",
|
||||
seats: 2,
|
||||
active: true,
|
||||
},
|
||||
{
|
||||
id: 16,
|
||||
table_number: 103,
|
||||
width: 130,
|
||||
height: 85,
|
||||
position_h: 100,
|
||||
position_v: 283,
|
||||
parent_id: false,
|
||||
shape: "square",
|
||||
floor_id: 3,
|
||||
color: "rgb(53,211,116)",
|
||||
seats: 2,
|
||||
active: true,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
patch(hootPosModels, [...hootPosModels, RestaurantTable]);
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
import { test, describe, expect } from "@odoo/hoot";
|
||||
import { setupPosEnv, getFilledOrder } from "@point_of_sale/../tests/unit/utils";
|
||||
import { definePosModels } from "@point_of_sale/../tests/unit/data/generate_model_definitions";
|
||||
|
||||
definePosModels();
|
||||
|
||||
describe("pos.order restaurant patches", () => {
|
||||
test("customer count and amount per guest", async () => {
|
||||
const store = await setupPosEnv();
|
||||
const order = await getFilledOrder(store);
|
||||
order.setCustomerCount(3);
|
||||
expect(order.getCustomerCount()).toBe(3);
|
||||
order.setCustomerCount(4);
|
||||
expect(order.amountPerGuest()).toBe(4.4625);
|
||||
});
|
||||
|
||||
test("isDirectSale", async () => {
|
||||
const store = await setupPosEnv();
|
||||
const order = store.addNewOrder();
|
||||
expect(order.isDirectSale).toBe(true);
|
||||
});
|
||||
|
||||
test("setPartner", async () => {
|
||||
const store = await setupPosEnv();
|
||||
const order = store.addNewOrder();
|
||||
const partner = store.models["res.partner"].get(18);
|
||||
order.setPartner(partner);
|
||||
expect(order.floating_order_name).toBe("Public user");
|
||||
});
|
||||
|
||||
test("cleanCourses", async () => {
|
||||
const store = await setupPosEnv();
|
||||
const order = await getFilledOrder(store);
|
||||
const course1 = store.addCourse();
|
||||
const line = order.lines[0];
|
||||
line.course_id = course1;
|
||||
const course2 = store.addCourse();
|
||||
course1.fired = true;
|
||||
order.cleanCourses();
|
||||
expect(order.course_ids.includes(course2)).toBe(false);
|
||||
expect(order.course_ids.includes(course1)).toBe(true);
|
||||
});
|
||||
|
||||
test("getNextCourseIndex", async () => {
|
||||
const store = await setupPosEnv();
|
||||
const order = await getFilledOrder(store);
|
||||
store.addCourse();
|
||||
store.addCourse();
|
||||
expect(order.getNextCourseIndex()).toBe(4);
|
||||
});
|
||||
|
||||
test("getName returns formatted name for table + children", async () => {
|
||||
const store = await setupPosEnv();
|
||||
const table = store.models["restaurant.table"].get(2);
|
||||
const order = store.addNewOrder({ table_id: table });
|
||||
const child = store.models["restaurant.table"].get(3);
|
||||
let name = order.getName();
|
||||
expect(name).toBe("T 1");
|
||||
child.parent_id = table;
|
||||
name = order.getName();
|
||||
expect(name).toBe("T 1 & 2");
|
||||
});
|
||||
|
||||
test("ensureCourseSelection and getSelectedCourse", async () => {
|
||||
const store = await setupPosEnv();
|
||||
const order = store.addNewOrder();
|
||||
const course1 = store.addCourse();
|
||||
course1.fired = false;
|
||||
const course2 = store.addCourse();
|
||||
course2.fired = true;
|
||||
order.ensureCourseSelection();
|
||||
expect(order.getSelectedCourse().uuid).toBe(course1.uuid);
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
import { test, expect } from "@odoo/hoot";
|
||||
import { setupPosEnv, getFilledOrder } from "@point_of_sale/../tests/unit/utils";
|
||||
import { definePosModels } from "@point_of_sale/../tests/unit/data/generate_model_definitions";
|
||||
|
||||
definePosModels();
|
||||
|
||||
test("name returns localized name with index", async () => {
|
||||
const store = await setupPosEnv();
|
||||
store.addNewOrder();
|
||||
const course = store.addCourse();
|
||||
expect(course.name).toBe("Course 1");
|
||||
});
|
||||
|
||||
test("isSelected", async () => {
|
||||
const store = await setupPosEnv();
|
||||
const order = store.addNewOrder();
|
||||
const course = store.addCourse();
|
||||
order.selectCourse(course);
|
||||
expect(course.isSelected()).toBe(true);
|
||||
});
|
||||
|
||||
test("isEmpty", async () => {
|
||||
const store = await setupPosEnv();
|
||||
store.addNewOrder();
|
||||
const course = store.addCourse();
|
||||
course.line_ids = [];
|
||||
expect(course.isEmpty()).toBe(true);
|
||||
});
|
||||
|
||||
test("isReadyToFire", async () => {
|
||||
const store = await setupPosEnv();
|
||||
const order = await getFilledOrder(store);
|
||||
const course = store.addCourse();
|
||||
const line = order.lines[0];
|
||||
line.course_id = course;
|
||||
course.line_ids = [line];
|
||||
expect(course.isReadyToFire()).toBe(true);
|
||||
});
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
import { test, expect } from "@odoo/hoot";
|
||||
import { setupPosEnv } from "@point_of_sale/../tests/unit/utils";
|
||||
import { definePosModels } from "@point_of_sale/../tests/unit/data/generate_model_definitions";
|
||||
|
||||
definePosModels();
|
||||
|
||||
test("getOrders", async () => {
|
||||
const store = await setupPosEnv();
|
||||
const table = store.models["restaurant.table"].get(2);
|
||||
const order = store.addNewOrder({ table_id: table });
|
||||
const tableOrders = table.getOrders();
|
||||
expect(tableOrders.length).toBe(1);
|
||||
expect(tableOrders[0].id).toBe(order.id);
|
||||
});
|
||||
|
||||
test("getParent and isParent", async () => {
|
||||
const store = await setupPosEnv();
|
||||
const models = store.models;
|
||||
const parent = models["restaurant.table"].get(2);
|
||||
const child = models["restaurant.table"].get(3);
|
||||
child.parent_id = parent;
|
||||
const result = child.getParent();
|
||||
expect(parent.isParent(child)).toBe(true);
|
||||
expect(result.id).toBe(2);
|
||||
});
|
||||
|
||||
test("getParentSide", async () => {
|
||||
const store = await setupPosEnv();
|
||||
const models = store.models;
|
||||
const parent = models["restaurant.table"].get(2);
|
||||
const child = models["restaurant.table"].get(3);
|
||||
child.parent_id = parent;
|
||||
child.position_h = parent.position_h + 50;
|
||||
child.position_v = parent.position_v;
|
||||
const side = child.getParentSide();
|
||||
expect(side).toBe("left");
|
||||
});
|
||||
|
||||
test("getX and getY", async () => {
|
||||
const store = await setupPosEnv();
|
||||
const table1 = store.models["restaurant.table"].get(2);
|
||||
const table2 = store.models["restaurant.table"].get(3);
|
||||
expect(table1.getX()).toBe(407);
|
||||
expect(table1.getY()).toBe(88);
|
||||
table2.parent_id = table1;
|
||||
table2.parent_side = "left";
|
||||
expect(table2.getX()).toBe(497);
|
||||
expect(table2.getY()).toBe(88);
|
||||
table2.parent_side = "top";
|
||||
expect(table2.getX()).toBe(407);
|
||||
expect(table2.getY()).toBe(-2);
|
||||
});
|
||||
|
||||
test("rootTable", async () => {
|
||||
const store = await setupPosEnv();
|
||||
const table1 = store.models["restaurant.table"].get(2);
|
||||
const table2 = store.models["restaurant.table"].get(3);
|
||||
const table3 = store.models["restaurant.table"].get(4);
|
||||
table2.parent_id = table1;
|
||||
table3.parent_id = table2;
|
||||
expect(table3.rootTable.id).toBe(table1.id);
|
||||
});
|
||||
|
|
@ -0,0 +1,466 @@
|
|||
import { describe, expect, test } from "@odoo/hoot";
|
||||
import { definePosModels } from "@point_of_sale/../tests/unit/data/generate_model_definitions";
|
||||
import {
|
||||
getFilledOrder,
|
||||
setupPosEnv,
|
||||
waitUntilOrdersSynced,
|
||||
} from "@point_of_sale/../tests/unit/utils";
|
||||
import { MockServer } from "@web/../tests/web_test_helpers";
|
||||
|
||||
const { DateTime } = luxon;
|
||||
|
||||
definePosModels();
|
||||
|
||||
describe("restaurant pos_store.js", () => {
|
||||
test("restoreOrdersToOriginalTable", async () => {
|
||||
const store = await setupPosEnv();
|
||||
const table1 = store.models["restaurant.table"].get(1);
|
||||
const table2 = store.models["restaurant.table"].get(2);
|
||||
const sourceOrder = store.addNewOrder({ table_id: table1 });
|
||||
const product = store.models["product.template"].get(5);
|
||||
await store.addLineToOrder(
|
||||
{
|
||||
product_tmpl_id: product,
|
||||
qty: 3,
|
||||
},
|
||||
sourceOrder
|
||||
);
|
||||
const line = sourceOrder.lines[0];
|
||||
sourceOrder.uiState.unmerge = {
|
||||
[line.uuid]: {
|
||||
table_id: table2.id,
|
||||
quantity: 1,
|
||||
},
|
||||
};
|
||||
const newOrder = await store.restoreOrdersToOriginalTable(sourceOrder, table2);
|
||||
expect(newOrder.table_id.id).toBe(table2.id);
|
||||
expect(newOrder.lines.length).toBe(1);
|
||||
});
|
||||
|
||||
test("fireCourse", async () => {
|
||||
const store = await setupPosEnv();
|
||||
store.addNewOrder();
|
||||
const course = store.addCourse();
|
||||
store.printCourseTicket = async () => true;
|
||||
const result = await store.fireCourse(course);
|
||||
expect(course.fired).toBe(true);
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
test("setTable", async () => {
|
||||
const store = await setupPosEnv();
|
||||
const table = store.models["restaurant.table"].get(2);
|
||||
const blankOrder = store.addNewOrder();
|
||||
expect(blankOrder.table_id).toBe(undefined);
|
||||
await store.setTable(table);
|
||||
expect(blankOrder.table_id.id).toBe(table.id);
|
||||
expect(store.getOrder().id).toBe(blankOrder.id);
|
||||
});
|
||||
|
||||
test("computeTableCount", async () => {
|
||||
const store = await setupPosEnv();
|
||||
const order1 = store.addNewOrder();
|
||||
const table = store.models["restaurant.table"].get(2);
|
||||
expect(table.uiState.orderCount).toBe(0);
|
||||
order1.table_id = table;
|
||||
store.computeTableCount();
|
||||
expect(table.uiState.orderCount).toBe(1);
|
||||
});
|
||||
|
||||
test("sync dirty order when unsetting table", async () => {
|
||||
const store = await setupPosEnv();
|
||||
const table = store.models["restaurant.table"].get(2);
|
||||
const order = await getFilledOrder(store);
|
||||
order.table_id = table;
|
||||
expect(store.getPendingOrder().orderToCreate).toHaveLength(1);
|
||||
await store.unsetTable();
|
||||
await waitUntilOrdersSynced(store);
|
||||
expect(store.getPendingOrder().orderToCreate).toHaveLength(0);
|
||||
expect(order.isDirty()).toBe(false);
|
||||
//Update the order
|
||||
order.setInternalNote("Test note");
|
||||
expect(order.isDirty()).toBe(true);
|
||||
await store.unsetTable();
|
||||
await waitUntilOrdersSynced(store);
|
||||
expect(order.isDirty()).toBe(false);
|
||||
expect(store.getPendingOrder().orderToUpdate).toHaveLength(0);
|
||||
});
|
||||
|
||||
describe("class DevicesSynchronisation", () => {
|
||||
test("Synchronization for a filled table has arrived", async () => {
|
||||
// If a local order is already create on a table when another device send another order
|
||||
// for the same table, we merge the orderlines of the local order with the synced order.
|
||||
const store = await setupPosEnv();
|
||||
const sync = store.deviceSync;
|
||||
const table = store.models["restaurant.table"].get(2);
|
||||
const filledOrder = await getFilledOrder(store);
|
||||
const product1 = filledOrder.lines[0].product_id;
|
||||
const product2 = filledOrder.lines[1].product_id;
|
||||
filledOrder.table_id = table;
|
||||
|
||||
expect(table.getOrder()).toBe(filledOrder);
|
||||
MockServer.env["pos.order"].create({
|
||||
config_id: store.config.id,
|
||||
session_id: store.session.id,
|
||||
table_id: table.id,
|
||||
lines: filledOrder.lines.map((line) => [
|
||||
0,
|
||||
0,
|
||||
{
|
||||
product_id: line.product_id.id,
|
||||
price_unit: line.price_unit,
|
||||
qty: 1,
|
||||
},
|
||||
]),
|
||||
});
|
||||
|
||||
await sync.collect({
|
||||
static_records: {},
|
||||
session_id: 1,
|
||||
device_identifier: 0,
|
||||
records: {},
|
||||
});
|
||||
|
||||
expect(store.models["pos.order"].length).toEqual(1);
|
||||
const order = store.models["pos.order"].get(1);
|
||||
expect(order.lines).toHaveLength(4);
|
||||
expect(table.getOrders()).toHaveLength(1);
|
||||
expect(order.lines[0].product_id).toEqual(product1);
|
||||
expect(order.lines[1].product_id).toEqual(product2);
|
||||
expect(order.lines[2].product_id).toEqual(product1);
|
||||
expect(order.lines[3].product_id).toEqual(product2);
|
||||
expect(order.lines[0].qty).toEqual(1);
|
||||
expect(order.lines[1].qty).toEqual(1);
|
||||
expect(order.lines[2].qty).toEqual(3);
|
||||
expect(order.lines[3].qty).toEqual(2);
|
||||
expect(order.lines[0].id).toBeOfType("number");
|
||||
expect(order.lines[1].id).toBeOfType("number");
|
||||
expect(order.lines[2].id).toBeOfType("string");
|
||||
expect(order.lines[3].id).toBeOfType("string");
|
||||
await store.syncAllOrders();
|
||||
expect(order.lines[0].id).toBeOfType("number");
|
||||
expect(order.lines[1].id).toBeOfType("number");
|
||||
expect(order.lines[2].id).toBeOfType("number");
|
||||
expect(order.lines[3].id).toBeOfType("number");
|
||||
});
|
||||
|
||||
test("Orders must be downloaded by opening a table.", async () => {
|
||||
const store = await setupPosEnv();
|
||||
const filledOrder = await getFilledOrder(store);
|
||||
const table = store.models["restaurant.table"].get(2);
|
||||
MockServer.env["pos.order"].create({
|
||||
config_id: store.config.id,
|
||||
session_id: store.session.id,
|
||||
table_id: table.id,
|
||||
lines: filledOrder.lines.map((line) => [
|
||||
0,
|
||||
0,
|
||||
{
|
||||
product_id: line.product_id.id,
|
||||
price_unit: line.price_unit,
|
||||
qty: 1,
|
||||
},
|
||||
]),
|
||||
});
|
||||
|
||||
// This function is called by setTable in pos_store, but it is not awaited.
|
||||
// So we need to await it here to ensure the test runs correctly.
|
||||
await store.deviceSync.readDataFromServer();
|
||||
expect(table.getOrder().id).toEqual(1);
|
||||
});
|
||||
|
||||
test("Orders updated from another device must be synchronized directly.", async () => {
|
||||
const store = await setupPosEnv();
|
||||
const filledOrder = await getFilledOrder(store);
|
||||
const table = store.models["restaurant.table"].get(2);
|
||||
filledOrder.table_id = table;
|
||||
await store.syncAllOrders();
|
||||
|
||||
expect(filledOrder.id).toBeOfType("number");
|
||||
expect(filledOrder.lines).toHaveLength(2);
|
||||
expect(filledOrder.table_id).toBe(table);
|
||||
MockServer.env["pos.order"].write([filledOrder.id], {
|
||||
lines: filledOrder.lines.map((line) => [
|
||||
0,
|
||||
0,
|
||||
{
|
||||
product_id: line.product_id.id,
|
||||
price_unit: line.price_unit,
|
||||
qty: 40,
|
||||
},
|
||||
]),
|
||||
});
|
||||
|
||||
await store.deviceSync.readDataFromServer();
|
||||
expect(filledOrder.lines).toHaveLength(4);
|
||||
expect(filledOrder.lines[2].qty).toEqual(40);
|
||||
expect(filledOrder.lines[3].qty).toEqual(40);
|
||||
expect(filledOrder.lines[2].id).toBeOfType("number");
|
||||
expect(filledOrder.lines[3].id).toBeOfType("number");
|
||||
});
|
||||
|
||||
test("Data from other devices overrides local data", async () => {
|
||||
const store = await setupPosEnv();
|
||||
const filledOrder = await getFilledOrder(store);
|
||||
const table = store.models["restaurant.table"].get(2);
|
||||
filledOrder.table_id = table;
|
||||
filledOrder.internal_note = "Hey give me a discount!";
|
||||
await store.syncAllOrders();
|
||||
|
||||
expect(filledOrder.id).toBeOfType("number");
|
||||
expect(filledOrder.internal_note).toEqual("Hey give me a discount!");
|
||||
|
||||
filledOrder.internal_note = "Hey give me a discount! But not too much!";
|
||||
MockServer.env["pos.order"].write([filledOrder.id], {
|
||||
internal_note: "Hey give me a discount!",
|
||||
});
|
||||
|
||||
await store.deviceSync.readDataFromServer();
|
||||
expect(filledOrder.internal_note).toEqual("Hey give me a discount!");
|
||||
});
|
||||
|
||||
test("There should only be one order per table.", async () => {
|
||||
const store = await setupPosEnv();
|
||||
const table = store.models["restaurant.table"].get(2);
|
||||
const date = DateTime.now().toFormat("yyyy-MM-dd HH:mm:ss");
|
||||
const filledOrder = await getFilledOrder(store);
|
||||
filledOrder.table_id = table;
|
||||
await store.syncAllOrders();
|
||||
|
||||
let id = 1;
|
||||
let lineId = 1;
|
||||
const createOrderForTable = async () => {
|
||||
const orderId = `${id++}_string`;
|
||||
const lines = [
|
||||
{
|
||||
id: `${lineId++}_string`,
|
||||
order_id: orderId,
|
||||
product_id: 5,
|
||||
qty: 1,
|
||||
write_date: date,
|
||||
},
|
||||
{
|
||||
id: `${lineId++}_string`,
|
||||
order_id: orderId,
|
||||
product_id: 6,
|
||||
qty: 1,
|
||||
write_date: date,
|
||||
},
|
||||
];
|
||||
const order = [
|
||||
{
|
||||
id: orderId,
|
||||
lines: lines.map((line) => line.id),
|
||||
write_date: date,
|
||||
table_id: table.id,
|
||||
pos_reference: "000-0-000000",
|
||||
session_id: store.session.id,
|
||||
config_id: store.config.id,
|
||||
},
|
||||
];
|
||||
const newData = {
|
||||
"pos.order": order,
|
||||
"pos.order.line": lines,
|
||||
};
|
||||
|
||||
await store.deviceSync.processDynamicRecords(newData);
|
||||
};
|
||||
|
||||
for (let i = 0; i < 8; i++) {
|
||||
await createOrderForTable();
|
||||
expect(table.getOrders()).toHaveLength(1);
|
||||
expect(table.getOrder().id).toBeOfType("number");
|
||||
expect(table.getOrder().lines).toHaveLength(4 + i * 2);
|
||||
}
|
||||
|
||||
expect(store.models["pos.order"].length).toEqual(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe("categoryCount", () => {
|
||||
test("Normal flow", async () => {
|
||||
const store = await setupPosEnv();
|
||||
const order = await getFilledOrder(store);
|
||||
order.lines[0].note = '[{"text":"Test Note","colorIndex":0}]';
|
||||
order.lines[1].note =
|
||||
'[{"text":"Test 1","colorIndex":0},{"text":"Test 2","colorIndex":0}]';
|
||||
order.general_customer_note = '[{"text":"General Note","colorIndex":0}]';
|
||||
const changes = store.categoryCount;
|
||||
expect(changes).toEqual([
|
||||
{ count: 3, name: "Category 1" },
|
||||
{ count: 2, name: "Category 2" },
|
||||
{ count: 1, name: "Message" },
|
||||
]);
|
||||
});
|
||||
|
||||
test("Unselected order", async () => {
|
||||
const store = await setupPosEnv();
|
||||
const order = await getFilledOrder(store);
|
||||
order.general_customer_note = '[{"text":"General Note","colorIndex":0}]';
|
||||
store.selectedOrderUuid = null;
|
||||
// without a selected order, `categoryCount` throws
|
||||
expect(() => store.categoryCount).toThrow();
|
||||
// explicitly specify the order to compute the changes for
|
||||
const changes = store.getCategoryCount(order);
|
||||
expect(changes).toEqual([
|
||||
{ count: 3, name: "Category 1" },
|
||||
{ count: 2, name: "Category 2" },
|
||||
{ count: 1, name: "Message" },
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
test("getDefaultSearchDetails", async () => {
|
||||
const store = await setupPosEnv();
|
||||
const result = store.getDefaultSearchDetails();
|
||||
expect(result).toEqual({
|
||||
fieldName: "REFERENCE",
|
||||
searchTerm: "",
|
||||
});
|
||||
});
|
||||
|
||||
test("findTable", async () => {
|
||||
const store = await setupPosEnv();
|
||||
const table1 = store.models["restaurant.table"].get(2);
|
||||
const floor = store.models["restaurant.floor"].get(2);
|
||||
store.currentFloor = floor;
|
||||
const result = store.findTable("1");
|
||||
expect(result.id).toBe(table1.id);
|
||||
});
|
||||
|
||||
test("searchOrder", async () => {
|
||||
const store = await setupPosEnv();
|
||||
const floor = store.models["restaurant.floor"].get(2);
|
||||
store.currentFloor = floor;
|
||||
const found = store.searchOrder("2");
|
||||
expect(found).toBe(true);
|
||||
const notFound = store.searchOrder("999");
|
||||
expect(notFound).toBe(false);
|
||||
});
|
||||
|
||||
test("getTableOrders", async () => {
|
||||
const store = await setupPosEnv();
|
||||
const table = store.models["restaurant.table"].get(2);
|
||||
store.addNewOrder({ table_id: table });
|
||||
const orders = store.getTableOrders(table.id);
|
||||
expect(orders.length).toBe(1);
|
||||
});
|
||||
|
||||
test("getActiveOrdersOnTable", async () => {
|
||||
const store = await setupPosEnv();
|
||||
const table = store.models["restaurant.table"].get(2);
|
||||
store.addNewOrder({ table_id: table });
|
||||
store.addNewOrder({ table_id: table });
|
||||
const orders = await store.getActiveOrdersOnTable(table);
|
||||
expect(orders.length).toBe(2);
|
||||
});
|
||||
|
||||
test("prepareOrderTransfer", async () => {
|
||||
const store = await setupPosEnv();
|
||||
const tableSrc = store.models["restaurant.table"].get(1);
|
||||
const tableDst = store.models["restaurant.table"].get(2);
|
||||
const order = store.addNewOrder({ table_id: tableSrc });
|
||||
store.alert = {
|
||||
dismiss: () => {},
|
||||
};
|
||||
const result = store.prepareOrderTransfer(order, tableDst);
|
||||
expect(result).toBe(false);
|
||||
expect(order.table_id).toBe(tableDst);
|
||||
expect(store.getOrder()).toBe(order);
|
||||
});
|
||||
|
||||
test("transferOrder", async () => {
|
||||
const store = await setupPosEnv();
|
||||
const tableSrc = store.models["restaurant.table"].get(1);
|
||||
const tableDst = store.models["restaurant.table"].get(2);
|
||||
const sourceOrder = store.addNewOrder({ table_id: tableSrc });
|
||||
const product1 = store.models["product.template"].get(5);
|
||||
await store.addLineToOrder(
|
||||
{
|
||||
product_tmpl_id: product1,
|
||||
qty: 2,
|
||||
},
|
||||
sourceOrder
|
||||
);
|
||||
const order = store.addNewOrder({ table_id: tableDst });
|
||||
await store.transferOrder(sourceOrder.uuid, tableDst);
|
||||
expect(sourceOrder.lines.length).toBe(0);
|
||||
expect(order.lines.length).toBe(1);
|
||||
expect(order.table_id.id).toBe(tableDst.id);
|
||||
});
|
||||
|
||||
test("mergeOrders merges lines and courses", async () => {
|
||||
const store = await setupPosEnv();
|
||||
const models = store.models;
|
||||
const table1 = models["restaurant.table"].get(2);
|
||||
const table2 = models["restaurant.table"].get(3);
|
||||
const order1 = store.addNewOrder({ table_id: table1 });
|
||||
const course1 = store.addCourse();
|
||||
const product1 = models["product.template"].get(5);
|
||||
const line1 = await store.addLineToOrder({ product_tmpl_id: product1, qty: 1 }, order1);
|
||||
line1.course_id = course1;
|
||||
course1.line_ids = [line1];
|
||||
const order2 = store.addNewOrder({ table_id: table2 });
|
||||
const course2 = store.addCourse();
|
||||
const product2 = models["product.template"].get(6);
|
||||
const line2 = await store.addLineToOrder({ product_tmpl_id: product2, qty: 2 }, order2);
|
||||
line2.course_id = course2;
|
||||
course2.line_ids = [line2];
|
||||
await store.mergeOrders(order1, order2);
|
||||
expect(order2.lines.length).toBe(2);
|
||||
expect(order1.lines.length).toBe(0);
|
||||
expect(order1.table_id).toBe(undefined);
|
||||
expect(order2.table_id.id).toBe(table2.id);
|
||||
expect(order2.course_ids.length).toBe(1);
|
||||
expect(line2.course_id.id).toBe(course2.id);
|
||||
});
|
||||
|
||||
test("mergeOrders sums guest counts", async () => {
|
||||
const store = await setupPosEnv();
|
||||
const models = store.models;
|
||||
const table1 = models["restaurant.table"].get(2);
|
||||
const table2 = models["restaurant.table"].get(3);
|
||||
const order1 = store.addNewOrder({ table_id: table1 });
|
||||
order1.setCustomerCount(3);
|
||||
const order2 = store.addNewOrder({ table_id: table2 });
|
||||
order2.setCustomerCount(5);
|
||||
await store.mergeOrders(order1, order2);
|
||||
expect(order2.getCustomerCount()).toBe(8);
|
||||
});
|
||||
|
||||
test("getCustomerCount", async () => {
|
||||
const store = await setupPosEnv();
|
||||
const table = store.models["restaurant.table"].get(2);
|
||||
store.addNewOrder({ table_id: table }).setCustomerCount(3);
|
||||
store.addNewOrder({ table_id: table }).setCustomerCount(6);
|
||||
const count = store.getCustomerCount(table.id);
|
||||
expect(count).toBe(9);
|
||||
});
|
||||
|
||||
test("firstPage", async () => {
|
||||
const store = await setupPosEnv();
|
||||
expect(store.firstPage.page).toBe("LoginScreen");
|
||||
});
|
||||
|
||||
describe("addCourse", () => {
|
||||
test("creates first course and selects it", async () => {
|
||||
const store = await setupPosEnv();
|
||||
const order = store.addNewOrder();
|
||||
const course = store.addCourse();
|
||||
expect(course.order_id).toBe(order);
|
||||
expect(order.getSelectedCourse()).toBe(course);
|
||||
});
|
||||
|
||||
test("creates second course and assigns existing lines to first", async () => {
|
||||
const store = await setupPosEnv();
|
||||
const order = store.addNewOrder();
|
||||
const product = store.models["product.template"].get(5);
|
||||
await store.addLineToOrder({ product_tmpl_id: product, qty: 1 }, order);
|
||||
const course1 = store.addCourse();
|
||||
const course2 = order.getSelectedCourse();
|
||||
expect(order.course_ids.length).toBe(2);
|
||||
expect(course1).not.toBe(course2);
|
||||
expect(order.lines[0].course_id).toBe(course1);
|
||||
});
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue