Multi-Currency Support
NexusRMS supports multi-currency billing across all financial documents, allowing you to quote, invoice, and accept payments in your clients' preferred currencies. The system handles exchange rate management, locale-aware formatting, and cross-currency conversion with configurable rounding precision.
Currency setup
Each Currency record defines how a specific currency is displayed, calculated, and maintained. The key fields are:
- code — ISO 4217 currency code (e.g., GBP, USD, EUR). This is the unique identifier used across all financial documents.
- name — Full currency name (e.g., British Pound, US Dollar, Euro)
- symbol — Currency symbol displayed on documents (e.g., £, $, €)
- symbol_position — Whether the symbol appears before or after the amount (e.g., £1,234.56 vs 1.234,56€)
- decimal_separator — Character used for the decimal point (period or comma)
- thousands_separator — Character used for grouping thousands (comma, period, or space)
- decimal_places — Number of decimal places for the currency (typically 2; Japanese Yen uses 0)
Common currencies
NexusRMS includes eight preconfigured currency definitions in the COMMON_CURRENCIES constant, which can be created using the createFromCommon(code, isBase) factory method:
- GBP — British Pound (£, 2 decimal places)
- USD — US Dollar ($, 2 decimal places)
- EUR — Euro (€, 2 decimal places)
- AUD — Australian Dollar (A$, 2 decimal places)
- CAD — Canadian Dollar (C$, 2 decimal places)
- CHF — Swiss Franc (CHF, 2 decimal places)
- JPY — Japanese Yen (¥, 0 decimal places)
- NZD — New Zealand Dollar (NZ$, 2 decimal places)
To add a common currency, call Currency::createFromCommon('USD', false) (or true to set it as the base currency). The factory method automatically configures the symbol, decimal places, and default formatting for the specified code.
Base currency
One currency must be designated as the base currency by setting is_base_currency to true. The base currency serves as the reference point for all exchange rate calculations:
- The base currency always has an exchange_rate of 1.000000
- All other currencies express their exchange rate relative to the base
- Cross-currency conversions route through the base (e.g., EUR to USD converts EUR to GBP first, then GBP to USD)
- Only one currency can be the base at any time; setting a new base automatically clears the flag from the previous base currency
Exchange rates
Each non-base currency has an exchange rate and related management fields:
- exchange_rate — The rate relative to the base currency, stored as a decimal with six decimal places for precision
- exchange_rate_updated_at — Timestamp of the last rate update
- exchange_rate_source — Where the rate was obtained from (e.g., ECB, OpenExchangeRates, manual entry)
Automatic rate updates
NexusRMS can automatically update exchange rates at configurable intervals:
- auto_update_rate — Toggle to enable automatic rate fetching
- update_frequency — How often rates are refreshed: hourly, daily, weekly, or manual
- needsRateUpdate() — Returns true if auto-update is enabled and the configured interval has elapsed since the last update
- updateExchangeRate(newRate) — Sets the new exchange rate and records the update timestamp
The needingUpdate() scope returns all currencies with auto-update enabled that have not been updated within their configured frequency.
Currency conversion
The Currency model provides three conversion methods:
- toBaseCurrency(amount) — Converts an amount from this currency to the base currency by dividing by the exchange rate
- fromBaseCurrency(amount) — Converts an amount from the base currency to this currency by multiplying by the exchange rate
- convertTo(amount, targetCurrency) — Converts an amount from this currency to any other currency. The conversion routes through the base currency: first converting to base, then from base to the target.
Formatting
The format(amount, includeSymbol) method produces locale-aware formatted output using the currency's configured separators, decimal places, and symbol position. For example:
- GBP with symbol: £1,234.56
- EUR with symbol after: 1.234,56€
- JPY with zero decimals: ¥1,234
- Without symbol: 1,234.56
Rounding
Financial precision requires consistent rounding. Each currency has a rounding_method field that controls how amounts are rounded via the roundAmount(amount) method:
- round — Standard mathematical rounding (0.5 rounds up)
- floor — Always rounds down to the nearest unit
- ceil — Always rounds up to the nearest unit
- bankers — Banker's rounding (round half to even), which minimises cumulative rounding bias across many transactions. This is the recommended method for financial applications.
Rounding is applied automatically by the format() method and should be used for all displayed amounts.
Currency on financial documents
The currency field appears on all financial document models:
- Quote — Currency for the quoted amounts
- Invoice — Currency for the invoiced amounts
- Payment — Currency in which payment was received
- CreditNote — Currency for the credited amounts
- Expense — Currency for the expense amounts
- RecurringInvoice — Currency for all generated invoices
The Client model has a currency field that sets the default currency for new documents created for that client. When creating a quote or invoice, the currency defaults to the client's preferred currency or the tenant's base currency if no client preference is set.
Exchange rates are locked at the time a document is created. This means that subsequent rate fluctuations do not affect the amounts on existing quotes and invoices, providing financial certainty for both you and your clients.
Tips
- Set your base currency first — Choose the currency your business primarily operates in (typically GBP for UK companies) and mark it as the base before adding other currencies.
- Use banker's rounding for financial precision — The bankers rounding method (PHP_ROUND_HALF_EVEN) eliminates systematic rounding bias across large numbers of transactions.
- Enable auto-update for active currencies — For currencies you bill in regularly, enable auto_update_rate with a daily frequency to keep rates current without manual intervention.
- Set client-level currency defaults — Configure each client's preferred currency on their client record so it is automatically selected when creating new quotes and invoices.
- Review exchange rates before large invoices — Even with auto-update, verify the current rate before generating a high-value invoice in a foreign currency to avoid unexpected discrepancies.
- Use createFromCommon for quick setup — Rather than manually configuring symbol, separators, and decimal places, use the createFromCommon(code, isBase) factory method for any of the eight preconfigured currencies.
Was this article helpful?