PHPackages                             michael-rubel/laravel-couponables - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. michael-rubel/laravel-couponables

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

michael-rubel/laravel-couponables
=================================

This package provides polymorphic coupon functionality for your Laravel application.

9.0.2(1y ago)19590.7k—0.7%15[1 PRs](https://github.com/michael-rubel/laravel-couponables/pulls)1MITPHPPHP ^8.1CI failing

Since Feb 11Pushed 1y ago4 watchersCompare

[ Source](https://github.com/michael-rubel/laravel-couponables)[ Packagist](https://packagist.org/packages/michael-rubel/laravel-couponables)[ Docs](https://github.com/michael-rubel/laravel-couponables)[ Fund](https://paypal.com/donate/?hosted_button_id=KHLEL8PFS4AXJ)[ RSS](/packages/michael-rubel-laravel-couponables/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (10)Dependencies (9)Versions (37)Used By (1)

[![Laravel Couponables](https://user-images.githubusercontent.com/37669560/224356302-5c021249-2290-4fb4-8bbe-99fbef4b5df5.png)](https://user-images.githubusercontent.com/37669560/224356302-5c021249-2290-4fb4-8bbe-99fbef4b5df5.png)

Laravel Couponables
===================

[](#laravel-couponables)

[![Latest Version on Packagist](https://camo.githubusercontent.com/6929153ca4b116821fb198f052a26e85058442a9cea4065b1a550786dd7036cc/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6d69636861656c2d727562656c2f6c61726176656c2d636f75706f6e61626c65732e7376673f7374796c653d666c61742d737175617265266c6f676f3d7061636b6167697374)](https://packagist.org/packages/michael-rubel/laravel-couponables)[![Tests](https://camo.githubusercontent.com/5589ed705fe2cb7ebe61b835ec97b9f776e864783fec259d0a73e052cea7d2c3/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f6d69636861656c2d727562656c2f6c61726176656c2d636f75706f6e61626c65732f72756e2d74657374732e796d6c3f6272616e63683d6d61696e267374796c653d666c61742d737175617265266c6162656c3d7465737473266c6f676f3d676974687562)](https://github.com/michael-rubel/laravel-couponables/actions)[![Code Quality](https://camo.githubusercontent.com/e2e445c6f1697ab6a2a8286052f631d2bb8040ea78b25ce4b69bea06cea8ab1e/68747470733a2f2f696d672e736869656c64732e696f2f7363727574696e697a65722f7175616c6974792f672f6d69636861656c2d727562656c2f6c61726176656c2d636f75706f6e61626c65732e7376673f7374796c653d666c61742d737175617265266c6f676f3d7363727574696e697a6572)](https://scrutinizer-ci.com/g/michael-rubel/laravel-couponables/?branch=main)[![Code Coverage](https://camo.githubusercontent.com/24af37f1bd40373a1308b117061b6d6084a6f8e84d5cf3aaa43b6c62ade6b5d1/68747470733a2f2f696d672e736869656c64732e696f2f7363727574696e697a65722f636f7665726167652f672f6d69636861656c2d727562656c2f6c61726176656c2d636f75706f6e61626c65732e7376673f7374796c653d666c61742d737175617265266c6f676f3d7363727574696e697a6572)](https://scrutinizer-ci.com/g/michael-rubel/laravel-couponables/?branch=main)[![Infection](https://camo.githubusercontent.com/4be3c78a228717b461f32bdd5cf7e6e28b52bdd6d4195e80a7c93e29cddcc3d2/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f6d69636861656c2d727562656c2f6c61726176656c2d636f75706f6e61626c65732f696e66656374696f6e2e796d6c3f6272616e63683d6d61696e267374796c653d666c61742d737175617265266c6162656c3d696e66656374696f6e266c6f676f3d706870)](https://github.com/michael-rubel/laravel-couponables/actions)[![Larastan](https://camo.githubusercontent.com/1c959acb9a7517eb2afde4c150e0cf6eebc219abbb3e79d27fee38c56145c371/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f6d69636861656c2d727562656c2f6c61726176656c2d636f75706f6e61626c65732f7068707374616e2e796d6c3f6272616e63683d6d61696e267374796c653d666c61742d737175617265266c6162656c3d6c6172617374616e266c6f676f3d6c61726176656c)](https://github.com/michael-rubel/laravel-couponables/actions)

This package provides coupons/promocodes functionality for your Laravel application leveraging Eloquent's polymorphic relationships.

The package requires `PHP 8.1` or higher and `Laravel 10` or higher.

---

\#StandWithUkraine
------------------

[](#standwithukraine)

[![SWUbanner](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/banner2-direct.svg)](https://github.com/vshymanskyy/StandWithUkraine/blob/main/docs/README.md)

---

Installation
------------

[](#installation)

Install the package using composer:

```
composer require michael-rubel/laravel-couponables
```

Publish the migrations:

```
php artisan vendor:publish --tag="couponables-migrations"
```

Publish the config file:

```
php artisan vendor:publish --tag="couponables-config"
```

---

Usage
-----

[](#usage)

After publishing migrations, apply a trait in the model you want to use as a `$redeemer`:

```
use HasCoupons;
```

---

### Artisan command

[](#artisan-command)

You can add coupons to your database using Artisan command:

```
php artisan make:coupon YourCouponCode
```

Optionally, you can pass the next arguments:

```
'--value'         // The 'value' to perform calculations based on the coupon provided
'--type'          // The 'type' to point out the calculation strategy
'--limit'         // Limit how many times the coupon can be applied by the model
'--quantity'      // Limit how many coupons are available overall (this value will decrement)
'--expires_at'    // Set expiration time for the coupon
'--redeemer_type' // Polymorphic model type. Can as well be morph-mapped value, i.e. 'users'
'--redeemer_id'   // Redeemer model ID
'--data'          // JSON column to store any metadata you want for this particular coupon
```

#### Adding coupons using model

[](#adding-coupons-using-model)

You can as well add coupons simply using model:

```
Coupon::create([
    'code'  => '...',
    'type'  => '...'
    'value' => '...',
    ...
]);
```

- **Note:** `type` and `value` columns are used for cost calculations (this is optional).
    If the `type` column is `null`, the `subtraction` strategy will be chosen.

---

### Basic operations

[](#basic-operations)

Verify the coupon code:

```
$redeemer->verifyCoupon($code);
```

Redeem the coupon:

```
$redeemer->redeemCoupon($code);
```

Redeem the coupon in context of another model:

```
$redeemer
  ->redeemCoupon($code)
  ->for($course);
```

Combined `redeemCoupon` and `for` behavior (assuming the `$course` includes `HasCoupons` trait):

```
$course->redeemBy($redeemer, $code);
```

If something's going wrong, methods `verifyCoupon` and `redeemCoupon` will throw an exception:

```
CouponDisabledException     // Coupon is disabled (`is_enabled` column).
CouponExpiredException      // Coupon is expired (`expires_at` column).
InvalidCouponException      // Coupon is not found in the database.
InvalidCouponTypeException  // Wrong coupon type found in the database (`type` column).
InvalidCouponValueException // Wrong coupon value passed from the database (`value` column).
NotAllowedToRedeemException // Coupon is assigned to the specific model (`redeemer` morphs).
OverLimitException          // Coupon is over the limit for the specific model (`limit` column).
OverQuantityException       // Coupon is exhausted (`quantity` column).
CouponException             // Generic exception for all cases.
```

If you want to bypass the exception and do something else:

```
$redeemer->verifyCouponOr($code, function ($code, $exception) {
    // Your action with $code or $exception!
});
```

```
$redeemer->redeemCouponOr($code, function ($code, $exception) {
    // Your action with $code or $exception!
});
```

### [Redeemer](https://github.com/michael-rubel/laravel-couponables/blob/main/src/HasCoupons.php) checks

[](#redeemer-checks)

Check if this coupon is already used by the model:

```
$redeemer->isCouponAlreadyUsed($code);
```

Check if the coupon is over the limit for the model:

```
$redeemer->isCouponOverLimit($code);
```

### [Coupon](https://github.com/michael-rubel/laravel-couponables/blob/main/src/Models/Coupon.php) checks

[](#coupon-checks)

```
public function isExpired(): bool;
public function isNotExpired(): bool;
public function isDisposable(): bool;
public function isOverQuantity(): bool;
public function isRedeemedBy(Model $redeemer): bool;
public function isOverLimitFor(Model $redeemer): bool;
```

This method references the model assigned to redeem the coupon:

```
public function redeemer(): ?Model;
```

### Calculations

[](#calculations)

```
$coupon = Coupon::create([
    'code'  => 'my-generated-coupon-code-to-use',
    'type'  => CouponContract::TYPE_PERCENTAGE, // 'percentage'
    'value' => '10', // calc(using: 300); // 270.00
```

The package supports three types of item cost calculations:

- `subtraction` - subtracts the given value from the value defined in the coupon model;
- `percentage` - subtracts the given value by the percentage defined in the coupon model;
- `fixed` - completely ignores the given value and takes the coupon model value instead.

Note: you can find constants for coupon types in the [`CouponContract`](https://github.com/michael-rubel/laravel-couponables/blob/main/src/Models/Contracts/CouponContract.php)

### Listeners

[](#listeners)

If you go event-driven, you can handle package events:

- [CouponVerified](https://github.com/michael-rubel/laravel-couponables/blob/main/src/Events/CouponVerified.php)
- [CouponRedeemed](https://github.com/michael-rubel/laravel-couponables/blob/main/src/Events/CouponRedeemed.php)
- [CouponExpired](https://github.com/michael-rubel/laravel-couponables/blob/main/src/Events/CouponExpired.php)
- [CouponIsOverLimit](https://github.com/michael-rubel/laravel-couponables/blob/main/src/Events/CouponIsOverLimit.php)
- [CouponIsOverQuantity](https://github.com/michael-rubel/laravel-couponables/blob/main/src/Events/CouponIsOverQuantity.php)
- [NotAllowedToRedeem](https://github.com/michael-rubel/laravel-couponables/blob/main/src/Events/NotAllowedToRedeem.php)

---

### Extending package functionality

[](#extending-package-functionality)

Traits [DefinesColumns](https://github.com/michael-rubel/laravel-couponables/blob/main/src/Models/Traits/DefinesColumns.php) and [DefinesPivotColumns](https://github.com/michael-rubel/laravel-couponables/blob/main/src/Models/Traits/DefinesPivotColumns.php) contain the methods that define column names to use by the package, so you can use inheritance to override them.

If you need to override the entire classes, use the [config values](https://github.com/michael-rubel/laravel-couponables/blob/main/config/couponables.php) or [container bindings](https://github.com/michael-rubel/laravel-couponables/blob/main/src/CouponableServiceProvider.php). All the classes in the package have their own contract (interface), so you're free to modify it as you wish.

`CouponService` has the `Macroable` trait, This way you can inject the methods to interact with the service without overriding anything.

Contributing
------------

[](#contributing)

If you see any ways we can improve the package, PRs are welcome. But remember to write tests for your use cases.

Testing
-------

[](#testing)

```
composer test
```

###  Health Score

51

—

FairBetter than 96% of packages

Maintenance49

Moderate activity, may be stable

Popularity49

Moderate usage in the ecosystem

Community20

Small or concentrated contributor base

Maturity69

Established project with proven stability

 Bus Factor1

Top contributor holds 97.5% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~35 days

Recently: every ~173 days

Total

34

Last Release

378d ago

Major Versions

4.0.2 → 5.0.02022-07-28

5.0.1 → 6.0.02022-11-22

6.0.0 → 7.0.02022-11-30

7.1.3 → 8.0.02023-06-14

8.0.1 → 9.0.02024-03-15

PHP version history (3 changes)1.0.0PHP ^8.0|^8.1

4.0.1PHP ^8.0

9.0.0PHP ^8.1

### Community

Maintainers

![](https://www.gravatar.com/avatar/9c060c69332d50a7cb290529ad84a7f216dec94d59950db7446dc93208787083?d=identicon)[michael-rubel](/maintainers/michael-rubel)

---

Top Contributors

[![michael-rubel](https://avatars.githubusercontent.com/u/37669560?v=4)](https://github.com/michael-rubel "michael-rubel (273 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (4 commits)")[![syamsoul](https://avatars.githubusercontent.com/u/15118790?v=4)](https://github.com/syamsoul "syamsoul (2 commits)")[![ShamarKellman](https://avatars.githubusercontent.com/u/4120411?v=4)](https://github.com/ShamarKellman "ShamarKellman (1 commits)")

---

Tags

couponcoupon-code-generatorcoupon-servicecouponslaravellooking-for-contributorsphplaravelmichael-rubellaravel-couponables

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/michael-rubel-laravel-couponables/health.svg)

```
[![Health](https://phpackages.com/badges/michael-rubel-laravel-couponables/health.svg)](https://phpackages.com/packages/michael-rubel-laravel-couponables)
```

###  Alternatives

[spatie/laravel-data

Create unified resources and data transfer objects

1.8k28.9M627](/packages/spatie-laravel-data)[spatie/laravel-livewire-wizard

Build wizards using Livewire

4061.0M4](/packages/spatie-laravel-livewire-wizard)[hirethunk/verbs

An event sourcing package that feels nice.

513162.9k6](/packages/hirethunk-verbs)[worksome/exchange

Check Exchange Rates for any currency in Laravel.

123544.7k](/packages/worksome-exchange)[ralphjsmit/livewire-urls

Get the previous and current url in Livewire.

82270.3k4](/packages/ralphjsmit-livewire-urls)[hydrat/filament-table-layout-toggle

Filament plugin adding a toggle button to tables, allowing user to switch between Grid and Table layouts.

6292.3k1](/packages/hydrat-filament-table-layout-toggle)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
