diff --git a/addons/sale_coupon/models/sale_coupon_program.py b/addons/sale_coupon/models/sale_coupon_program.py index 295e37e4b64..f4669f2d3a9 100644 --- a/addons/sale_coupon/models/sale_coupon_program.py +++ b/addons/sale_coupon/models/sale_coupon_program.py @@ -146,6 +146,19 @@ class SaleCouponProgram(models.Model): self.discount_type == 'percentage' and \ self.discount_apply_on == 'on_order' + def _keep_only_most_interesting_auto_applied_global_discount_program(self): + '''Given a record set of programs, remove the less interesting auto + applied global discount to keep only the most interesting one. + We should not take promo code programs into account as a 10% auto + applied is considered better than a 50% promo code, as the user might + not know about the promo code. + ''' + programs = self.filtered(lambda p: p._is_global_discount_program() and p.promo_code_usage == 'no_code_needed') + if not programs: return self + most_interesting_program = max(programs, key=lambda p: p.discount_percentage) + # remove least interesting programs + return self - (programs - most_interesting_program) + def _check_promo_code(self, order, coupon_code): message = {} applicable_programs = order._get_applicable_programs() diff --git a/addons/sale_coupon/models/sale_order.py b/addons/sale_coupon/models/sale_order.py index 56047b64180..f19668de7b5 100644 --- a/addons/sale_coupon/models/sale_order.py +++ b/addons/sale_coupon/models/sale_order.py @@ -287,6 +287,7 @@ class SaleOrder(models.Model): self.ensure_one() order = self programs = order._get_applicable_no_code_promo_program() + programs = programs._keep_only_most_interesting_auto_applied_global_discount_program() for program in programs: error_status = program._check_promo_code(order, False) if not error_status.get('error'): @@ -355,6 +356,7 @@ class SaleOrder(models.Model): order = self applicable_programs = order._get_applicable_no_code_promo_program() + order._get_applicable_programs() + order._get_valid_applied_coupon_program() + applicable_programs = applicable_programs._keep_only_most_interesting_auto_applied_global_discount_program() applied_programs = order._get_applied_programs_with_rewards_on_current_order() + order._get_applied_programs_with_rewards_on_next_order() programs_to_remove = applied_programs - applicable_programs products_to_remove = programs_to_remove.mapped('discount_line_product_id') diff --git a/addons/sale_coupon/tests/test_program_rules.py b/addons/sale_coupon/tests/test_program_rules.py index 727f71bcadc..beacbe31d7f 100644 --- a/addons/sale_coupon/tests/test_program_rules.py +++ b/addons/sale_coupon/tests/test_program_rules.py @@ -240,3 +240,54 @@ class TestProgramRules(TestSaleCouponCommon): self.assertEqual(len(order.order_line.ids), 2, "The discount line should have been removed as we don't meet the program requirements") self.assertEqual(coupon.state, 'new', "The coupon should be reset to Valid as it's reward got removed") + + + def test_program_rules_promotion_use_best(self): + ''' This test will: + * Verify the best global promotion according to the + current sale order is used. + ''' + self.immediate_promotion_program.active = False # Avoid having this program to add rewards on this test + order = self.empty_order + + program_5pc = self.env['sale.coupon.program'].create({ + 'name': 'Get 5% discount if buy at least 2 Product', + 'program_type': 'promotion_program', + 'reward_type': 'discount', + 'discount_type': 'percentage', + 'discount_percentage': 5.0, + 'rule_min_quantity': 2, + 'promo_code_usage': 'no_code_needed', + }) + program_10pc = self.env['sale.coupon.program'].create({ + 'name': 'Get 10% discount if buy at least 4 Product', + 'program_type': 'promotion_program', + 'reward_type': 'discount', + 'discount_type': 'percentage', + 'discount_percentage': 10.0, + 'rule_min_quantity': 4, + 'promo_code_usage': 'no_code_needed', + }) + sol = self.env['sale.order.line'].create({ + 'product_id': self.product_A.id, + 'name': 'Product A', + 'product_uom_qty': 1.0, + 'order_id': order.id, + }) + + order.recompute_coupon_lines() + self.assertEqual(len(order.order_line.ids), 1, "The order should only contains the Product A line") + + sol.product_uom_qty = 3 + order.recompute_coupon_lines() + discounts = set(order.order_line.mapped('name')) - {'Product A'} + self.assertEqual(len(discounts), 1, "The order should contains the Product A line and a discount") + # The name of the discount is dynamically changed to smth looking like: + # "Discount: Get 5% discount if buy at least 2 Product - On product with following tax: Tax 15.00%" + self.assertTrue('Get 5% discount' in discounts.pop(), "The discount should be a 5% discount") + + sol.product_uom_qty = 5 + order.recompute_coupon_lines() + discounts = set(order.order_line.mapped('name')) - {'Product A'} + self.assertEqual(len(discounts), 1, "The order should contains the Product A line and a discount") + self.assertTrue('Get 10% discount' in discounts.pop(), "The discount should be a 10% discount")