From 23aa895cf79d2d8c33c69504f0fc33c1833ba0cb Mon Sep 17 00:00:00 2001 From: "Thomas Lefebvre (thle)" Date: Tue, 17 Oct 2023 12:55:44 +0200 Subject: [PATCH] [FIX] website_sale_loyalty: manage multi rewards with "Discount code" Steps to reproduce: ------------------- - create a promotion program with the type "Discount code"; - add a rule to trigger the promotion with the code "12345"; - add two rewards; - go to ecommerce and create a cart; - apply the promo code. Issue: ------ It is not possible to claim a reward. Cause: ------ When we apply the code "12345", we call the `pricelist` method, which will try to apply the code. If it's not a coupon and it's not nominative, we create a loyalty card (a coupon) with a default code (for example: "044d-3364-42d0"). This previously created loyalty card is linked to the current sale order, which is only fair since we don't want to be able to apply it a second time. The two rewards are linked to the same coupon and therefore have the same code (which is right because we can apply only one of these rewards). This problem doesn't occur with a single reward, because when only one reward is detected, we automatically apply it when we call the `pricelist` method. In the case of two rewards, it is possible to select the reward. This will trigger the `claim_reward` method. In this method, if we use a coupon with a code (which is the case here, "044d-3364-42d0"), we call the `pricelist` method with this code. This will trigger an error, as the code is already in use with the loyalty card linked to the sale order. Solution: --------- When claiming a reward generated by a program of the `promo_code` type, i.e. in the case of more than a rewards, don't call the `pricelist` method (which triggers an error due to the code) but `_apply_reward`. This will apply the reward to the sale order. A redirect will be use which will remove all "claimable and showable rewards" from this program. If we want to re-trigger it via code "12345", this will no longer be possible. Note: ----- Modification of the view to distinguish between coupons and "Discount Code" programs. The current display suggests that rewards are coupons (with the same code) that we use, whereas they are rewards that we can claim. Furthermore, there's no description of the rewards. opw-3520137 closes odoo/odoo#144349 X-original-commit: d56b46ccb6c736856af3dd62df8c2c8b99a8eaa5 Signed-off-by: Thomas Lefebvre (thle) --- .../website_sale_loyalty/controllers/main.py | 2 +- .../tests/tours/test_apply_discount_code.js | 61 +++++++++++++++++++ .../tests/test_shop_sale_coupon.py | 38 +++++++++++- .../views/website_sale_templates.xml | 7 ++- 4 files changed, 104 insertions(+), 4 deletions(-) create mode 100644 addons/website_sale_loyalty/static/tests/tours/test_apply_discount_code.js diff --git a/addons/website_sale_loyalty/controllers/main.py b/addons/website_sale_loyalty/controllers/main.py index 514adc86fce..6f83d49660e 100644 --- a/addons/website_sale_loyalty/controllers/main.py +++ b/addons/website_sale_loyalty/controllers/main.py @@ -91,7 +91,7 @@ class WebsiteSale(main.WebsiteSale): if reward_sudo in rewards: coupon = coupon_ if code == coupon.code and ( - program_sudo.trigger == 'with_code' + (program_sudo.trigger == 'with_code' and program_sudo.program_type != 'promo_code') or (program_sudo.trigger == 'auto' and program_sudo.applies_on == 'future') ): return self.pricelist(code) diff --git a/addons/website_sale_loyalty/static/tests/tours/test_apply_discount_code.js b/addons/website_sale_loyalty/static/tests/tours/test_apply_discount_code.js new file mode 100644 index 00000000000..4ea2f584f67 --- /dev/null +++ b/addons/website_sale_loyalty/static/tests/tours/test_apply_discount_code.js @@ -0,0 +1,61 @@ +/** @odoo-module **/ + +import { registry } from "@web/core/registry"; +import tourUtils from '@website_sale/js/tours/tour_utils'; + +registry.category("web_tour.tours").add('apply_discount_code_program_multi_rewards', { + test: true, + url: '/shop?search=Super%20Chair', + steps: () => [ + { + content: 'select Super Chair', + extra_trigger: '.oe_search_found', + trigger: '.oe_product_cart a:contains("Super Chair")', + }, + { + content: 'Add Super Chair into cart', + trigger: 'a:contains(Add to cart)', + }, + tourUtils.goToCart(), + { + content: 'insert discount code', + extra_trigger: 'form[name="coupon_code"]', + trigger: 'form[name="coupon_code"] input[name="promo"]', + run: 'text 12345' + }, + { + content: 'validate the promo code', + trigger: 'form[name="coupon_code"] .a-submit', + }, + { + content: 'check reward', + trigger: '.alert:contains("10% on Super Chair")', + isCheck: true, + }, + { + content: 'claim reward', + trigger: '.alert:contains("10% on Super Chair") .btn:contains("Claim")', + }, + { + content: 'check claimed reward', + trigger: 'div>strong:contains("10% on Super Chair")', + isCheck: true, + }, + // Try to reapply the same promo code + { + content: 'insert discount code', + extra_trigger: 'form[name="coupon_code"]', + trigger: 'form[name="coupon_code"] input[name="promo"]', + run: 'text 12345' + }, + { + content: 'validate the promo code', + trigger: 'form[name="coupon_code"] .a-submit', + }, + { + content: 'check refused message', + trigger: '.alert-danger:contains("This promo code is already applied")', + isCheck: true, + }, + ], +}); diff --git a/addons/website_sale_loyalty/tests/test_shop_sale_coupon.py b/addons/website_sale_loyalty/tests/test_shop_sale_coupon.py index 50f27cfcb40..cce84d8c4fc 100644 --- a/addons/website_sale_loyalty/tests/test_shop_sale_coupon.py +++ b/addons/website_sale_loyalty/tests/test_shop_sale_coupon.py @@ -170,7 +170,7 @@ class TestUi(TestSaleProductAttributeValueCommon, HttpCase): @tagged('post_install', '-at_install') -class TestWebsiteSaleCoupon(TransactionCase): +class TestWebsiteSaleCoupon(HttpCase): @classmethod def setUpClass(cls): @@ -259,3 +259,39 @@ class TestWebsiteSaleCoupon(TransactionCase): order._gc_abandoned_coupons() self.assertEqual(len(order.applied_coupon_ids), 0, "The coupon should've been removed from the order as more than 4 days") + + def test_02_apply_discount_code_program_multi_rewards(self): + """ + Check the triggering of a promotion program based on a promo code with multiple rewards + """ + self.env['loyalty.program'].search([]).write({'active': False}) + chair = self.env['product.product'].create({ + 'name': 'Super Chair', 'list_price': 1000, 'website_published': True + }) + self.discount_code_program_multi_rewards = self.env['loyalty.program'].create({ + 'name': 'Discount code program', + 'program_type': 'promo_code', + 'applies_on': 'current', + 'trigger': 'with_code', + 'rule_ids': [(0, 0, { + 'code': '12345', + 'reward_point_amount': 1, + 'reward_point_mode': 'order', + })], + 'reward_ids': [ + (0, 0, { + 'reward_type': 'discount', + 'discount': 10, + 'discount_applicability': 'specific', + 'required_points': 1, + 'discount_product_ids': chair, + }), + (0, 0, { + 'reward_type': 'discount', + 'discount': 50, + 'discount_applicability': 'order', + 'required_points': 1, + }), + ], + }) + self.start_tour('/', 'apply_discount_code_program_multi_rewards', login='admin') diff --git a/addons/website_sale_loyalty/views/website_sale_templates.xml b/addons/website_sale_loyalty/views/website_sale_templates.xml index 881e49aab64..456927bdcd3 100644 --- a/addons/website_sale_loyalty/views/website_sale_templates.xml +++ b/addons/website_sale_loyalty/views/website_sale_templates.xml @@ -42,7 +42,7 @@
- + - @@ -66,6 +66,9 @@
+ + +
@@ -88,7 +91,7 @@ Pay with eWallet - + Use Claim