Column.Money (Column v1.0.0)

Copy Markdown View Source

Money formatting and parsing helpers for Column API amounts.

Column represents all monetary amounts as integer cents (or the smallest currency unit). This module provides helpers for converting between cents and display strings, and for formatting amounts for API payloads.

Examples

iex> Column.Money.to_cents(10.50, "USD")
1050

iex> Column.Money.from_cents(1050, "USD")
"10.50"

iex> Column.Money.format(100_000, "USD")
"$1,000.00"

iex> Column.Money.format(100_000, "EUR")
"€1,000.00"

iex> Column.Money.to_cents(0.10, "USD")
10

Note on floating-point

Avoid using floats for financial amounts in production. Where possible, accept integer cents from your UI layer and skip conversion altogether. If you must convert, use Decimal (add the :decimal dep):

Decimal.new("10.50")
|> Decimal.mult(100)
|> Decimal.round(0)
|> Decimal.to_integer()
# => 1050

Summary

Functions

Return the number of decimal places for a currency.

Return currency metadata (symbol, decimals). Defaults to 2 decimal places for unknown currencies.

Format cents as a human-readable currency string with symbol.

Convert integer cents to a decimal string.

Convert a float or integer amount to integer cents.

Returns true if the amount is a valid positive integer cent amount.

Types

cents()

@type cents() :: non_neg_integer()

currency()

@type currency() :: String.t()

Functions

currency_decimals(currency)

@spec currency_decimals(currency()) :: non_neg_integer()

Return the number of decimal places for a currency.

currency_info(currency)

@spec currency_info(currency()) :: %{symbol: String.t(), decimals: non_neg_integer()}

Return currency metadata (symbol, decimals). Defaults to 2 decimal places for unknown currencies.

format(cents, currency)

@spec format(cents(), currency()) :: String.t()

Format cents as a human-readable currency string with symbol.

Column.Money.format(100_000, "USD")  # => "$1,000.00"
Column.Money.format(500, "EUR")      # => "€5.00"

from_cents(cents, currency)

@spec from_cents(cents(), currency()) :: String.t()

Convert integer cents to a decimal string.

Column.Money.from_cents(1050, "USD")  # => "10.50"
Column.Money.from_cents(100, "JPY")   # => "100"

to_cents(amount, currency)

@spec to_cents(number(), currency()) :: cents()

Convert a float or integer amount to integer cents.

Uses banker's rounding (round-half-to-even) to minimise cumulative error.

Column.Money.to_cents(10.50, "USD")  # => 1050
Column.Money.to_cents(1000, "USD")   # => 1000 (already cents)

valid_amount?(amount)

@spec valid_amount?(term()) :: boolean()

Returns true if the amount is a valid positive integer cent amount.