hasyirin/laravel-running-number

Sequential, zero-padded, formatted running numbers for Laravel — with resets, gap-safe concurrency, and skip/undo support.

Maintainers

Package info

github.com/hasyirin/laravel-running-number

pkg:composer/hasyirin/laravel-running-number

Transparency log

Fund package maintenance!

Hasyirin

Statistics

Installs: 3

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v2.0.0 2026-07-26 11:40 UTC

This package is auto-updated.

Last update: 2026-07-26 11:41:49 UTC


README

Latest Version on Packagist GitHub Tests Action Status GitHub Code Style Action Status Total Downloads

A Laravel package for generating sequential, zero-padded running numbers — invoice numbers, permit numbers, or any other per-type counter that needs to reset on a schedule. Numbers are generated under a database row lock for gap-safe concurrency, and issued or reserved numbers can be skipped or undone without breaking the sequence.

Installation

You can install the package via composer:

composer require hasyirin/laravel-running-number

You can publish and run the migrations with:

php artisan vendor:publish --tag="laravel-running-number-migrations"
php artisan migrate

You can publish the config file with:

php artisan vendor:publish --tag="laravel-running-number-config"

This is the contents of the published config file:

<?php

use Hasyirin\RunningNumber\Enums\ResetInterval;
use Hasyirin\RunningNumber\Enums\UndoMode;

return [

    // If true, generate() silently registers an unknown type using the defaults below
    // instead of throwing RunningNumberTypeNotRegistered.
    'auto_register' => false,

    'default_padding' => 5,

    'default_interval' => ResetInterval::NEVER,

    'default_format' => '{number}',

    // null = fall back to config('app.timezone').
    'default_timezone' => null,

    'default_undo_mode' => UndoMode::RECLAIM,

    // Statically-declared types, upserted into the database by:
    //   php artisan running-number:sync
    'types' => [
        // 'invoice' => [
        //     'padding' => 4,
        //     'interval' => ResetInterval::YEARLY,
        //     'resetMonth' => 12,
        //     'resetDay' => 14,
        // ],
    ],

];

Usage

Every type (e.g. 'invoice', 'permit') must be registered before you can generate numbers for it — either at runtime with register(), or declaratively via the running-number.types config array kept in sync with php artisan running-number:sync.

Generating

use Hasyirin\RunningNumber\Facades\RunningNumber;
use Hasyirin\RunningNumber\Enums\ResetInterval;

RunningNumber::for('invoice')->register(interval: ResetInterval::YEARLY, padding: 4);

RunningNumber::generate('invoice'); // "0001"
RunningNumber::generate('invoice'); // "0002"

Anchored resets

Reset boundaries aren't limited to calendar year/month/week starts. Pass resetMonth / resetDay (or resetWeekday / resetHour for weekly/daily intervals) to anchor the reset to any recurring date — for example, a yearly counter that resets every December 14th instead of January 1st:

RunningNumber::for('invoice')->register(
    interval: ResetInterval::YEARLY,
    resetMonth: 12,
    resetDay: 14,
    padding: 4,
);

Skipping and undoing numbers

skip() reserves numbers so generate() steps over them instead of reissuing them; useSkipped() later formats one of those reserved numbers for actual use. undo() reclaims an already-issued number so the next generate() call reuses it before incrementing further.

$pending = RunningNumber::for('invoice');

$pending->skip(6, 'test');
$pending->useSkipped(6); // "0006"

$pending->undo(2, 'voided');
$pending->generate(); // "0002" — reclaimed before a fresh number is issued

Testing with fake()

Swap the manager for an in-memory fake so your tests don't touch the database, then assert on what was generated:

RunningNumber::fake();

$result = RunningNumber::generate('invoice');

RunningNumber::assertGenerated('invoice', times: 1);

Testing

composer test

Changelog

Please see CHANGELOG for more information on what has changed recently.

Contributing

Please see CONTRIBUTING for details.

Security Vulnerabilities

Please review our security policy on how to report security vulnerabilities.

Credits

License

The MIT License (MIT). Please see License File for more information.