Laravel Discount: Coupons, Limits &amp; Stacking | Mohamed Said       [Skip to content](#main)  [ ![](https://cdn.msaied.com/01KT78WE565VEMM3PSNQAAB0MH.png) Mohamed SaidLaravel Backend Engineer ](https://www.msaied.com/public) - [Home](https://www.msaied.com/public)
- [Projects](https://www.msaied.com/public/projects)
- [Articles](https://www.msaied.com/public/articles)
- [Certificates](https://www.msaied.com/public/certificates)
- [About](https://www.msaied.com/public#about)

           [  Contact](https://www.msaied.com/public#contact) Menu 

Menu
----

Close 

 - [HomeStart here](https://www.msaied.com/public)
- [ProjectsCase studies](https://www.msaied.com/public/projects)
- [ArticlesEngineering notes](https://www.msaied.com/public/articles)
- [CertificatesCredentials](https://www.msaied.com/public/certificates)
- [AboutHow I work](https://www.msaied.com/public#about)
- [ContactGet in touch](https://www.msaied.com/public#contact)

  [Start a conversation](https://www.msaied.com/public#contact) [WhatsApp](https://wa.me/201094619204) [Email](mailto:hello@msaied.com) 

 1. [Home](https://www.msaied.com/public)
2. /
3. [Articles](https://www.msaied.com/public/articles)
4. /
5. [Laravel](https://www.msaied.com/public/articles?category=laravel)
6. /
7. Laravel Discount: Coupon Codes, Usage Limits, and Stacking

   [Laravel](https://www.msaied.com/public/articles?category=laravel) [Composer Pacakge](https://www.msaied.com/public/articles?category=composer-pacakge) 

 Laravel Discount: Coupon Codes, Usage Limits, and Stacking
===========================================================

 Laravel Discount by Milwad Khosravi adds coupon codes, time windows, per-user usage limits, stackable discounts, and cart integration to any Laravel application through a single Eloquent-backed facade.

 ![](https://cdn.msaied.com/01M22N44A70A5MC2S599JP0MPH.webp) [Mohamed Said](https://www.msaied.com/public#person) Published 9 Aug 2026 · Updated 12 Aug 2026 · 4 min read

ShareCopy linkCopied

 ![Laravel Discount: Coupon Codes, Usage Limits, and Stacking](https://cdn.msaied.com/539/74138a5313c0865164df1324379b1df5.png) 

  On this page +1. [Overview](#overview)
2. [Installation](#installation)
3. [Percentage and Fixed Discounts](#percentage-and-fixed-discounts)
4. [Coupon Codes, Expiry, and Usage Limits](#coupon-codes-expiry-and-usage-limits)
5. [Stackable Discounts and Model Attachment](#stackable-discounts-and-model-attachment)
6. [Cart Integration](#cart-integration)
7. [Validation and Exceptions](#validation-and-exceptions)
8. [Key Takeaways](#key-takeaways)

 Overview
--------

Building a discount system from scratch in Laravel means writing the same percentage-vs-fixed logic, expiry checks, and race-condition-safe redemption code over and over. [Laravel Discount](https://github.com/binafy/laravel-discount) by Milwad Khosravi packages all of that into Eloquent models evaluated through a single `LaravelDiscount` facade.

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

The package requires PHP 8.1+ and Laravel 9–13.

```bash
composer require binafy/laravel-discount
php artisan migrate

```

Migrations create `discounts`, `discount_usages`, and `discountables` tables. Publish the config only if you need to change table names, the user model, or code-generation defaults:

```bash
php artisan vendor:publish --tag="laravel-discount-config"

```

Percentage and Fixed Discounts
------------------------------

A discount is a standard Eloquent model. Apply it through the facade and receive a `DiscountResult`:

```php
use Binafy\LaravelDiscount\Enums\DiscountType;
use Binafy\LaravelDiscount\Models\Discount;
use Binafy\LaravelDiscount\Facades\LaravelDiscount;

$discount = Discount::query()->create([
    'name'  => 'Summer Sale',
    'type'  => DiscountType::Percentage,
    'value' => 20,
]);

$result = LaravelDiscount::apply($discount, 200);
// originalAmount: 200.0 | discountAmount: 40.0 | payableAmount(): 160.0

```

Add `max_discount_amount` to cap a percentage discount — the classic "20% off, up to $100" scenario — without hardcoding anything in a controller.

Coupon Codes, Expiry, and Usage Limits
--------------------------------------

Setting a `code` column turns a discount into a promotional coupon. `applyCode()` validates the code and throws `DiscountNotFoundException` on a miss:

```php
$result = LaravelDiscount::applyCode('WELCOME10', 200, $user);

```

Bulk codes are generated with `random_int()`, stripping ambiguous characters like `0`/`O` and `1`/`I`:

```php
LaravelDiscount::generateCode();             // "8FJ2K9QW"
LaravelDiscount::generateCodes(100, 'VIP'); // Collection of 100 unique codes

```

Time windows use `starts_at` and `expires_at`. A `valid()` query scope filters to currently active discounts. Applying outside the window throws typed exceptions (`DiscountNotStartedException`, `DiscountExpiredException`) and fires a `DiscountExpired` event.

Usage limits are enforced at redemption time, not application time, using a database-level increment inside a transaction:

```php
LaravelDiscount::redeem($discount, $user, $result->discountAmount);

```

If two customers claim the last redemption simultaneously, only one succeeds — the database decides. Guests are tracked via session ID instead of a user model.

Stackable Discounts and Model Attachment
----------------------------------------

Mark a discount `is_stackable` and `applyMany()` resolves the optimal combination automatically: it sums all stackable discounts, finds the single best non-stackable one, and returns whichever side saves more.

```php
$result = LaravelDiscount::applyMany([$tenPercent, $tenFixed, $bigSolo], 100);
// $result->discounts  — the codes that actually applied
// $result->discountAmount — the winning total

```

The `HasDiscounts` trait attaches discounts to any Eloquent model via a polymorphic relationship:

```php
class Product extends Model
{
    use HasDiscounts;
}

$product->discounts()->attach($discount);
$result = $product->applyDiscounts($product->price);

```

Cart Integration
----------------

Install the companion `binafy/laravel-cart` package and a `CartDiscount` service handles cart-level and item-level discounts:

```php
$cartDiscount->applyToCart($cart, 'SUMMER-8FJ2K9QW');  // cart total
$cartDiscount->applyToItem($cartItem, $discount);       // single line item
$cartDiscount->applyItemDiscounts($cart);               // all items via HasDiscounts

```

Validation and Exceptions
-------------------------

A `ValidDiscountCode` form-request rule rejects invalid codes before any business logic runs, returning a specific failure reason rather than a generic message. Every failure case has its own exception extending `DiscountException`, each exposing the failing discount via `getDiscount()`:

```php
try {
    $result = LaravelDiscount::applyCode($code, $total, $user);
} catch (DiscountExpiredException $e) {
    return back()->withErrors("Code {$e->getDiscount()->code} has expired.");
} catch (DiscountException $e) {
    return back()->withErrors($e->getMessage());
}

```

Three lifecycle events — `DiscountApplied`, `DiscountRedeemed`, and `DiscountExpired` — carry enough data to drive analytics without additional queries.

Key Takeaways
-------------

- **Two discount types** (`Percentage`, `Fixed`) with an optional `max_discount_amount` cap.
- **Race-condition-safe redemption** via database-level transactional increments.
- **Guest support** through session ID tracking alongside nullable `user_id`.
- **Stacking resolver** automatically picks the combination that saves the customer the most.
- **`HasDiscounts` trait** attaches discounts polymorphically to any Eloquent model.
- **Artisan commands** `discount:generate` and `discount:prune` for terminal and scheduler use.

---

*Source: [Laravel Discount: Coupon Codes, Usage Limits, and Stacking — Laravel News](https://laravel-news.com/laravel-discount)*

- [Laravel](https://www.msaied.com/public/articles?search=Laravel)
- [Packages](https://www.msaied.com/public/articles?search=Packages)
- [E-commerce](https://www.msaied.com/public/articles?search=E-commerce)
- [Coupons](https://www.msaied.com/public/articles?search=Coupons)
- [Discounts](https://www.msaied.com/public/articles?search=Discounts)

 Frequently asked questions 
---------------------------

  How does Laravel Discount prevent two users from claiming the last redemption at the same time?Redemption runs inside a database transaction that increments `used\_count` only when the current count is still below the limit in the WHERE clause. If two requests arrive simultaneously, the database allows only one increment, and the other receives a `DiscountUsageLimitReachedException`.

   How does the stacking resolver decide which discounts to apply?`applyMany()` drops any discount that fails validation, splits the rest into stackable and non-stackable groups, sums the stackable ones (capped at the order total), finds the single best non-stackable discount, and returns whichever side produces the larger saving.

   Can Laravel Discount be used for guest (unauthenticated) users?Yes. Pass a session ID instead of a user model to both `applyCode()` and `redeem()`. The package tracks guest usage in the `session\_id` column of the `discount\_usages` table alongside the nullable `user\_id`.

   ![Mohamed Said](https://cdn.msaied.com/01M22N44A70A5MC2S599JP0MPH.webp)About the author
----------------

[Mohamed Said](https://www.msaied.com/public#person)Senior Backend Engineer specializing in Laravel, scalable SaaS platforms, APIs, and cloud infrastructure. I build secure, high-performance web applications that help businesses grow.

[About](https://www.msaied.com/public#about) [GitHub ↗](https://github.com/EG-Mohamed) [LinkedIn ↗](https://www.linkedin.com/in/msaiedm/) [WhatsApp ↗](https://wa.me/201094619204) [Email Address ↗](mailto:hello@msaied.com) [My CV ↗](https://drive.google.com/file/u/0/d/1MF20IPRJyzfy32mhEutjL5EpSls0w2Q8/view)  

   [Previous articleLaravel Truss: Live Interactive Database ER Diagrams in the Browser](https://www.msaied.com/public/articles/laravel-truss-live-interactive-database-er-diagrams-in-the-browser) [Next articleContextual Binding and Method Injection in Laravel's Service Container](https://www.msaied.com/public/articles/contextual-binding-and-method-injection-in-laravels-service-container-1)  

   On this page
-------------

1. [Overview](#overview)
2. [Installation](#installation)
3. [Percentage and Fixed Discounts](#percentage-and-fixed-discounts)
4. [Coupon Codes, Expiry, and Usage Limits](#coupon-codes-expiry-and-usage-limits)
5. [Stackable Discounts and Model Attachment](#stackable-discounts-and-model-attachment)
6. [Cart Integration](#cart-integration)
7. [Validation and Exceptions](#validation-and-exceptions)
8. [Key Takeaways](#key-takeaways)

 ###  Have a technical challenge?

 Tell me what you’re building. I reply within two working days.

[Start a conversation](https://www.msaied.com/public#contact) 

   Related articles
-----------------

 [ ![](https://cdn.msaied.com/740/cce86edc21eddcbdd2f2454fadaf9c70.png)  · 3 min read### The Pipeline Pattern in Laravel: Custom Pipelines Beyond Middleware

5 Oct 2026 ](https://www.msaied.com/public/articles/the-pipeline-pattern-in-laravel-custom-pipelines-beyond-middleware-1) [ ![](https://cdn.msaied.com/739/2d6897fdcdcf090613f96f72a64b8a78.png)  · 4 min read### MySQL Full-Text Search in Laravel: Indexes, Relevance Scoring, and Boolean Mode

4 Oct 2026 ](https://www.msaied.com/public/articles/mysql-full-text-search-in-laravel-indexes-relevance-scoring-and-boolean-mode) [ ![](https://cdn.msaied.com/738/073696a3fefe18bec825beec5ac658f5.png)  · 4 min read### Laravel Queue Rate-Limited Middleware: Throttling Jobs Without Losing Work

4 Oct 2026 ](https://www.msaied.com/public/articles/laravel-queue-rate-limited-middleware-throttling-jobs-without-losing-work) 

  Have a technical challenge?
----------------------------

Tell me what you’re building. I reply within two working days.

 [Discuss your project ↗](https://www.msaied.com/public#contact) 

  © 2026 Mohamed Said · Built with Laravel, meant to last.Senior Backend Engineer specializing in Laravel, scalable SaaS platforms, APIs, and cloud infrastructure. I build secure, high-performance web applications that help businesses grow.

 - [Home](https://www.msaied.com/public)
- [Articles](https://www.msaied.com/public/articles)
- [Certificates](https://www.msaied.com/public/certificates)
- [GitHub](https://github.com/EG-Mohamed)
- [LinkedIn](https://www.linkedin.com/in/msaiedm/)
- [WhatsApp](https://wa.me/201094619204)
- [Email Address](mailto:hello@msaied.com)
- [My CV](https://drive.google.com/file/u/0/d/1MF20IPRJyzfy32mhEutjL5EpSls0w2Q8/view)
- [Sitemap](https://www.msaied.com/public/sitemap.xml)
