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 neededOn 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.rounding | rounding: argument | Behaviour |
|---|---|---|
half_away_from_zero | \RoundingMode::HalfAwayFromZero | Halves away from zero (the default). |
half_towards_zero | \RoundingMode::HalfTowardsZero | Halves toward zero. |
half_even | \RoundingMode::HalfEven | Halves to the nearest even digit — banker’s rounding. |
half_odd | \RoundingMode::HalfOdd | Halves to the nearest odd digit. |
towards_zero | \RoundingMode::TowardsZero | Always truncates toward zero. |
away_from_zero | \RoundingMode::AwayFromZero | Always rounds away from zero. |
positive_infinity | \RoundingMode::PositiveInfinity | Always rounds up (ceiling). |
negative_infinity | \RoundingMode::NegativeInfinity | Always 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 cryptoBy 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.