laravel-quotes maintained by mimisk
LaravelQuotes
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.