[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 <lse@odoo.com>
This commit is contained in:
Victor Feyens
2020-10-19 14:49:14 +00:00
co-authored by Loan Sens
parent 5468b9bf98
commit 70295e5c44
+22 -14
View File
@@ -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):