mimisk / laravel-quotes
Simple quote utilities for Laravel applications.
Requires
- php: ^8.4
- illuminate/support: ^12.0|^13.0
Requires (Dev)
- larastan/larastan: ^3.0
- orchestra/testbench: ^10.0|^11.0
- pestphp/pest: ^4.0
- pestphp/pest-plugin-laravel: ^4.0
This package is auto-updated.
Last update: 2026-04-26 06:36:11 UTC
README
A lightweight Laravel package that provides quote helpers with config-driven defaults.
Installation
Via Composer
composer require mimisk/laravel-quotes
Usage
Publish config (optional):
php artisan vendor:publish --tag=quotes-config
Create a quote (owner can be any morphable Eloquent model, e.g. Customer):
use Mimisk\LaravelQuotes\Actions\CreateQuoteAction; use Mimisk\LaravelQuotes\DTOs\QuoteData; $quote = app(CreateQuoteAction::class)->handle(QuoteData::fromArray([ 'owner' => $customer, 'title' => 'Customer Products Quote', 'currency' => 'EUR', 'discount_type' => 'fixed', // fixed | percentage 'discount_value' => 50, 'items' => [ [ 'name' => 'Product A', 'quantity' => 2, 'unit_price' => 120, 'tax_rate' => 24, ], [ 'name' => 'Product B', 'quantity' => 1, 'unit_price' => 85, 'tax_rate' => 24, ], ], ]));
Update a draft quote:
use Mimisk\LaravelQuotes\Actions\UpdateQuoteAction; use Mimisk\LaravelQuotes\DTOs\QuoteData; app(UpdateQuoteAction::class)->handle( $quote, QuoteData::fromArray([ 'owner' => $customer, 'title' => 'Updated Customer Quote', 'items' => [ [ 'name' => 'Product A (Updated)', 'quantity' => 3, 'unit_price' => 110, 'tax_rate' => 24, ], ], ]) );
Status transitions:
use Mimisk\LaravelQuotes\Actions\AcceptQuoteAction; use Mimisk\LaravelQuotes\Actions\ExpireQuoteAction; use Mimisk\LaravelQuotes\Actions\RejectQuoteAction; use Mimisk\LaravelQuotes\Actions\SendQuoteAction; app(SendQuoteAction::class)->handle($quote); // draft -> sent app(AcceptQuoteAction::class)->handle($quote); // sent -> accepted app(RejectQuoteAction::class)->handle($quote); // sent -> rejected app(ExpireQuoteAction::class)->handle($quote); // sent -> expired
Delete a quote:
use Mimisk\LaravelQuotes\Actions\DeleteQuoteAction; app(DeleteQuoteAction::class)->handle($quote); // only draft or rejected
Error Handling
Actions may throw domain exceptions when an invalid operation is attempted.
For example, trying to accept a quote that is not in the sent state will throw an InvalidQuoteTransition exception.
You can handle these exceptions using a simple try/catch:
use Mimisk\LaravelQuotes\Exceptions\InvalidQuoteTransition; try { app(AcceptQuoteAction::class)->handle($quote); } catch (InvalidQuoteTransition $exception) { return back()->with('error', $exception->getMessage()); }
Alternatively, you may handle these exceptions globally using Laravel's exception handler:
// bootstrap/app.php use Mimisk\LaravelQuotes\Exceptions\InvalidQuoteTransition; ->withExceptions(function ($exceptions) { $exceptions->render(function (InvalidQuoteTransition $exception) { return back()->with('error', $exception->getMessage()); }); })
Quote Expiration Automation
The package provides an Artisan command to automatically expire quotes based on the valid_until field.
Run the command manually:
php artisan quotes:expire
The command will find all sent quotes where valid_until has passed and mark them as expired.
You may schedule it in your application using Laravel's scheduler:
use Illuminate\Support\Facades\Schedule; Schedule::command('quotes:expire')->daily();
You can adjust the frequency as needed:
Schedule::command('quotes:expire')->hourly();
Events
The package dispatches the following events:
QuoteCreatedQuoteUpdatedQuoteSentQuoteAcceptedQuoteRejectedQuoteExpired
Change log
Please see the CHANGELOG for more information on what has changed recently.
Testing
composer test
Security
If you discover any security related issues, please email mimisk88@gmail.com instead of using the issue tracker.
Credits
License
MIT. Please see the LICENSE file for more information.