From e482adc1792eb2d740cdacb2e24bfef3e5ca1a9f Mon Sep 17 00:00:00 2001
From: "Andrea Grazioso (agr-odoo)" <agr@odoo.com>
Date: Fri, 3 Jul 2020 09:36:37 +0000
Subject: [PATCH] [FIX] sale_coupon: fix step like programs discount

Create four promotion programs:

if the order > 1500 than 10% discount
if the order > 1750 than 15% discount
if the order > 2000 than 20% discount
if the order > 2500 than 25% discount

Take a product with a price of $300 and add 5 to cart > the 10% discount
is correctly applied.
Add 1 more product (6) > it should now qualify for 15% discount, but it
stays at 10%
Add 1 more product (7) > it (correctly) gets the 20% discount
The 25% discount does not get applied until 11 of the product is in the
cart, even though it should qualify at 9
If you then decrease the quantity, the right discount will
sometimes display.

This occur because when the order amount change and the new total is
used to match the right promo the previously applied discount is not
removed from the amount.
This occur as side effect of
1d59785 in which the amount has to be
kept in order to avoid discount line removal on cart update.

opw-2285656

closes odoo/odoo#54400

X-original-commit: 28c099e6d5b02518b6b5a0be66b2b74a57f0c936
Signed-off-by: Nicolas Martinelli (nim) <nim@odoo.com>
---
 addons/sale_coupon/models/coupon_program.py   |  3 +-
 .../sale_coupon/tests/test_program_numbers.py | 81 +++++++++++++++++++
 2 files changed, 83 insertions(+), 1 deletion(-)

diff --git a/addons/sale_coupon/models/coupon_program.py b/addons/sale_coupon/models/coupon_program.py
index 35fa15cb72ef..ae348eae3404 100644
--- a/addons/sale_coupon/models/coupon_program.py
+++ b/addons/sale_coupon/models/coupon_program.py
@@ -75,7 +75,8 @@ class CouponProgram(models.Model):
             lines = order.order_line.filtered(lambda line:
                 program.reward_type == 'discount' and
                 (line.product_id == program.discount_line_product_id or
-                line.product_id == program.reward_id.discount_line_product_id
+                line.product_id == program.reward_id.discount_line_product_id or
+                (program.program_type == 'promotion_program' and line.is_reward_line)
             ))
             untaxed_amount = order_amount['amount_untaxed'] - sum([line.price_subtotal for line in lines])
             tax_amount = order_amount['amount_tax'] - sum([line.price_tax for line in lines])
diff --git a/addons/sale_coupon/tests/test_program_numbers.py b/addons/sale_coupon/tests/test_program_numbers.py
index f29b45430790..2adf58064e49 100644
--- a/addons/sale_coupon/tests/test_program_numbers.py
+++ b/addons/sale_coupon/tests/test_program_numbers.py
@@ -772,3 +772,84 @@ class TestSaleCouponProgramNumbers(TestSaleCouponCommon):
         sol1.write({'product_uom_qty': 2.0})
         order.recompute_coupon_lines()
         self.assertEqual(len(order.order_line.ids), 1, "The promotion lines should have been removed")
+
+    def test_program_step_percentages(self):
+        # test step-like percentages increase over amount
+        testprod = self.env['product.product'].create({
+            'name': 'testprod',
+            'lst_price': 118.0,
+        })
+
+        test10 = self.env['coupon.program'].create({
+            'name': '10% discount',
+            'promo_code_usage': 'no_code_needed',
+            'program_type': 'promotion_program',
+            'discount_type': 'percentage',
+            'discount_percentage': 10.0,
+            'rule_minimum_amount': 1500.0,
+            'rule_minimum_amount_tax_inclusion': 'tax_included',
+        })
+        test15 = self.env['coupon.program'].create({
+            'name': '15% discount',
+            'promo_code_usage': 'no_code_needed',
+            'program_type': 'promotion_program',
+            'discount_type': 'percentage',
+            'discount_percentage': 15.0,
+            'rule_minimum_amount': 1750.0,
+            'rule_minimum_amount_tax_inclusion': 'tax_included',
+        })
+        test20 = self.env['coupon.program'].create({
+            'name': '20% discount',
+            'promo_code_usage': 'no_code_needed',
+            'program_type': 'promotion_program',
+            'discount_type': 'percentage',
+            'discount_percentage': 20.0,
+            'rule_minimum_amount': 2000.0,
+            'rule_minimum_amount_tax_inclusion': 'tax_included',
+        })
+        test25 = self.env['coupon.program'].create({
+            'name': '25% discount',
+            'promo_code_usage': 'no_code_needed',
+            'program_type': 'promotion_program',
+            'discount_type': 'percentage',
+            'discount_percentage': 25.0,
+            'rule_minimum_amount': 2500.0,
+            'rule_minimum_amount_tax_inclusion': 'tax_included',
+        })
+
+        #apply 10%
+        order = self.empty_order
+        order_line = self.env['sale.order.line'].create({
+            'product_id': testprod.id,
+            'name': 'testprod',
+            'product_uom_qty': 14.0,
+            'price_unit': 118.0,
+            'order_id': order.id,
+            'tax_id': False,
+        })
+        order.recompute_coupon_lines()
+        self.assertEqual(order.amount_total, 1486.80, "10% discount should be applied")
+        self.assertEqual(len(order.order_line.ids), 2, "discount should be applied")
+
+        #switch to 15%
+        order_line.write({'product_uom_qty': 15})
+        self.assertEqual(order.amount_total, 1604.8, "Discount improperly applied")
+        self.assertEqual(len(order.order_line.ids), 2, "No discount applied while it should")
+
+        #switch to 20%
+        order_line.write({'product_uom_qty': 17})
+        order.recompute_coupon_lines()
+        self.assertEqual(order.amount_total, 1604.8, "Discount improperly applied")
+        self.assertEqual(len(order.order_line.ids), 2, "No discount applied while it should")
+
+        #still 20%
+        order_line.write({'product_uom_qty': 20})
+        order.recompute_coupon_lines()
+        self.assertEqual(order.amount_total, 1888.0, "Discount improperly applied")
+        self.assertEqual(len(order.order_line.ids), 2, "No discount applied while it should")
+
+        #back to 10%
+        order_line.write({'product_uom_qty': 14})
+        order.recompute_coupon_lines()
+        self.assertEqual(order.amount_total, 1486.80, "Discount improperly applied")
+        self.assertEqual(len(order.order_line.ids), 2, "No discount applied while it should")
-- 
GitLab