19.0 vanilla

This commit is contained in:
Ernad Husremovic 2026-03-09 09:29:53 +01:00
parent 6e54c1af6c
commit 3ca647e428
1087 changed files with 132065 additions and 108499 deletions

View file

@ -0,0 +1,219 @@
import * as PosLoyalty from "@pos_loyalty/../tests/tours/utils/pos_loyalty_util";
import * as ProductScreen from "@point_of_sale/../tests/pos/tours/utils/product_screen_util";
import * as TicketScreen from "@point_of_sale/../tests/pos/tours/utils/ticket_screen_util";
import * as Dialog from "@point_of_sale/../tests/generic_helpers/dialog_util";
import * as Chrome from "@point_of_sale/../tests/pos/tours/utils/chrome_util";
import * as PartnerList from "@point_of_sale/../tests/pos/tours/utils/partner_list_util";
import * as PaymentScreen from "@point_of_sale/../tests/pos/tours/utils/payment_screen_util";
import * as Numpad from "@point_of_sale/../tests/generic_helpers/numpad_util";
import * as Order from "@point_of_sale/../tests/generic_helpers/order_widget_util";
import { negateStep } from "@point_of_sale/../tests/generic_helpers/utils";
import { delay } from "@web/core/utils/concurrency";
import { registry } from "@web/core/registry";
registry.category("web_tour.tours").add("EWalletProgramTour1", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
// Topup 50$ for partner_aaa
ProductScreen.clickDisplayedProduct("Top-up eWallet"),
PosLoyalty.orderTotalIs("50.00"),
ProductScreen.clickPayButton(false),
// If there's no partner, we asked to redirect to the partner list screen.
Dialog.confirm(),
PartnerList.clickPartner("AAAAAAA"),
PosLoyalty.finalizeOrder("Cash", "50"),
// Topup 10$ for partner_bbb
ProductScreen.clickPartnerButton(),
ProductScreen.clickCustomer("BBBBBBB"),
ProductScreen.addOrderline("Top-up eWallet", "1", "10"),
PosLoyalty.orderTotalIs("10.00"),
PosLoyalty.finalizeOrder("Cash", "10"),
// Check numpad visibility when clicking on eWallet orderline
ProductScreen.addOrderline("Whiteboard Pen"),
ProductScreen.clickPartnerButton(),
ProductScreen.clickCustomer("AAAAAAA"),
PosLoyalty.eWalletButtonState({
highlighted: true,
text: getEWalletText("Pay"),
click: true,
}),
PosLoyalty.orderTotalIs("0.00"),
...ProductScreen.clickLine("eWallet"),
// Added a small wait because the clickLine function uses a 300ms timeout
{
content: "Wait 300ms after clicking orderline",
trigger: "body",
async run() {
await delay(300);
},
},
Numpad.isVisible(),
...Order.hasLine({
withClass: ".selected",
run: "click",
productName: "eWallet",
quantity: "1.0",
}),
{
content: "Wait 300ms after clicking orderline",
trigger: "body",
async run() {
await delay(300);
},
},
negateStep(Numpad.isVisible()),
{
content: "Click Current Balance line in orderline",
trigger: ".orderline li:contains(Current Balance:)",
run: "click",
},
Numpad.isVisible(),
].flat(),
});
const getEWalletText = (suffix) => "eWallet" + (suffix !== "" ? ` ${suffix}` : "");
registry.category("web_tour.tours").add("EWalletProgramTour2", {
steps: () =>
[
Chrome.startPoS(),
ProductScreen.addOrderline("Whiteboard Pen", "2", "6", "12.00"),
PosLoyalty.eWalletButtonState({ highlighted: false }),
ProductScreen.clickPartnerButton(),
ProductScreen.clickCustomer("AAAAAAA"),
PosLoyalty.eWalletButtonState({
highlighted: true,
text: getEWalletText("Pay"),
click: true,
}),
PosLoyalty.orderTotalIs("0.00"),
PosLoyalty.finalizeOrder("Cash", "0"),
// Consume partner_bbb's full eWallet.
ProductScreen.clickPartnerButton(),
ProductScreen.clickCustomer("BBBBBBB"),
PosLoyalty.eWalletButtonState({ highlighted: false }),
ProductScreen.addOrderline("Desk Pad", "6", "6", "36.00"),
PosLoyalty.eWalletButtonState({
highlighted: true,
text: getEWalletText("Pay"),
click: true,
}),
PosLoyalty.eWalletButtonState({ highlighted: false }),
PosLoyalty.orderTotalIs("26.00"),
PosLoyalty.finalizeOrder("Cash", "26"),
// Switching partners should work.
ProductScreen.clickPartnerButton(),
ProductScreen.clickCustomer("BBBBBBB"),
ProductScreen.addOrderline("Desk Pad", "2", "19", "38.00"),
PosLoyalty.eWalletButtonState({ highlighted: false }),
ProductScreen.clickPartnerButton(),
ProductScreen.clickCustomer("AAAAAAA"),
PosLoyalty.eWalletButtonState({
highlighted: true,
text: getEWalletText("Pay"),
click: true,
}),
PosLoyalty.orderTotalIs("0.00"),
ProductScreen.clickPartnerButton(),
ProductScreen.clickCustomer("BBBBBBB"),
PosLoyalty.eWalletButtonState({ highlighted: false }),
PosLoyalty.orderTotalIs("38.00"),
ProductScreen.clickPartnerButton(),
ProductScreen.clickCustomer("AAAAAAA"),
PosLoyalty.eWalletButtonState({
highlighted: true,
text: getEWalletText("Pay"),
click: true,
}),
PosLoyalty.orderTotalIs("0.00"),
PosLoyalty.finalizeOrder("Cash", "0"),
// Refund with eWallet.
// - Make an order to refund.
ProductScreen.clickPartnerButton(),
ProductScreen.clickCustomer("BBBBBBB"),
ProductScreen.addOrderline("Whiteboard Pen", "1", "20", "20.00"),
PosLoyalty.orderTotalIs("20.00"),
PosLoyalty.finalizeOrder("Cash", "20"),
// - Refund order.
...ProductScreen.clickRefund(),
TicketScreen.filterIs("Paid"),
TicketScreen.selectOrder("2004"),
TicketScreen.confirmRefund(),
PaymentScreen.isShown(),
PaymentScreen.clickBack(),
ProductScreen.isShown(),
PosLoyalty.eWalletButtonState({
highlighted: true,
text: getEWalletText("Refund"),
click: true,
}),
PosLoyalty.orderTotalIs("0.00"),
PosLoyalty.finalizeOrder("Cash", "0"),
].flat(),
});
registry.category("web_tour.tours").add("ExpiredEWalletProgramTour", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.clickPartnerButton(),
ProductScreen.clickCustomer("AAAA"),
ProductScreen.addOrderline("Whiteboard Pen", "2", "6", "12.00"),
PosLoyalty.eWalletButtonState({ highlighted: false, click: true }),
Dialog.is({ title: "No valid eWallet found" }),
Dialog.confirm(),
].flat(),
});
registry.category("web_tour.tours").add("PosLoyaltyPointsEwallet", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.clickPartnerButton(),
ProductScreen.clickCustomer("AAAA"),
PosLoyalty.eWalletButtonState({ highlighted: false }),
ProductScreen.addOrderline("product_a", "1"),
PosLoyalty.eWalletButtonState({
highlighted: true,
text: getEWalletText("Pay"),
click: true,
}),
PosLoyalty.pointsAwardedAre("100"),
PosLoyalty.finalizeOrder("Cash", "90.00"),
].flat(),
});
registry.category("web_tour.tours").add("EWalletLoyaltyHistory", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.clickDisplayedProduct("Top-up eWallet"),
PosLoyalty.orderTotalIs("50.00"),
ProductScreen.clickPartnerButton(),
PartnerList.clickPartner("AAAAAAA"),
PosLoyalty.finalizeOrder("Cash", "50"),
ProductScreen.addOrderline("Whiteboard Pen", "2", "6", "12.00"),
PosLoyalty.eWalletButtonState({ highlighted: false }),
ProductScreen.clickPartnerButton(),
ProductScreen.clickCustomer("AAAAAAA"),
PosLoyalty.eWalletButtonState({
highlighted: true,
text: getEWalletText("Pay"),
click: true,
}),
PosLoyalty.orderTotalIs("0.00"),
PosLoyalty.finalizeOrder("Cash", "0"),
].flat(),
});

View file

@ -0,0 +1,311 @@
import * as PosLoyalty from "@pos_loyalty/../tests/tours/utils/pos_loyalty_util";
import * as ProductScreen from "@point_of_sale/../tests/pos/tours/utils/product_screen_util";
import * as Chrome from "@point_of_sale/../tests/pos/tours/utils/chrome_util";
import * as Dialog from "@point_of_sale/../tests/generic_helpers/dialog_util";
import { registry } from "@web/core/registry";
import * as TicketScreen from "@point_of_sale/../tests/pos/tours/utils/ticket_screen_util";
import * as Order from "@point_of_sale/../tests/generic_helpers/order_widget_util";
import * as ReceiptScreen from "@point_of_sale/../tests/pos/tours/utils/receipt_screen_util";
import * as PaymentScreen from "@point_of_sale/../tests/pos/tours/utils/payment_screen_util";
registry.category("web_tour.tours").add("GiftCardProgramTour1", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.clickDisplayedProduct("Gift Card"),
PosLoyalty.orderTotalIs("50.00"),
PosLoyalty.finalizeOrder("Cash", "50"),
].flat(),
});
registry.category("web_tour.tours").add("GiftCardProgramTour2", {
steps: () =>
[
Chrome.startPoS(),
ProductScreen.clickDisplayedProduct("Whiteboard Pen"),
PosLoyalty.enterCode("044123456"),
PosLoyalty.orderTotalIs("0.00"),
PosLoyalty.finalizeOrder("Cash", "0"),
].flat(),
});
registry.category("web_tour.tours").add("GiftCardWithRefundtTour", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.addOrderline("Magnetic Board", "1"), // 1.98
PosLoyalty.orderTotalIs("1.98"),
PosLoyalty.finalizeOrder("Cash", "20"),
...ProductScreen.clickRefund(),
TicketScreen.selectOrder("001"),
Order.hasLine({
withClass: ".selected",
productName: "Magnetic Board",
}),
ProductScreen.clickNumpad("1"),
TicketScreen.confirmRefund(),
PaymentScreen.isShown(),
PaymentScreen.clickBack(),
ProductScreen.isShown(),
ProductScreen.clickLine("Magnetic Board", "-1"),
ProductScreen.selectedOrderlineHas("Magnetic Board", "-1"),
ProductScreen.addOrderline("Gift Card", "1"),
ProductScreen.selectedOrderlineHas("Gift Card", "1"),
PosLoyalty.orderTotalIs("0.0"),
].flat(),
});
registry.category("web_tour.tours").add("GiftCardProgramPriceNoTaxTour", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
// Use gift card
ProductScreen.addOrderline("Magnetic Board", "1", "1.98", "1.98"),
PosLoyalty.enterCode("043123456"),
Dialog.confirm(),
ProductScreen.clickOrderline("Gift Card"),
ProductScreen.selectedOrderlineHas("Gift Card", "1", "-1.00"),
PosLoyalty.orderTotalIs("0.98"),
].flat(),
});
registry.category("web_tour.tours").add("PosLoyaltyPointsGiftcard", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.addOrderline("Gift Card", "1", "50", "50"),
PosLoyalty.createManualGiftCard("044123456", 50),
PosLoyalty.orderTotalIs("50.00"),
PosLoyalty.finalizeOrder("Cash", "50"),
ProductScreen.clickPartnerButton(),
ProductScreen.clickCustomer("AAAA"),
ProductScreen.addOrderline("product_a", "1"),
PosLoyalty.enterCode("044123456"),
PosLoyalty.orderTotalIs("50.00"),
PosLoyalty.pointsAwardedAre("100"),
PosLoyalty.finalizeOrder("Cash", "50"),
].flat(),
});
registry.category("web_tour.tours").add("PosLoyaltyGiftCardTaxes", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.addOrderline("Gift Card", "1", "50", "50"),
PosLoyalty.createManualGiftCard("044123456", 50),
PosLoyalty.orderTotalIs("50.00"),
PosLoyalty.finalizeOrder("Cash", "50"),
ProductScreen.clickDisplayedProduct("Test Product A"),
PosLoyalty.enterCode("044123456"),
PosLoyalty.orderTotalIs("50.00"),
ProductScreen.checkTaxAmount("-6.52"),
].flat(),
});
registry.category("web_tour.tours").add("PhysicalGiftCardProgramSaleTour", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.addOrderline("Gift Card", "1", "50", "50"),
PosLoyalty.createManualGiftCard("test-card-0000", 125),
ProductScreen.selectedOrderlineHas("Gift Card", "1", "125"),
PosLoyalty.orderTotalIs("125"),
PosLoyalty.finalizeOrder("Cash", "125"),
ProductScreen.addOrderline("Gift Card", "1", "50", "50"),
PosLoyalty.createManualGiftCard("test-card-0001", 100),
PosLoyalty.clickPhysicalGiftCard("test-card-0001"),
ProductScreen.selectedOrderlineHas("Gift Card", "1", "100"),
ProductScreen.addOrderline("Gift Card", "1", "50", "50"),
PosLoyalty.createManualGiftCard("new-card-0001", 250),
PosLoyalty.clickPhysicalGiftCard("new-card-0001"),
ProductScreen.selectedOrderlineHas("Gift Card", "1", "250"),
PosLoyalty.orderTotalIs("350"),
PosLoyalty.finalizeOrder("Cash", "350"),
].flat(),
});
registry.category("web_tour.tours").add("MultiplePhysicalGiftCardProgramSaleTour", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.clickDisplayedProduct("Gift Card"),
PosLoyalty.clickGiftCardProgram("Gift Cards1"),
PosLoyalty.createManualGiftCard("test-card-0000", 125),
PosLoyalty.clickGiftCardProgram("Gift Cards"),
ProductScreen.selectedOrderlineHas("Gift Card", "1.00", "125"),
PosLoyalty.orderTotalIs("125"),
PosLoyalty.finalizeOrder("Cash", "125"),
ProductScreen.clickDisplayedProduct("Gift Card"),
PosLoyalty.clickGiftCardProgram("Gift Cards2"),
PosLoyalty.createManualGiftCard("test-card-0001", 125),
PosLoyalty.clickGiftCardProgram("Gift Cards2"),
ProductScreen.selectedOrderlineHas("Gift Card", "1.00", "125"),
PosLoyalty.orderTotalIs("125"),
PosLoyalty.finalizeOrder("Cash", "125"),
ProductScreen.clickDisplayedProduct("Gift Card"),
PosLoyalty.clickGiftCardProgram("Gift Cards3"),
PosLoyalty.createManualGiftCard("test-card-0002", 125),
PosLoyalty.clickGiftCardProgram("Gift Cards3"),
ProductScreen.selectedOrderlineHas("Gift Card", "1.00", "125"),
PosLoyalty.orderTotalIs("125"),
PosLoyalty.finalizeOrder("Cash", "125"),
].flat(),
});
registry.category("web_tour.tours").add("GiftCardProgramInvoice", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.clickDisplayedProduct("Gift Card"),
ProductScreen.clickPartnerButton(),
ProductScreen.clickCustomer("A Test Partner"),
PosLoyalty.orderTotalIs("50.00"),
ProductScreen.clickPayButton(),
PaymentScreen.clickPaymentMethod("Bank"),
PaymentScreen.clickInvoiceButton(),
PaymentScreen.clickValidate(),
ReceiptScreen.isShown(),
].flat(),
});
registry.category("web_tour.tours").add("test_gift_card_no_date", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.clickDisplayedProduct("Gift Card"),
PosLoyalty.createManualGiftCard("test", "42", ""),
PosLoyalty.finalizeOrder("Cash", "42"),
].flat(),
});
registry.category("web_tour.tours").add("test_physical_gift_card_invoiced", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.clickPartnerButton(),
ProductScreen.clickCustomer("AABBCC Test Partner"),
ProductScreen.clickDisplayedProduct("Gift Card"),
PosLoyalty.createManualGiftCard("test-card-1234", 125),
ProductScreen.selectedOrderlineHas("Gift Card", "1.00", "125"),
PosLoyalty.orderTotalIs("125"),
ProductScreen.clickPayButton(),
PaymentScreen.clickPaymentMethod("Bank"),
PaymentScreen.clickInvoiceButton(),
PaymentScreen.clickValidate(),
ReceiptScreen.isShown(),
].flat(),
});
registry.category("web_tour.tours").add("EmptyProductScreenTour", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.isEmpty(),
ProductScreen.loadSampleButtonIsThere(),
].flat(),
});
registry.category("web_tour.tours").add("test_physical_gift_card", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.clickDisplayedProduct("Gift Card"),
// Gift card cannot be used as it's already linked to a partner
PosLoyalty.useExistingLoyaltyCard("gift_card_partner", false),
// Gift card cannot be used as it's expired
PosLoyalty.useExistingLoyaltyCard("gift_card_expired", false),
// Gift card is already sold
PosLoyalty.useExistingLoyaltyCard("gift_card_sold", false),
// Use gift_card_generated_but_not_sold - Warning is triggered
PosLoyalty.enterCode("gift_card_generated_but_not_sold"),
Dialog.cancel(),
// Sell the unsold gift card
PosLoyalty.useExistingLoyaltyCard("gift_card_generated_but_not_sold", true),
ProductScreen.selectedOrderlineHas("Gift Card", "1", "60.00"),
ProductScreen.clickNumpad("2"), // Cannot edit a physical gift card
Dialog.confirm(), // Warning is triggered
PosLoyalty.orderTotalIs("60.00"),
PosLoyalty.finalizeOrder("Cash", "60"),
// Use gift_card_valid - No warning should be triggered
ProductScreen.clickDisplayedProduct("Whiteboard Pen"),
PosLoyalty.enterCode("gift_card_valid"),
ProductScreen.clickLine("Gift Card"),
ProductScreen.selectedOrderlineHas("Gift Card", "1", "-3.20"),
PosLoyalty.orderTotalIs("0.00"),
PosLoyalty.finalizeOrder("Cash", "0"),
// Use gift_card_partner - No warning should be triggered
ProductScreen.clickDisplayedProduct("Whiteboard Pen"),
PosLoyalty.enterCode("gift_card_partner"),
ProductScreen.clickLine("Gift Card"),
ProductScreen.selectedOrderlineHas("Gift Card", "1", "-3.20"),
PosLoyalty.orderTotalIs("0.00"),
PosLoyalty.finalizeOrder("Cash", "0"),
// Use gift_card_sold - Warning should be triggered
ProductScreen.clickDisplayedProduct("Whiteboard Pen"),
ProductScreen.clickDisplayedProduct("Whiteboard Pen"),
PosLoyalty.enterCode("gift_card_sold"),
ProductScreen.clickLine("Gift Card"),
ProductScreen.selectedOrderlineHas("Gift Card", "1", "-6.40"),
PosLoyalty.orderTotalIs("0.00"),
PosLoyalty.finalizeOrder("Cash", "0"),
// Use gift_card_generated_but_not_sold - No warning should be triggered
ProductScreen.clickDisplayedProduct("Whiteboard Pen"),
ProductScreen.clickDisplayedProduct("Whiteboard Pen"),
ProductScreen.clickDisplayedProduct("Whiteboard Pen"),
ProductScreen.clickDisplayedProduct("Whiteboard Pen"),
PosLoyalty.enterCode("gift_card_generated_but_not_sold"),
ProductScreen.clickLine("Gift Card"),
ProductScreen.selectedOrderlineHas("Gift Card", "1", "-12.80"),
PosLoyalty.orderTotalIs("0.00"),
PosLoyalty.finalizeOrder("Cash", "0"),
// Try to use expired gift card
ProductScreen.clickDisplayedProduct("Whiteboard Pen"),
ProductScreen.clickDisplayedProduct("Whiteboard Pen"),
ProductScreen.clickDisplayedProduct("Whiteboard Pen"),
PosLoyalty.enterCode("gift_card_expired"),
PosLoyalty.orderTotalIs("9.60"),
PosLoyalty.finalizeOrder("Cash", "9.60"),
// Sell a new gift card with a partner
ProductScreen.clickPartnerButton(),
ProductScreen.clickCustomer("A powerful PoS man!"),
ProductScreen.clickDisplayedProduct("Gift Card"),
ProductScreen.clickNumpad("Price", "9", "9", "9"),
PosLoyalty.orderTotalIs("999.00"),
PosLoyalty.finalizeOrder("Cash", "999"),
].flat(),
});
registry.category("web_tour.tours").add("test_multiple_physical_gift_card_sale", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.clickDisplayedProduct("Gift Card"),
PosLoyalty.createManualGiftCard("test-card-0000", 125),
ProductScreen.selectedOrderlineHas("Gift Card", "1.00", "125"),
ProductScreen.addOrderline("Gift Card", "1", "0", "0"),
PosLoyalty.createManualGiftCard("test-card-0001", 100),
PosLoyalty.finalizeOrder("Cash", "225"),
].flat(),
});

View file

@ -0,0 +1,19 @@
import * as PosLoyalty from "@pos_loyalty/../tests/tours/utils/pos_loyalty_util";
import * as ProductScreen from "@point_of_sale/../tests/pos/tours/utils/product_screen_util";
import * as Chrome from "@point_of_sale/../tests/pos/tours/utils/chrome_util";
import * as Dialog from "@point_of_sale/../tests/generic_helpers/dialog_util";
import { registry } from "@web/core/registry";
registry.category("web_tour.tours").add("LoyaltyHistoryTour", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.addOrderline("Whiteboard Pen", "1"),
ProductScreen.clickPartnerButton(),
ProductScreen.clickCustomer("AAA Test Partner"),
PosLoyalty.orderTotalIs("10"),
PosLoyalty.finalizeOrder("Cash", "10"),
].flat(),
});

View file

@ -0,0 +1,79 @@
import * as PosLoyalty from "@pos_loyalty/../tests/tours/utils/pos_loyalty_util";
import * as ProductScreen from "@point_of_sale/../tests/pos/tours/utils/product_screen_util";
import * as SelectionPopup from "@point_of_sale/../tests/generic_helpers/selection_popup_util";
import * as Dialog from "@point_of_sale/../tests/generic_helpers/dialog_util";
import * as Chrome from "@point_of_sale/../tests/pos/tours/utils/chrome_util";
import { registry } from "@web/core/registry";
const getEWalletText = (suffix) => "eWallet" + (suffix !== "" ? ` ${suffix}` : "");
registry.category("web_tour.tours").add("MultipleGiftWalletProgramsTour", {
steps: () =>
[
// One card for gift_card_1.
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.clickDisplayedProduct("Gift Card"),
SelectionPopup.has("gift_card_1"),
SelectionPopup.has("gift_card_2"),
SelectionPopup.has("gift_card_1", { run: "click" }),
ProductScreen.selectedOrderlineHas("Gift Card"),
ProductScreen.clickNumpad("Price"),
ProductScreen.modeIsActive("Price"),
ProductScreen.clickNumpad("1", "0"),
PosLoyalty.orderTotalIs("10.00"),
PosLoyalty.finalizeOrder("Cash", "10"),
// One card for gift_card_1.
ProductScreen.clickDisplayedProduct("Gift Card"),
SelectionPopup.has("gift_card_2", { run: "click" }),
ProductScreen.selectedOrderlineHas("Gift Card"),
ProductScreen.clickNumpad("Price"),
ProductScreen.modeIsActive("Price"),
ProductScreen.clickNumpad("2", "0"),
PosLoyalty.orderTotalIs("20.00"),
PosLoyalty.finalizeOrder("Cash", "20"),
// Top up ewallet_1 for AAAAAAA.
ProductScreen.clickDisplayedProduct("Top-up eWallet"),
SelectionPopup.has("ewallet_1"),
SelectionPopup.has("ewallet_2"),
SelectionPopup.has("ewallet_1", { run: "click" }),
ProductScreen.clickPartnerButton(),
ProductScreen.clickCustomer("AAAAAAA"),
ProductScreen.clickNumpad("Price"),
ProductScreen.modeIsActive("Price"),
ProductScreen.clickNumpad("3", "0"),
PosLoyalty.orderTotalIs("30.00"),
PosLoyalty.finalizeOrder("Cash", "30"),
// Top up ewallet_2 for AAAAAAA.
ProductScreen.clickDisplayedProduct("Top-up eWallet"),
SelectionPopup.has("ewallet_2", { run: "click" }),
ProductScreen.clickPartnerButton(),
ProductScreen.clickCustomer("AAAAAAA"),
ProductScreen.clickNumpad("Price"),
ProductScreen.modeIsActive("Price"),
ProductScreen.clickNumpad("4", "0"),
PosLoyalty.orderTotalIs("40.00"),
PosLoyalty.finalizeOrder("Cash", "40"),
// Top up ewallet_1 for BBBBBBB.
ProductScreen.clickDisplayedProduct("Top-up eWallet"),
SelectionPopup.has("ewallet_1", { run: "click" }),
ProductScreen.clickPartnerButton(),
ProductScreen.clickCustomer("BBBBBBB"),
PosLoyalty.orderTotalIs("50.00"),
PosLoyalty.finalizeOrder("Cash", "50"),
// Consume 12$ from ewallet_1 of AAAAAAA.
ProductScreen.addOrderline("Whiteboard Pen", "2", "6", "12.00"),
PosLoyalty.eWalletButtonState({ highlighted: false }),
ProductScreen.clickPartnerButton(),
ProductScreen.clickCustomer("AAAAAAA"),
PosLoyalty.eWalletButtonState({
highlighted: true,
text: getEWalletText("Pay"),
click: true,
}),
SelectionPopup.has("ewallet_1"),
SelectionPopup.has("ewallet_2"),
SelectionPopup.has("ewallet_1", { run: "click" }),
PosLoyalty.orderTotalIs("0.00"),
PosLoyalty.finalizeOrder("Cash", "0"),
].flat(),
});

View file

@ -0,0 +1,403 @@
import * as PosLoyalty from "@pos_loyalty/../tests/tours/utils/pos_loyalty_util";
import * as ProductScreen from "@point_of_sale/../tests/pos/tours/utils/product_screen_util";
import * as PaymentScreen from "@point_of_sale/../tests/pos/tours/utils/payment_screen_util";
import * as Chrome from "@point_of_sale/../tests/pos/tours/utils/chrome_util";
import * as Dialog from "@point_of_sale/../tests/generic_helpers/dialog_util";
import * as combo from "@point_of_sale/../tests/pos/tours/utils/combo_popup_util";
import * as Order from "@point_of_sale/../tests/generic_helpers/order_widget_util";
import { inLeftSide } from "@point_of_sale/../tests/pos/tours/utils/common";
import { registry } from "@web/core/registry";
import { negate } from "@point_of_sale/../tests/generic_helpers/utils";
registry.category("web_tour.tours").add("PosLoyaltyLoyaltyProgram1", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
// Order1: Generates 2 points.
ProductScreen.addOrderline("Whiteboard Pen", "2"),
ProductScreen.clickPartnerButton(),
ProductScreen.clickCustomer("AAA Test Partner"),
PosLoyalty.orderTotalIs("6.40"),
PosLoyalty.finalizeOrder("Cash", "10"),
// Order2: Consumes points to get free product.
ProductScreen.clickPartnerButton(),
ProductScreen.clickCustomer("AAA Test Partner"),
ProductScreen.clickDisplayedProduct("Whiteboard Pen", true, "1"),
ProductScreen.clickDisplayedProduct("Whiteboard Pen", true, "2"),
// At this point, AAA Test Partner has 4 points.
PosLoyalty.isMoreControlButtonActive(true),
PosLoyalty.isRewardButtonHighlighted(true),
ProductScreen.clickDisplayedProduct("Whiteboard Pen", true, "3"),
PosLoyalty.hasRewardLine("Free Product - Whiteboard Pen", "-3.20", "1"),
PosLoyalty.isMoreControlButtonActive(false),
PosLoyalty.isRewardButtonHighlighted(false),
PosLoyalty.orderTotalIs("6.40"),
PosLoyalty.finalizeOrder("Cash", "10"),
// Order3: Generate 4 points.
// - Initially gets free product, but was removed automatically by changing the
// number of items to zero.
// - It's impossible to checked here if the free product reward is really removed
// so we check in the backend the number of orders that consumed the reward.
ProductScreen.addOrderline("Whiteboard Pen", "4"),
PosLoyalty.orderTotalIs("12.80"),
ProductScreen.clickPartnerButton(),
ProductScreen.clickCustomer("AAA Test Partner"),
PosLoyalty.isRewardButtonHighlighted(true),
ProductScreen.clickDisplayedProduct("Whiteboard Pen"),
PosLoyalty.hasRewardLine("Free Product - Whiteboard Pen", "-3.20", "1"),
PosLoyalty.isRewardButtonHighlighted(false),
ProductScreen.clickNumpad("⌫"),
// At this point, the reward line should have been automatically removed
// because there is not enough points to purchase it. Unfortunately, we
// can't check that here.
PosLoyalty.orderTotalIs("0.00"),
ProductScreen.clickDisplayedProduct("Whiteboard Pen", true, "1.00"),
ProductScreen.clickDisplayedProduct("Whiteboard Pen", true, "2.00"),
ProductScreen.clickDisplayedProduct("Whiteboard Pen", true, "3.00"),
PosLoyalty.isRewardButtonHighlighted(false),
ProductScreen.clickDisplayedProduct("Whiteboard Pen"),
ProductScreen.selectedOrderlineHas("Whiteboard Pen", "4.00"),
PosLoyalty.isRewardButtonHighlighted(true),
PosLoyalty.orderTotalIs("12.80"),
PosLoyalty.finalizeOrder("Cash", "20"),
].flat(),
});
registry.category("web_tour.tours").add("PosLoyaltyLoyaltyProgram2", {
steps: () =>
[
// Order1: Immediately set the customer to Test Partner AAA which has 4 points.
// - He has enough points to purchase a free product but since there is still
// no product in the order, reward button should not yet be highlighted.
// - Furthermore, clicking the reward product should not add it as reward product.
Chrome.startPoS(),
ProductScreen.clickPartnerButton(),
ProductScreen.clickCustomer("AAA Test Partner"),
// No item in the order, so reward button is off.
PosLoyalty.isRewardButtonHighlighted(false),
ProductScreen.clickDisplayedProduct("Whiteboard Pen"),
PosLoyalty.isRewardButtonHighlighted(true),
ProductScreen.clickDisplayedProduct("Whiteboard Pen"),
PosLoyalty.hasRewardLine("Free Product - Whiteboard Pen", "-3.20", "1"),
PosLoyalty.isRewardButtonHighlighted(false),
PosLoyalty.orderTotalIs("3.20"),
PosLoyalty.finalizeOrder("Cash", "10"),
// Order2: Generate 4 points for CCC Test Partner.
// - Reference: Order2_CCC
// - But set BBB Test Partner first as the customer.
ProductScreen.clickPartnerButton(),
ProductScreen.clickCustomer("BBB Test Partner"),
PosLoyalty.isRewardButtonHighlighted(false),
ProductScreen.clickDisplayedProduct("Whiteboard Pen", true, "1"),
ProductScreen.clickDisplayedProduct("Whiteboard Pen", true, "2"),
ProductScreen.clickDisplayedProduct("Whiteboard Pen", true, "3"),
PosLoyalty.isRewardButtonHighlighted(false),
ProductScreen.clickDisplayedProduct("Whiteboard Pen", true, "4"),
PosLoyalty.isRewardButtonHighlighted(true),
ProductScreen.clickPartnerButton(),
ProductScreen.clickCustomer("CCC Test Partner"),
PosLoyalty.customerIs("CCC Test Partner"),
PosLoyalty.orderTotalIs("12.80"),
PosLoyalty.finalizeOrder("Cash", "20"),
// Order3: Generate 3 points for BBB Test Partner.
// - Reference: Order3_BBB
// - But set CCC Test Partner first as the customer.
ProductScreen.clickPartnerButton(),
ProductScreen.clickCustomer("CCC Test Partner"),
PosLoyalty.isRewardButtonHighlighted(false),
ProductScreen.addOrderline("Whiteboard Pen", "3"),
ProductScreen.clickPartnerButton(),
ProductScreen.clickCustomer("BBB Test Partner"),
PosLoyalty.customerIs("BBB Test Partner"),
PosLoyalty.orderTotalIs("9.60"),
PosLoyalty.finalizeOrder("Cash", "10"),
// Order4: Should not have reward because the customer will be removed.
// - Reference: Order4_no_reward
ProductScreen.clickDisplayedProduct("Whiteboard Pen", true, "1"),
PosLoyalty.isRewardButtonHighlighted(false),
ProductScreen.clickPartnerButton(),
ProductScreen.clickCustomer("CCC Test Partner"),
PosLoyalty.isRewardButtonHighlighted(true),
PosLoyalty.claimReward("Free Product - Whiteboard Pen"),
PosLoyalty.hasRewardLine("Free Product - Whiteboard Pen", "-3.20", "1"),
ProductScreen.clickPartnerButton(),
// This deselects the customer.
PosLoyalty.unselectPartner(),
PosLoyalty.customerIs("Customer"),
PosLoyalty.orderTotalIs("6.40"),
PosLoyalty.finalizeOrder("Cash", "10"),
].flat(),
});
registry.category("web_tour.tours").add("PosLoyaltyChangeRewardQty", {
steps: () =>
[
Chrome.startPoS(),
ProductScreen.clickPartnerButton(),
ProductScreen.clickCustomer("DDD Test Partner"),
ProductScreen.addOrderline("Desk Organizer", "1"),
PosLoyalty.isRewardButtonHighlighted(true),
PosLoyalty.claimReward("Free Product - Whiteboard Pen"),
PosLoyalty.hasRewardLine("Free Product - Whiteboard Pen", "-3.20", "1"),
ProductScreen.clickNumpad("Qty"),
ProductScreen.clickNumpad("1"),
PosLoyalty.hasRewardLine("Free Product - Whiteboard Pen", "-3.20", "1"),
].flat(),
});
registry.category("web_tour.tours").add("PosLoyaltyLoyaltyProgram3", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
// Generates 10.2 points and use points to get the reward product with zero sale price
ProductScreen.addOrderline("Desk Organizer", "2"),
ProductScreen.clickPartnerButton(),
ProductScreen.clickCustomer("AAA Test Partner"),
// At this point, the free_product program is triggered.
// The reward button should be highlighted.
PosLoyalty.isRewardButtonHighlighted(true, true),
PosLoyalty.claimReward("Free Product - Whiteboard Pen"),
PosLoyalty.hasRewardLine("Free Product - Whiteboard Pen", "-1.00", "1"),
PosLoyalty.orderTotalIs("10.2"),
PosLoyalty.finalizeOrder("Cash", "10.2"),
].flat(),
});
registry.category("web_tour.tours").add("PosLoyaltyPromotion", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.clickPartnerButton(),
ProductScreen.clickCustomer("AAA Partner"),
ProductScreen.addOrderline("Test Product 1", "1", "100"),
ProductScreen.totalAmountIs("90.00"),
].flat(),
});
registry.category("web_tour.tours").add("PosLoyaltyDontGrantPointsForRewardOrderLines", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.clickPartnerButton(),
ProductScreen.clickCustomer("A Test Partner"),
ProductScreen.addOrderline("Desk Organizer", "1"),
ProductScreen.addOrderline("Whiteboard Pen", "1"),
PosLoyalty.isRewardButtonHighlighted(true, true),
PosLoyalty.claimReward("100% on the cheapest product"),
PosLoyalty.orderTotalIs("5.10"),
PosLoyalty.finalizeOrder("Cash", "5.10"),
].flat(),
});
registry.category("web_tour.tours").add("PosLoyaltyNextOrderCouponExpirationDate", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.addOrderline("Desk Organizer", "3"),
PosLoyalty.finalizeOrder("Cash", "15.3"),
].flat(),
});
registry.category("web_tour.tours").add("PosComboCheapestRewardProgram", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.clickDisplayedProduct("Expensive product"),
ProductScreen.clickDisplayedProduct("Office Combo"),
combo.select("Combo Product 1"),
combo.select("Combo Product 4"),
combo.select("Combo Product 6"),
Dialog.confirm(),
inLeftSide(Order.hasLine({ productName: "10% on the cheapest product" })),
PosLoyalty.orderTotalIs("1,204.25"),
PosLoyalty.finalizeOrder("Cash", "1204.25"),
ProductScreen.clickDisplayedProduct("Cheap product"),
ProductScreen.clickDisplayedProduct("Office Combo"),
combo.select("Combo Product 1"),
combo.select("Combo Product 4"),
combo.select("Combo Product 6"),
Dialog.confirm(),
Order.hasLine({ productName: "10% on the cheapest product" }),
PosLoyalty.orderTotalIs("61.03"),
PosLoyalty.finalizeOrder("Cash", "61.03"),
].flat(),
});
registry.category("web_tour.tours").add("PosComboSpecificProductProgram", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.clickDisplayedProduct("Office Combo"),
combo.select("Combo Product 1"),
combo.select("Combo Product 4"),
combo.select("Combo Product 6"),
Dialog.confirm(),
Order.hasLine({ productName: "10% on Office Combo" }),
PosLoyalty.orderTotalIs("216.00"),
PosLoyalty.finalizeOrder("Cash", "216.00"),
].flat(),
});
registry.category("web_tour.tours").add("PosCheapestProductTaxInclude", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.clickDisplayedProduct("Product"),
ProductScreen.addOrderline("Desk Organizer", "1"),
Order.hasLine({ productName: "10% on the cheapest product" }),
PosLoyalty.orderTotalIs("6.00"), // taxe of 9 cents (≈ 10% HT)
].flat(),
});
registry.category("web_tour.tours").add("test_not_create_loyalty_card_expired_program", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.clickPartnerButton(),
ProductScreen.clickCustomer("Test Partner", true),
ProductScreen.addOrderline("Desk Organizer", "3"),
PosLoyalty.finalizeOrder("Cash", "15.3"),
].flat(),
});
registry.category("web_tour.tours").add("PosOrderClaimReward", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.clickPartnerButton(),
ProductScreen.clickCustomer("Test Partner"),
ProductScreen.addOrderline("Desk Organizer", "3"),
PosLoyalty.isPointsDisplayed(true),
PosLoyalty.claimReward("Free Product - Whiteboard Pen"),
PosLoyalty.hasRewardLine("Free Product - Whiteboard Pen", "-3.20", "1.00"),
PosLoyalty.finalizeOrder("Cash", "15.3"),
].flat(),
});
registry.category("web_tour.tours").add("PosOrderNoPoints", {
steps: () =>
[
Chrome.startPoS(),
ProductScreen.clickPartnerButton(),
ProductScreen.clickCustomer("Test Partner 2"),
ProductScreen.addOrderline("Desk Organizer", "3"),
PosLoyalty.isPointsDisplayed(false),
PosLoyalty.finalizeOrder("Cash", "15.3"),
].flat(),
});
registry.category("web_tour.tours").add("PosLoyaltyMultipleOrders", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
// Order1: Add a product and leave the order in draft.
ProductScreen.addOrderline("Whiteboard Pen", "2"),
ProductScreen.clickPartnerButton(),
ProductScreen.clickCustomer("Partner Test 1"),
ProductScreen.clickPayButton(),
PaymentScreen.clickPaymentMethod("Cash"),
// Order2: Finalize a different order.
Chrome.createFloatingOrder(),
ProductScreen.addOrderline("Desk Organizer", "1"),
PosLoyalty.finalizeOrder("Cash", "10"),
].flat(),
});
registry.category("web_tour.tours").add("test_combo_product_dont_grant_point", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.clickDisplayedProduct("Office Combo"),
combo.select("Combo Product 1"),
combo.select("Combo Product 4"),
combo.select("Combo Product 6"),
Dialog.confirm(),
ProductScreen.clickDisplayedProduct("Office Combo"),
combo.select("Combo Product 1"),
combo.select("Combo Product 4"),
combo.select("Combo Product 6"),
Dialog.confirm(),
Order.hasLine({ productName: "100% on the cheapest product" }),
ProductScreen.totalAmountIs("50.00"),
].flat(),
});
registry.category("web_tour.tours").add("test_buy_x_get_y_reward_qty", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.addOrderline("Whiteboard Pen", "10"),
ProductScreen.clickDisplayedProduct("Whiteboard Pen"),
PosLoyalty.hasRewardLine("Free Product - Whiteboard Pen", "-3.20", "1.00"),
ProductScreen.clickDisplayedProduct("Whiteboard Pen"),
PosLoyalty.hasRewardLine("Free Product - Whiteboard Pen", "-6.40", "2.00"),
PosLoyalty.finalizeOrder("Cash", "32"),
ProductScreen.addOrderline("Whiteboard Pen", "10"),
PosLoyalty.claimReward("Free Product - Whiteboard Pen"),
PosLoyalty.hasRewardLine("Free Product - Whiteboard Pen", "-9.60", "3.00"),
PosLoyalty.finalizeOrder("Cash", "32"),
].flat(),
});
registry.category("web_tour.tours").add("test_multiple_loyalty_products", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.clickDisplayedProduct("Whiteboard Pen"),
{
content: "Check that selection popup is not opened",
trigger: negate(`.selection-item`),
},
Order.hasLine({ productName: "Whiteboard Pen", quantity: "1" }),
Order.hasLine({ productName: "10% on your order", quantity: "1" }),
].flat(),
});
registry.category("web_tour.tours").add("test_max_usage_partner_with_point", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.addOrderline("Desk Organizer", "3"),
ProductScreen.clickPartnerButton(),
ProductScreen.clickCustomer("AAA Partner 2"),
PosLoyalty.isRewardButtonHighlighted(true),
PosLoyalty.claimReward("100% on your order"),
PosLoyalty.finalizeOrder("Cash", "0"),
ProductScreen.clickPartnerButton(),
ProductScreen.clickCustomer("AAA Partner"),
ProductScreen.addOrderline("Desk Organizer", "3"),
PosLoyalty.isRewardButtonHighlighted(false),
].flat(),
});

View file

@ -0,0 +1,325 @@
import * as Dialog from "@point_of_sale/../tests/generic_helpers/dialog_util";
import * as PosLoyalty from "@pos_loyalty/../tests/tours/utils/pos_loyalty_util";
import * as ProductScreen from "@point_of_sale/../tests/pos/tours/utils/product_screen_util";
import * as Chrome from "@point_of_sale/../tests/pos/tours/utils/chrome_util";
import * as SelectionPopup from "@point_of_sale/../tests/generic_helpers/selection_popup_util";
import { registry } from "@web/core/registry";
import * as ProductConfiguratorPopup from "@point_of_sale/../tests/pos/tours/utils/product_configurator_util";
import { negateStep } from "@point_of_sale/../tests/generic_helpers/utils";
import * as PartnerList from "@point_of_sale/../tests/pos/tours/utils/partner_list_util";
registry.category("web_tour.tours").add("PosLoyaltyFreeProductTour", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.addOrderline("Desk Organizer", "2"),
// At this point, the free_product program is triggered.
// The reward button should be highlighted.
PosLoyalty.isRewardButtonHighlighted(true),
// Since the reward button is highlighted, clicking the reward product should be added as reward.
ProductScreen.clickDisplayedProduct("Desk Organizer", "3"),
PosLoyalty.hasRewardLine("Free Product - Desk Organizer", "-5.10", "1"),
// In the succeeding 2 clicks on the product, it is considered as a regular product.
// In the third click, the product will be added as reward.
ProductScreen.clickDisplayedProduct("Desk Organizer"),
ProductScreen.clickDisplayedProduct("Desk Organizer"),
PosLoyalty.isRewardButtonHighlighted(true),
ProductScreen.clickDisplayedProduct("Desk Organizer", true, "6"),
PosLoyalty.hasRewardLine("Free Product - Desk Organizer", "-10.20", "2"),
ProductScreen.clickDisplayedProduct("Desk Organizer"),
PosLoyalty.isRewardButtonHighlighted(false),
PosLoyalty.orderTotalIs("25.50"),
// Finalize order that consumed a reward.
PosLoyalty.finalizeOrder("Cash", "30"),
ProductScreen.clickDisplayedProduct("Desk Organizer", true, "1"),
ProductScreen.clickDisplayedProduct("Desk Organizer", true, "2"),
ProductScreen.clickDisplayedProduct("Desk Organizer"),
PosLoyalty.hasRewardLine("Free Product - Desk Organizer", "-5.10", "1"),
ProductScreen.clickNumpad("9"),
ProductScreen.selectedOrderlineHas("Desk Organizer", "9"),
PosLoyalty.hasRewardLine("Free Product - Desk Organizer", "-15.30", "3"),
ProductScreen.clickNumpad("⌫"),
ProductScreen.selectedOrderlineHas("Desk Organizer", "0"),
ProductScreen.clickDisplayedProduct("Desk Organizer", true, "1"),
ProductScreen.clickDisplayedProduct("Desk Organizer", true, "2"),
PosLoyalty.isRewardButtonHighlighted(true),
// Finalize order but without the reward.
// This step is important. When syncing the order, no reward should be synced.
PosLoyalty.orderTotalIs("10.20"),
PosLoyalty.finalizeOrder("Cash", "20"),
ProductScreen.addOrderline("Magnetic Board", "2"),
PosLoyalty.isRewardButtonHighlighted(false),
ProductScreen.clickDisplayedProduct("Magnetic Board"),
PosLoyalty.isRewardButtonHighlighted(true),
ProductScreen.clickDisplayedProduct("Whiteboard Pen"),
PosLoyalty.isRewardButtonHighlighted(false),
PosLoyalty.hasRewardLine("Free Product - Whiteboard Pen", "-3.20", "1"),
ProductScreen.clickOrderline("Magnetic Board", "3"),
ProductScreen.selectedOrderlineHas("Magnetic Board", "3"),
ProductScreen.clickNumpad("6"),
ProductScreen.selectedOrderlineHas("Magnetic Board", "6"),
PosLoyalty.isRewardButtonHighlighted(true),
PosLoyalty.claimReward("Free Product - Whiteboard Pen"),
PosLoyalty.isRewardButtonHighlighted(false),
PosLoyalty.hasRewardLine("Free Product - Whiteboard Pen", "-6.40", "2"),
// Finalize order that consumed a reward.
PosLoyalty.orderTotalIs("11.88"),
PosLoyalty.finalizeOrder("Cash", "20"),
ProductScreen.addOrderline("Magnetic Board", "6"),
ProductScreen.clickDisplayedProduct("Whiteboard Pen"),
PosLoyalty.hasRewardLine("Free Product - Whiteboard Pen", "-3.20", "1"),
PosLoyalty.isRewardButtonHighlighted(true),
ProductScreen.clickOrderline("Magnetic Board", "6"),
ProductScreen.clickNumpad("⌫"),
// At this point, the reward should have been removed.
PosLoyalty.isRewardButtonHighlighted(false),
ProductScreen.selectedOrderlineHas("Magnetic Board", "0"),
ProductScreen.clickDisplayedProduct("Magnetic Board"),
ProductScreen.selectedOrderlineHas("Magnetic Board", "1"),
ProductScreen.clickDisplayedProduct("Magnetic Board"),
ProductScreen.selectedOrderlineHas("Magnetic Board", "2"),
ProductScreen.clickDisplayedProduct("Magnetic Board"),
ProductScreen.selectedOrderlineHas("Magnetic Board", "3"),
PosLoyalty.hasRewardLine("Free Product - Whiteboard Pen", "-3.20", "1"),
PosLoyalty.isRewardButtonHighlighted(false),
PosLoyalty.orderTotalIs("5.94"),
PosLoyalty.finalizeOrder("Cash", "10"),
// Promotion: 2 items of shelves, get desk_pad/monitor_stand free
// This is the 5th order.
ProductScreen.clickDisplayedProduct("Wall Shelf Unit"),
ProductScreen.selectedOrderlineHas("Wall Shelf Unit", "1"),
PosLoyalty.isRewardButtonHighlighted(false),
ProductScreen.clickDisplayedProduct("Small Shelf"),
ProductScreen.selectedOrderlineHas("Small Shelf", "1"),
PosLoyalty.isRewardButtonHighlighted(true),
// Click reward product. Should be automatically added as reward.
ProductScreen.clickDisplayedProduct("Desk Pad"),
PosLoyalty.isRewardButtonHighlighted(false),
PosLoyalty.hasRewardLine("Free Product", "-1.98", "1"),
// Remove the reward line. The next steps will check if cashier
// can select from the different reward products.
ProductScreen.clickNumpad("⌫"),
ProductScreen.clickNumpad("⌫"),
PosLoyalty.isRewardButtonHighlighted(true),
PosLoyalty.claimReward("Free Product - [Desk Pad, Monitor Stand]"),
SelectionPopup.has("Monitor Stand"),
SelectionPopup.has("Desk Pad"),
SelectionPopup.has("Desk Pad", { run: "click" }),
PosLoyalty.isRewardButtonHighlighted(false),
PosLoyalty.hasRewardLine("Free Product", "-1.98", "1"),
ProductScreen.clickNumpad("⌫"),
ProductScreen.clickNumpad("⌫"),
PosLoyalty.isRewardButtonHighlighted(true),
PosLoyalty.claimReward("Free Product - [Desk Pad, Monitor Stand]"),
SelectionPopup.has("Monitor Stand"),
SelectionPopup.has("Desk Pad"),
SelectionPopup.has("Monitor Stand", { run: "click" }),
PosLoyalty.isRewardButtonHighlighted(false),
ProductScreen.selectedOrderlineHas("Monitor Stand", "1", "3.19"),
PosLoyalty.hasRewardLine("Free Product", "-3.19", "1"),
PosLoyalty.orderTotalIs("4.81"),
PosLoyalty.finalizeOrder("Cash", "10"),
].flat(),
});
registry.category("web_tour.tours").add("PosLoyaltyFreeProductTour2", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.clickPartnerButton(),
ProductScreen.clickCustomer("AAA Partner"),
ProductScreen.addOrderline("Test Product A", "1"),
PosLoyalty.isRewardButtonHighlighted(true, true),
ProductScreen.clickControlButton("Reward"),
SelectionPopup.has("Free Product - Test Product A", { run: "click" }),
PosLoyalty.hasRewardLine("Free Product - Test Product A", "-11.50", "1"),
PosLoyalty.isRewardButtonHighlighted(false),
].flat(),
});
registry.category("web_tour.tours").add("test_loyalty_free_product_rewards_2", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.clickDisplayedProduct("Desk Organizer"),
ProductScreen.clickDisplayedProduct("Desk Organizer"),
ProductScreen.clickDisplayedProduct("Desk Organizer"),
PosLoyalty.hasRewardLine("Free Product - Desk Organizer", "-5.10", "1.00"),
PosLoyalty.orderTotalIs("10.20"),
PosLoyalty.finalizeOrder("Cash", "10.20"),
].flat(),
});
registry.category("web_tour.tours").add("PosLoyaltySpecificDiscountTour", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.clickDisplayedProduct("Test Product A"),
ProductScreen.selectedOrderlineHas("Test Product A", "1", "40.00"),
ProductScreen.clickDisplayedProduct("Test Product B"),
ProductScreen.selectedOrderlineHas("Test Product B", "1", "40.00"),
ProductScreen.clickControlButton("Reward"),
SelectionPopup.has("$ 10 on specific products", { run: "click" }),
PosLoyalty.hasRewardLine("$ 10 on specific products", "-10.00", "1"),
PosLoyalty.orderTotalIs("70.00"),
ProductScreen.clickControlButton("Reward"),
SelectionPopup.has("$ 10 on specific products", { run: "click" }),
PosLoyalty.orderTotalIs("60.00"),
ProductScreen.clickControlButton("Reward"),
SelectionPopup.has("$ 30 on specific products", { run: "click" }),
PosLoyalty.hasRewardLine("$ 30 on specific products", "-30.00", "1"),
PosLoyalty.orderTotalIs("30.00"),
].flat(),
});
registry.category("web_tour.tours").add("PosLoyaltySpecificDiscountWithFreeProductTour", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.clickDisplayedProduct("Test Product A"),
ProductScreen.clickDisplayedProduct("Test Product C"),
PosLoyalty.orderTotalIs("130.00"),
PosLoyalty.isRewardButtonHighlighted(true, false),
{
content: `click Reward button`,
trigger: ProductScreen.controlButtonTrigger("Reward"),
run: "click",
},
Dialog.cancel(),
PosLoyalty.orderTotalIs("130.00"),
].flat(),
});
registry.category("web_tour.tours").add("PosLoyaltySpecificDiscountWithRewardProductDomainTour", {
steps: () =>
[
// Steps to check if the alert dialog for invalid domain loyalty program is present, only then will the pos screen load correctly
Dialog.is("A reward could not be loaded"),
Dialog.confirm("Ok"),
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.clickDisplayedProduct("Product A"),
ProductScreen.selectedOrderlineHas("Product A", "1", "15.00"),
PosLoyalty.orderTotalIs("15.00"),
ProductScreen.clickDisplayedProduct("Product B"),
ProductScreen.selectedOrderlineHas("Product B", "1", "50.00"),
PosLoyalty.orderTotalIs("40.00"),
ProductScreen.clickControlButton("Reward"),
SelectionPopup.has("10$ on your order - Product B - Saleable", { run: "click" }),
ProductScreen.clickControlButton("Reward"),
SelectionPopup.has("10$ on your order - Product B - Not Saleable", { run: "click" }),
PosLoyalty.orderTotalIs("30.00"),
].flat(),
});
registry.category("web_tour.tours").add("PosLoyaltyRewardProductTag", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.clickDisplayedProduct("Desk Organizer"),
ProductScreen.clickDisplayedProduct("Desk Organizer"),
PosLoyalty.isRewardButtonHighlighted(true, true),
PosLoyalty.claimReward("Free Product - [Product A, Product B]"),
SelectionPopup.has("Product A", { run: "click" }),
PosLoyalty.hasRewardLine("Free Product", "-2", "1"),
PosLoyalty.isRewardButtonHighlighted(false, true),
ProductScreen.clickDisplayedProduct("Desk Organizer"),
ProductScreen.clickDisplayedProduct("Desk Organizer"),
PosLoyalty.isRewardButtonHighlighted(true, true),
PosLoyalty.claimReward("Free Product - [Product A, Product B]"),
SelectionPopup.has("Product B", { run: "click" }),
PosLoyalty.hasRewardLine("Free Product", "-5", "1"),
PosLoyalty.isRewardButtonHighlighted(false, true),
ProductScreen.clickDisplayedProduct("Desk Organizer"),
ProductScreen.clickDisplayedProduct("Desk Organizer"),
PosLoyalty.isRewardButtonHighlighted(true, true),
PosLoyalty.claimReward("Free Product - [Product A, Product B]"),
SelectionPopup.has("Product B", { run: "click" }),
PosLoyalty.hasRewardLine("Free Product", "-10", "2"),
PosLoyalty.isRewardButtonHighlighted(false, true),
].flat(),
});
registry.category("web_tour.tours").add("test_loyalty_on_order_with_fixed_tax", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.clickDisplayedProduct("Product A"),
PosLoyalty.enterCode("563412"),
PosLoyalty.hasRewardLine("10% on your order", "-1.50"),
].flat(),
});
registry.category("web_tour.tours").add("test_loyalty_reward_with_variant", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.clickPartnerButton(),
PartnerList.searchCustomerValue("Test Partner", true),
ProductScreen.clickCustomer("Test Partner"),
ProductScreen.clickDisplayedProduct("Test Product"),
Dialog.discard(),
ProductScreen.clickDisplayedProduct("Test Product"),
ProductConfiguratorPopup.pickRadio("Value 1"),
Dialog.confirm(),
ProductScreen.clickDisplayedProduct("Test Product"),
ProductConfiguratorPopup.pickRadio("Value 1"),
Dialog.confirm(),
ProductScreen.clickDisplayedProduct("Test Product"),
ProductConfiguratorPopup.pickRadio("Value 1"),
Dialog.confirm(),
PosLoyalty.hasRewardLine("Free Product", "-10", "1.00"),
].flat(),
});
registry.category("web_tour.tours").add("test_multiple_reward_line_free_product", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.clickDisplayedProduct("Product A"),
ProductScreen.clickDisplayedProduct("Product A"),
ProductScreen.clickDisplayedProduct("Product A"),
PosLoyalty.hasRewardLine("Free Product - Product A", "-10", "1.00"),
ProductScreen.clickDisplayedProduct("Product B"),
ProductScreen.clickDisplayedProduct("Product B"),
PosLoyalty.hasRewardLine("Free Product - Product B").map(negateStep),
ProductScreen.clickDisplayedProduct("Product B"),
PosLoyalty.hasRewardLine("Free Product - Product B", "-5", "1.00"),
PosLoyalty.hasRewardLine("Free Product - Product A", "-10", "1.00"),
ProductScreen.clickDisplayedProduct("Product B"),
ProductScreen.clickDisplayedProduct("Product B"),
PosLoyalty.hasRewardLine("Free Product - Product B", "-5", "1.00"),
PosLoyalty.hasRewardLine("Free Product - Product A", "-10", "1.00"),
ProductScreen.clickDisplayedProduct("Product A"),
PosLoyalty.hasRewardLine("Free Product - Product B", "-5", "1.00"),
PosLoyalty.hasRewardLine("Free Product - Product A", "-20", "2.00"),
].flat(),
});

View file

@ -0,0 +1,806 @@
/* global posmodel */
import * as PosLoyalty from "@pos_loyalty/../tests/tours/utils/pos_loyalty_util";
import * as ProductScreen from "@point_of_sale/../tests/pos/tours/utils/product_screen_util";
import * as TicketScreen from "@point_of_sale/../tests/pos/tours/utils/ticket_screen_util";
import * as ReceiptScreen from "@point_of_sale/../tests/pos/tours/utils/receipt_screen_util";
import * as SelectionPopup from "@point_of_sale/../tests/generic_helpers/selection_popup_util";
import * as PartnerList from "@point_of_sale/../tests/pos/tours/utils/partner_list_util";
import * as Dialog from "@point_of_sale/../tests/generic_helpers/dialog_util";
import * as Chrome from "@point_of_sale/../tests/pos/tours/utils/chrome_util";
import * as PaymentScreen from "@point_of_sale/../tests/pos/tours/utils/payment_screen_util";
import * as Notification from "@point_of_sale/../tests/generic_helpers/notification_util";
import * as Utils from "@point_of_sale/../tests/generic_helpers/utils";
import { registry } from "@web/core/registry";
import { scan_barcode } from "@point_of_sale/../tests/generic_helpers/utils";
registry.category("web_tour.tours").add("PosLoyaltyTour1", {
steps: () =>
[
// --- PoS Loyalty Tour Basic Part 1 ---
// Generate coupons for PosLoyaltyTour2.
Chrome.startPoS(),
Dialog.confirm("Open Register"),
// basic order
// just accept the automatically applied promo program
// applied programs:
// - on cheapest product
ProductScreen.addOrderline("Whiteboard Pen", "5"),
PosLoyalty.hasRewardLine("90% on the cheapest product", "-2.88"),
PosLoyalty.selectRewardLine("on the cheapest product"),
PosLoyalty.orderTotalIs("13.12"),
PosLoyalty.finalizeOrder("Cash", "20"),
// remove the reward from auto promo program
// no applied programs
ProductScreen.addOrderline("Whiteboard Pen", "6"),
PosLoyalty.hasRewardLine("on the cheapest product", "-2.88"),
PosLoyalty.orderTotalIs("16.32"),
PosLoyalty.removeRewardLine("90% on the cheapest product"),
PosLoyalty.orderTotalIs("19.2"),
PosLoyalty.finalizeOrder("Cash", "20"),
// order with coupon code from coupon program
// applied programs:
// - coupon program
ProductScreen.addOrderline("Desk Organizer", "9"),
PosLoyalty.hasRewardLine("on the cheapest product", "-4.59"),
PosLoyalty.removeRewardLine("90% on the cheapest product"),
PosLoyalty.orderTotalIs("45.90"),
PosLoyalty.enterCode("invalid_code"),
Notification.has("invalid_code"),
PosLoyalty.enterCode("1234"),
PosLoyalty.hasRewardLine("Free Product - Desk Organizer", "-15.30"),
PosLoyalty.finalizeOrder("Cash", "50"),
// Use coupon but eventually remove the reward
// applied programs:
// - on cheapest product
ProductScreen.addOrderline("Letter Tray", "4"),
ProductScreen.addOrderline("Desk Organizer", "9"),
PosLoyalty.hasRewardLine("90% on the cheapest product", "-4.59"),
PosLoyalty.orderTotalIs("62.43"),
PosLoyalty.enterCode("5678"),
PosLoyalty.hasRewardLine("Free Product - Desk Organizer", "-15.30"),
PosLoyalty.orderTotalIs("47.13"),
PosLoyalty.removeRewardLine("Free Product"),
PosLoyalty.orderTotalIs("62.43"),
PosLoyalty.finalizeOrder("Cash", "90"),
// specific product discount
// applied programs:
// - on cheapest product
// - on specific products
ProductScreen.addOrderline("Magnetic Board", "10"), // 1.98
ProductScreen.addOrderline("Desk Organizer", "3"), // 5.1
ProductScreen.addOrderline("Letter Tray", "4"), // 4.8 tax 10%
PosLoyalty.hasRewardLine("90% on the cheapest product", "-1.78"),
PosLoyalty.orderTotalIs("54.44"),
PosLoyalty.enterCode("promocode"),
PosLoyalty.hasRewardLine("50% on specific products", "-16.66"), // 17.55 - 1.78*0.5
PosLoyalty.orderTotalIs("37.78"),
PosLoyalty.finalizeOrder("Cash", "50"),
].flat(),
});
registry.category("web_tour.tours").add("PosLoyaltyTour2", {
steps: () =>
[
// --- PoS Loyalty Tour Basic Part 2 ---
// Using the coupons generated from PosLoyaltyTour1.
// Test that global discount and cheapest product discounts can be accumulated.
// Applied programs:
// - global discount
// - on cheapest discount
Chrome.startPoS(),
ProductScreen.addOrderline("Desk Organizer", "10"), // 5.1
PosLoyalty.hasRewardLine("on the cheapest product", "-4.59"),
ProductScreen.addOrderline("Letter Tray", "4"), // 4.8 tax 10%
PosLoyalty.hasRewardLine("on the cheapest product", "-4.59"),
PosLoyalty.enterCode("123456"),
PosLoyalty.hasRewardLine("10% on your order", "-4.64"),
PosLoyalty.hasRewardLine("10% on your order", "-2.11"),
PosLoyalty.orderTotalIs("60.78"), //SUBTOTAL
PosLoyalty.finalizeOrder("Cash", "70"),
// Scanning coupon twice.
// Also apply global discount on top of free product to check if the
// calculated discount is correct.
// Applied programs:
// - coupon program (free product)
// - global discount
// - on cheapest discount
ProductScreen.addOrderline("Desk Organizer", "11"), // 5.1 per item
PosLoyalty.hasRewardLine("90% on the cheapest product", "-4.59"),
PosLoyalty.orderTotalIs("51.51"),
// add global discount and the discount will be replaced
PosLoyalty.enterCode("345678"),
PosLoyalty.hasRewardLine("10% on your order", "-5.15"),
// add free product coupon (for qty=11, free=4)
// the discount should change after having free products
// it should go back to cheapest discount as it is higher
PosLoyalty.enterCode("5678"),
PosLoyalty.hasRewardLine("Free Product - Desk Organizer", "-20.40"),
PosLoyalty.hasRewardLine("90% on the cheapest product", "-4.59"),
// set quantity to 18
// free qty stays the same since the amount of points on the card only allows for 4 free products
//TODO: The following step should works with ProductScreen.clickNumpad("⌫", "8"),
ProductScreen.clickNumpad("⌫", "⌫", "1", "8"),
PosLoyalty.hasRewardLine("10% on your order", "-6.68"),
PosLoyalty.hasRewardLine("Free Product - Desk Organizer", "-20.40"),
// scan the code again and check notification
PosLoyalty.enterCode("5678"),
PosLoyalty.orderTotalIs("60.13"),
PosLoyalty.finalizeOrder("Cash", "65"),
// Specific products discount (with promocode) and free product (1357)
// Applied programs:
// - discount on specific products
// - free product
ProductScreen.addOrderline("Desk Organizer", "6"), // 5.1 per item
PosLoyalty.hasRewardLine("on the cheapest product", "-4.59"),
PosLoyalty.removeRewardLine("90% on the cheapest product"),
PosLoyalty.enterCode("promocode"),
PosLoyalty.hasRewardLine("50% on specific products", "-15.30"),
PosLoyalty.enterCode("1357"),
PosLoyalty.hasRewardLine("Free Product - Desk Organizer", "-10.20"),
PosLoyalty.hasRewardLine("50% on specific products", "-10.20"),
PosLoyalty.orderTotalIs("10.20"),
PosLoyalty.finalizeOrder("Cash", "20"),
// Check reset program
// Enter two codes and reset the programs.
// The codes should be checked afterwards. They should return to new.
// Applied programs:
// - cheapest product
ProductScreen.addOrderline("Monitor Stand", "6"), // 3.19 per item
PosLoyalty.enterCode("098765"),
PosLoyalty.hasRewardLine("90% on the cheapest product", "-2.87"),
PosLoyalty.hasRewardLine("10% on your order", "-1.63"),
PosLoyalty.orderTotalIs("14.64"),
PosLoyalty.removeRewardLine("90% on the cheapest product"),
PosLoyalty.hasRewardLine("10% on your order", "-1.91"),
PosLoyalty.orderTotalIs("17.23"),
ProductScreen.clickControlButton("Reset Programs"),
PosLoyalty.hasRewardLine("90% on the cheapest product", "-2.87"),
PosLoyalty.orderTotalIs("16.27"),
PosLoyalty.finalizeOrder("Cash", "20"),
].flat(),
});
registry.category("web_tour.tours").add("PosLoyaltyTour3", {
steps: () =>
[
// --- PoS Loyalty Tour Basic Part 3 ---
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.clickDisplayedProduct("Promo Product"),
PosLoyalty.orderTotalIs("34.50"),
ProductScreen.clickDisplayedProduct("Product B"),
PosLoyalty.hasRewardLine("100% on specific products", "25.00"),
ProductScreen.clickDisplayedProduct("Product A"),
PosLoyalty.hasRewardLine("100% on specific products", "15.00"),
PosLoyalty.orderTotalIs("34.50"),
ProductScreen.clickDisplayedProduct("Product A"),
PosLoyalty.hasRewardLine("100% on specific products", "21.82"),
PosLoyalty.hasRewardLine("100% on specific products", "18.18"),
PosLoyalty.orderTotalIs("49.50"),
].flat(),
});
registry.category("web_tour.tours").add("PosLoyaltyTour4", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.addOrderline("Test Product 1", "1"),
ProductScreen.addOrderline("Test Product 2", "1"),
ProductScreen.clickPriceList("Public Pricelist"),
PosLoyalty.enterCode("abcda"),
PosLoyalty.orderTotalIs("0.00"),
ProductScreen.clickPriceList("Test multi-currency"),
PosLoyalty.orderTotalIs("0.00"),
].flat(),
});
registry.category("web_tour.tours").add("PosCouponTour5", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.clickPartnerButton(),
ProductScreen.clickCustomer("AAAA"),
ProductScreen.addOrderline("Test Product 1", "1", "100"),
PosLoyalty.pointsAwardedAre("115"),
PosLoyalty.clickDiscountButton(),
Dialog.confirm(),
ProductScreen.totalAmountIs("92.00"),
PosLoyalty.pointsAwardedAre("92"),
Chrome.endTour(),
].flat(),
});
//transform the last tour to match the new format
registry.category("web_tour.tours").add("PosLoyaltyTour6", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.clickPartnerButton(),
ProductScreen.clickCustomer("AAA Partner"),
ProductScreen.clickDisplayedProduct("Test Product A"),
PosLoyalty.checkAddedLoyaltyPoints("26.5"),
ProductScreen.clickControlButton("Reward"),
SelectionPopup.has("$ 1 per point on your order", { run: "click" }),
ProductScreen.totalAmountIs("165.00"),
ProductScreen.clickPayButton(),
PaymentScreen.clickPaymentMethod("Cash"),
PaymentScreen.clickValidate(),
ReceiptScreen.isShown(),
PosLoyalty.isLoyaltyPointsAvailable(),
Utils.refresh(),
ReceiptScreen.isShown(),
PosLoyalty.isLoyaltyPointsAvailable(),
].flat(),
});
registry.category("web_tour.tours").add("PosLoyaltyTour7", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.addOrderline("Test Product", "1"),
PosLoyalty.orderTotalIs("100"),
PosLoyalty.enterCode("abcda"),
PosLoyalty.orderTotalIs("90"),
].flat(),
});
registry.category("web_tour.tours").add("PosLoyaltyTour8", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.clickDisplayedProduct("Product B"),
ProductScreen.clickDisplayedProduct("Product A"),
ProductScreen.totalAmountIs("50.00"),
].flat(),
});
registry.category("web_tour.tours").add("PosLoyaltySpecificDiscountCategoryTour", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.clickDisplayedProduct("Product A", true, "1", "15.00"),
PosLoyalty.orderTotalIs("15.00"),
ProductScreen.clickDisplayedProduct("Product B", true, "1", "50.00"),
PosLoyalty.orderTotalIs("40.00"),
].flat(),
});
registry.category("web_tour.tours").add("PosLoyaltyTour9", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.clickPartnerButton(),
ProductScreen.clickCustomer("AAA Partner"),
ProductScreen.clickDisplayedProduct("Product B"),
ProductScreen.clickDisplayedProduct("Product A"),
ProductScreen.totalAmountIs("210.00"),
PosLoyalty.isRewardButtonHighlighted(true),
PosLoyalty.claimReward("$ 5"),
ProductScreen.totalAmountIs("205.00"),
].flat(),
});
registry.category("web_tour.tours").add("PosLoyaltyTour10", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.clickPartnerButton(),
ProductScreen.clickCustomer("AAA Partner"),
PosLoyalty.customerIs("AAA Partner"),
ProductScreen.clickDisplayedProduct("Product Test"),
ProductScreen.totalAmountIs("1.00"),
ProductScreen.selectedOrderlineHas("Product Test", "1"),
PosLoyalty.isRewardButtonHighlighted(true),
PosLoyalty.claimReward("Free Product B"),
{
content: `click on reward item`,
trigger: `.selection-item:contains("Free Product B")`,
run: "click",
},
PosLoyalty.hasRewardLine("Free Product B", "-1.00"),
ProductScreen.totalAmountIs("1.00"),
PosLoyalty.isRewardButtonHighlighted(false),
].flat(),
});
registry.category("web_tour.tours").add("PosLoyaltyTour11.1", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.clickPartnerButton(),
ProductScreen.clickCustomer("AAA Partner"),
PosLoyalty.customerIs("AAA Partner"),
ProductScreen.addOrderline("Product Test", "3"),
ProductScreen.totalAmountIs("150.00"),
PosLoyalty.isRewardButtonHighlighted(false),
PosLoyalty.finalizeOrder("Cash", "150"),
].flat(),
});
registry.category("web_tour.tours").add("PosLoyaltyTour11.2", {
steps: () =>
[
Chrome.startPoS(),
ProductScreen.clickPartnerButton(),
ProductScreen.clickCustomer("AAA Partner"),
PosLoyalty.customerIs("AAA Partner"),
ProductScreen.clickDisplayedProduct("Product Test"),
ProductScreen.totalAmountIs("50.00"),
PosLoyalty.isRewardButtonHighlighted(false),
PosLoyalty.enterCode("123456"),
PosLoyalty.isRewardButtonHighlighted(true),
PosLoyalty.claimReward("Free Product"),
PosLoyalty.hasRewardLine("Free Product", "-3.00"),
PosLoyalty.isRewardButtonHighlighted(false),
ProductScreen.totalAmountIs("50.00"),
PosLoyalty.finalizeOrder("Cash", "50"),
].flat(),
});
registry.category("web_tour.tours").add("PosLoyaltyMinAmountAndSpecificProductTour", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.clickDisplayedProduct("Product A"),
ProductScreen.selectedOrderlineHas("Product A", "1", "20.00"),
PosLoyalty.orderTotalIs("20.00"),
ProductScreen.clickDisplayedProduct("Product B"),
ProductScreen.selectedOrderlineHas("Product B", "1", "30.00"),
PosLoyalty.orderTotalIs("50.00"),
ProductScreen.clickDisplayedProduct("Product A"),
ProductScreen.selectedOrderlineHas("Product A", "2", "40.00"),
PosLoyalty.orderTotalIs("66.00"),
].flat(),
});
registry.category("web_tour.tours").add("PosLoyaltyTour12", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.addOrderline("Free Product A", "2"),
ProductScreen.clickDisplayedProduct("Free Product A"),
ProductScreen.totalAmountIs("2.00"),
PosLoyalty.hasRewardLine("Free Product", "-1.00"),
ProductScreen.addOrderline("Free Product B", "2"),
ProductScreen.clickDisplayedProduct("Free Product B"),
ProductScreen.totalAmountIs("12.00"),
PosLoyalty.hasRewardLine("Free Product", "-5.00"),
ProductScreen.clickDisplayedProduct("Free Product B"),
ProductScreen.clickDisplayedProduct("Free Product B"),
ProductScreen.clickDisplayedProduct("Free Product B"),
ProductScreen.selectedOrderlineHas("Free Product B", "6"),
ProductScreen.totalAmountIs("22.00"),
PosLoyalty.hasRewardLine("Free Product", "-10.00"),
].flat(),
});
function createOrderCoupon(totalAmount, couponName, couponAmount, loyaltyPoints) {
return [
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.clickPartnerButton(),
ProductScreen.clickCustomer("AAAA"),
ProductScreen.addOrderline("product_a", "1"),
ProductScreen.addOrderline("product_b", "1"),
PosLoyalty.enterCode("promocode"),
PosLoyalty.hasRewardLine(`${couponName}`, `${couponAmount}`),
PosLoyalty.orderTotalIs(`${totalAmount}`),
PosLoyalty.pointsAwardedAre(`${loyaltyPoints}`),
PosLoyalty.finalizeOrder("Cash", `${totalAmount}`),
].flat();
}
registry.category("web_tour.tours").add("PosLoyaltyPointsDiscountNoDomainProgramNoDomain", {
steps: () => [createOrderCoupon("135.00", "10% on your order", "-15.00", "135")].flat(),
});
registry.category("web_tour.tours").add("PosLoyaltyPointsDiscountNoDomainProgramDomain", {
steps: () => [createOrderCoupon("135.00", "10% on your order", "-15.00", "100")].flat(),
});
registry.category("web_tour.tours").add("PosLoyaltyPointsDiscountWithDomainProgramDomain", {
steps: () => [createOrderCoupon("140.00", "10% on food", "-10.00", "90")].flat(),
});
registry.category("web_tour.tours").add("PosLoyaltyPointsGlobalDiscountProgramNoDomain", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.addOrderline("product_a", "1"),
ProductScreen.clickPartnerButton(),
ProductScreen.clickCustomer("AAAA"),
PosLoyalty.hasRewardLine("10% on your order", "-10.00"),
PosLoyalty.orderTotalIs("90"),
PosLoyalty.pointsAwardedAre("90"),
PosLoyalty.finalizeOrder("Cash", "90"),
].flat(),
});
registry.category("web_tour.tours").add("ChangeRewardValueWithLanguage", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.clickDisplayedProduct("Desk Organizer"),
ProductScreen.selectedOrderlineHas("Desk Organizer", "1", "5.10"),
ProductScreen.clickPartnerButton(),
ProductScreen.clickCustomer("Partner Test 1"),
PosLoyalty.isRewardButtonHighlighted(true, true),
PosLoyalty.claimReward("$ 2 on your order"),
PosLoyalty.hasRewardLine("$ 2 on your order", "-2.00"),
PosLoyalty.orderTotalIs("3.10"),
].flat(),
});
registry.category("web_tour.tours").add("PosLoyaltyArchivedRewardProductsInactive", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.clickDisplayedProduct("Test Product A"),
ProductScreen.clickPartnerButton(),
ProductScreen.clickCustomer("AAAA"),
PosLoyalty.isRewardButtonHighlighted(false, true),
ProductScreen.selectedOrderlineHas("Test Product A", "1", "100.00"),
PosLoyalty.finalizeOrder("Cash", "100"),
].flat(),
});
registry.category("web_tour.tours").add("PosLoyaltyArchivedRewardProductsActive", {
steps: () =>
[
Chrome.startPoS(),
ProductScreen.clickDisplayedProduct("Test Product A"),
ProductScreen.clickPartnerButton(),
ProductScreen.clickCustomer("AAAA"),
PosLoyalty.isRewardButtonHighlighted(true),
ProductScreen.selectedOrderlineHas("Test Product A", "1", "100.00"),
PosLoyalty.finalizeOrder("Cash", "100"),
].flat(),
});
registry.category("web_tour.tours").add("CustomerLoyaltyPointsDisplayed", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.clickDisplayedProduct("product_a"),
ProductScreen.selectedOrderlineHas("product_a", "1", "100.00"),
ProductScreen.clickPartnerButton(),
ProductScreen.clickCustomer("John Doe"),
PosLoyalty.orderTotalIs("100.00"),
PosLoyalty.pointsAwardedAre("100"),
PosLoyalty.finalizeOrder("Cash", "100.00"),
PosLoyalty.checkPartnerPoints("John Doe", "100.00"),
].flat(),
});
registry.category("web_tour.tours").add("PosLoyalty2DiscountsSpecificGlobal", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.clickPartnerButton(),
ProductScreen.clickCustomer("AAAA"),
ProductScreen.addOrderline("Test Product A", "5"),
ProductScreen.clickDisplayedProduct("Test Product B"),
PosLoyalty.hasRewardLine("10% on your order", "-3.00"),
PosLoyalty.hasRewardLine("10% on Test Product B", "-0.45"),
PosLoyalty.finalizeOrder("Cash", "100"),
].flat(),
});
registry.category("web_tour.tours").add("PosLoyaltySpecificProductDiscountWithGlobalDiscount", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.addOrderline("Product A", "1"),
PosLoyalty.hasRewardLine("$ 40 on Product A", "-40.00"),
PosLoyalty.clickDiscountButton(),
Dialog.confirm(),
PosLoyalty.hasRewardLine("$ 40 on Product A", "-40.00"),
PosLoyalty.orderTotalIs("20.00"),
].flat(),
});
registry.category("web_tour.tours").add("PosRewardProductScan", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
scan_barcode("95412427100283"),
ProductScreen.selectedOrderlineHas("product_a", "1", "1,150.00"),
PosLoyalty.hasRewardLine("50% on your order", "-575.00"),
PosLoyalty.orderTotalIs("575.00"),
PosLoyalty.finalizeOrder("Cash", "575.00"),
].flat(),
});
registry.category("web_tour.tours").add("PosRewardProductScanGS1", {
steps: () =>
[
Chrome.startPoS(),
scan_barcode("0195412427100283"),
ProductScreen.selectedOrderlineHas("product_a", "1", "1,150.00"),
PosLoyalty.hasRewardLine("50% on your order", "-575.00"),
PosLoyalty.orderTotalIs("575.00"),
PosLoyalty.finalizeOrder("Cash", "575.00"),
].flat(),
});
registry.category("web_tour.tours").add("PosLoyaltyPromocodePricelist", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.addOrderline("Test Product 1", "1"),
PosLoyalty.enterCode("hellopromo"),
PosLoyalty.orderTotalIs("25.87"),
].flat(),
});
registry.category("web_tour.tours").add("RefundRulesProduct", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.clickDisplayedProduct("product_a"),
PosLoyalty.finalizeOrder("Cash", "1000"),
ProductScreen.isShown(),
...ProductScreen.clickRefund(),
TicketScreen.filterIs("Paid"),
TicketScreen.selectOrder("001"),
ProductScreen.clickNumpad("1"),
TicketScreen.confirmRefund(),
PaymentScreen.isShown(),
].flat(),
});
registry.category("web_tour.tours").add("test_two_variant_same_discount", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.clickDisplayedProduct("Sofa"),
Chrome.clickBtn("Add"),
].flat(),
});
registry.category("web_tour.tours").add("test_settle_dont_give_points_again", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.clickPartnerButton(),
PartnerList.settleCustomerAccount("AAA Partner", "10.00", "TSJ/"),
].flat(),
});
registry.category("web_tour.tours").add("test_refund_does_not_decrease_points", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.clickPartnerButton(),
ProductScreen.clickCustomer("Refunding Guy", true),
ProductScreen.clickDisplayedProduct("Refund Product"),
ProductScreen.clickControlButton("Reward"),
SelectionPopup.has("$ 1 per point on your order", { run: "click" }),
PosLoyalty.finalizeOrder("Cash", "200"),
ProductScreen.clickRefund(),
TicketScreen.selectOrder("001"),
ProductScreen.clickNumpad("1"),
ProductScreen.clickLine("$ 1 per point on your order"),
ProductScreen.clickNumpad("1"),
TicketScreen.confirmRefund(),
PaymentScreen.totalIs("-200.00"),
PaymentScreen.clickPaymentMethod("Cash"),
PaymentScreen.clickValidate(),
].flat(),
});
registry.category("web_tour.tours").add("test_discount_after_unknown_scan", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.addOrderline("Test Product A", "1"),
scan_barcode("00998877665544332211"), //should be unknown
PosLoyalty.hasRewardLine("10% on Test Product A", "-0.50"),
ProductScreen.totalAmountIs("4.50"),
].flat(),
});
registry.category("web_tour.tours").add("test_scan_loyalty_card_select_customer", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
scan_barcode("0444-e050-4548"),
ProductScreen.customerIsSelected("AAA Test Partner"),
].flat(),
});
registry.category("web_tour.tours").add("test_min_qty_points_awarded", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.clickPartnerButton(),
ProductScreen.clickCustomer("AA Partner"),
ProductScreen.clickDisplayedProduct("Whiteboard Pen"),
PosLoyalty.claimReward("Free Product"),
PosLoyalty.pointsTotalIs("90"),
PosLoyalty.orderTotalIs("0.0"),
PosLoyalty.finalizeOrder("Cash", "0.0"),
].flat(),
});
registry.category("web_tour.tours").add("test_confirm_coupon_programs_one_by_one", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
{
trigger: "body",
content: "Create fake orders",
run: async () => {
// Create 5 orders that will be synced one by one
for (let i = 0; i < 5; i++) {
const order = posmodel.createNewOrder();
const product = posmodel.models["product.template"].find(
(p) => p.name === "Desk Pad"
);
const pm = posmodel.models["pos.payment.method"].getFirst();
const program = posmodel.models["loyalty.program"].find(
(p) => p.program_type === "gift_card"
);
await posmodel.addLineToOrder({ product_tmpl_id: product }, order);
posmodel.addPendingOrder([order.id]);
order.addPaymentline(pm);
order.state = "paid";
// Create fake coupon point changes to simulate coupons to be confirmed
order.uiState.couponPointChanges = [
{
points: 124.2,
program_id: program.id,
coupon_id: -(i + 1),
barcode: "",
},
];
}
},
},
// Create one more order to be able to trigger the sync from the UI
ProductScreen.clickDisplayedProduct("Desk Pad"),
ProductScreen.clickPayButton(),
PaymentScreen.clickPaymentMethod("Bank"),
PaymentScreen.clickValidate(),
ReceiptScreen.isShown(),
].flat(),
});
registry.category("web_tour.tours").add("test_order_reward_product_tax_included_included", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.addOrderline("Product Include", "1"),
PosLoyalty.enterCode("hellopromo"),
PosLoyalty.hasRewardLine("$ 10 on your order", "-10.00"),
].flat(),
});
registry.category("web_tour.tours").add("test_order_reward_product_tax_included_excluded", {
steps: () =>
[
Chrome.startPoS(),
ProductScreen.addOrderline("Product Include", "1"),
PosLoyalty.enterCode("hellopromo"),
PosLoyalty.hasRewardLine("$ 10 on your order", "-10.00"),
].flat(),
});
registry.category("web_tour.tours").add("test_specific_reward_product_tax_included_included", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.addOrderline("Product Include", "1"),
PosLoyalty.enterCode("hellopromo"),
PosLoyalty.hasRewardLine("$ 10 on Product Include", "-10.00"),
].flat(),
});
registry.category("web_tour.tours").add("test_specific_reward_product_tax_included_excluded", {
steps: () =>
[
Chrome.startPoS(),
ProductScreen.addOrderline("Product Include", "1"),
PosLoyalty.enterCode("hellopromo"),
PosLoyalty.hasRewardLine("$ 10 on Product Include", "-10.00"),
].flat(),
});
registry.category("web_tour.tours").add("test_loyalty_is_not_processed_for_draft_order", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.clickPartnerButton(),
ProductScreen.clickCustomer("AAAA"),
ProductScreen.addOrderline("Whiteboard Pen", "1", "100"),
PosLoyalty.pointsAwardedAre("100"),
PosLoyalty.pointsTotalIs("150"),
ProductScreen.saveOrder(),
ProductScreen.selectFloatingOrder(0),
PosLoyalty.pointsAwardedAre("100"),
PosLoyalty.pointsTotalIs("150"),
].flat(),
});
registry.category("web_tour.tours").add("test_race_conditions_update_program", {
steps: () =>
[
Chrome.startPoS(),
Dialog.confirm("Open Register"),
ProductScreen.clickDisplayedProduct("Test Product"),
PosLoyalty.orderTotalIs("34.87"),
{
trigger: "body",
run: async () => {
// Check the number of lines in the order
const line_count = document.querySelectorAll(".orderline").length;
if (line_count !== 11) {
throw new Error(`Expected 11 orderlines, found ${line_count}`);
}
},
},
].flat(),
});

View file

@ -0,0 +1,39 @@
import * as PosLoyalty from "@pos_loyalty/../tests/tours/utils/pos_loyalty_util";
import * as ProductScreen from "@point_of_sale/../tests/pos/tours/utils/product_screen_util";
import * as Chrome from "@point_of_sale/../tests/pos/tours/utils/chrome_util";
import * as Dialog from "@point_of_sale/../tests/generic_helpers/dialog_util";
import { registry } from "@web/core/registry";
registry.category("web_tour.tours").add("PosLoyaltyValidity1", {
steps: () =>
[
// First tour should not get any automatic rewards
Chrome.startPoS(),
Dialog.confirm("Open Register"),
// Not valid -> date
ProductScreen.addOrderline("Whiteboard Pen", "5"),
PosLoyalty.isRewardButtonHighlighted(false, true),
PosLoyalty.orderTotalIs("16.00"),
PosLoyalty.finalizeOrder("Cash", "16"),
].flat(),
});
registry.category("web_tour.tours").add("PosLoyaltyValidity2", {
steps: () =>
[
// Second tour
// Valid
Chrome.startPoS(),
ProductScreen.addOrderline("Whiteboard Pen", "5"),
PosLoyalty.hasRewardLine("90% on the cheapest product", "-2.88"),
PosLoyalty.finalizeOrder("Cash", "20"),
// Not valid -> usage
ProductScreen.addOrderline("Whiteboard Pen", "5"),
PosLoyalty.isRewardButtonHighlighted(false, true),
PosLoyalty.orderTotalIs("16.00"),
PosLoyalty.finalizeOrder("Cash", "16.00"),
].flat(),
});

View file

@ -0,0 +1,267 @@
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 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 Dialog from "@point_of_sale/../tests/generic_helpers/dialog_util";
import { negate } from "@point_of_sale/../tests/generic_helpers/utils";
import * as Chrome from "@point_of_sale/../tests/pos/tours/utils/chrome_util";
export function selectRewardLine(rewardName) {
return [
...Order.hasLine({
withClass: ".fst-italic",
withoutClass: ".selected",
run: "click",
productName: rewardName,
}),
...Order.hasLine({
withClass: ".selected.fst-italic",
productName: rewardName,
}),
];
}
export function enterCode(code) {
return [
...ProductScreen.clickControlButton("Enter Code"),
TextInputPopup.inputText(code),
Dialog.confirm(),
];
}
export function clickEWalletButton(text = "eWallet") {
return [{ trigger: ProductScreen.controlButtonTrigger(text), run: "click" }];
}
export function claimReward(rewardName) {
return [
...ProductScreen.clickControlButton("Reward"),
{
// There should be description because a program always has a name.
trigger: ".selection-item span:nth-child(2)",
},
{
content: "select reward",
trigger: `.selection-item:contains("${rewardName}")`,
run: "click",
},
];
}
export function unselectPartner() {
return [{ trigger: ".unselect-tag", run: "click" }];
}
export function clickDiscountButton() {
return [
...ProductScreen.clickControlButtonMore(),
{
content: "click discount button",
trigger: ".js_discount",
run: "click",
},
];
}
export function hasRewardLine(rewardName, amount, qty) {
return Order.hasLine({
withClass: ".fst-italic",
productName: rewardName,
price: amount,
quantity: qty,
});
}
export function orderTotalIs(total_str) {
return [...Order.hasTotal(total_str)];
}
export function isRewardButtonHighlighted(isHighlighted, closeModal = true) {
const steps = [
...ProductScreen.clickControlButtonMore(),
{
trigger: isHighlighted
? '.control-buttons button.highlight:contains("Reward")'
: '.control-buttons button.disabled:contains("Reward")',
},
];
if (closeModal) {
steps.push({
content: "Close modal after checked if reward button is highlighted",
trigger: ".modal header .btn-close",
run: "click",
});
}
return steps;
}
export function eWalletButtonState({ highlighted, text = "eWallet", click = false }) {
const step = {
trigger: highlighted
? `.control-buttons button.highlight:contains("${text}")`
: `.control-buttons button.disabled:contains("${text}")`,
};
if (click) {
step.run = "click";
}
const steps = [...ProductScreen.clickControlButtonMore(), step];
if (!click) {
steps.push({
//Previous step is just a check. No need to keep modal openened
trigger: ".modal header .btn-close",
run: "click",
});
}
return steps;
}
export function customerIs(name) {
return [
{
trigger: `.product-screen .set-partner:contains("${name}")`,
},
];
}
export function isPointsDisplayed(isDisplayed) {
return [
{
trigger: isDisplayed
? ".loyalty-points-title"
: "body:not(:has(.loyalty-points-title))",
},
];
}
export function pointsAwardedAre(points_str) {
return [
{
content: "loyalty points awarded " + points_str,
trigger: '.loyalty-points-won:contains("' + points_str + '")',
},
];
}
export function pointsTotalIs(points_str) {
return [
{
content: "loyalty points awarded " + points_str,
trigger: '.loyalty-points-totaltext-end:contains("' + points_str + '")',
},
];
}
export function finalizeOrder(paymentMethod, amount) {
return [
...ProductScreen.clickPayButton(),
...PaymentScreen.clickPaymentMethod(paymentMethod),
...PaymentScreen.clickNumpad([...amount].join(" ")),
...PaymentScreen.clickValidate(),
...ReceiptScreen.clickNextOrder(),
];
}
export function removeRewardLine(name) {
return [selectRewardLine(name), ProductScreen.clickNumpad("⌫"), Dialog.confirm()].flat();
}
export function checkAddedLoyaltyPoints(points) {
return [
{
trigger: `.loyalty-points-won:contains("${points}")`,
},
];
}
export function useExistingLoyaltyCard(code, valid = true) {
const steps = [
{
trigger: `a:contains("Sell physical gift card?")`,
run: "click",
},
{
content: `Input code '${code}'`,
trigger: `input[id="code"]`,
run: `edit ${code}`,
},
{
content: "Not loading",
trigger: negate(".gift-card-loading"),
},
];
if (!valid) {
steps.push(Dialog.confirm("Ok"));
steps.push(Dialog.cancel());
steps.push({
trigger: `a:contains("Sell physical gift card?")`,
run: () => {},
});
} else {
steps.push(...Chrome.waitRequest());
steps.push(Dialog.confirm());
}
return steps;
}
export function createManualGiftCard(code, amount, date = false) {
const steps = [
{
trigger: `a:contains("Sell physical gift card?")`,
run: "click",
},
{
content: `Input code '${code}'`,
trigger: `input[id="code"]`,
run: `edit ${code}`,
},
{
content: `Input amount '${amount}'`,
trigger: `input[id="amount"]`,
run: `edit ${amount}`,
},
];
if (date !== false) {
steps.push({
content: `Input date '${date}'`,
trigger: `.modal input.o_datetime_input.cursor-pointer.form-control.form-control-lg`,
run: `edit ${date}`,
});
}
steps.push({
trigger: `.btn-primary:contains("Add Balance")`,
run: "click",
});
return steps;
}
export function clickGiftCardProgram(name) {
return [
{
content: `Click gift card program '${name}'`,
trigger: `button.selection-item:has(span:contains("${name}"))`,
run: "click",
},
];
}
export function clickPhysicalGiftCard(code = "Sell physical gift card?") {
return [
{
trigger: `ul.info-list .text-wrap:contains("${code}")`,
run: "click",
},
];
}
export function checkPartnerPoints(name, points) {
return [
...ProductScreen.clickPartnerButton(),
{
content: `Check '${name}' has ${points} Loyalty Points`,
trigger: `.partner-list .partner-line:contains(${name}) .partner-line-balance:contains(${points} Loyalty Point(s))`,
},
];
}
export function isMoreControlButtonActive(active) {
return {
content: "More control button is " + (active ? "active" : "not active"),
trigger: active
? ".control-buttons .more-btn.active"
: ".control-buttons:not(:has(.more-btn.active))",
};
}
export function isLoyaltyPointsAvailable() {
return {
content: "Loyalty Points are visible on the receipt",
trigger: ".pos-receipt .loyalty",
};
}

View file

@ -0,0 +1,48 @@
import { test, expect } from "@odoo/hoot";
import { mockDate } from "@odoo/hoot-mock";
import { mountWithCleanup } from "@web/../tests/web_test_helpers";
import { getFilledOrder, setupPosEnv } from "@point_of_sale/../tests/unit/utils";
import { definePosModels } from "@point_of_sale/../tests/unit/data/generate_model_definitions";
import { ManageGiftCardPopup } from "@pos_loyalty/app/components/popups/manage_giftcard_popup/manage_giftcard_popup";
definePosModels();
test("addBalance", async () => {
const store = await setupPosEnv();
// Freeze current date so luxon.DateTime.now() is fixed
mockDate("2025-01-01");
let payloadResult = null;
const order = await getFilledOrder(store);
const popup = await mountWithCleanup(ManageGiftCardPopup, {
props: {
line: order.lines[0],
title: "Sell/Manage physical gift card",
getPayload: (code, amount, expDate) => {
payloadResult = { code, amount, expDate };
},
close: () => {},
},
});
popup.state.inputValue = "";
popup.state.amountValue = "";
const valid = popup.validateCode();
expect(valid).toBe(false);
expect(popup.state.error).toBe(true);
popup.state.inputValue = "101";
popup.state.amountValue = "100";
popup.state.error = false;
popup.state.amountError = false;
await popup.addBalance();
expect(payloadResult.code).toBe("101");
expect(payloadResult.amount).toBe(100);
// expiration is +1 year
expect(payloadResult.expDate).toBe("2026-01-01");
});

View file

@ -0,0 +1,52 @@
import { test, expect } from "@odoo/hoot";
import { mountWithCleanup } from "@web/../tests/web_test_helpers";
import { setupPosEnv } from "@point_of_sale/../tests/unit/utils";
import { ControlButtons } from "@point_of_sale/app/screens/product_screen/control_buttons/control_buttons";
import { definePosModels } from "@point_of_sale/../tests/unit/data/generate_model_definitions";
import { addProductLineToOrder } from "@pos_loyalty/../tests/unit/utils";
definePosModels();
test("_applyReward", async () => {
const store = await setupPosEnv();
const models = store.models;
const order = store.addNewOrder();
// Get card #1 - belongs to a loyalty-type program
const card = models["loyalty.card"].get(1);
// Get reward #2 - belongs to the same loyalty program, type = discount reward
const reward = models["loyalty.reward"].get(2);
await addProductLineToOrder(store, order);
// Total quantity in the order
const potentialQty = order.getOrderlines().reduce((acc, line) => acc + line.qty, 0);
const component = await mountWithCleanup(ControlButtons, {});
const result = await component._applyReward(reward, card.id, potentialQty);
expect(result).toBe(true);
});
test("getPotentialRewards", async () => {
const store = await setupPosEnv();
const models = store.models;
const order = store.addNewOrder();
// Get loyalty program #1 - type = loyalty
const loyaltyProgram = models["loyalty.program"].get(1);
// Get card #1 - linked to loyalty program #1
const card = models["loyalty.card"].get(1);
await addProductLineToOrder(store, order);
order._code_activated_coupon_ids = [card];
const component = await mountWithCleanup(ControlButtons, {});
const rewards = component.getPotentialRewards();
const reward = rewards[0].reward;
expect(reward).toEqual(models["loyalty.reward"].get(1));
expect(reward.program_id).toEqual(loyaltyProgram);
});

View file

@ -0,0 +1,43 @@
import { test, expect } from "@odoo/hoot";
import { mountWithCleanup } from "@web/../tests/web_test_helpers";
import { OrderSummary } from "@point_of_sale/app/screens/product_screen/order_summary/order_summary";
import { setupPosEnv } from "@point_of_sale/../tests/unit/utils";
import { definePosModels } from "@point_of_sale/../tests/unit/data/generate_model_definitions";
import { addProductLineToOrder } from "@pos_loyalty/../tests/unit/utils";
definePosModels();
test("_updateGiftCardOrderline", async () => {
const store = await setupPosEnv();
const models = store.models;
const order = store.addNewOrder();
const product = models["product.product"].get(1);
// Program #3 - loyalty program for gift cards
const program = models["loyalty.program"].get(3);
// Card #3 - gift card which program type is gift_card
const card = models["loyalty.card"].get(3);
await addProductLineToOrder(store, order);
const points = product.lst_price;
order.uiState.couponPointChanges[card.id] = {
coupon_id: card.id,
program_id: program.id,
product_id: product.id,
points: points,
manual: false,
};
const component = await mountWithCleanup(OrderSummary, {});
await component._updateGiftCardOrderline("ABC123", points);
const updatedLine = order.getSelectedOrderline();
expect(updatedLine.gift_code).toBe("ABC123");
expect(updatedLine.product_id.id).toBe(product.id);
expect(updatedLine.getQuantity()).toBe(1);
expect(order.uiState.couponPointChanges[card.id]).toBe(undefined);
});

View file

@ -0,0 +1,49 @@
import { test, expect } from "@odoo/hoot";
import { mountWithCleanup } from "@web/../tests/web_test_helpers";
import { setupPosEnv } from "@point_of_sale/../tests/unit/utils";
import { PartnerLine } from "@point_of_sale/app/screens/partner_list/partner_line/partner_line";
import { definePosModels } from "@point_of_sale/../tests/unit/data/generate_model_definitions";
definePosModels();
test("_getLoyaltyPointsRepr", async () => {
const store = await setupPosEnv();
const models = store.models;
const partner = models["res.partner"].get(1);
// Get first 3 loyalty cards and map them with program
const loyaltyCards = models["loyalty.card"]
.getAll()
.slice(0, 3)
.map((element) => ({
id: element.id,
points: element.points,
partner_id: partner.id,
program_id: models["loyalty.program"].get(element.id),
}));
const component = await mountWithCleanup(PartnerLine, {
props: {
partner,
close: () => {},
isSelected: false,
isBalanceDisplayed: true,
onClickEdit: () => {},
onClickUnselect: () => {},
onClickPartner: () => {},
onClickOrders: () => {},
},
env: {
...store.env,
utils: {
formatCurrency: (val) => `$${val.toFixed(2)}`,
},
},
});
const results = loyaltyCards.map((card) => component._getLoyaltyPointsRepr(card));
expect(results[0]).toBe("10.00 Points");
expect(results[1]).toBe("E-Wallet Program: $25.00");
expect(results[2]).toMatch("15.00 Gift Card Points");
});

View file

@ -0,0 +1,52 @@
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";
const { DateTime } = luxon;
export class LoyaltyCard extends models.ServerModel {
_name = "loyalty.card";
_load_pos_data_fields() {
return ["partner_id", "code", "points", "program_id", "expiration_date", "write_date"];
}
_records = [
{
id: 1,
code: "CARD001",
points: 10,
partner_id: 1,
program_id: 1,
expiration_date: DateTime.now().plus({ days: 1 }).toISODate(),
write_date: DateTime.now().minus({ days: 1 }).toFormat("yyyy-MM-dd HH:mm:ss"),
},
{
id: 2,
code: "CARD002",
points: 25,
partner_id: 1,
program_id: 2,
expiration_date: DateTime.now().minus({ days: 1 }).toISODate(),
write_date: DateTime.now().minus({ days: 2 }).toFormat("yyyy-MM-dd HH:mm:ss"),
},
{
id: 3,
code: "CARD003",
points: 15,
partner_id: 3,
program_id: 3,
write_date: DateTime.now().toFormat("yyyy-MM-dd HH:mm:ss"),
},
{
id: 4,
code: "CARD004",
points: 3,
partner_id: 1,
program_id: 7,
write_date: DateTime.now().minus({ days: 2 }).toFormat("yyyy-MM-dd HH:mm:ss"),
},
];
}
patch(hootPosModels, [...hootPosModels, LoyaltyCard]);

View file

@ -0,0 +1,178 @@
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";
const { DateTime } = luxon;
export class LoyaltyProgram extends models.ServerModel {
_name = "loyalty.program";
_load_pos_data_fields() {
return [
"name",
"trigger",
"applies_on",
"program_type",
"pricelist_ids",
"date_from",
"date_to",
"limit_usage",
"max_usage",
"is_nominative",
"portal_visible",
"portal_point_name",
"trigger_product_ids",
"rule_ids",
"reward_ids",
];
}
_records = [
{
id: 1,
name: "Loyalty Program",
trigger: "auto",
applies_on: "both",
program_type: "loyalty",
pricelist_ids: [1],
date_from: false,
date_to: false,
limit_usage: false,
max_usage: 0,
is_nominative: false,
portal_visible: true,
portal_point_name: "Points",
trigger_product_ids: [],
rule_ids: [1],
reward_ids: [],
},
{
id: 2,
name: "E-Wallet Program",
trigger: "auto",
applies_on: "future",
program_type: "ewallet",
pricelist_ids: [],
date_from: false,
date_to: false,
limit_usage: false,
max_usage: 0,
is_nominative: false,
portal_visible: true,
portal_point_name: "E-Wallet Points",
trigger_product_ids: [],
rule_ids: [],
reward_ids: [],
},
{
id: 3,
name: "Gift Card Program",
trigger: "auto",
applies_on: "future",
program_type: "gift_card",
pricelist_ids: [],
date_from: false,
date_to: false,
limit_usage: false,
max_usage: 0,
is_nominative: false,
portal_visible: true,
portal_point_name: "Gift Card Points",
trigger_product_ids: [],
rule_ids: [1],
reward_ids: [],
},
{
id: 4,
name: "E-Wallet Program 2",
trigger: "auto",
applies_on: "future",
program_type: "ewallet",
pricelist_ids: [],
date_from: false,
date_to: false,
limit_usage: false,
max_usage: 0,
is_nominative: false,
portal_visible: true,
portal_point_name: "E-Wallet Points 2",
trigger_product_ids: [],
rule_ids: [],
reward_ids: [],
},
{
id: 5,
name: "Nominative Gift Card Program",
trigger: "auto",
applies_on: "future",
program_type: "gift_card",
pricelist_ids: [],
date_from: false,
date_to: false,
limit_usage: false,
max_usage: 0,
is_nominative: true,
portal_visible: true,
portal_point_name: "Nominative Gift Card Points",
trigger_product_ids: [],
rule_ids: [1],
reward_ids: [],
},
{
id: 6,
name: "E-Wallet Program 2",
trigger: "auto",
applies_on: "future",
program_type: "ewallet",
pricelist_ids: [],
date_from: DateTime.now().minus({ days: 10 }).toISODate(),
date_to: DateTime.now().minus({ days: 1 }).toISODate(),
limit_usage: false,
max_usage: 0,
is_nominative: false,
portal_visible: true,
portal_point_name: "E-Wallet Points",
trigger_product_ids: [],
rule_ids: [],
reward_ids: [],
},
{
id: 7,
name: "Loyalty Program Future",
trigger: "auto",
applies_on: "future",
program_type: "loyalty",
pricelist_ids: [1],
date_from: false,
date_to: false,
limit_usage: false,
max_usage: 0,
is_nominative: true,
portal_visible: true,
portal_point_name: "Points",
trigger_product_ids: [],
rule_ids: [4],
reward_ids: [3],
},
{
id: 8,
name: "100% Cheapest Discount Program",
trigger: "auto",
applies_on: "current",
program_type: "promotion",
pricelist_ids: [1],
date_from: false,
date_to: false,
limit_usage: false,
max_usage: 0,
is_nominative: false,
portal_visible: true,
portal_point_name: "Points",
trigger_product_ids: [],
rule_ids: [5],
reward_ids: [4],
},
];
}
patch(hootPosModels, [...hootPosModels, LoyaltyProgram]);

View file

@ -0,0 +1,124 @@
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 LoyaltyReward extends models.ServerModel {
_name = "loyalty.reward";
_load_pos_data_fields() {
return [
"description",
"program_id",
"reward_type",
"required_points",
"clear_wallet",
"currency_id",
"discount",
"discount_mode",
"discount_applicability",
"all_discount_product_ids",
"is_global_discount",
"discount_max_amount",
"discount_line_product_id",
"reward_product_id",
"multi_product",
"reward_product_ids",
"reward_product_qty",
"reward_product_uom_id",
"reward_product_domain",
];
}
_records = [
{
id: 1,
description: "10% Discount",
program_id: 1,
reward_type: "discount",
required_points: 10,
clear_wallet: false,
currency_id: 1,
discount: 10,
discount_mode: "percent",
discount_applicability: "order",
all_discount_product_ids: [],
is_global_discount: true,
discount_max_amount: 0,
discount_line_product_id: false,
reward_product_id: false,
multi_product: false,
reward_product_ids: [5],
reward_product_qty: 1,
reward_product_uom_id: false,
reward_product_domain: "[]",
},
{
id: 2,
description: "20% Discount",
program_id: 2,
reward_type: "product",
required_points: 10,
clear_wallet: false,
currency_id: 1,
discount: 0,
discount_mode: "percent",
discount_applicability: "order",
all_discount_product_ids: [],
is_global_discount: true,
discount_max_amount: 0,
discount_line_product_id: false,
reward_product_id: false,
multi_product: false,
reward_product_ids: [5],
reward_product_qty: 1,
reward_product_uom_id: false,
reward_product_domain: "[]",
},
{
id: 3,
description: "Free Product - Whiteboard Pen",
program_id: 7,
reward_type: "product",
required_points: 1,
clear_wallet: false,
currency_id: 1,
discount: 0,
discount_mode: "percent",
discount_applicability: "order",
all_discount_product_ids: [],
is_global_discount: true,
discount_max_amount: 0,
discount_line_product_id: 18,
reward_product_id: 10,
multi_product: false,
reward_product_ids: [10],
reward_product_qty: 1,
reward_product_uom_id: false,
reward_product_domain: "[]",
},
{
id: 4,
description: "100% Cheapest Discount",
program_id: 8,
reward_type: "discount",
required_points: 1,
clear_wallet: false,
currency_id: 1,
discount: 100,
discount_mode: "percent",
discount_applicability: "cheapest",
all_discount_product_ids: [],
is_global_discount: false,
discount_max_amount: 0,
discount_line_product_id: 5,
reward_product_id: false,
multi_product: false,
reward_product_ids: [5],
reward_product_qty: 1,
reward_product_uom_id: false,
reward_product_domain: "[]",
},
];
}
patch(hootPosModels, [...hootPosModels, LoyaltyReward]);

View file

@ -0,0 +1,100 @@
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 LoyaltyRule extends models.ServerModel {
_name = "loyalty.rule";
_load_pos_data_fields() {
return [
"program_id",
"valid_product_ids",
"any_product",
"currency_id",
"reward_point_amount",
"reward_point_split",
"reward_point_mode",
"minimum_qty",
"minimum_amount",
"minimum_amount_tax_mode",
"mode",
"code",
];
}
_records = [
{
id: 1,
program_id: 1,
valid_product_ids: [5],
any_product: true,
currency_id: 1,
reward_point_amount: 1,
reward_point_split: true,
reward_point_mode: "order",
minimum_qty: 0,
minimum_amount: 0,
minimum_amount_tax_mode: "incl",
mode: "auto",
code: false,
},
{
id: 2,
program_id: 2,
valid_product_ids: [5],
any_product: true,
currency_id: 1,
reward_point_amount: 1,
reward_point_split: true,
reward_point_mode: "order",
minimum_qty: 3,
minimum_amount: 40,
minimum_amount_tax_mode: "excl",
mode: "auto",
code: false,
},
{
id: 3,
program_id: 6,
valid_product_ids: [5],
any_product: true,
currency_id: 1,
reward_point_amount: 1,
reward_point_split: true,
reward_point_mode: "order",
minimum_qty: 3,
minimum_amount: 40,
minimum_amount_tax_mode: "excl",
mode: "with_code",
code: "EXPIRED",
},
{
id: 4,
program_id: 7,
any_product: true,
currency_id: 1,
reward_point_amount: 1,
reward_point_split: false,
reward_point_mode: "unit",
minimum_qty: 1,
minimum_amount: 0,
minimum_amount_tax_mode: "incl",
mode: "auto",
},
{
id: 5,
program_id: 8,
any_product: true,
currency_id: 1,
reward_point_amount: 1,
reward_point_split: false,
reward_point_mode: "unit",
minimum_qty: 1,
minimum_amount: 0,
minimum_amount_tax_mode: "incl",
mode: "auto",
},
];
}
patch(hootPosModels, [...hootPosModels, LoyaltyRule]);

View file

@ -0,0 +1,110 @@
import { patch } from "@web/core/utils/patch";
import { PosOrder } from "@point_of_sale/../tests/unit/data/pos_order.data";
import { _t } from "@web/core/l10n/translation";
patch(PosOrder.prototype, {
validate_coupon_programs(self, point_changes) {
const couponIdsFromPos = new Set(Object.keys(point_changes).map((id) => parseInt(id)));
const coupons = this.env["loyalty.card"]
.browse([...couponIdsFromPos])
.filter((c) => c && c.program_id);
const couponDifference = new Set(
[...couponIdsFromPos].filter((id) => !coupons.find((c) => c.id === id))
);
if (couponDifference.size > 0) {
return {
successful: false,
payload: {
message: _t(
"Some coupons are invalid. The applied coupons have been updated. Please check the order."
),
removed_coupons: [...couponDifference],
},
};
}
for (const coupon of coupons) {
const needed = -point_changes[coupon.id];
if (parseFloat(coupon.points.toFixed(2)) < parseFloat(needed.toFixed(2))) {
return {
successful: false,
payload: {
message: _t("There are not enough points for the coupon: %s.", coupon.code),
updated_points: Object.fromEntries(coupons.map((c) => [c.id, c.points])),
},
};
}
}
return {
successful: true,
payload: {},
};
},
confirm_coupon_programs(self, coupon_data) {
const couponNewIdMap = {};
for (const k of Object.keys(coupon_data)) {
const id = parseInt(k);
if (id > 0) {
couponNewIdMap[id] = id;
}
}
const couponsToCreate = Object.fromEntries(
Object.entries(coupon_data).filter(([k]) => parseInt(k) < 0)
);
const couponCreateVals = Object.values(couponsToCreate).map((p) => ({
program_id: p.program_id,
partner_id: p.partner_id || false,
code: p.code || p.barcode || `CODE${Math.floor(Math.random() * 10000)}`,
points: p.points || 0,
}));
const newCouponIds = this.env["loyalty.card"].create(couponCreateVals);
const newCoupons = this.env["loyalty.card"].browse(newCouponIds);
for (let i = 0; i < Object.keys(couponsToCreate).length; i++) {
const oldId = parseInt(Object.keys(couponsToCreate)[i], 10);
const newCoupon = newCouponIds[i];
couponNewIdMap[oldId] = newCoupon.id;
}
const allCoupons = this.env["loyalty.card"].browse(Object.keys(couponNewIdMap).map(Number));
for (const coupon of allCoupons) {
const oldId = couponNewIdMap[coupon.id];
if (oldId && coupon_data[oldId]) {
coupon.points += coupon_data[oldId].points;
}
}
return {
coupon_updates: allCoupons.map((coupon) => ({
old_id: couponNewIdMap[coupon.id],
id: coupon.id,
points: coupon.points,
code: coupon.code,
program_id: coupon.program_id,
partner_id: coupon.partner_id,
})),
program_updates: [...new Set(allCoupons.map((c) => c.program_id))].map((program) => ({
program_id: program,
usages: this.env["loyalty.program"].browse(program)?.[0]?.total_order_count,
})),
new_coupon_info: newCoupons.map((c) => ({
program_name: this.env["loyalty.program"].browse(c.program_id)?.[0]?.name || "",
expiration_date: c.expiration_date || false,
code: c.code,
})),
coupon_report: {},
};
},
add_loyalty_history_lines() {
return true;
},
});

View file

@ -0,0 +1,15 @@
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(),
"is_reward_line",
"reward_id",
"coupon_id",
"reward_identifier_code",
"points_cost",
];
},
});

View file

@ -0,0 +1,14 @@
import { patch } from "@web/core/utils/patch";
import { PosSession } from "@point_of_sale/../tests/unit/data/pos_session.data";
patch(PosSession.prototype, {
_load_pos_data_models() {
return [
...super._load_pos_data_models(),
"loyalty.card",
"loyalty.program",
"loyalty.reward",
"loyalty.rule",
];
},
});

View file

@ -0,0 +1,8 @@
import { patch } from "@web/core/utils/patch";
import { ProductProduct } from "@point_of_sale/../tests/unit/data/product_product.data";
patch(ProductProduct.prototype, {
_load_pos_data_fields() {
return [...super._load_pos_data_fields(), "all_product_tag_ids"];
},
});

View file

@ -0,0 +1,359 @@
import { test, describe, expect } from "@odoo/hoot";
import { tick } from "@odoo/hoot-mock";
import { setupPosEnv, getFilledOrder } from "@point_of_sale/../tests/unit/utils";
import { definePosModels } from "@point_of_sale/../tests/unit/data/generate_model_definitions";
import { addProductLineToOrder } from "@pos_loyalty/../tests/unit/utils";
definePosModels();
const { DateTime } = luxon;
describe("pos.order - loyalty", () => {
test("_getIgnoredProductIdsTotalDiscount", async () => {
const store = await setupPosEnv();
const order = store.addNewOrder();
const ignoredProductIds = order._getIgnoredProductIdsTotalDiscount();
expect(ignoredProductIds.length).toBeGreaterThan(0);
});
test("getOrderlines, _get_reward_lines and _get_regular_order_lines", async () => {
const store = await setupPosEnv();
const order = await getFilledOrder(store);
const [line1, line2] = order.getOrderlines();
line1.update({ is_reward_line: true });
line2.update({ is_reward_line: false, refunded_orderline_id: 123 });
// Verify getOrderlines method
const orderedLines = order.getOrderlines();
expect(orderedLines[0]).toBe(line2);
expect(orderedLines[1]).toBe(line1);
expect(orderedLines[0].is_reward_line).toBe(false);
expect(orderedLines[1].is_reward_line).toBe(true);
expect(order.getLastOrderline()).toBe(line2);
// Verify _get_reward_lines method
const rewardLines = order._get_reward_lines();
expect(rewardLines).toEqual([line1]);
expect(rewardLines[0].is_reward_line).toBe(true);
// Verify _get_regular_order_lines
const regularLine = await addProductLineToOrder(store, order);
expect(order.getOrderlines().length).toBe(3);
const regularLines = order._get_regular_order_lines();
expect(regularLines.length).toBe(2);
expect(regularLines[1].id).toBe(regularLine.id);
});
test("setPricelist", async () => {
const store = await setupPosEnv();
const models = store.models;
const order = store.addNewOrder();
const pricelist2 = models["product.pricelist"].get(2);
order.uiState.couponPointChanges = {
key1: { program_id: 1, points: 100 },
key2: { program_id: 2, points: 50 },
};
order.setPricelist(pricelist2);
const remainingKeys = Object.keys(order.uiState.couponPointChanges);
expect(remainingKeys.length).toBe(1);
expect(order.uiState.couponPointChanges[remainingKeys[0]].program_id).toBe(2);
});
test("_resetPrograms", async () => {
const store = await setupPosEnv();
const order = store.addNewOrder();
order.uiState.disabledRewards = new Set(["reward1"]);
order.uiState.codeActivatedProgramRules = ["rule1"];
order.uiState.couponPointChanges = { key1: { points: 100 } };
await addProductLineToOrder(store, order, {
is_reward_line: true,
});
order._resetPrograms();
expect(order.uiState.disabledRewards.size).toBeEmpty();
expect(order.uiState.codeActivatedProgramRules.length).toBeEmpty();
expect(order.uiState.couponPointChanges).toMatchObject({});
});
test("_programIsApplicable", async () => {
const store = await setupPosEnv();
const models = store.models;
const order = store.addNewOrder();
// Get loyalty program #1 - type = "ewallet"
const program = models["loyalty.program"].get(1);
expect(order._programIsApplicable(program)).toBe(true);
program.partner_id = false;
program.is_nominative = true;
expect(order._programIsApplicable(program)).toBe(false);
});
test("_getRealCouponPoints", async () => {
const store = await setupPosEnv();
const models = store.models;
const order = store.addNewOrder();
// Get loyalty card #1 which program_id = 1 (loyalty)
const card = models["loyalty.card"].get(1);
order.uiState.couponPointChanges = {
1: {
coupon_id: 1,
program_id: 1,
points: 25,
},
};
await addProductLineToOrder(store, order, {
is_reward_line: true,
coupon_id: card,
points_cost: 5,
});
expect(order._getRealCouponPoints(card.id)).toBe(30);
});
test("processGiftCard", async () => {
const store = await setupPosEnv();
const models = store.models;
const order = store.addNewOrder();
// Get loyalty program #3 - type = "gift_card"
const giftProgram = models["loyalty.program"].get(3);
const line = await addProductLineToOrder(store, order, {
price_unit: 10,
eWalletGiftCardProgram: giftProgram,
});
order.selected_orderline = line;
const expirationDate = DateTime.now().plus({ days: 1 }).toISODate();
order.processGiftCard("GIFT9999", 100, expirationDate);
const couponChanges = Object.values(order.uiState.couponPointChanges);
expect(couponChanges.length).toBe(1);
expect(couponChanges[0].code).toBe("GIFT9999");
expect(couponChanges[0].points).toBe(100);
expect(couponChanges[0].expiration_date).toBe(expirationDate);
expect(couponChanges[0].manual).toBe(true);
});
test("_getDiscountableOnOrder", async () => {
const store = await setupPosEnv();
const models = store.models;
const order = store.addNewOrder();
await addProductLineToOrder(store, order, {
qty: 2,
});
await addProductLineToOrder(store, order, {
price_unit: 5,
});
// Get loyalty reward #1 - type = "discount"
const reward = models["loyalty.reward"].get(1);
const result = order._getDiscountableOnOrder(reward);
expect(result.discountable).toBe(25);
});
test("_computeNItems", async () => {
const store = await setupPosEnv();
const models = store.models;
const order = await getFilledOrder(store);
// Get loyalty rule #1 - which program_id = 1 (loyalty)
const rule = models["loyalty.rule"].get(1);
expect(order.getOrderlines().length).toBe(2);
expect(order._computeNItems(rule)).toBe(5);
});
test("_canGenerateRewards", async () => {
const store = await setupPosEnv();
const models = store.models;
const order = store.addNewOrder();
await addProductLineToOrder(store, order, {
qty: 5,
});
// Get loyalty program #2 - type = "ewallet"
const program = models["loyalty.program"].get(2);
expect(order._canGenerateRewards(program, 50, 50)).toBe(true);
expect(order._canGenerateRewards(program, 30, 30)).toBe(false);
});
test("isProgramsResettable", async () => {
const store = await setupPosEnv();
const order = store.addNewOrder();
expect(order.isProgramsResettable()).toBe(false);
order.uiState.disabledRewards = [...new Set(["RULE1"])];
expect(order.isProgramsResettable()).toBe(true);
order.uiState.disabledRewards = new Set();
order.uiState.codeActivatedProgramRules.push("RULE2");
expect(order.isProgramsResettable()).toBe(true);
order.uiState.codeActivatedProgramRules = [];
order.uiState.couponPointChanges = { key1: { points: 10 } };
expect(order.isProgramsResettable()).toBe(true);
});
test("removeOrderline", async () => {
const store = await setupPosEnv();
const models = store.models;
const order = store.addNewOrder();
// Get loyalty reward #1 - type = "discount"
const reward = models["loyalty.reward"].get(1);
// Get loyalty card #1 - which program_id = 1 (loyalty)
const coupon = models["loyalty.card"].get(1);
const rewardLine = await addProductLineToOrder(store, order, {
is_reward_line: true,
reward_id: reward,
coupon_id: coupon,
reward_identifier_code: "ABC123",
});
const normalLine = await addProductLineToOrder(store, order, {
price_unit: 20,
is_reward_line: false,
});
expect(order.getOrderlines().length).toBe(2);
const result = order.removeOrderline(rewardLine);
expect(result).toBe(true);
expect(order.getOrderlines().length).toBe(1);
const remainingLines = order.getOrderlines();
expect(remainingLines.length).toBe(1);
expect(remainingLines[0].id).toBe(normalLine.id);
expect(remainingLines[0].is_reward_line).toBe(false);
});
test("isSaleDisallowed", async () => {
const store = await setupPosEnv();
const models = store.models;
const order = store.addNewOrder();
// Get loyalty program #3 - type = "gift_card"
const giftProgram = models["loyalty.program"].get(3);
const result = order.isSaleDisallowed({}, { eWalletGiftCardProgram: giftProgram });
expect(result).toBe(false);
});
test("setPartner and getLoyaltyPoints", async () => {
const store = await setupPosEnv();
const models = store.models;
const order = store.addNewOrder();
const partner1 = models["res.partner"].get(1);
const partner2 = models["res.partner"].get(3);
order.setPartner(partner1);
order.uiState.couponPointChanges = {
key1: { program_id: 5, points: 100 },
key2: { program_id: 2, points: 50 },
};
order.setPartner(partner2);
const remainingKeys = Object.keys(order.uiState.couponPointChanges);
expect(remainingKeys.length).toBe(1);
expect(order.uiState.couponPointChanges[remainingKeys[0]].program_id).toBe(2);
// Verify getLoyaltyPoints method
order.uiState.couponPointChanges = {
1: {
coupon_id: 1,
program_id: 1,
points: 25,
},
};
const loyaltyStats = order.getLoyaltyPoints();
expect(loyaltyStats.length).toBe(1);
expect(loyaltyStats[0].points.name).toBe("Points");
expect(loyaltyStats[0].points.won).toBe(25);
expect(loyaltyStats[0].points.balance).toBe(10);
});
test("getLoyaltyPoints adapts to qty decreasing", async () => {
const store = await setupPosEnv();
const models = store.models;
const order = store.addNewOrder();
const partner1 = models["res.partner"].get(1);
order.setPartner(partner1);
await store.orderUpdateLoyaltyPrograms();
const reward = models["loyalty.reward"].get(3);
const loyalty_card = models["loyalty.card"].get(4);
const line = await addProductLineToOrder(store, order, {
productId: 10,
templateId: 10,
qty: 3,
});
await store.orderUpdateLoyaltyPrograms();
order._applyReward(reward, loyalty_card.id);
const loyaltyStats = order.getLoyaltyPoints();
expect(loyaltyStats[0].points.won).toBe(0);
expect(loyaltyStats[0].points.spent).toBe(3);
expect(loyaltyStats[0].points.total).toBe(0);
expect(loyaltyStats[0].points.balance).toBe(3);
line.setQuantity(2);
await store.updateRewards();
await tick();
const loyaltyStats2 = order.getLoyaltyPoints();
expect(loyaltyStats2[0].points.won).toBe(0);
expect(loyaltyStats2[0].points.spent).toBe(2);
expect(loyaltyStats2[0].points.total).toBe(1);
expect(loyaltyStats2[0].points.balance).toBe(3);
});
test("reward amount tax included cheapest product", async () => {
const store = await setupPosEnv();
const order = store.addNewOrder();
const line = await addProductLineToOrder(store, order, {
productId: 24,
templateId: 24,
qty: 1,
});
expect(line.prices.total_included).toBe(10);
expect(line.prices.total_excluded).toBe(8.7);
await store.updateRewards();
await tick();
expect(order.getOrderlines().length).toBe(2);
const rewardLine = order._get_reward_lines()[0];
expect(rewardLine.prices.total_included).toBe(-10);
});
});

View file

@ -0,0 +1,59 @@
import { test, describe, 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";
import { addProductLineToOrder } from "@pos_loyalty/../tests/unit/utils";
definePosModels();
describe("pos.order.line - loyalty", () => {
test("getEWalletGiftCardProgramType", async () => {
const store = await setupPosEnv();
const models = store.models;
const order = store.addNewOrder();
// Get loyalty program #2 - type = "ewallet"
const program = models["loyalty.program"].get(2);
const line = await addProductLineToOrder(store, order, {
_e_wallet_program_id: program,
});
expect(line.getEWalletGiftCardProgramType()).toBe(`${program.program_type}`);
});
test("ignoreLoyaltyPoints", async () => {
const store = await setupPosEnv();
const models = store.models;
const order = store.addNewOrder();
// Get loyalty program #2 - type = "ewallet"
const programA = models["loyalty.program"].get(2);
// Get loyalty program #4 - type = "ewallet"
const programB = models["loyalty.program"].get(4);
const line = await addProductLineToOrder(store, order);
line.update({ _e_wallet_program_id: programB });
expect(line.ignoreLoyaltyPoints({ program: programA })).toBe(true);
});
test("getGiftCardOrEWalletBalance", async () => {
const store = await setupPosEnv();
const models = store.models;
// Get loyalty card #3 which program_id = 3 (gift_card)
const card = models["loyalty.card"].get(3);
const order = store.addNewOrder();
const line = await addProductLineToOrder(store, order, {
is_reward_line: true,
coupon_id: card,
});
const balance = line.getGiftCardOrEWalletBalance();
expect(balance).toBeOfType("string");
expect(balance).toMatch(new RegExp(`${card.points}`));
});
});

View file

@ -0,0 +1,44 @@
import { test, expect } from "@odoo/hoot";
import { mountWithCleanup } from "@web/../tests/web_test_helpers";
import { definePosModels } from "@point_of_sale/../tests/unit/data/generate_model_definitions";
import { setupPosEnv } from "@point_of_sale/../tests/unit/utils";
import { addProductLineToOrder } from "@pos_loyalty/../tests/unit/utils";
import { TicketScreen } from "@point_of_sale/app/screens/ticket_screen/ticket_screen";
definePosModels();
test("TicketScreen.setOrder keeps reward line and triggers pos.updateRewards", async () => {
const store = await setupPosEnv();
const models = store.models;
const order = store.addNewOrder();
const reward = models["loyalty.reward"].get(1);
const coupon = models["loyalty.card"].get(1);
await addProductLineToOrder(store, order, {
is_reward_line: true,
reward_id: reward,
coupon_id: coupon,
reward_identifier_code: "LOAD-ORDER-REWARD",
points_cost: 10,
});
order.uiState.couponPointChanges = {};
store.selectedOrderUuid = null;
let updateRewardsCalled = false;
const originalUpdateRewards = store.updateRewards.bind(store);
store.updateRewards = () => {
updateRewardsCalled = true;
return originalUpdateRewards();
};
const comp = await mountWithCleanup(TicketScreen, {});
await comp.setOrder(order);
expect(updateRewardsCalled).toBe(true);
const currentOrder = store.getOrder();
expect(currentOrder).toBe(order);
const rewardLines = currentOrder.lines.filter((l) => l.is_reward_line);
expect(rewardLines.length).toBe(1);
expect(rewardLines[0].reward_id.id).toBe(reward.id);
expect(rewardLines[0].coupon_id.id).toBe(coupon.id);
});

View file

@ -0,0 +1,68 @@
import { test, describe, 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";
import { addProductLineToOrder } from "@pos_loyalty/../tests/unit/utils";
import { onRpc } from "@web/../tests/web_test_helpers";
definePosModels();
describe("PosStore - loyalty essentials", () => {
test("updatePrograms", async () => {
const store = await setupPosEnv();
const models = store.models;
const order = store.addNewOrder();
const partner = models["res.partner"].get(1);
// Get loyalty program #5 with program_type = "gift_card" and is_nominative = true
const program = models["loyalty.program"].get(5);
models["loyalty.program"].getAll = () => [program];
order.setPartner(partner);
order._programIsApplicable = () => true;
order._code_activated_coupon_ids = [];
order.uiState.couponPointChanges = {};
order.pricelist_id = { id: 1 };
const line = await addProductLineToOrder(store, order, {
gift_code: "XYZ123",
});
order.pointsForPrograms = () => ({
[program.id]: [{ points: 10 }],
});
await store.updatePrograms();
const changes = order.uiState.couponPointChanges;
const changeList = Object.values(changes);
expect(changeList).toHaveLength(1);
expect(changeList[0].program_id).toBe(program.id);
expect(changeList[0].points).toBe(10);
expect(changeList[0].code).toBe("XYZ123");
expect(changeList[0].product_id).toBe(line.product_id.id);
});
test("activateCode", async () => {
onRpc("loyalty.card", "get_loyalty_card_partner_by_code", () => false);
const store = await setupPosEnv();
store.addNewOrder();
const result = await store.activateCode("EXPIRED");
expect(result).toBe(true);
});
test("fetchLoyaltyCard", async () => {
const store = await setupPosEnv();
const models = store.models;
// Get loyalty program #2 with program_type = "ewallet"
const program = models["loyalty.program"].get(2);
const partner = models["res.partner"].get(1);
const card = await store.fetchLoyaltyCard(program.id, partner.id);
expect(card.id).toBe(2);
});
});

View file

@ -0,0 +1,48 @@
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";
import { addProductLineToOrder } from "@pos_loyalty/../tests/unit/utils";
import OrderPaymentValidation from "@point_of_sale/app/utils/order_payment_validation";
definePosModels();
test("validateOrder", async () => {
const store = await setupPosEnv();
const models = store.models;
const order = store.addNewOrder();
const fastPaymentMethod = order.config.fast_payment_method_ids[0];
// Get loyalty program #1 - type = "loyalty"
const loyaltyProgram = models["loyalty.program"].get(1);
// Get loyalty card #1 - linked to Partner #1
const card = models["loyalty.card"].get(1);
// Get loyalty reward #1 - type = "discount"
const reward = models["loyalty.reward"].get(1);
order.uiState.couponPointChanges = {
[card.id]: { coupon_id: card.id, program_id: loyaltyProgram.id, points: 100 },
"-1": { coupon_id: -1, program_id: loyaltyProgram.id, points: 30, partner_id: 1 },
};
await addProductLineToOrder(store, order, {
coupon_id: card,
is_reward_line: true,
reward_id: reward,
points_cost: 60,
});
const validation = new OrderPaymentValidation({
pos: store,
orderUuid: store.getOrder().uuid,
fastPaymentMethod: fastPaymentMethod,
});
validation.isOrderValid = async () => true;
await validation.validateOrder();
expect(card.points).toBe(50);
expect(loyaltyProgram.total_order_count).toBe(0);
expect(order.new_coupon_info[0].code).toMatch(/^[A-Za-z0-9]+$/);
expect(order.new_coupon_info[0].program_name).toBe(loyaltyProgram.name);
});

View file

@ -0,0 +1,20 @@
export const addProductLineToOrder = async (
store,
order,
{ templateId = 1, productId = 1, qty = 1, price_unit = 10, ...extraFields } = {}
) => {
const template = store.models["product.template"].get(templateId);
const product = store.models["product.product"].get(productId);
const lineData = {
product_tmpl_id: template,
product_id: product,
qty,
price_unit,
...extraFields,
};
const line = await store.addLineToOrder(lineData, order);
return line;
};