[FIX] website_sale_loyalty: allow to remove coupon from cart

Steps to reproduce
- Install eCommerce app
- Go to Settings and enable Discounts, Loyalty & Gift Card option
- Go to Website app > eCommerce > Loyalty > Discount & Loyalty
- Create a new coupon by setting the Program Type to Coupons and then save.
- Generate a new coupon by clicking the GENERATE COUPONS button.
- Go to Website > site > Homepage
- Go to Shop page
- Add a product to the cart
- Apply the coupon code created
- Remove the coupon code by clicking the bin icon next to the coupon code line
- The coupon code is NOT removed.

Investigation
First, we'll take a look on what happens when a coupon code is applied
- When a coupon code is applied, a new sale.order.line is created for it.
- That triggers `super()._compute_website_order_line()` https://github.com/odoo/odoo/blob/d8ec7735aa8759fa94fc0223945ac9b19e05312e/addons/website_sale_loyalty/models/sale_order.py#L111 which filters out the discount order line https://github.com/odoo/odoo/blob/d8ec7735aa8759fa94fc0223945ac9b19e05312e/addons/website_sale/models/sale_order.py#L66 via the `_show_in_cart()` method https://github.com/odoo/odoo/blob/d8ec7735aa8759fa94fc0223945ac9b19e05312e/addons/website_sale_loyalty/models/sale_order_line.py#L12
- Then a new temporary sale.order.line is created by https://github.com/odoo/odoo/blob/d8ec7735aa8759fa94fc0223945ac9b19e05312e/addons/website_sale_loyalty/models/sale_order.py#L121 meaning that is has no `id`
- Note that we can only apply one coupon from the same program type.

Second, Let's take a look on what happens when we try to remove a coupon code
- A call is made to `cart_update_json()` which calls https://github.com/odoo/odoo/blob/d8ec7735aa8759fa94fc0223945ac9b19e05312e/addons/website_sale/controllers/main.py#L811-L819 which calls https://github.com/odoo/odoo/blob/d8ec7735aa8759fa94fc0223945ac9b19e05312e/addons/website_sale_loyalty/models/sale_order.py#L159
- But as noted above the coupon order line has no id being a temporary record. Hence the `line_id` is None which basically cancels the cart update.

opw-3744910

closes odoo/odoo#156553

X-original-commit: 1657d6f165f78f971d5bf975a8b4e366655d1ab0
Signed-off-by: Morgane Demesmaeker <edm@odoo.com>
Signed-off-by: Ali Hassan Youssef (alhy) <alhy@odoo.com>
This commit is contained in:
AH-Yussef
2024-03-06 02:24:51 +00:00
parent 6178be67c8
commit f72751dbfb
2 changed files with 36 additions and 0 deletions
@@ -162,6 +162,14 @@ class SaleOrder(models.Model):
return code
def _cart_update(self, *args, **kwargs):
product_id, set_qty = kwargs['product_id'], kwargs.get('set_qty')
line = self.order_line.filtered(lambda l: l.product_id.id == product_id)
reward_id = line.reward_id
if set_qty == 0 and line.coupon_id and reward_id and reward_id.reward_type == 'discount':
# Force the deletion of the line even if it's a temporary record created by new()
kwargs['line_id'] = line.id
res = super(SaleOrder, self)._cart_update(*args, **kwargs)
self._update_programs_and_rewards()
self._auto_apply_rewards()
@@ -338,3 +338,31 @@ class TestWebsiteSaleCoupon(HttpCase):
],
})
self.start_tour('/', 'apply_discount_code_program_multi_rewards', login='admin')
def test_03_remove_coupon(self):
# 1. Simulate a frontend order (website, product)
order = self.empty_order
order.website_id = self.env['website'].browse(1)
self.env['sale.order.line'].create({
'product_id': self.env['product.product'].create({
'name': 'Product A', 'list_price': 100, 'sale_ok': True
}).id,
'name': 'Product A',
'order_id': order.id,
})
# 2. Apply the coupon
self._apply_promo_code(order, self.coupon.code)
# 3. Remove the coupon
coupon_line = order.website_order_line.filtered(
lambda l: l.coupon_id and l.coupon_id.id == self.coupon.id
)
kwargs = {
'line_id': None, 'product_id': coupon_line.product_id.id, 'add_qty': None, 'set_qty': 0
}
order._cart_update(**kwargs)
msg = "The coupon should've been removed from the order"
self.assertEqual(len(order.applied_coupon_ids), 0, msg=msg)