[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) <thle@odoo.com>
This commit is contained in:
Thomas Lefebvre (thle)
2023-12-05 07:37:42 +00:00
parent 75cc7e99be
commit 23aa895cf7
4 changed files with 104 additions and 4 deletions
@@ -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)
@@ -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,
},
],
});
@@ -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')
@@ -42,7 +42,7 @@
<div class="flex-grow-1">
<t t-set="program" t-value="reward.program_id"/>
<t t-set="points" t-value="website_sale_order._get_real_points_for_coupon(coupon)"/>
<t t-if="program.program_type != 'ewallet' and (program.trigger == 'with_code' or (program.trigger == 'auto' and program.applies_on == 'future'))">
<t t-if="program.program_type not in ['ewallet', 'promo_code'] and (program.trigger == 'with_code' or (program.trigger == 'auto' and program.applies_on == 'future'))">
<t t-if="program.program_type == 'gift_card'">
<strong t-esc="reward.description"/>
<strong> - </strong>
@@ -66,6 +66,9 @@
</t>
</div>
</t>
<t t-elif="program.program_type == 'promo_code'">
<strong t-esc="reward.description"/>
</t>
<t t-else="">
<strong t-esc="reward.description"/>
<div t-if="program.portal_visible">
@@ -88,7 +91,7 @@
<t t-if="reward.program_id.program_type == 'ewallet'">
Pay with eWallet
</t>
<t t-elif="reward.program_id.trigger == 'with_code' or (reward.program_id.trigger == 'auto' and reward.program_id.applies_on == 'future')">
<t t-elif="(reward.program_id.trigger == 'with_code' and reward.program_id.program_type != 'promo_code') or (reward.program_id.trigger == 'auto' and reward.program_id.applies_on == 'future')">
Use
</t>
<t t-else="">Claim</t>