NewWe open-sourced 50+ Laravel packages
Custom AI apps, agents and automation — Roundly ConsultingRoundly
All packages
Credits for Laravel

Fractional credits & display

Credits are stored as whole integers to avoid floating-point drift. To represent fractional credits, treat the stored value as minor units and set scale to the number of decimal places they represent — with scale = 2, a stored 150 means 1.50 credits. Store and deduct the minor units; storage stays a bigInteger and the core math is unchanged.

Display helpers

Credits::for($user)->format() formats one bucket’s balance and Credits::format() any integer amount. Both return a locale-free plain decimal string — no thousands separators or locale formatting; wrap the result with Laravel’s Number helper if you need that:

config(['credits.scale' => 2]);

Credits::for($user)->format();                        // the default bucket's balance, e.g. "1234.50"
Credits::for($user)->bucket('promotional')->format(scale: 0, rounding: \RoundingMode::HalfEven);

Credits::format(123450);                              // "1234.50" — any integer amount, no model needed

On the model, displayCreditsBalance() and displayCredits() are the trait forms:

config(['credits.scale' => 2]);

$user->modifyCredits(123450);            // stores 123450 minor units

$user->displayCreditsBalance();          // "1234.50"  (a single bucket's balance)
$user->displayCredits(123450);           // "1234.50"  (format any integer amount)
$user->displayCredits(-123450);          // "-1234.50"
$user->displayCredits(5);                // "0.05"

Scale and rounding overrides

Every helper takes an optional per-call scale (the decimal places to render) and rounding mode. When the requested scale is smaller than the stored scale, the dropped digits are rounded once using the mode — a native \RoundingMode, defaulting to config('credits.rounding'). displayCreditsBalance() also accepts a point in time:

$user->displayCredits(123450, scale: 0);                                          // "1235"
$user->displayCredits(123450, scale: 0, rounding: \RoundingMode::HalfTowardsZero); // "1234"
$user->displayCredits(1250, scale: 0, rounding: \RoundingMode::HalfEven);          // "12"
$user->displayCredits(1350, scale: 0, rounding: \RoundingMode::HalfEven);          // "14"

$user->displayCreditsBalance(bucket: 'promotional', scale: 0, at: now()->subWeek());

Every rounding mode, by its config name:

credits.roundingrounding: argumentBehaviour
half_away_from_zero\RoundingMode::HalfAwayFromZeroHalves away from zero (the default).
half_towards_zero\RoundingMode::HalfTowardsZeroHalves toward zero.
half_even\RoundingMode::HalfEvenHalves to the nearest even digit — banker’s rounding.
half_odd\RoundingMode::HalfOddHalves to the nearest odd digit.
towards_zero\RoundingMode::TowardsZeroAlways truncates toward zero.
away_from_zero\RoundingMode::AwayFromZeroAlways rounds away from zero.
positive_infinity\RoundingMode::PositiveInfinityAlways rounds up (ceiling).
negative_infinity\RoundingMode::NegativeInfinityAlways rounds down (floor).

Exact at any size

A display scale larger than the stored scale renders exactly — the rescale runs on arbitrary-precision integer strings in money-for-laravel, so even PHP_INT_MAX never degrades to a float:

config(['credits.scale' => 0]);

$user->displayCredits(PHP_INT_MAX, scale: 6); // "9223372036854775807.000000"

Display scales are capped at 36 decimal places; a negative display scale is treated as zero.

Displaying totals

There are no dedicated display-total methods — compose them from the totals:

$user->displayCredits($user->totalCreditsBalance());                               // formatted grand total
$user->displayCredits($user->creditsBalanceForBuckets(['promotional', 'purchased']));

Show your open-source love

This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.

More ways to support, including crypto

By donating, you agree to our donation terms.

Want this built into your product?

We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.