From 70295e5c44294da1ea9f4e5de6f22c5aed086f14 Mon Sep 17 00:00:00 2001 From: Victor Feyens Date: Mon, 5 Oct 2020 10:48:25 +0000 Subject: [PATCH] [FIX] sale_coupon: reorder costly method to avoid useless operations When coupon is installed, all cart (SO) updates on the e-commerce go through the _remove_invalid_lines method. It has been proved to be a performance bottleneck on big instances with a lot of coupon programs. To reduce the performance impact of this method, this commit reorganize it to avoid unnecessary operations as much as possible. X-original-commit: 447057cfbe28db760834fba2dfd2c79303825cbc Co-authored-by: Loan Sens --- addons/sale_coupon/models/sale_order.py | 36 +++++++++++++++---------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/addons/sale_coupon/models/sale_order.py b/addons/sale_coupon/models/sale_order.py index fce9ba2ab95..cc600810f85 100644 --- a/addons/sale_coupon/models/sale_order.py +++ b/addons/sale_coupon/models/sale_order.py @@ -353,30 +353,38 @@ class SaleOrder(models.Model): self.ensure_one() 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() + applicable_programs = self.env['coupon.program'] + if applied_programs: + 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() programs_to_remove = applied_programs - applicable_programs - products_to_remove = programs_to_remove.mapped('discount_line_product_id') # delete reward line coming from an archived coupon (it will never be updated/removed when recomputing the order) invalid_lines = order.order_line.filtered(lambda line: line.is_reward_line and line.product_id.id not in (applied_programs).mapped('discount_line_product_id').ids) - # Invalid generated coupon for which we are not eligible anymore ('expired' since it is specific to this SO and we may again met the requirements) - self.generated_coupon_ids.filtered(lambda coupon: coupon.program_id.discount_line_product_id.id in products_to_remove.ids).write({'state': 'expired'}) - # Reset applied coupons for which we are not eligible anymore ('valid' so it can be use on another ) - coupons_to_remove = order.applied_coupon_ids.filtered(lambda coupon: coupon.program_id in programs_to_remove) - coupons_to_remove.write({'state': 'new'}) - - # Unbind promotion and coupon programs which requirements are not met anymore if programs_to_remove: + product_ids_to_remove = programs_to_remove.discount_line_product_id.ids + + if product_ids_to_remove: + # Invalid generated coupon for which we are not eligible anymore ('expired' since it is specific to this SO and we may again met the requirements) + self.generated_coupon_ids.filtered(lambda coupon: coupon.program_id.discount_line_product_id.id in product_ids_to_remove).write({'state': 'expired'}) + + # Reset applied coupons for which we are not eligible anymore ('valid' so it can be use on another ) + coupons_to_remove = order.applied_coupon_ids.filtered(lambda coupon: coupon.program_id in programs_to_remove) + coupons_to_remove.write({'state': 'new'}) + + # Unbind promotion and coupon programs which requirements are not met anymore order.no_code_promo_program_ids -= programs_to_remove order.code_promo_program_id -= programs_to_remove - if coupons_to_remove: - order.applied_coupon_ids -= coupons_to_remove - # Remove their reward lines - invalid_lines |= order.order_line.filtered(lambda line: line.product_id.id in products_to_remove.ids) + if coupons_to_remove: + order.applied_coupon_ids -= coupons_to_remove + + # Remove their reward lines + if product_ids_to_remove: + invalid_lines |= order.order_line.filtered(lambda line: line.product_id.id in product_ids_to_remove) + invalid_lines.unlink() def _get_applied_programs_with_rewards_on_current_order(self):