ekyna/sale
Laravel/PHP interfaces and traits for sales management. Provides core abstractions to model and manage sale workflows and related behaviors (e.g., timestampable traits). Lightweight component intended for integration into larger commerce/payment systems.
Installation
composer require ekyna/sale
Add the service provider to config/app.php:
'providers' => [
// ...
Ekyna\Sale\SaleServiceProvider::class,
],
Publish Config
php artisan vendor:publish --provider="Ekyna\Sale\SaleServiceProvider" --tag="config"
Locate the config file at config/sale.php and adjust discount rules, tax settings, or currency defaults.
First Use Case: Basic Sale Creation
use Ekyna\Sale\Sale;
$sale = new Sale();
$sale->addItem('Product A', 10.00, 2); // name, unit price, quantity
$sale->calculateTotal();
echo $sale->getTotal(); // Outputs: 20.00
Sale class: Core class for managing sales, discounts, and taxes.SaleRepository: Interface for persisting sales (if using database integration).'discounts' => [
'bulk' => [
'condition' => ['quantity' => 5],
'value' => 0.1, // 10% discount
],
],
$sale = new Sale();
$sale->addItem('Product B', 5.00, 6); // Quantity triggers bulk discount
$sale->applyDiscounts();
echo $sale->getDiscountedTotal(); // Outputs: ~$27.00 (after 10% off)
'taxes' => [
'default' => 0.08, // 8% tax
'exempt' => [123], // Product IDs exempt from tax
],
$sale->calculateTaxes();
echo $sale->getTaxAmount(); // Outputs: tax amount
sale.created or sale.updated for post-sale logic.
Event::listen('sale.created', function ($sale) {
// Send notification, log, etc.
});
SaleResource (if using Laravel API tools).SaleRepository to persist sales to a sales table.| Use Case | Implementation |
|---|---|
| Cart System | Extend Sale to track items pre-purchase. |
| Checkout Flow | Use Sale to compute totals before DB commit. |
| Reporting | Query sales table for analytics. |
| Multi-Currency | Override getTotal() to handle currency conversion. |
Deprecated Package
No Built-in Database Schema
sales table. Example:
Schema::create('sales', function (Blueprint $table) {
$table->id();
$table->decimal('total', 8, 2);
$table->decimal('tax', 8, 2);
$table->json('items'); // Store items as JSON
$table->timestamps();
});
Discount/Tax Logic in Config
Sale class to add runtime logic:
class CustomSale extends Sale {
public function applyCustomDiscount() {
if ($this->getTotal() > 1000) {
$this->addDiscount(0.15); // 15% for large orders
}
}
}
Floating-Point Precision
bcmath or round() for financial calculations to avoid precision errors:
$total = bcdiv($sale->getTotal(), '1', 2); // Round to 2 decimal places
Enable Logging
Add to config/sale.php:
'debug' => env('SALE_DEBUG', false),
Logs calculations to storage/logs/sale.log.
Test Discounts/Taxes
Temporarily set debug: true to inspect applied rules:
$sale->setDebug(true);
$sale->calculateTotal();
// Check logs for breakdown of discounts/taxes.
Custom Calculations
Override methods like calculateTotal() or applyDiscounts() in a child class.
Payment Integration
Hook into sale.paid event to sync with payment gateways:
Event::listen('sale.paid', function ($sale, $paymentMethod) {
// Update order status, trigger webhooks, etc.
});
Localization
Extend SaleFormatter to customize currency/tax displays:
class CustomFormatter extends SaleFormatter {
public function formatCurrency($amount) {
return '$' . number_format($amount, 2, ',', '.');
}
}
Testing
Use mock SaleRepository for unit tests:
$repository = Mockery::mock(SaleRepository::class);
$sale = new Sale($repository);
How can I help you explore Laravel packages today?