From 0a565abfad5b9d6fc2d67ce10a54b3212c98726a Mon Sep 17 00:00:00 2001 From: Romain Derie Date: Wed, 28 Mar 2018 18:00:48 +0200 Subject: [PATCH] [FIX] sale_coupon(_delivery): correct discount when specific product Before this commit: 1. With a coupon set on 'specific_product', the discount amount was multiplied by the product quantity twice. (Introduced by a42c27f which apply discount on the full price by using price_total (already multiplied by quantity) over price_unit. 2. With a coupon set on 'cheapest_product', the discount was not discounting taxes. 3. With a coupon set on 'cheapest_product' and `sale_coupon_delivery` installed, it would simply crashes and throws an error since `sale.order.line` has no `program_id` attribute. Now: 1. We no longer multiply by the quantity twice; 2. We apply discount on the full price (with taxes); 3. We use correct attribute to avoid crash. opw-1830986 --- models/sale_order.py | 5 +++-- tests/test_program_numbers.py | 8 ++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/models/sale_order.py b/models/sale_order.py index d3789d5413b..cd835ac4b18 100644 --- a/models/sale_order.py +++ b/models/sale_order.py @@ -110,7 +110,8 @@ class SaleOrder(models.Model): return fixed_amount def _get_lines_unit_prices(self): - return [x.price_unit for x in self.order_line.filtered(lambda x: not x.is_reward_line)] + # Unit prices tax included + return [x.price_total / x.product_uom_qty for x in self.order_line.filtered(lambda x: not x.is_reward_line)] def _get_reward_values_discount_percentage(self, program): discount_amount = 0 @@ -122,7 +123,7 @@ class SaleOrder(models.Model): unit_prices = self._get_lines_unit_prices() discount_amount = (min(unit_prices) * (program.discount_percentage) / 100) if program.discount_apply_on == 'specific_product': - discount_amount = sum([(x.price_total * x.product_uom_qty) * (program.discount_percentage / 100) for x in self.order_line.filtered( + discount_amount = sum([x.price_total * (program.discount_percentage / 100) for x in self.order_line.filtered( lambda x: x.product_id == program.discount_specific_product_id)]) if program.discount_max_amount and discount_amount > max_amount: discount_amount = max_amount diff --git a/tests/test_program_numbers.py b/tests/test_program_numbers.py index fcb5002d5c0..9a698f3cf9b 100644 --- a/tests/test_program_numbers.py +++ b/tests/test_program_numbers.py @@ -178,3 +178,11 @@ class TestSaleCouponProgramNumbers(TestSaleCouponCommon): order.recompute_coupon_lines() # (10x25) + (320 +15% tax) - (20% of (320 + 15% tax) = 250 + 368 - 73.6 = 544.4 self.assertEqual(order.amount_total, 544.4, "We should only get reduction on ipad") + sol1.product_uom_qty = 10 + order.recompute_coupon_lines() + # (10x25) + (10x (320 +15% tax)) - (20% of (10x (320 + 15% tax))) - 2 free iPads = 250 + 3680 - 736 - 736 = 2458 + self.assertEqual(order.amount_total, 2458, "Changing ipad quantity should change discount amount correctly") + + p_specific_product.discount_max_amount = 200 + order.recompute_coupon_lines() + self.assertEqual(order.amount_total, 2994, "The discount should be limited to $200")