frittenkeez/laravel-vouchers
Laravel Vouchers offers an Eloquent-backed way to create, issue, and redeem voucher codes. Track usage, associate vouchers with models, and manage redemption state through a simple API for discounts, invites, credits, or other redeemable rewards.
Vouchers::withCounter(), withCounterPadding(), withCodeFormatter()) remove the previous hard limit where a static withCode() could only safely produce a single voucher. This directly unlocks "batch-generate 10,000 codes for a seasonal campaign" as a scoped feature rather than a custom build.Consider adoption when:
Voucher/Redeemer/VoucherEntity relations.ArrayObject cast, which is a better ergonomic fit for accumulating redemption context than reassigning arrays wholesale.withCodeFormatter() and the new CodeFormat value object rather than string concatenation scattered through your domain.Look elsewhere or build your own when:
12.4.Voucher::code() → Voucher::withCode()), made scope methods protected, renamed a widely used parameter, and changed the runtime type of $metadata. That is a fast-moving surface.ArrayObject conversions, named-argument callers of redeem()/unredeem()/redeemable()/unredeemable(), subclasses overriding scopes, and any code relying on withCode() + amount > 1 throwing instead of appending a counter.To executives: This is a mature-enough open-source Laravel package that gives us voucher and coupon code issuance and redemption as a solved primitive, so we invest engineering time in campaign rules and customer experience instead of re-implementing code generation and redemption bookkeeping. The 0.9.0 release materially improves our bulk-campaign economics: generating a hundred codes now costs one database lookup instead of a hundred, and static-code collisions are handled with configurable counters and custom formatting instead of failing. The trade-off is that it is pre-1.0 and 0.9.0 is a breaking release requiring Laravel 12.4+; we should adopt it pinned, with a named owner and a scheduled upgrade cadence, and budget a small amount of maintenance per upgrade cycle.
To engineering: 0.9.0 is a breaking release; read UPGRADING.md before merging. Concretely: minimum Laravel is now 12.4 (for the #[Scope] attribute), all model scopes moved from scopeXxx() to #[Scope] and are now protected—affects anyone extending the models or overriding scopes. Voucher::code() is now Voucher::withCode() because a scope named code shadowed the column and broke $voucher->code when the attribute wasn't loaded. Voucher::$metadata and Redeemer::$metadata return ArrayObject, so any code passing them into array functions needs ->toArray(). The first parameter of redeem()/unredeem()/redeemable()/unredeemable() is renamed $code → $voucher, which breaks named-argument callers; those methods now also accept a Voucher instance directly, skipping a lookup query—worth adopting in hot paths. withCode() with an amount greater than one now appends a counter instead of throwing InfiniteLoopException; withMask() with a static mask still throws. New AsNullableArrayObject cast preserves null instead of storing the JSON string 'null'—useful if we have nullable JSON columns. Published migrations changed metadata from text to json and modernized to $table->id() / foreignId()->constrained()->cascadeOnDelete(); schema is unchanged and existing installs are unaffected, so no action needed. Also fixed: Voucher::withOwner() and VoucherEntity::withEntity() now use the instance's own getMorphClass(), which matters if we override morph types without a morph map. Deprecations: Laravel 11 and PEST 3 support dropped.
How can I help you explore Laravel packages today?