gordi256 / laravel-promocodes
Coupons and promotional codes generator
Requires
- php: ^8.2
- illuminate/broadcasting: ^11.0
- illuminate/console: ^11.0
- illuminate/container: ^11.0
- illuminate/database: ^11.0
- illuminate/queue: ^11.0
- illuminate/support: ^11.0
This package is auto-updated.
Last update: 2025-04-26 07:04:20 UTC
README
Coupons and promotional codes generator for Laravel. This package requires Laravel 11.x and PHP 8.1.
Installation
You can install the package via composer:
composer require gordi256/laravel-promocodes
Configuration
You can publish the config file with:
php artisan vendor:publish --tag="laravel-promocodes-config"
This is the contents of the published config file:
return [ 'models' => [ 'promocodes' => [ 'model' => \NagSamayam\Promocodes\Models\Promocode::class, 'table_name' => 'promocodes', 'foreign_id' => 'promocode_id', ], 'users' => [ 'model' => \App\Models\User::class, 'table_name' => 'users', 'foreign_id' => 'user_id', ], 'pivot' => [ 'model' => \NagSamayam\Promocodes\Models\PromocodeUser::class, 'table_name' => 'promocode_user', ], ], 'code_mask' => '**-****-****', 'allowed_symbols' => 'ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789', ];
After you configure this file, publish and run the migrations with:
php artisan vendor:publish --tag="laravel-promocodes-migrations"
php artisan migrate
Now you will need to use AppliesPromocode on your user model.
namespace App\Models; use Illuminate\Foundation\Auth\User as Authenticatable; use NagSamayam\Promocodes\Traits\AppliesPromocode; class User extends Authenticatable { use AppliesPromocode; // }
Usage
It's very easy to use. Methods are combined, so that you can configure promocodes easily.
- Reference
- Creating Promocodes
- Generating Promocodes
- Applying Promocode
- Expiring Promocode
- Applicable Discount
- Note
Reference
Name | Explanation |
---|---|
Mask | Astrisks will be replaced with random symbol |
Characters | Allowed symbols to use in mask replacement |
Type | Promocode type. flat or percent |
Multi use | Define if single code can be used multiple times, by the same user |
Unlimited | Generated code will have unlimited usages |
Bound to user | Define if promocode can be used only one user, if user is not assigned initially, first user will be bound to promocode |
User | Define user who will be initially bound to promocode |
Count | Amount of unique promocodes should be generated |
Usages | Define how many times can promocode be used |
Expiration | DateTime when promocode should be expired. Null means that promocode will never expire |
Details | Array of details which will be retrieved upon apply. discount key for flat type. percent_off key for percent type |
Min order value | Define order minimum value |
Max discount | Define maximum discount to be applied for an order. |
Status | Promocode status. active or inactive. default inactive |
Creating Promocodes
Using class
Combine methods as you need. You can skip any method that you don't need, most of them already have default values. For custom code generation, create
method should have argument. Or you can use createWithCustomCode
with argument. Both the options works.
use NagSamayam\Promocodes\Facades\Promocodes; use NagSamayam\Promocodes\Enums\PromocodeType; use NagSamayam\Promocodes\Enums\PromocodeStatus; Promocodes::mask('AA-***-BB') // default: config('promocodes.code_mask') ->characters('ABCDE12345') // default: config('promocodes.allowed_symbols') ->multiUse() // default: false ->unlimited() // default: false ->boundToUser() // default: false ->user(User::find(1)) // default: null ->count(5) // default: 1 ->expiration(now()->addYear()) // default: null ->details(['percent_off' => 50]) // default: [] ->minOrderValue(500) // default: null ->maxDiscount(5) // default: null ->createdByAdmin(User::find(1)) // default: null ->type(PromocodeType::PERCENT->value) // default: PromocodeType::FLAT->value ->status(PromocodeStatus::ACTIVE->value); // default: 'inactive' ->create(); // default: null Promocodes::multiUse() // default: false ->boundToUser() // default: false ->user(User::find(1)) // default: null ->usages(5) // default: 1 ->expiration(now()->addYear()) // default: null ->details(['discount' => 50]) // default: [] ->minOrderValue(500) // default: null ->maxDiscount(5) // default: null ->createdByAdmin(User::find(1)) // default: null ->type(PromocodeType::FLAT->value) // default: PromocodeType::FLAT->value ->status(PromocodeStatus::ACTIVE->value); // default: 'inactive' ->create('AA-A4C-B1'); // default: null // Custom promo code can be passed // Equivalent to createWithCustomCode('MO-OT2P-897P') method Promocodes::multiUse() // default: false ->boundToUser() // default: false ->user(User::find(1)) // default: null ->usages(5) // default: 1 ->expiration(now()->addYear()) // default: null ->details([ 'percent_off' => 50, 'message' => 'This one is for you. I hope you like it', ]) // default: [] ->minOrderValue(500) // default: null ->maxDiscount(5) // default: null ->createdByAdmin(User::find(1)) // default: null ->type(PromocodeType::PERCENT->value) // default: PromocodeType::FLAT->value ->status(); // default: 'inactive' ->createWithCustomCode('MO-OT2P-897P');
Using helper
There is a global helper function which will do the same as promocodes class. You can use named arguments magic from php 8.1.
use NagSamayam\Promocodes\Enums\PromocodeType; use NagSamayam\Promocodes\Enums\PromocodeStatus; create_promocodes( type: PromocodeType::PERCENT->value, // default: PromocodeType::FLAT->value mask: 'AA-***-BB', // default: config('promocodes.code_mask') characters: 'ABCDE12345', // default: config('promocodes.allowed_symbols') multiUse: true, // default: false unlimited: true, // default: false boundToUser: true, // default: false user: User::find(1), // default: null count: 5, // default: 1 expiration: now()->addYear(), // default: null details: ['percent_off' => 50], // default: [], createdByAdmin: User::find(98), // default: null maxDiscount: 101, // default: null minOrderValue: 1000, // default: null status: PromocodeStatus::ACTIVE->value // default: PromocodeStatus::INACTIVE->value ); create_custom_promocode( code: '66-OMPY-ULZU', type: PromocodeType::FLAT->value, // default: PromocodeType::FLAT->value multiUse: true, // default: false boundToUser: true, // default: false user: User::find(1), // default: null usages: 5, // default: 1 expiration: now()->addYear(), // default: null details: ['discount' => 50], // default: [], createdByAdmin: User::find(98), // default: null maxDiscount: 101, // default: null minOrderValue: 1000 // default: null status: PromocodeStatus::ACTIVE->value // default: PromocodeStatus::INACTIVE->value );
Generating Promocodes
If you want to output promocodes and not save them to database, you can call generate method instead of create.
use NagSamayam\Promocodes\Facades\Promocodes; use NagSamayam\Promocodes\Enums\PromocodeType; use NagSamayam\Promocodes\Enums\PromocodeStatus; Promocodes::mask('AA-***-BB') // default: config('promocodes.code_mask') ->characters('ABCDE12345') // default: config('promocodes.allowed_symbols') ->multiUse() // default: false ->unlimited() // default: false ->boundToUser() // default: false ->user(User::find(1)) // default: null ->count(5) // default: 1 ->expiration(now()->addYear()) // default: null ->details(['percent_off' => 50]) // default: [] ->minOrderValue(500) ->maxDiscount(5) ->createdByAdmin(User::find(1)) ->status(PromocodeStatus::ACTIVE->value) // default: PromocodeStatus::INACTIVE->value ->type(PromocodeType::PERCENT->value) // default: PromocodeType::FLAT->value ->generate();
Applying Promocode
Using class
Combine methods as you need. You can skip any method that you don't need.
use NagSamayam\Promocodes\Facades\Promocodes; Promocodes::code('ABC-DEF') ->user(User::find(1)) // default: null ->apply(['order_id' => '405-6828433-4214765']); // default: null // Good to send unique order ID // Preferbly string format
Using helper
There is a global helper function which will do the same as promocodes class.
apply_promocode( 'ABC-DEF', User::find(1), // default: null, ['order_id' => '405-6828433-4214765'] // default: null // Good to send unique order ID // Preferbly string format );
Exceptions
While trying to apply promocode, you should be aware of exceptions. Most part of the code throws exceptions, when there is a problem:
// NagSamayam\Promocodes\Exceptions\* PromocodeAlreadyUsedByUserException - "The given code `ABC-DEF` is already used by user with id 1." PromocodeBoundToOtherUserException - "The given code `ABC-DEF` is bound to other user, not user with id 1." PromocodeDoesNotExistException - "The given code `ABC-DEF` doesn't exist." | "The code was not event provided." PromocodeExpiredException - "The given code `ABC-DEF` already expired." PromocodeNoUsagesLeftException - "The given code `ABC-DEF` has no usages left." UserHasNoAppliesPromocodeTrait - "The given user model doesn't have AppliesPromocode trait." UserRequiredToAcceptPromocode - "The given code `ABC-DEF` requires to be used by user, not by guest." PromocodeAlreadyExistedException - "The given promocode `10s%discount` is already existed. Please try with a new one." PromocodeAlreadyUsedForOrderException - "The given code `ABC-DEF` is already applied for the order with id 405-6828433-4214765." PromocodeNotAcitveException - "The given promocode `ABC-DEF` is not active. Please try with a new one."
Events
There are two events which are fired upon applying.
// NagSamayam\Promocodes\Events\* GuestAppliedPromocode // Fired when guest applies promocode // It has public variable: promocode UserAppliedPromocode // Fired when user applies promocode // It has public variable: promocode // It has public variable: user
Expiring Promocode
Using helper
There is a global helper function which will expire promocode.
expire_promocode('ABC-DEF');
Update Promocode status
Using class
use NagSamayam\Promocodes\Facades\Promocodes; use NagSamayam\Promocodes\Enums\PromocodeStatus; Promocodes::code('ABC-DEF') ->updatedByAdmin(User::find(6)) ->updateStatus(PromocodeStatus::ACTIVE->value);
Using helper
update_promocode_status('ABC-DEF', PromocodeStatus::ACTIVE->value, User::find(6) );
Trait Methods
If you added AppliesPromocode trait to your user model, you will have some additional methods on user.
$user = User::find(1); $user->appliedPromocodes; // Returns promocodes applied by user $user->boundPromocodes; // Returns promocodes bound to user $user->applyPromocode('ABC-DEF', ['order_id' => '405-6828433-4214765']); // Applies promocode to user
Get applicable discount
There is a way to get the discount to be applied on total order value.
use NagSamayam\Promocodes\Facades\Promocodes; Promocodes::code('ABC-DEF') ->orderTotal(1000) // default: 0 ->getApplicableDiscount($forceCheck = true); // default: false // If false, it will not check for usagesLeft, status and expiry
Testing
Will be added very soon
Changelog
Please see CHANGELOG for more information on what has changed recently.
Contributing
Please see CONTRIBUTING for details.
Security Vulnerabilities
If you discover any security related issues, please email nag.samayam@gmail.com instead of using the issue tracker.
Credits
This package is heavily based on the Laravel Promocodes package from Zura Gabievi. You can find the code on GitHub.
License
The MIT License (MIT). Please see License File for more information.
Note
I have developed this package for my personal use. I made this public. Hope it helps you. Please do not expect the immediate bug fixes. Hope you understand.