[FIX] sale_coupon: Better performance

On instances with a lot of coupons programs, performance issue arise while using eccommerce (adding item in basket ant opening it in particular).
In the client case, he have ~2000 of them.

Opening the basket with 1 product take:
 Before this commit: ~10s
 After this commit: ~2s

( pyflame is available in the ticket attachment )

`_get_valid_products` use the v13 `filtered_domain` method
Average execution time:
  Before change: 0.001 s
  After change: 0.0001 s
=> 10x times gained

The average execution time of `_is_valid_product` is 0.002 s (20 times slower than `_get_valid_products` for the same result).
=> All use of `_is_valid_product` were replaced by `_get_valid_products`

In this commit targeting master, we also completely remove
`_is_valid_product` as it effectively is no longer used and there are no
stable compatibility requirements.

OPW-2323599

closes odoo/odoo#56460

X-original-commit: c3a9738e25dbd773e3ee7c2175e62219346ef764
Signed-off-by: Adrian Torres (adt) <adt@odoo.com>
This commit is contained in:
Loan (lse)
2020-08-25 08:08:47 +00:00
committed by Adrian Torres
parent d1391314d9
commit 54c74bb433
3 changed files with 5 additions and 13 deletions
+2 -10
View File
@@ -139,16 +139,8 @@ class CouponProgram(models.Model):
else:
return True
def _is_valid_product(self, product):
# NOTE: if you override this method, think of also overriding _get_valid_products
if self.rule_products_domain:
domain = ast.literal_eval(self.rule_products_domain) + [('id', '=', product.id)]
return bool(self.env['product.product'].search_count(domain))
else:
return True
def _get_valid_products(self, products):
if self.rule_products_domain:
domain = ast.literal_eval(self.rule_products_domain) + [('id', 'in', products.ids)]
return self.env['product.product'].search(domain)
domain = ast.literal_eval(self.rule_products_domain)
return products.filtered_domain(domain)
return products
+1 -1
View File
@@ -121,7 +121,7 @@ class CouponProgram(models.Model):
ordered_rule_products_qty = sum(products_qties[product] for product in valid_products)
# Avoid program if 1 ordered foo on a program '1 foo, 1 free foo'
if program.promo_applicability == 'on_current_order' and \
program._is_valid_product(program.reward_product_id) and program.reward_type == 'product':
program.reward_type == 'product' and program._get_valid_products(program.reward_product_id):
ordered_rule_products_qty -= program.reward_product_quantity
if ordered_rule_products_qty >= program.rule_min_quantity:
valid_programs |= program
+2 -2
View File
@@ -78,10 +78,10 @@ class SaleOrder(models.Model):
def _get_reward_values_product(self, program):
price_unit = self.order_line.filtered(lambda line: program.reward_product_id == line.product_id)[0].price_reduce
order_lines = (self.order_line - self._get_reward_lines()).filtered(lambda x: program._is_valid_product(x.product_id))
order_lines = (self.order_line - self._get_reward_lines()).filtered(lambda x: program._get_valid_products(x.product_id))
max_product_qty = sum(order_lines.mapped('product_uom_qty')) or 1
# Remove needed quantity from reward quantity if same reward and rule product
if program._is_valid_product(program.reward_product_id):
if program._get_valid_products(program.reward_product_id):
# number of times the program should be applied
program_in_order = max_product_qty // (program.rule_min_quantity + program.reward_product_quantity)
# multipled by the reward qty