[FIX] sale_coupon: avoid duplicated checks/filters
Avoid filtering/checking the same condition multiple times on the same records... This allows to avoid n more fetch of all applicable coupon programs from the database (because _check_promo_code is called on each program in a loop). Also apply the date filter directly in SQL: * The computation of inherited fields (_inherits) by the orm is intrinsically slow. The fields rule_date_from and rule_date_to checked in the _filter_on_validity_dates python filter are inherited from sale.coupon.program.rule model. * Filtering recordsets in SQL is faster. closes odoo/odoo#60292 X-original-commit: 679ebc3381179f6b18364c6f2b4d4f7f34274698 Signed-off-by: Victor Feyens (vfe) <vfe@odoo.com>
This commit is contained in:
@@ -30,7 +30,6 @@ class CouponProgram(models.Model):
|
||||
|
||||
def _check_promo_code(self, order, coupon_code):
|
||||
message = {}
|
||||
applicable_programs = order._get_applicable_programs()
|
||||
if self.maximum_use_number != 0 and self.order_count >= self.maximum_use_number:
|
||||
message = {'error': _('Promo code %s has been expired.') % (coupon_code)}
|
||||
elif not self._filter_on_mimimum_amount(order):
|
||||
@@ -57,8 +56,9 @@ class CouponProgram(models.Model):
|
||||
message = {'error': _("The customer doesn't have access to this reward.")}
|
||||
elif not self._filter_programs_on_products(order):
|
||||
message = {'error': _("You don't have the required product quantities on your sales order. If the reward is same product quantity, please make sure that all the products are recorded on the sales order (Example: You need to have 3 T-shirts on your sales order if the promotion is 'Buy 2, Get 1 Free'.")}
|
||||
else:
|
||||
if self not in applicable_programs and self.promo_applicability == 'on_current_order':
|
||||
elif self.promo_applicability == 'on_current_order' and not self.env.context.get('applicable_coupon'):
|
||||
applicable_programs = order._get_applicable_programs()
|
||||
if self not in applicable_programs:
|
||||
message = {'error': _('At least one of the required conditions is not met to get the reward!')}
|
||||
return message
|
||||
|
||||
@@ -160,7 +160,8 @@ class CouponProgram(models.Model):
|
||||
# Minimum requirement should not be checked if the coupon got generated by a promotion program (the requirement should have only be checked to generate the coupon)
|
||||
if not next_order:
|
||||
programs = programs and programs._filter_on_mimimum_amount(order)
|
||||
programs = programs and programs._filter_on_validity_dates(order)
|
||||
if not self.env.context.get("no_outdated_coupons"):
|
||||
programs = programs and programs._filter_on_validity_dates(order)
|
||||
programs = programs and programs._filter_unexpired_programs(order)
|
||||
programs = programs and programs._filter_programs_on_partners(order)
|
||||
# Product requirement should not be checked if the coupon got generated by a promotion program (the requirement should have only be checked to generate the coupon)
|
||||
|
||||
@@ -254,8 +254,12 @@ class SaleOrder(models.Model):
|
||||
This method is used to return the valid applicable programs on given order.
|
||||
"""
|
||||
self.ensure_one()
|
||||
programs = self.env['coupon.program'].search([
|
||||
('company_id', 'in', [self.company_id.id, False])
|
||||
programs = self.env['coupon.program'].with_context(
|
||||
no_outdated_coupons=True,
|
||||
).search([
|
||||
('company_id', 'in', [self.company_id.id, False]),
|
||||
'|', ('rule_date_from', '=', False), ('rule_date_from', '<=', self.date_order),
|
||||
'|', ('rule_date_to', '=', False), ('rule_date_to', '>=', self.date_order),
|
||||
], order="id")._filter_programs_from_common_rules(self)
|
||||
# no impact code...
|
||||
# should be programs = programs.filtered if we really want to filter...
|
||||
@@ -265,8 +269,13 @@ class SaleOrder(models.Model):
|
||||
|
||||
def _get_applicable_no_code_promo_program(self):
|
||||
self.ensure_one()
|
||||
programs = self.env['coupon.program'].search([
|
||||
programs = self.env['coupon.program'].with_context(
|
||||
no_outdated_coupons=True,
|
||||
applicable_coupon=True,
|
||||
).search([
|
||||
('promo_code_usage', '=', 'no_code_needed'),
|
||||
'|', ('rule_date_from', '=', False), ('rule_date_from', '<=', self.date_order),
|
||||
'|', ('rule_date_to', '=', False), ('rule_date_to', '>=', self.date_order),
|
||||
'|', ('company_id', '=', self.company_id.id), ('company_id', '=', False),
|
||||
])._filter_programs_from_common_rules(self)
|
||||
return programs
|
||||
@@ -288,6 +297,9 @@ class SaleOrder(models.Model):
|
||||
programs = order._get_applicable_no_code_promo_program()
|
||||
programs = programs._keep_only_most_interesting_auto_applied_global_discount_program()
|
||||
for program in programs:
|
||||
# VFE REF in master _get_applicable_no_code_programs already filters programs
|
||||
# why do we need to reapply this bunch of checks in _check_promo_code ????
|
||||
# We should only apply a little part of the checks in _check_promo_code...
|
||||
error_status = program._check_promo_code(order, False)
|
||||
if not error_status.get('error'):
|
||||
if program.promo_applicability == 'on_next_order':
|
||||
|
||||
Reference in New Issue
Block a user