Display helpers
For views and APIs, read coupon state without manual math or try/catch. Each helper is safe to call anywhere:
$coupon->remainingUsage(); // ?int — e.g. 37; null when unlimited (max_usage <= 0)
$coupon->remainingUsageFor($user); // ?int — null when untracked or per-redeemer unlimited
$coupon->usagePercentage(); // ?float — e.g. 92.6 (0..100); null when unlimited
$coupon->isRedeemableBy($user, $cart); // bool — pass a price to also check currency + minimum spend
$coupon->previewDiscount($cart); // Money — zero on a currency mismatch| Method | Returns |
|---|---|
remainingUsage(): ?int | Uses left under the global cap; null when unlimited. |
remainingUsageFor(Model $redeemer): ?int | Uses left for that redeemer; null when tracking is off or the per-redeemer cap is 0. |
usagePercentage(): ?float | Share of the global cap used, 0..100, rounded to 2 decimals; null when unlimited. |
isRedeemableBy(?Model $redeemer = null, ?Money $price = null): bool | The same checks as redemption; pass a price to also check currency and minimum spend. |
previewDiscount(Money $price): Money | Like discountFor(), but zero on a currency mismatch — safe in views. |
isRedeemableBy() asks Coupons::check() — the same checks, in the same order, as redeem() and the Redeemable rule — so they never drift apart: a soft-deleted Coupon instance, for one, is NotFound for all of them, just as redeem() throws CouponNotFound. Use Coupons::check() itself when you need the reason, not just a yes or no; Coupons::code($code)->preview($cart) is the facade form of previewDiscount() when you only have a code.
Example: a coupon preview endpoint
use RoundlyConsulting\Coupons\Facades\Coupons;
$coupon = Coupons::findOrFail((string) $request->input('code'));
return [
'code' => $coupon->code,
'redeemable' => $coupon->isRedeemableBy($request->user(), $cartTotal),
'you_save' => (string) $coupon->previewDiscount($cartTotal), // e.g. "4.50 EUR"
'uses_left' => $coupon->remainingUsage(),
'free_shipping' => $coupon->appliesToShipping(),
];One edge case: a Fixed row written around CreateCouponAction without a currency can’t be priced at all, so previewDiscount() still throws InvalidCouponDefinition for it.
Show your open-source love
This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.
More ways to support, including cryptoBy donating, you agree to our donation terms.
Want this built into your product?
We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.