From 03145907b8cdc3a69a5a4069ab4dacfa6ec922e4 Mon Sep 17 00:00:00 2001 From: roen-odoo Date: Fri, 9 Jun 2023 12:58:31 +0000 Subject: [PATCH] [FIX] pos_loyalty:reward should not affect point rewarded Current behavior: When creating a loyalty program, with a rules that award points for each dollar spent, the value of the point was inconsistent because it was taking the rewards into account. Steps to reproduce: - Create a loyalty program with a rule that award 0.1 point for each dollar spent, and a reward that gives 1$ per points. - Create a product with a price of 265$. - Open the PoS and create a new order for 1000$. - Select a customer and pay the order.(The customer now have 100 points) - Create a new order with the product created earlier, and apply the reward. - The value of the reward shoudl be 126.5$ (100 points + 26.5 points from the current order) but it is not. opw-3275585 closes odoo/odoo#129963 X-original-commit: 70256e5cf8359a09687acc3e2d4f8792ef4f9801 Signed-off-by: Joseph Caburnay (jcb) Signed-off-by: Robin Engels (roen) --- .../static/src/overrides/models/loyalty.js | 4 +- .../static/tests/tours/PosLoyaltyTour.js | 115 +++++++++++------- addons/pos_loyalty/tests/test_frontend.py | 46 +++++++ 3 files changed, 117 insertions(+), 48 deletions(-) diff --git a/addons/pos_loyalty/static/src/overrides/models/loyalty.js b/addons/pos_loyalty/static/src/overrides/models/loyalty.js index 06b26480e0a..1753bdb60b3 100644 --- a/addons/pos_loyalty/static/src/overrides/models/loyalty.js +++ b/addons/pos_loyalty/static/src/overrides/models/loyalty.js @@ -803,7 +803,9 @@ patch(Order.prototype, "pos_loyalty.Order", { qtyPerProduct[line.reward_product_id || line.get_product().id] = lineQty; } - orderedProductPaid += line.get_price_with_tax(); + if (!line.is_reward_line) { + orderedProductPaid += line.get_price_with_tax(); + } } } if (totalProductQty < rule.minimum_qty) { diff --git a/addons/pos_loyalty/static/tests/tours/PosLoyaltyTour.js b/addons/pos_loyalty/static/tests/tours/PosLoyaltyTour.js index 39e8d37028d..bd8601dcbaf 100644 --- a/addons/pos_loyalty/static/tests/tours/PosLoyaltyTour.js +++ b/addons/pos_loyalty/static/tests/tours/PosLoyaltyTour.js @@ -2,23 +2,24 @@ import { PosLoyalty } from "@pos_loyalty/../tests/tours/PosLoyaltyTourMethods"; import { ProductScreen } from "@point_of_sale/../tests/tours/helpers/ProductScreenTourMethods"; +import { SelectionPopup } from "@point_of_sale/../tests/tours/helpers/SelectionPopupTourMethods"; import { getSteps, startSteps } from "@point_of_sale/../tests/tours/helpers/utils"; import { registry } from "@web/core/registry"; registry .category("web_tour.tours") - .add("PosLoyaltyTour1", { - test: true, - url: "/pos/web", + .add("PosLoyaltyTour1", { + test: true, + url: "/pos/web", steps: () => { // --- PoS Loyalty Tour Basic Part 1 --- // Generate coupons for PosLoyaltyTour2. startSteps(); - + ProductScreen.do.confirmOpeningPopup(); ProductScreen.do.clickHomeCategory(); - + // basic order // just accept the automatically applied promo program // applied programs: @@ -28,7 +29,7 @@ registry PosLoyalty.do.selectRewardLine("on the cheapest product"); PosLoyalty.check.orderTotalIs("13.12"); PosLoyalty.exec.finalizeOrder("Cash", "20"); - + // remove the reward from auto promo program // no applied programs ProductScreen.exec.addOrderline("Whiteboard Pen", "6"); @@ -37,7 +38,7 @@ registry PosLoyalty.exec.removeRewardLine("90% on the cheapest product"); PosLoyalty.check.orderTotalIs("19.2"); PosLoyalty.exec.finalizeOrder("Cash", "20"); - + // order with coupon code from coupon program // applied programs: // - coupon program @@ -50,7 +51,7 @@ registry PosLoyalty.do.enterCode("1234"); PosLoyalty.check.hasRewardLine("Free Product - Desk Organizer", "-15.30"); PosLoyalty.exec.finalizeOrder("Cash", "50"); - + // Use coupon but eventually remove the reward // applied programs: // - on cheapest product @@ -64,7 +65,7 @@ registry PosLoyalty.exec.removeRewardLine("Free Product"); PosLoyalty.check.orderTotalIs("62.27"); PosLoyalty.exec.finalizeOrder("Cash", "90"); - + // specific product discount // applied programs: // - on cheapest product @@ -78,23 +79,23 @@ registry PosLoyalty.check.hasRewardLine("50% on specific products", "-16.66"); // 17.55 - 1.78*0.5 PosLoyalty.check.orderTotalIs("37.78"); PosLoyalty.exec.finalizeOrder("Cash", "50"); - return getSteps(); - } + return getSteps(); + } }); - + registry .category("web_tour.tours") - .add("PosLoyaltyTour2", { - test: true, - url: "/pos/web", + .add("PosLoyaltyTour2", { + test: true, + url: "/pos/web", steps: () => { // --- PoS Loyalty Tour Basic Part 2 --- // Using the coupons generated from PosLoyaltyTour1. startSteps(); - + ProductScreen.do.clickHomeCategory(); - + // Test that global discount and cheapest product discounts can be accumulated. // Applied programs: // - global discount @@ -108,7 +109,7 @@ registry PosLoyalty.check.hasRewardLine("10% on your order", "-1.64"); PosLoyalty.check.orderTotalIs("60.63"); //SUBTOTAL PosLoyalty.exec.finalizeOrder("Cash", "70"); - + // Scanning coupon twice. // Also apply global discount on top of free product to check if the // calculated discount is correct. @@ -137,7 +138,7 @@ registry PosLoyalty.do.enterCode("5678"); PosLoyalty.check.orderTotalIs("60.13"); PosLoyalty.exec.finalizeOrder("Cash", "65"); - + // Specific products discount (with promocode) and free product (1357) // Applied programs: // - discount on specific products @@ -152,7 +153,7 @@ registry PosLoyalty.check.hasRewardLine("50% on specific products", "-10.20"); PosLoyalty.check.orderTotalIs("10.20"); PosLoyalty.exec.finalizeOrder("Cash", "20"); - + // Check reset program // Enter two codes and reset the programs. // The codes should be checked afterwards. They should return to new. @@ -170,23 +171,23 @@ registry PosLoyalty.check.hasRewardLine("90% on the cheapest product", "-2.87"); PosLoyalty.check.orderTotalIs("16.27"); PosLoyalty.exec.finalizeOrder("Cash", "20"); - return getSteps(); - } + return getSteps(); + } }); - + registry .category("web_tour.tours") - .add("PosLoyaltyTour3", { - test: true, - url: "/pos/web", + .add("PosLoyaltyTour3", { + test: true, + url: "/pos/web", steps: () => { // --- PoS Loyalty Tour Basic Part 3 --- - + startSteps(); - + ProductScreen.do.confirmOpeningPopup(); ProductScreen.do.clickHomeCategory(); - + ProductScreen.do.clickDisplayedProduct("Promo Product"); PosLoyalty.check.orderTotalIs("34.50"); ProductScreen.do.clickDisplayedProduct("Product B"); @@ -198,22 +199,22 @@ registry PosLoyalty.check.hasRewardLine("100% on specific products", "21.82"); PosLoyalty.check.hasRewardLine("100% on specific products", "18.18"); PosLoyalty.check.orderTotalIs("49.50"); - - return getSteps(); - } + + return getSteps(); + } }); - + registry .category("web_tour.tours") - .add("PosLoyaltyTour4", { - test: true, - url: "/pos/web", + .add("PosLoyaltyTour4", { + test: true, + url: "/pos/web", steps: () => { startSteps(); - + ProductScreen.do.confirmOpeningPopup(); ProductScreen.do.clickHomeCategory(); - + ProductScreen.exec.addOrderline("Test Product 1", "1"); ProductScreen.exec.addOrderline("Test Product 2", "1"); ProductScreen.do.selectPriceList("Public Pricelist"); @@ -221,24 +222,44 @@ registry PosLoyalty.check.orderTotalIs("0.00"); ProductScreen.do.selectPriceList("Test multi-currency"); PosLoyalty.check.orderTotalIs("0.00"); - return getSteps(); - } + return getSteps(); + } }); registry .category("web_tour.tours") - .add("PosCouponTour5", { - test: true, - url: "/pos/web", + .add("PosCouponTour5", { + test: true, + url: "/pos/web", steps: () => { startSteps(); - + ProductScreen.do.clickHomeCategory(); - + ProductScreen.exec.addOrderline("Test Product 1", "1.00", "100"); PosLoyalty.do.clickDiscountButton(); PosLoyalty.do.clickConfirmButton(); ProductScreen.check.totalAmountIs("92.00"); - return getSteps(); - } + return getSteps(); + } + }); + +//transform the last tour to match the new format +registry + .category("web_tour.tours") + .add("PosLoyaltyTour6", { + test: true, + url: "/pos/web", + steps: () => { + ProductScreen.do.confirmOpeningPopup(); + ProductScreen.do.clickHomeCategory(); + + ProductScreen.do.clickPartnerButton(); + ProductScreen.do.clickCustomer('AAA Partner'); + ProductScreen.do.clickDisplayedProduct('Test Product A'); + PosLoyalty.do.clickRewardButton(); + SelectionPopup.do.clickItem("$ 1 per point on your order"); + ProductScreen.check.totalAmountIs('138.50'); + return getSteps(); + } }); diff --git a/addons/pos_loyalty/tests/test_frontend.py b/addons/pos_loyalty/tests/test_frontend.py index 2d62562afa1..2669061b0fc 100644 --- a/addons/pos_loyalty/tests/test_frontend.py +++ b/addons/pos_loyalty/tests/test_frontend.py @@ -1034,3 +1034,49 @@ class TestUi(TestPointOfSaleHttpCommon): self.main_pos_config.open_ui() self.start_tour('/pos/web?config_id=%d' % self.main_pos_config.id, 'PosLoyaltySpecificDiscountWithFreeProductTour', login='pos_user') + + def test_point_per_money_spent(self): + """Test the point per $ spent feature""" + LoyaltyProgram = self.env['loyalty.program'] + (LoyaltyProgram.search([])).write({'pos_ok': False}) + self.loyalty_program = self.env['loyalty.program'].create({ + 'name': 'Loyalty Program Test', + 'program_type': 'loyalty', + 'trigger': 'auto', + 'applies_on': 'both', + 'pos_ok': True, + 'pos_config_ids': [Command.link(self.main_pos_config.id)], + 'rule_ids': [(0, 0, { + 'reward_point_mode': 'money', + 'reward_point_amount': 0.1, + 'minimum_amount': 1, + })], + 'reward_ids': [(0, 0, { + 'reward_type': 'discount', + 'required_points': 1, + 'discount': 1, + 'discount_mode': 'per_point', + })], + }) + + self.product_a = self.env["product.product"].create({ + "name": "Test Product A", + "type": "product", + "list_price": 265, + "available_in_pos": True, + "taxes_id": False, + }) + + partner_aaa = self.env['res.partner'].create({'name': 'AAA Partner'}) + self.env['loyalty.card'].create({ + 'partner_id': partner_aaa.id, + 'program_id': self.loyalty_program.id, + 'points': 100, + }) + + self.main_pos_config.open_ui() + self.start_tour( + "/pos/web?config_id=%d" % self.main_pos_config.id, + "PosLoyaltyTour6", + login="pos_user", + )