You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
45 lines
1.4 KiB
45 lines
1.4 KiB
<?php
|
|
|
|
namespace App\Domains\Billing\Actions\Invoicing;
|
|
|
|
use App\Domains\Billing\Models\Invoice;
|
|
use Illuminate\Support\Facades\DB;
|
|
use Illuminate\Support\Str;
|
|
use Throwable;
|
|
|
|
class GenerateInvoiceCode
|
|
{
|
|
/**
|
|
* @throws Throwable
|
|
*/
|
|
public function execute(int $clientId, ?string $prefix = null): string
|
|
{
|
|
$token = $prefix ? strtoupper(Str::slug($prefix)) : "C{$clientId}";
|
|
$yearMonth = now()->format('Ym');
|
|
|
|
$basePrefix = sprintf('INV-%s-%s-', $token, $yearMonth);
|
|
|
|
return DB::transaction(function () use ($basePrefix) {
|
|
// Find the last generated code with lock
|
|
$lastInvoice = Invoice::query()
|
|
->where('code', 'LIKE', "{$basePrefix}%")
|
|
->lockForUpdate()
|
|
->orderByDesc('id')
|
|
->first();
|
|
|
|
if (! $lastInvoice) {
|
|
$nextSequence = 1;
|
|
} else {
|
|
// Extract sequence number from the tail end of string
|
|
$parts = explode('-', $lastInvoice->code);
|
|
$lastSequence = (int) end($parts);
|
|
$nextSequence = $lastSequence + 1;
|
|
}
|
|
|
|
// Zero-pad sequence to 5 digits (e.g., 00001, 00002)
|
|
$paddedSequence = str_pad((string) $nextSequence, 5, '0', STR_PAD_LEFT);
|
|
|
|
return $basePrefix . $paddedSequence;
|
|
});
|
|
}
|
|
}
|
|
|