Tutorial last revisioned on March 17, 2024 with Laravel 11
When working with invoices, you need to deal with serial numbers that look like ABC-000001. Do you know how to auto-generate them in Laravel? This tutorial will cover a few ways to do this.

DB Structure
For our example, we will use a simple invoice DB table with the following columns:
-
id -
user_id -
due_date -
amount -
serial- Full serial number likeABC-1 -
serial_number- Serial number like1 -
serial_series- Serial series likeABC
Here's how that looks in our migration:
Migration
Schema::create('invoices', function (Blueprint $table) { $table->id(); $table->foreignIdFor(User::class)->constrained(); $table->date('due_date'); $table->integer('amount'); $table->string('serial')->nullable(); $table->string('serial_series'); $table->integer('serial_number')->nullable(); $table->timestamps();});
This makes our Model look like this:
app/Models/Invoice.php
use Illuminate\Database\Eloquent\Casts\Attribute;use Illuminate\Database\Eloquent\Factories\HasFactory;use Illuminate\Database\Eloquent\Model;use Illuminate\Database\Eloquent\Relations\BelongsTo; class Invoice extends Model{ use HasFactory; protected $fillable = [ 'user_id', 'due_date', 'amount', 'serial', 'serial_number', 'serial_series', ]; protected function amount(): Attribute { return Attribute::make( get: fn($value) => $value / 100, set: fn($value) => $value * 100, ); } public function user(): BelongsTo { return $this->belongsTo(User::class); }}
Create Invoice: Form
Let's create the Controller methods to save a new invoice and auto-generate the serial number.
This is the form, with series options coming from the config.
app/Http/Controllers/InvoiceController.php
use App\Http\Requests\StoreInvoiceRequest;use App\Models\Invoice;use App\Models\User; class InvoiceController extends Controller{ public function create() { $users = User::pluck('name', 'id'); $invoiceSeries = config('invoiceSettings.availableInvoiceSeries'); return view('invoices.create', [ 'users' => $users, 'invoiceSeries' => $invoiceSeries, ]); }}
These are the config values:
config/invoiceSettings.php
return [ 'availableInvoiceSeries' => [ 'ABC', 'DAF', 'GHI', 'UKS' ],];
And here's the form in...
Premium Members Only
This advanced tutorial is available exclusively to Laravel Daily Premium members.
Already a member? Login here
Premium membership includes:
Is there a way to make it restart every year? 0001-2022 0002-2022 .... 0160-2022 0001-2023
yes!
Set your serial series to the year and that's it!
For example in config file set it to now("Y")
like this?
return [ 'availableInvoiceSeries' => [ now("Y"); ], ];
Yes, just without typos:
Of course, this will be the only selection in the dropdown, but you can make it a hidden field instead of select (if you don't need to select the series)
thank you very much for your help
Hello
Hi,
Verry usefull, i found this for primary, would this avoid using the job? I mean if some of the columns used is autoincrement. https://laravel.com/api/10.x/Illuminate/Database/Schema/Blueprint.html#method_primary
The main purpose of the job is not only to avoid the issue with repeating numbers, but to also solve the problem of re-trying the job.
Imagine, you have an index that's unique (mentioned in 3rd option) and when trying to create the invoice - it fails. Then you have to manually re-try the saving with a new number. Job does by itself.
Also, auto-increment is okay, but it would not be PER each of the series, so that causes other issues where gaps will appear. And gaps are pretty bad!
What about soft deleted records? how to deal with them? here:
You can add withTrashed() and that will cover it