Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Cashier Laravel Package

andrey-helldar/cashier

Cashier is a Laravel package that provides a simple, fluent interface for managing user balances and transactions. Integrate it with your Eloquent models to handle deposits, withdrawals, and payment records using clean, expressive code and minimal configuration.

View on GitHub
Deep Wiki
Context7

Getting Started

Name check before anything else. andrey-helldar/cashier is not Laravel Cashier. It is a Composer subtree split of the cashbox/foundation component — a money/currency toolkit from Andrey Helldar's Cashbox family (amounts, currencies, formatting, exchange). If you arrived expecting Stripe subscriptions, billable models, and webhooks, you're in the wrong repo; look at laravel/cashier instead. A surprising amount of day-to-day confusion evaporates once you accept that the name is a historical accident and start reading it as "money primitives for Laravel/PHP."

Install the source of truth, not the split. A subtree split is (in practice) a read-only mirror: commits land in cashbox/foundation and get pushed here mechanically. Issues and PRs belong upstream, and the split's README/changelog is often thinner than the original. For day-to-day work, require the canonical package:

composer require cashbox/foundation

…plus whichever sibling package provides the Laravel integration (service provider, config, facades) for the version you're targeting — check the upstream monorepo README for the exact names in the release line you're on. Confirm what actually resolved with composer show cashbox/foundation and cross-check the version against the 2023-07-09 split tag.

Check compatibility first, because the package is archived. Last release was July 2023 and the repo is frozen. Before designing around it, run composer why-not cashbox/foundation against your current PHP/Laravel constraints. If your app is on a recent PHP/Laravel, you may need a pin, or the package may simply not fit — learn that in ten minutes rather than after a week of integration.

Where to look first, in order:

  1. The README and docs/ in the upstream cashbox/foundation repo — the split often carries a stale or truncated version.
  2. The Money/Currency DTO classes. These define the mental model; everything else is a helper around them.
  3. The formatting layer (formatters / locale handling) — this is the part you'll touch every day.
  4. The exchange-rate abstraction, if you need conversions — it is the piece most likely to require a driver of your own.

First use case to build. The smallest honest slice: take a price stored as an integer minor amount + ISO currency code, wrap it in the package's money object, format it for a given locale, and render it. Then round-trip the same object through one calculation (add tax, multiply by quantity) and format the result. If both outputs match what finance expects, the package earns its place; if the formatter can't produce your required output, you've learned that cheaply.

Implementation Patterns

Store minor units, format at the edge. The value objects want integer minor units plus a currency code. Keep that invariant through the whole app: database columns are BIGINT amount + CHAR(3) currency, models cast to the package's money DTO, and the formatter runs only at the render boundary (Blade components, API resources, PDF templates). Never let a float enter the pipeline "just for the calculation" — convert explicitly and keep the currency attached to every value.

Centralise currency creation. Don't scatter new Currency('USD') through the codebase. A tiny CurrencyFactory/helper that resolves from a config list of enabled currencies gives you one place to add locales, precision, and display symbols — and one place to fix when a symbol or decimal rule is wrong.

Wrap calculations in a service. Money math ("subtotal → discount → tax → total") is business logic, not a package feature. Put it in one class that takes DTOs and returns DTOs; the package supplies primitives, you supply the rules. This is also where you decide rounding strategy per step — round per line item vs. round the total — which materially changes invoices.

Make rounding explicit, never implicit. Every calculation should state its rounding mode and precision. The package knows currency precision; capture it, then decide at each step whether you round. Silent intermediate rounding is the bug you'll chase for weeks.

Put exchange rates behind an interface. If you need conversion, wrap rate retrieval behind your own interface (a DB table you refresh on schedule, or a cached third-party API) and inject it. Don't call a rate API from inside a view. Cache rates with a timestamp, and store the rate used alongside any converted amount so an old invoice is reproducible.

Locale as a parameter, not a global. Always pass the target locale into the formatter. Reading App::getLocale() inside a DTO or formatter makes it untestable and makes queue workers format with whatever locale the worker defaulted to. Default at the controller if you must, but thread the value down.

Testing. Assert on integer amounts and currency codes (1099, 'USD') — not on formatted strings — everywhere except one or two dedicated formatter tests keyed by locale. Keep a fixture table of "amount → expected display" per locale so a formatter or library upgrade shows up as a diff, not a manual review.

Gotchas and Tips

Archived means no fixes. The 2023-07-09 tag is the last one. Newer PHP/Laravel versions, new currency codes (and countries that change currencies), and dependency bumps will not arrive. Treat it as vendored infrastructure: pin exactly, record why, and budget for replacement — the domain is small enough that a hand-rolled Money value object plus NumberFormatter is a realistic fallback if it becomes a liability.

Subtree splits lag, and it's the wrong place to file bugs. The split repo can trail cashbox/foundation, and issues raised here often go unanswered because maintainers work upstream. If you hit a bug, read the upstream commit log rather than trusting split release notes — the splits are mechanical and carry no changelog of their own. The single v2.6.1 note is just a changelog link; scan commits for keywords (currency, precision, format, locale, BC, deprecat) before promoting a bump past staging.

The name traps search and code review. composer require .../cashier pulls a currency library, not a billing one. Put a one-line note in your own README explaining the choice so the next developer doesn't assume you're running Stripe subscriptions. Also grep composer.lock — it's easy to end up with both this and laravel/cashier transitively and mix them up during debugging.

Floating point sneaks in via the database. A FLOAT/DECIMAL column read through an ORM can arrive as float or string depending on driver and casts. Verify the type your model hands the package: DECIMAL as string is fine (parse to integer), float is not. Add a model cast and a test that asserts the type.

Zero- and three-decimal currencies. JPY (0 decimals) and KWD/BHD (3 decimals) break naive amount / 100. Use the package's per-currency precision, not a hardcoded 100. This is the classic invoice-off-by-an-order-of-magnitude bug.

Locale convention vs. currency convention. 1.234,56 € vs $1,234.56 is locale; CHF 1'234.56 is currency convention. They differ, and most formatting bugs are one applied where the other was intended. Test a German and a Swiss locale specifically — apostrophe thousands separators expose string-based hacks immediately.

Negative amounts and rounding direction. Round-half-up and round-half-even disagree on 0.5; discounts and tax adjustments generate exactly those cases. Pin the rounding mode in one place and document it — it will be the first question finance asks.

Don't format inside jobs or logs. Queue workers have no request locale; a formatted amount in a queued receipt or a log line is a future support ticket. Persist and log the integer + currency, and format at the consumer (email template, UI, export).

Temporal boundaries are out of scope. This package does not help with period-end dates, and the name tempts you into subscription-shaped work. If you build anything billing-adjacent on top, store and compare timestamps in UTC yourself — the money package won't catch an off-by-hours entitlement bug around renewals.

Extension points. Use the public DTOs and formatter interfaces rather than subclassing internals — the library is small and was not designed for deep inheritance. For a custom formatter (e.g. your own symbol table), implement the interface and bind it, and keep a test that runs your full production currency list through it so a data change doesn't silently produce blank symbols.

Debugging checklist. At the point of formatting, log the tuple: raw amount, currency code, precision, locale, rounding mode. Nine times out of ten the mismatch is visible there. If output is blank or null, verify the currency code is in the package's known list (unknown codes may fail silently or throw depending on version) and that the locale data the formatter depends on is installed and reachable from the runtime.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels
wazza/laravel-db-encryption
hokny/laravel-generator
vonsogt/backup
jengo/queues
jeremykenedy/laravel-observability
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums