webrek/laravel-money
A Laravel package for working with money and currencies in your application. It offers convenient helpers and integrations for formatting, parsing, and managing monetary values safely, helping keep currency handling consistent across models, views, and business logic.
Architecture fit: The package introduces Money as an immutable value object with aggregation and percentage helpers, which fits Laravel applications that need domain-safe monetary calculations. Money::sum(), min(), and max() support reporting and reconciliation workflows, while the sumMoney() Collection macro aligns naturally with Laravel’s collection pipeline. Money::percentage() is useful for simple tax/discount calculations but should not be treated as a full tax engine. The design encourages moving money logic out of controllers and Eloquent models into services/domain layers.
Integration feasibility: Integration cost is low for teams already using Laravel collections and value objects. The Collection macro can be registered globally and used in existing query/collection flows. The main effort is standardizing storage and serialization: monetary amounts should live as integer minor units or decimal strings, not floats. Existing numeric fields need mapping via casts/accessors, and API resources need consistent formatting. Compatibility with existing money libraries, Eloquent casts, and validation rules should be verified before adoption.
Technical risk: The primary risks are currency mixing, rounding behavior, and null propagation. sum()/min()/max() likely require consistent currencies, but the release notes do not state enforcement behavior. Money::percentage() introduces rounding-policy decisions, especially for line-item vs. total-level tax/discount allocation. sumMoney() returning null for empty collections is intentional but can cause type errors if callers expect a zero-value Money object. Large in-memory collections may also create performance/memory pressure compared with database-side aggregation. Float-backed Money implementations would carry precision risk; minor-unit integer storage is safer.
Key questions: Does sum() enforce same-currency inputs and how does it fail on mixed currencies? What rounding mode and allocation strategy does percentage() use? Is percentage inclusive or exclusive of tax, and does it support negative amounts/refunds? Does sumMoney() preserve currency and consistently return null only for empty collections? How does the macro behave with missing keys or mixed value types? What are the Laravel/PHP version constraints and extension requirements (bcmath/gmp)? Does the package provide Eloquent casts, JSON serialization, and validation helpers? What is the semantic-versioning and upgrade policy?
Stack fit: The package is Laravel-native and fits cleanly into service layers, actions, jobs, and API resources. Use it for cart totals, invoice line aggregation, payout reconciliation, tax/discount calculation, and reporting collections. Avoid embedding monetary rules directly in Blade templates or fat models. Pair the package with database columns storing minor units and with Eloquent casts that expose Money objects.
Migration path: Adopt incrementally. Start with read-only reporting paths using sumMoney() and Money::sum() to validate against existing calculations. Then introduce Money and percentage() in new tax/discount features behind tests. Next, migrate write paths and Eloquent casts, running parallel calculations to compare legacy float results with Money results. Finally, remove ad hoc float helpers. Backfill existing data into minor units where needed and use feature flags for high-risk billing flows.
Compatibility: Confirm support for the current Laravel and PHP versions before rollout. Check for conflicts with any existing money package or custom Money class. Verify extension requirements and currency data sources. Test collection macro registration in the application’s service provider and ensure no macro name collisions. Validate behavior across MySQL/PostgreSQL and queue workers. Confirm JSON/API serialization expectations with frontend consumers.
Sequencing: Phase 1: register sumMoney() and use it only in non-critical reporting. Phase 2: add Money casts and use percentage() for new tax/discount calculations with rounding tests. Phase 3: migrate core checkout/invoice calculations and add mixed-currency guardrails. Phase 4: deprecate legacy float-based helpers and document standards. Include tests for empty collections, mixed currencies, rounding boundaries, negative amounts, and large collections before each phase.
Maintenance: The package adds a bounded dependency with a small API surface, but money handling is business-critical. Pin the version and review release notes for changes to rounding, currency enforcement, and macro signatures. Maintain internal conventions for storage format, rounding, and serialization. Currency data and tax rules may require separate ownership even if the package handles arithmetic.
Support: Support burden will center on incorrect totals, tax rounding disputes, and null-related errors from empty collections. Provide shared helpers, code review checklists, and documented behavior for sumMoney() returning null. Finance and accounting stakeholders should validate percentage and rounding behavior before production use. Teams unfamiliar with value objects and minor-unit storage will need guidance.
Scaling: Money::percentage() is constant-time and low risk. Collection aggregation is fine for moderate result sets but scales poorly for very large in-memory collections; prefer database aggregation or chunking for high-volume reporting. min()/max() and sum() over iterables require full iteration. Watch memory usage when eager-loading large relations and summing in PHP. Use query-level sums where possible.
Failure modes: Mixed-currency aggregation may throw or produce invalid totals if not guarded. Empty collections returning null can cause null pointer/type errors in strict callers. Rounding drift can appear when percentages are applied per line vs. per total. Integer overflow is possible for very large minor-unit sums. Incorrect tax-inclusive/exclusive assumptions can produce compliance issues. Serialization mismatches between API and database representations can cause reconciliation errors.
Ramp-up: Laravel developers can adopt the collection macro quickly, but correct money handling requires domain training: minor units, currency codes, rounding modes, and tax semantics. Expect a few days of onboarding for engineering and additional validation time with finance. Start with documented examples for tax, discount, refunds, and empty collections, and pair the rollout with automated tests and a shared money-handling standard.
How can I help you explore Laravel packages today?