Skip to Content
FeaturesPromotions

Promotions

Hoikka supports coupon codes and automatic discounts with flexible targeting rules.

Promotion Types

TypeDescription
orderDiscount on the entire order total
productDiscount on specific products
free_shippingWaives shipping cost

Methods

  • Code — customer enters a coupon code at checkout
  • Automatic — applied automatically when conditions are met

Targeting

Promotions can apply to:

  • All products
  • Specific products — linked via promotion_products
  • Specific collections — linked via promotion_collections

Collection targeting resolves products through the collection service (promotionService.getQualifyingProductIds), so every collection filter type is honored: product, facet, price, stock, visibility, and variant.

Discount Calculation

Two discount types:

  • percentage — percentage off (e.g. 20% off)
  • fixed_amount — fixed amount in cents (e.g. 500 = 5.00 EUR off)

Constraints

ConstraintDescription
minOrderAmountMinimum order total required
usageLimitMax total uses across all customers
usageLimitPerCustomerMax uses per individual customer
customerGroupIdRestrict to a specific customer group
startsAt / endsAtActive time window
combinesWithOtherPromotionsWhether it stacks with other promotions

Service API

// Validate and apply a coupon code const result = await orderService.applyPromotion(orderId, "SUMMER20", customerId); // List active automatic promotions const promos = await promotionService.listActiveAutomatic(); // Get discounted prices for storefront display const discounts = await promotionService.getActiveProductDiscounts();

The discount formula lives in exactly one place: calculateDiscount in src/lib/promotion-utils.ts (percentage rounds, fixed amount is clamped to the base amount), re-exported by src/lib/server/services/promotion-utils.ts. It is shared by storefront price display and order math, so the shown discount can never drift from the charged one. On the order side, OrderService.computePromotionDiscount applies it per promotion type (order subtotal, qualifying product lines, or the shipping price) for coupon codes, automatic promotions, and totals recalculation alike.

getActiveProductDiscounts() runs on every storefront page load, so its result is cached briefly (per server process / Workers isolate, ~60s TTL). Admin mutations clear the cache so price changes show up immediately.

Schema

Promotions are stored in the promotions table with junction tables promotion_products and promotion_collections for targeting. Applied discounts are tracked in order_promotions.

Last updated on