From 2a84495a478b2234ed027bd7ab3f54dc7cf17e14 Mon Sep 17 00:00:00 2001 From: "Mahdi Cheikh Rouhou (macr)" Date: Tue, 21 Nov 2023 09:28:10 +0000 Subject: [PATCH] [FIX] website_sale_loyalty: add product when exists as reward in cart Issue: ====== When we have a product as a free product reward in cart and we want to add the same product from the shop nothing will happen and the cart stays the same. Steps to reproduce the issue: ============================= - Create a loyalty program with the following options: type: pormotions rule: minimum quantity :1 , gran 1, minimum purchase 0, per order, product: select anyone reward: type : free product , quantity rewarded : 1, product : select any other product - Go to website and add the product from the rule to cart - Go to cart and claim reward - Go back to shop and add the product from the reward to cart - Go to cart - The cart stays the same Issue: ====== When searching for the `line` it doesn't consider if the line is a reward or not. Solution: ========= We filter the reward lines if `line_id=False` opw-3550585 closes odoo/odoo#143581 X-original-commit: 2b97bb83b312f553d3ec1b6e96a74c744955aed6 Signed-off-by: Morgane Demesmaeker --- .../website_sale_loyalty/models/sale_order.py | 9 +++ addons/website_sale_loyalty/tests/__init__.py | 1 + .../tests/test_free_product_reward.py | 81 +++++++++++++++++++ 3 files changed, 91 insertions(+) create mode 100644 addons/website_sale_loyalty/tests/test_free_product_reward.py diff --git a/addons/website_sale_loyalty/models/sale_order.py b/addons/website_sale_loyalty/models/sale_order.py index 07b942ec950..d43e4232190 100644 --- a/addons/website_sale_loyalty/models/sale_order.py +++ b/addons/website_sale_loyalty/models/sale_order.py @@ -220,3 +220,12 @@ class SaleOrder(models.Model): else: res[coupon] = reward return res + + def _cart_find_product_line(self, product_id, line_id=None, **kwargs): + """ Override to filter out reward lines from the cart lines. + + These are handled by the _update_programs_and_rewards and _auto_apply_rewards methods. + """ + lines = super()._cart_find_product_line(product_id, line_id, **kwargs) + lines = lines.filtered(lambda l: not l.is_reward_line) if not line_id else lines + return lines diff --git a/addons/website_sale_loyalty/tests/__init__.py b/addons/website_sale_loyalty/tests/__init__.py index a22705b35c1..cd32bf5ba49 100644 --- a/addons/website_sale_loyalty/tests/__init__.py +++ b/addons/website_sale_loyalty/tests/__init__.py @@ -4,3 +4,4 @@ from . import test_apply_pending_coupon from . import test_sale_coupon_multiwebsite from . import test_shop_sale_coupon from . import test_website_sale_loyalty_delivery +from . import test_free_product_reward diff --git a/addons/website_sale_loyalty/tests/test_free_product_reward.py b/addons/website_sale_loyalty/tests/test_free_product_reward.py new file mode 100644 index 00000000000..065f5ac6816 --- /dev/null +++ b/addons/website_sale_loyalty/tests/test_free_product_reward.py @@ -0,0 +1,81 @@ +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import http +from odoo.tests.common import HttpCase +from odoo.tests import tagged +from odoo.addons.website.tools import MockRequest +from odoo.addons.website_sale_loyalty.controllers.main import WebsiteSale + +@tagged('post_install', '-at_install') +class TestFreeProductReward(HttpCase): + + def setUp(self): + super().setUp() + + self.WebsiteSaleController = WebsiteSale() + self.website = self.env['website'].browse(1) + + self.sofa = self.env['product.product'].create({ + 'name': 'Test Sofa', + 'list_price': 2950.0, + 'website_published': True, + }) + + self.carpet = self.env['product.product'].create({ + 'name': 'Test Carpet', + 'list_price': 500.0, + 'website_published': True, + }) + + # Disable any other program + self.program = self.env['loyalty.program'].search([]).write({'active': False}) + + self.program = self.env['loyalty.program'].create({ + 'name': 'Get a product for free', + 'program_type': 'promotion', + 'applies_on': 'current', + 'trigger': 'auto', + 'rule_ids': [(0, 0, { + 'minimum_qty': 1, + 'minimum_amount': 0.00, + 'reward_point_amount': 1, + 'reward_point_mode': 'order', + 'product_ids': self.sofa, + })], + 'reward_ids': [(0, 0, { + 'reward_type': 'product', + 'reward_product_id': self.carpet.id, + 'reward_product_qty': 1, + 'required_points': 1, + })], + }) + + self.steve = self.env['res.partner'].create({ + 'name': 'Steve Bucknor', + 'email': 'steve.bucknor@example.com', + }) + + self.empty_order = self.env['sale.order'].create({ + 'partner_id': self.steve.id + }) + + installed_modules = set(self.env['ir.module.module'].search([ + ('state', '=', 'installed'), + ]).mapped('name')) + for _ in http._generate_routing_rules(installed_modules, nodb_only=False): + pass + + def test_add_product_to_cart_when_it_exist_as_free_product(self): + # This test the flow when we claim a reward in the cart page and then we + # want to add the product again + order = self.empty_order + with MockRequest(self.env, website=self.website, sale_order_id=order.id, website_sale_current_pl=1): + self.WebsiteSaleController.cart_update_json(self.sofa.id, set_qty=1) + self.WebsiteSaleController.claim_reward(self.program.reward_ids[0].id) + self.WebsiteSaleController.cart_update_json(self.carpet.id, set_qty=1) + sofa_line = order.order_line.filtered(lambda line: line.product_id.id == self.sofa.id) + carpet_reward_line = order.order_line.filtered(lambda line: line.product_id.id == self.carpet.id and line.is_reward_line) + carpet_line = order.order_line.filtered(lambda line: line.product_id.id == self.carpet.id and not line.is_reward_line) + self.assertEqual(sofa_line.product_uom_qty, 1, "Should have only 1 qty of Sofa") + self.assertEqual(carpet_reward_line.product_uom_qty, 1, "Should have only 1 qty for the carpet as reward") + self.assertEqual(carpet_line.product_uom_qty, 1, "Should have only 1 qty for carpet as non reward")