Improve performance for batches involving promotions/coupons

Created on 17 January 2024, 6 months ago
Updated 9 February 2024, 5 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.69.0 2024