Improve performance for batches involving promotions/coupons

Created on 17 January 2024, 11 months ago
Updated 9 February 2024, 10 months ago

Any kind of batch process involving promotions/coupons (most notably coupon generation) will run into exponential performance issues as the number of the promotion's coupons will grow.

This is because both entities enfore a reference to eachother in their respective postSave().

In the coupon's postSave(), after a redundant check if the promotion has the coupon (because addCoupon() already checks this), addCoupon() will trigger a promotion save:

// Ensure there's a reference on each promotion.
$promotion = $this->getPromotion();
if ($promotion) {
  if (!$promotion->hasCoupon($this)) {
    $promotion->addCoupon($this);
  }
  if (!$promotion->requiresCoupon()) {
    $promotion->set('require_coupon', TRUE);
  }
  if ($promotion->hasTranslationChanges()) {
    $promotion->save();
  }
}

Then, in the promotion's postSave(), we loop all of its coupons and enforce the reference:

// Ensure there's a back-reference on each coupon.
foreach ($this->getCoupons() as $coupon) {
  if (!$coupon->getPromotionId()) {
    $coupon->promotion_id = $this->id();
    $coupon->save();
  }
}

When generating (or running a custom import of) coupons, this last piece of code is entirely redundant and will exponentially affect performance (try generating 10k coupons).

Ideally, the promotion entity would greatly benefit from a refresh service similar to that of the order entity, which would execute certain operations only when prompted.

Feature request
Status

Needs work

Version

2.0

Component

Promotions

Created by

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Production build 0.71.5 2024