azaharizaman / laravel-serial-numbering
A Laravel 12 Composer package for configurable serial number generation with optional audit logging and model integration.
Installs: 7
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 0
pkg:composer/azaharizaman/laravel-serial-numbering
Requires
- php: ^8.1
- illuminate/console: ^12.0
- illuminate/database: ^12.0
- illuminate/support: ^12.0
Requires (Dev)
- phpunit/phpunit: ^10.5
README
A powerful Laravel 12 package for generating configurable serial numbers with dynamic segments, auto-reset rules, and comprehensive audit logging. Perfect for invoices, orders, tickets, and any entity requiring unique sequential identifiers.
Features
- ๐ฏ Pattern-Based Generation - Create serial numbers using dynamic segments like
{year},{month},{number}, and custom model properties - ๐ Auto-Reset Rules - Configure daily, weekly, monthly, yearly, or custom interval resets
- ๐ Concurrency Safe - Built-in atomic locks prevent race conditions in high-traffic environments
- ๐ Audit Logging - Track every serial number generation with user information and timestamps
- โ Uniqueness Enforcement - Automatic collision detection and prevention
- ๐๏ธ Serial Voiding - Soft-delete approach for cancelled or erroneous serials
- ๐งฉ Eloquent Integration - Simple trait for seamless model integration
- ๐ Extensible - Register custom segment resolvers for specialized patterns
- ๐งช Well Tested - Comprehensive test suite included
Installation
Install via Composer:
composer require azaharizaman/controlled-number
Publish the configuration file:
php artisan vendor:publish --tag=serial-pattern-config
Run migrations:
php artisan migrate
Quick Start
1. Configure Patterns
Edit config/serial-pattern.php:
'patterns' => [ 'invoice' => [ 'pattern' => 'INV-{year}-{month}-{number}', 'start' => 1000, 'digits' => 5, 'reset' => 'monthly', 'interval' => 1, ], 'order' => [ 'pattern' => 'ORD-{year}{month}{day}-{number}', 'start' => 1, 'digits' => 4, 'reset' => 'daily', ], ],
2. Use in Models
Add the trait to your Eloquent model:
use AzahariZaman\ControlledNumber\Traits\HasSerialNumbering; use Illuminate\Database\Eloquent\Model; class Invoice extends Model { use HasSerialNumbering; protected $serialPattern = 'invoice'; protected $serialColumn = 'invoice_number'; protected $fillable = ['invoice_number', 'amount', 'customer_id']; }
3. Generate Serials
Serials are generated automatically on model creation:
$invoice = Invoice::create([ 'amount' => 1500.00, 'customer_id' => 1, ]); echo $invoice->invoice_number; // INV-2024-10-01000
Or generate manually:
use AzahariZaman\ControlledNumber\Services\SerialManager; $manager = app(SerialManager::class); $serial = $manager->generate('invoice');
Available Segments
Built-in Date/Time Segments
{year}- Four-digit year (e.g., 2024){year_short}- Two-digit year (e.g., 24){month}- Two-digit month (01-12){month_name}- Short month name (Jan-Dec){day}- Two-digit day (01-31){hour}- Two-digit hour (00-23){minute}- Two-digit minute (00-59){second}- Two-digit second (00-59){week}- ISO week number (01-53){quarter}- Quarter number (1-4){timestamp}- Unix timestamp
Model Property Segments
Use dot notation to access model properties and relationships:
'pattern' => 'INV-{year}-{department.code}-{number}'
Custom Segments
Register custom segment resolvers in config/serial-pattern.php:
'segments' => [ 'custom.branch' => \App\Segments\BranchCodeResolver::class, ],
Create your resolver:
namespace App\Segments; use AzahariZaman\ControlledNumber\Contracts\SegmentInterface; use Illuminate\Database\Eloquent\Model; class BranchCodeResolver implements SegmentInterface { public function resolve(?Model $model = null, array $context = []): string { return auth()->user()->branch->code ?? 'HQ'; } public function getName(): string { return 'custom.branch'; } public function validate(): bool { return true; } }
Reset Types
Configure automatic counter resets:
never- Counter never resetsdaily- Reset at midnight each dayweekly- Reset at start of each weekmonthly- Reset on first day of each monthyearly- Reset on January 1stinterval- Reset after specified number of days
'invoice' => [ 'pattern' => 'INV-{year}{month}-{number}', 'reset' => 'monthly', 'interval' => 1, // Required for 'interval' reset type ],
Advanced Usage
Preview Serial Numbers
Preview the next serial without generating it:
$manager = app(SerialManager::class); $preview = $manager->preview('invoice');
Or in a model:
$nextSerial = $invoice->previewSerialNumber();
Void Serial Numbers
Mark a serial as void (soft delete for audit purposes):
$manager->void('INV-2024-10-01000', 'Duplicate invoice'); // Or via model $invoice->voidSerial('Customer cancelled order');
Manual Reset
Reset a sequence counter manually:
$manager->resetSequence('invoice'); // Reset to configured start value $manager->resetSequence('invoice', 5000); // Reset to specific value
Export Audit Logs
use AzahariZaman\ControlledNumber\Helpers\SerialHelper; // Export to CSV $csv = SerialHelper::exportToCsv([ 'pattern' => 'invoice', 'start_date' => '2024-01-01', 'end_date' => '2024-12-31', ]); // Export to JSON $json = SerialHelper::exportToJson(['is_void' => false]);
Pattern Statistics
$stats = SerialHelper::getPatternStats('invoice'); /* [ 'pattern' => 'invoice', 'total' => 1523, 'active' => 1487, 'voided' => 36, 'void_rate' => 2.36, ] */
Artisan Commands
Validate Patterns
Check all configured patterns for errors:
php artisan serial:validate-patterns
Validate a specific pattern:
php artisan serial:validate-patterns --pattern=invoice
Show statistics:
php artisan serial:validate-patterns --stats
Query Scopes
The SerialLog model provides useful query scopes:
use AzahariZaman\ControlledNumber\Models\SerialLog; // Get active serials $active = SerialLog::active()->get(); // Get voided serials $voided = SerialLog::voided()->get(); // Filter by pattern $invoices = SerialLog::forPattern('invoice')->get(); // Filter by user $userSerials = SerialLog::byUser(auth()->id())->get(); // Filter by date range $recent = SerialLog::betweenDates('2024-10-01', '2024-10-31')->get();
Configuration
Disable Logging
'logging' => [ 'enabled' => false, 'track_user' => false, ],
Concurrency Settings
'lock' => [ 'enabled' => true, 'timeout' => 10, // seconds 'store' => 'redis', // cache store for locks ],
Testing
Run the test suite:
composer test
Security
Serial logs cannot be deleted for audit trail integrity. Attempting to delete will throw SerialDeletionNotAllowedException.
Changelog
Please see CHANGELOG for more information on recent changes.
Contributing
Contributions are welcome! Please see CONTRIBUTING for details.
Credits
License
The MIT License (MIT). Please see License File for more information.
Support
- Documentation: Full documentation
- Issues: GitHub Issues
- Email: azaharizaman@gmail.com