@xbstracts/medusa-coupons
v0.0.14
Published
Reusable Medusa coupon product plugin.
Maintainers
Readme
medusa-coupons
Reusable Medusa v2 plugin for coupon products.
Scope
medusa-coupons treats a coupon product as a normal Medusa product or variant with coupon issuance configuration. When a configured product is purchased, the plugin creates generic Medusa-owned customer coupon entitlements and emits coupon events that a project integration can consume.
This plugin intentionally does not implement gift cards, store credit, POS sync, digital downloads, license keys, Strapi sync, or His/Her-specific behavior. Medusa's loyalty plugin remains responsible for gift cards and store credit.
Main Surfaces
- Module:
coupon - Admin routes:
/admin/coupon-products/* - Dashboard pages:
/dashboard/couponsand/dashboard/coupons/products - Subscriber:
payment.capturedcoupon issuance and redemption - Events:
coupon_product_config.createdcoupon_product_config.updatedcoupon_product_config.deletedcoupon_product.purchasedcoupon_issuance.createdcustomer_coupon_entitlement.issuedcustomer_coupon_entitlement.redeemedcustomer_coupon_entitlement.canceledcoupon_promotion_mirror.createdcoupon_promotion_mirror.failed
Data Model
CouponProductConfig: product-level coupon defaults.CouponProductVariantConfig: optional variant-level overrides.CouponIssuance: idempotent order line issuance record.CustomerCouponEntitlement: generic Medusa-owned customer entitlement.CouponPromotionMirror: optional Medusa Promotion mirror state.
Product config is authoritative. Product metadata only receives a small metadata.medusa_coupons marker for discovery.
Fixed-amount coupons use amounts: [{ currency_code, amount }]. Issued
entitlements keep an immutable copy of every configured currency amount. The
plugin translates entitlement codes applied to Medusa carts and draft orders
into one-use internal promotions for the exact order currency; it never
converts currencies or falls back to another configured amount.
Percentage coupons can target products or the whole order. Product-scoped
coupons preserve each or once allocation. Order-scoped coupons persist
promotion_template.application_method.target_type = "order" and always use
allocation = "across". The target and allocation are copied into immutable
issuance and entitlement snapshots.
Expiration Policies
Configure the coupon module with an IANA timezone. It defaults to UTC and is
copied into every issuance and entitlement expiration-policy snapshot:
{
resolve: "@xbstracts/medusa-coupons/coupon",
options: { expiration_timezone: "Asia/Bangkok" },
}Coupon products support no expiration (none), the end of the issue month
(month_end), a calendar duration in days or months (duration), and an
explicit instant (fixed). Dynamic policies use either the exact issue clock
or the end of the resolved local day. Month arithmetic clamps missing target
days to the target month's last day, including February in leap years. A
campaign or explicit cap is applied only after the policy expiry is resolved.
Legacy { type: "duration", duration_days: N } values remain readable and are
normalized to duration, days, and exactly; the module migration updates
stored configurations and snapshots without changing an entitlement's concrete
expires_at value.
Purchase Conditions
Coupon products can restrict purchase by customer group, region, shipping
country, sales channel, and currency. Conditions use eq, in, or ne, each
attribute can appear once, and all configured conditions must match. A product
without conditions is available to every cart context.
Fixed-amount coupons require a Currency Code condition. Their coupon values are
stored once per effective currency; product selling prices remain independent.
A ne currency condition derives its effective values from the store's current
supported currencies, so the coupon must be reviewed when a new store currency
is introduced.
The Sales Channel condition also synchronizes the product's Medusa sales-channel
links. Country validation is deferred while adding a line when the cart has no
shipping address, then enforced strictly by completeCartWorkflow. Every other
condition is enforced during both add-to-cart and checkout. Issuance snapshots
retain the configured conditions and the cart context that matched them.
Promotion Mirroring
Promotion mirroring is opt-in. Shared-code configs can create reusable Medusa
promotions. Unique and shared entitlement codes are also resolved at checkout
to customer-bound, one-use internal promotions. Percentage-off-order coupons
map to a Medusa PERCENTAGE + ORDER + ACROSS application method; percentage
redemption is recorded separately from fixed-amount redemption.
Commands
npm install
npm test
npm run build