View Source Money (Money v5.18.0)

Money implements a set of functions to store, retrieve, convert and perform arithmetic on a Money.t/0 type that is composed of a currency code and a decimal currency amount.

Money is very opinionated in the interests of serving as a dependable library that can underpin accounting and financial applications.

This opinion expressed by ensuring that:

  1. Money must always have both a amount and a currency code.

  2. The currency code must always be valid.

  3. Money arithmetic can only be performed when both operands are of the same currency.

  4. Money amounts are represented as a Decimal.

  5. Money is serialised to the database as a custom Postgres composite type that includes both the amount and the currency. Therefore for Ecto serialization Postgres is assumed as the data store. Serialization is entirely optional and Ecto is not a package dependency.

  6. All arithmetic functions work in fixed point decimal. No rounding occurs automatically (unless expressly called out for a function).

  7. Explicit rounding obeys the rounding rules for a given currency. The rounding rules are defined by the Unicode consortium in its CLDR repository as implemented by the hex package ex_cldr. These rules define the number of fractional digits for a currency and the rounding increment where appropriate.

Summary

Types

An amount can be expressed as a float, an integer, a Decimal or a string (which is converted to a Decimal)

A currency code is an ISO 4217 code expressed as an atom or binary or an ISO 24165 Digital Token ID or Digital Token short name.

t()

Money is composed of an atom representation of an ISO4217 currency code and a Decimal representation of an amount.

Functions

The absolute value of a Money.t/0 amount. Returns a Money.t/0 type with a positive sign for the amount.

Add two Money values.

Add two Money.t/0 values or raise on error.

Clamps a Money.t/0 to be in the range of minimum to maximum.

Clamps a Money.t/0 to be in the range of minimum to maximum or raises an exception.

Compares two Money values numerically. If the first number is greater than the second #Integer<1> is returned, if less than Integer<-1> is returned. Otherwise, if both numbers are equal Integer<0> is returned.

Compares two Money values numerically and raises on error.

Compares two Money values numerically. If the first number is greater than the second :gt is returned, if less than :lt is returned, if both numbers are equal :eq is returned.

Compares two Money values numerically and raises on error.

Returns the effective cross-rate to convert from one currency to another.

Returns the effective cross-rate to convert from one currency to another.

Returns the default ex_cldr backend configured for Money, if any. If no default backing is configured, an exception is raised.

Divide a Money value by a number.

Divide a Money value by a number and raise on error.

Returns a boolean indicating if two Money values are equal

Returns a %Money{} struct from a currency code and a float amount, or an error tuple of the form {:error, {exception, message}}.

Returns a %Money{} struct from a currency code and a float amount, or raises an exception if the currency code is invalid.

Convert an integer representation of money into a Money struct.

Returns a boolean indicating if Money.t/0 is an integer value (has no significant fractional digits).

Localizes a Money by converting it to the currency of the specified locale.

Return the maximum of two Money.t/0 amounts.

Return the maximum of two Money.t/0 amounts or raises an exception.

Return the minimum of two Money.t/0 amounts.

Return the minimum of two Money.t/0 amounts or raises an exception.

Multiply a Money value by a number.

Multiply a Money value by a number and raise on error.

Negate a Money.t/0 value.

Negate a Money.t/0 value or raises an exception.

Returns a boolean indicating if Money.t/0 has a negative value.

Returns a %Money{} struct from a currency code and a currency amount or an error tuple of the form {:error, {exception, message}}.

Returns a %Money{} struct from a currency code and a currency amount. Raises an exception if the current code is invalid.

Normalizes the underlying decimal amount in a given Money.t/0.

Parse a string and return a Money.t/0 or an error.

Returns a boolean indicating if Money.t/0 has a positive value.

Set the fractional part of a Money.

reduce(money) deprecated

Round a Money value into the acceptable range for the requested currency.

Split a Money value into a number of parts maintaining the currency's precision and rounding and ensuring that the parts sum to the original amount.

Subtract one Money.t/0 value struct from another.

Subtract one Money value struct from another and raise on error.

Sum a list of monies that may be in different currencies.

Convert money from one currency to another or raises on error.

Returns the currecny code of a Money type as an atom.

Returns the amount part of a Money type as a Decimal

Returns a tuple comprising the currency code, integer amount, exponent and remainder.

Returns a formatted string representation of a Money.t/0.

Returns a formatted string representation of a Money.t/0 or raises if there is an error.

Returns a boolean indicating if the Money.t/0 is in the range minimum..maximum.

Return a zero amount Money.t/0 in the given currency.

Returns a boolean indicating if Money.t/0 has a zero value.

Types

@type amount() :: float() | integer() | Decimal.t() | String.t()

An amount can be expressed as a float, an integer, a Decimal or a string (which is converted to a Decimal)

@type currency_code() :: atom() | String.t()

A currency code is an ISO 4217 code expressed as an atom or binary or an ISO 24165 Digital Token ID or Digital Token short name.

@type t() :: %Money{
  amount: Decimal.t(),
  currency: currency_code(),
  format_options: Keyword.t()
}

Money is composed of an atom representation of an ISO4217 currency code and a Decimal representation of an amount.

Functions

@spec abs(money :: t()) :: t()

The absolute value of a Money.t/0 amount. Returns a Money.t/0 type with a positive sign for the amount.

Arguments

Returns

Example

iex> m = Money.new("USD", -100)
iex> Money.abs(m)
Money.new(:USD, "100")
@spec add(money_1 :: t(), money_2 :: t()) ::
  {:ok, t()} | {:error, {module(), String.t()}}

Add two Money values.

Arguments

Returns

  • {:ok, money} or

  • {:error, reason}

Example

iex> Money.add Money.new(:USD, 200), Money.new(:USD, 100)
{:ok, Money.new(:USD, 300)}

iex> Money.add Money.new(:USD, 200), Money.new(:AUD, 100)
{:error, {ArgumentError, "Cannot add monies with different currencies. " <>
  "Received :USD and :AUD."}}
@spec add!(money_1 :: t(), money_2 :: t()) :: t() | no_return()

Add two Money.t/0 values or raise on error.

Arguments

Returns

Examples

iex> Money.add! Money.new(:USD, 200), Money.new(:USD, 100)
Money.new(:USD, "300")

Money.add! Money.new(:USD, 200), Money.new(:CAD, 500)
** (ArgumentError) Cannot add two %Money{} with different currencies. Received :USD and :CAD.
Link to this function

clamp(money, minimum, maximum)

View Source (since 5.18.0)
@spec clamp(money :: t(), minimum :: t(), maximum :: t()) ::
  {:ok, t()} | {:error, {module(), String.t()}}

Clamps a Money.t/0 to be in the range of minimum to maximum.

Arguments

  • money, minimum and maximum are any valid Money.t/0 types returned by Money.new/2. They should be of the same currency.

Returns

  • {:ok, money] where money is clamped to the minimum or maximum if required.

    • If money is within the range minimum..maximum then money is returned unchanged.
    • If money is less than minimum then minimum is returned.
    • If money is greater than maximum then maximum is returned.
  • or {:error, reason}.

Examples

iex> Money.clamp(Money.new(:USD, 100), Money.new(:USD, 50), Money.new(:USD, 200))
{:ok, Money.new(:USD, 100)}

iex> Money.clamp(Money.new(:USD, 300), Money.new(:USD, 50), Money.new(:USD, 200))
{:ok, Money.new(:USD, 200)}

iex> Money.clamp(Money.new(:USD, 10), Money.new(:USD, 50), Money.new(:USD, 200))
{:ok, Money.new(:USD, 50)}

iex> Money.clamp(Money.new(:USD, 10), Money.new(:USD, 300), Money.new(:USD, 200))
{:error,
  {ArgumentError,
    "Minimum must be less than maximum. Found Money.new(:USD, \"300\") and Money.new(:USD, \"200\")"}}

iex> Money.clamp(Money.new(:USD, 10), Money.new(:AUD, 300), Money.new(:EUR, 200))
{:error, {ArgumentError, "Cannot compare monies with different currencies. Received :USD, :AUD and :EUR"}}
Link to this function

clamp!(money, minimum, maximum)

View Source (since 5.18.0)
@spec clamp!(money :: t(), minimum :: t(), maximum :: t()) :: t() | no_return()

Clamps a Money.t/0 to be in the range of minimum to maximum or raises an exception.

Arguments

  • money, minimum and maximum are any valid Money.t/0 types returned by Money.new/2. They should be of the same currency.

Returns

  • money where money is clamped to the minimum or maximum if required.

    • If money is within the range minimum..maximum then money is returned unchanged.
    • If money is less than minimum then minimum is returned.
    • If money is greater than maximum then maximum is returned.
  • or {:error, reason}.

Examples

iex> Money.clamp!(Money.new(:USD, 100), Money.new(:USD, 50), Money.new(:USD, 200))
Money.new(:USD, 100)

iex> Money.clamp!(Money.new(:USD, 300), Money.new(:USD, 50), Money.new(:USD, 200))
Money.new(:USD, 200)

iex> Money.clamp!(Money.new(:USD, 10), Money.new(:USD, 50), Money.new(:USD, 200))
Money.new(:USD, 50)

iex> Money.clamp!(Money.new(:USD, 10), Money.new(:USD, 300), Money.new(:USD, 200))
** (ArgumentError) Minimum must be less than maximum. Found Money.new(:USD, "300") and Money.new(:USD, "200")

iex> Money.clamp!(Money.new(:USD, 10), Money.new(:AUD, 300), Money.new(:EUR, 200))
** (ArgumentError) Cannot compare monies with different currencies. Received :USD, :AUD and :EUR
@spec cmp(money_1 :: t(), money_2 :: t()) ::
  -1 | 0 | 1 | {:error, {module(), String.t()}}

Compares two Money values numerically. If the first number is greater than the second #Integer<1> is returned, if less than Integer<-1> is returned. Otherwise, if both numbers are equal Integer<0> is returned.

Arguments

Returns

  • -1 | 0 | 1 or

  • {:error, {module(), String.t}}

Examples

iex> Money.cmp Money.new(:USD, 200), Money.new(:USD, 100)
1

iex> Money.cmp Money.new(:USD, 200), Money.new(:USD, 200)
0

iex> Money.cmp Money.new(:USD, 200), Money.new(:USD, 500)
-1

iex> Money.cmp Money.new(:USD, 200), Money.new(:CAD, 500)
{:error,
 {ArgumentError,
  "Cannot compare monies with different currencies. Received :USD and :CAD."}}

Compares two Money values numerically and raises on error.

Arguments

Returns

  • -1 | 0 | 1 or

  • raises an exception

Examples

Money.cmp! Money.new(:USD, 200), Money.new(:CAD, 500)
** (ArgumentError) Cannot compare monies with different currencies. Received :USD and :CAD.
@spec compare(money_1 :: t(), money_2 :: t()) ::
  :gt | :eq | :lt | {:error, {module(), String.t()}}

Compares two Money values numerically. If the first number is greater than the second :gt is returned, if less than :lt is returned, if both numbers are equal :eq is returned.

Arguments

Returns

  • :gt | :eq | :lt or

  • {:error, {module(), String.t}}

Examples

iex> Money.compare Money.new(:USD, 200), Money.new(:USD, 100)
:gt

iex> Money.compare Money.new(:USD, 200), Money.new(:USD, 200)
:eq

iex> Money.compare Money.new(:USD, 200), Money.new(:USD, 500)
:lt

iex> Money.compare Money.new(:USD, 200), Money.new(:CAD, 500)
{:error,
 {ArgumentError,
  "Cannot compare monies with different currencies. Received :USD and :CAD."}}
Link to this function

compare!(money_1, money_2)

View Source

Compares two Money values numerically and raises on error.

Arguments

Returns

  • :gt | :eq | :lt or

  • raises an exception

Examples

Money.compare! Money.new(:USD, 200), Money.new(:CAD, 500)
** (ArgumentError) Cannot compare monies with different currencies. Received :USD and :CAD.
Link to this function

cross_rate(from, to, rates \\ Money.ExchangeRates.latest_rates())

View Source
@spec cross_rate(
  t() | currency_code(),
  currency_code(),
  Money.ExchangeRates.t() | {:ok, Money.ExchangeRates.t()}
) :: {:ok, Decimal.t()} | {:error, {module(), String.t()}}

Returns the effective cross-rate to convert from one currency to another.

Arguments

  • from is any Money.t/0 struct returned by Cldr.Currency.new/2 or a valid currency code.

  • to_currency is a valid currency code into which the money is converted.

  • rates is a Map of currency rates where the map key is an upcased atom or string and the value is a Decimal conversion factor. The default is the latest available exchange rates returned from Money.ExchangeRates.latest_rates/0.

Examples

Money.cross_rate(Money.new(:USD, 100), :AUD, %{USD: Decimal.new(1), AUD: Decimal.new("0.7345")})
{:ok, Decimal.new("0.7345")}

Money.cross_rate Money.new(:USD, 100), :ZZZ, %{USD: Decimal.new(1), AUD: Decimal.new(0.7345)}
** (Cldr.UnknownCurrencyError) Currency :ZZZ is not known
Link to this function

cross_rate!(from, to_currency, rates \\ Money.ExchangeRates.latest_rates())

View Source
@spec cross_rate!(
  t() | currency_code(),
  currency_code(),
  Money.ExchangeRates.t() | {:ok, Money.ExchangeRates.t()}
) :: Decimal.t() | no_return()

Returns the effective cross-rate to convert from one currency to another.

Arguments

  • from is any Money.t/0 struct returned by Cldr.Currency.new/2 or a valid currency code.

  • to_currency is a valid currency code into which the money is converted.

  • rates is a Map of currency rates where the map key is an upcased atom or string and the value is a Decimal conversion factor. The default is the latest available exchange rates returned from Money.ExchangeRates.latest_rates/0.

Examples

iex> Money.cross_rate!(Money.new(:USD, 100), :AUD, %{USD: Decimal.new(1), AUD: Decimal.new("0.7345")})
Decimal.new("0.7345")

iex> Money.cross_rate!(:USD, :AUD, %{USD: Decimal.new(1), AUD: Decimal.new("0.7345")})
Decimal.new("0.7345")

Money.cross_rate Money.new(:USD, 100), :ZZZ, %{USD: Decimal.new(1), AUD: Decimal.new("0.7345")}
** (Cldr.UnknownCurrencyError) Currency :ZZZ is not known

Returns the default ex_cldr backend configured for Money, if any. If no default backing is configured, an exception is raised.

@spec div(t(), Cldr.Math.number_or_decimal()) ::
  {:ok, t()} | {:error, {module(), String.t()}}

Divide a Money value by a number.

Arguments

Note that dividing one %Money{} by another is not supported.

Returns

  • {:ok, money} or

  • {:error, reason}

Example

iex> Money.div Money.new(:USD, 200), 2
{:ok, Money.new(:USD, 100)}

iex> Money.div(Money.new(:USD, 200), "xx")
{:error, {ArgumentError, "Cannot divide money by \"xx\""}}
@spec div!(t(), Cldr.Math.number_or_decimal()) :: t() | none()

Divide a Money value by a number and raise on error.

Arguments

Returns

Examples

iex> Money.div!(Money.new(:USD, 200), 2)
Money.new(:USD, "100")

iex> Money.div!(Money.new(:USD, 200), "xx")
** (ArgumentError) Cannot divide money by "xx"
@spec equal?(money_1 :: t(), money_2 :: t()) :: boolean()

Returns a boolean indicating if two Money values are equal

Arguments

Returns

  • true or false

Example

iex> Money.equal?(Money.new(:USD, 200), Money.new(:USD, 200))
true

iex> Money.equal?(Money.new(:USD, 200), Money.new(:USD, 100))
false
Link to this function

from_float(currency_code, amount, options \\ [])

View Source (since 2.0.0)
@spec from_float(float() | currency_code(), float() | currency_code(), Keyword.t()) ::
  t() | {:error, {module(), String.t()}}

Returns a %Money{} struct from a currency code and a float amount, or an error tuple of the form {:error, {exception, message}}.

Floats are fraught with danger in computer arithmetic due to the unexpected loss of precision during rounding. The IEEE754 standard indicates that a number with a precision of 16 digits should round-trip convert without loss of fidelity. This function supports numbers with a precision up to 15 digits and will error if the provided amount is outside that range.

Note that Money cannot detect lack of precision or rounding errors introduced upstream. This function therefore should be used with great care and its use should be considered potentially harmful.

Arguments

  • currency_code is an ISO4217 binary or atom currency code or an ISO 24165 token identifier or shortname.

  • amount is a float

  • options is a keyword list of options passed to Money.new/3. The default is [].

Examples

iex> Money.from_float 1.23456, :USD
Money.new(:USD, "1.23456")

iex> Money.from_float 1.234567890987656, :USD
{:error,
  {Money.InvalidAmountError,
    "The precision of the float 1.234567890987656 is " <>
    "greater than 15 which could lead to unexpected results. " <>
    "Reduce the precision or call Money.new/2 with a Decimal or String amount"}}
Link to this function

from_float!(currency_code, amount, options \\ [])

View Source (since 2.0.0)
@spec from_float!(currency_code(), float(), Keyword.t()) :: t() | no_return()

Returns a %Money{} struct from a currency code and a float amount, or raises an exception if the currency code is invalid.

See Money.from_float/2 for further information.

Note that Money cannot detect lack of precision or rounding errors introduced upstream. This function therefore should be used with great care and its use should be considered potentially harmful.

Arguments

  • currency_code is an ISO4217 binary or atom currency code or an ISO 24165 token identifier or shortname.

  • amount is a float

  • options is a keyword list of options passed to Money.new/3. The default is [].

Examples

iex> Money.from_float!(:USD, 1.234)
Money.new(:USD, "1.234")

Money.from_float!(:USD, 1.234567890987654)
#=> ** (Money.InvalidAmountError) The precision of the float 1.234567890987654 is greater than 15 which could lead to unexpected results. Reduce the precision or call Money.new/2 with a Decimal or String amount
    (ex_money) lib/money.ex:293: Money.from_float!/2
Link to this function

from_integer(amount, currency, options \\ [])

View Source
@spec from_integer(integer(), currency_code(), Keyword.t()) ::
  t() | {:error, {module(), String.t()}}

Convert an integer representation of money into a Money struct.

Arguments

  • integer is an integer representation of a money amount including any decimal digits. ie. 20000 would be interpreted to mean $200.00 if the currency is :USD and no :fractional_digits option was provided.

  • currency is the currency code for the integer. The assumed decimal precision is derived from the currency code if no fractional_digits option is specified.

  • options is a keyword list of options.

Options

  • :fractional_digits which determines the currency precision implied by the integer. The valid options are :cash, :accounting, :iso or a non-negative integer. The default is :iso which uses the ISO 4217 definition of currency digits.

All other options are passed to Money.new/3.

Returns

  • A Money.t/0 struct or

  • {:error, {exception, message}}

Notes

Some currencies, like the Iraqi Dinar have a difference in the decimal digits defined by CLDR versus those defined by ISO 4217. CLDR defines the decimal digits for IQD as 0 whereas ISO 4217 defines 3 decimal digits.

Since converting an integer to a money amount is very sensitive to the number of fractional digits specified it is important to be very clear about the precision of the data used with this function and care taken in specifying the :fractional_digits parameter.

Examples

iex> Money.from_integer(20000, :USD)
Money.new(:USD, "200.00")

iex> Money.from_integer(200, :JPY)
Money.new(:JPY, "200")

iex> Money.from_integer(20012, :USD)
Money.new(:USD, "200.12")

iex> Money.from_integer(20012, :USD, fractional_digits: 3)
Money.new(:USD, "20.012")

iex> Money.from_integer(20012, :IQD)
Money.new(:IQD, "20.012")
Link to this function

get_env(key, default, atom)

View Source
Link to this function

integer?(map)

View Source (since 5.10.0)
@spec integer?(t()) :: boolean()

Returns a boolean indicating if Money.t/0 is an integer value (has no significant fractional digits).

Arguments

Example

iex> Money.integer?(Money.new(:USD, 0))
true

iex> Money.integer?(Money.new(:USD, "1.10"))
false

See Cldr.known_currencies/0.

Link to this function

known_current_currencies()

View Source

See Money.Currency.known_current_currencies/0.

Link to this function

known_historic_currencies()

View Source

See Money.Currency.known_historic_currencies/0.

Link to this function

known_tender_currencies()

View Source

See Money.Currency.known_tender_currencies/0.

Link to this function

localize(money, options \\ [])

View Source (since 5.12.0)
@spec localize(t(), Keyword.t()) :: {:ok, t()} | {:error, {module(), String.t()}}

Localizes a Money by converting it to the currency of the specified locale.

Arguments

Options

Returns

  • {:ok, localized_money} or

  • {:error, {exception, reason}}

Link to this function

max(money_1, money_2)

View Source (since 5.18.0)
@spec max(money_1 :: t(), money_2 :: t()) ::
  {:ok, t()} | {:error, {module(), String.t()}}

Return the maximum of two Money.t/0 amounts.

Arguments

  • money_1 and money_2 are any valid Money.t/0 types returned by Money.new/2. money_1 and money_2 should be of the same currency.

Returns

  • {:ok, maximum_money} or

  • {:error, reason}.

Example

iex> Money.max(Money.new(:USD, 200), Money.new(:USD, 300))
{:ok, Money.new(:USD, 300)}

iex> Money.max(Money.new(:USD, 200), Money.new(:AUD, 200))
{:error,
  {ArgumentError, "Cannot compare monies with different currencies. Received :USD and :AUD."}}
Link to this function

max!(money_1, money_2)

View Source (since 5.18.0)
@spec max!(money_1 :: t(), money_2 :: t()) :: t() | no_return()

Return the maximum of two Money.t/0 amounts or raises an exception.

Arguments

  • money_1 and money_2 are any valid Money.t/0 types returned by Money.new/2. money_1 and money_2 should be of the same currency.

Returns

  • maximum_money or

  • raises an exception.

Example

iex> Money.max!(Money.new(:USD, 200), Money.new(:USD, 300))
Money.new(:USD, 300)

iex> Money.max!(Money.new(:USD, 200), Money.new(:AUD, 200))
** (ArgumentError) Cannot compare monies with different currencies. Received :USD and :AUD.
Link to this function

min(money_1, money_2)

View Source (since 5.18.0)
@spec min(money_1 :: t(), money_2 :: t()) ::
  {:ok, t()} | {:error, {module(), String.t()}}

Return the minimum of two Money.t/0 amounts.

Arguments

  • money_1 and money_2 are any valid Money.t/0 types returned by Money.new/2. money_1 and money_2 should be of the same currency.

Returns

  • {:ok, minimum_money} or

  • {:error, reason}

Example

iex> Money.min(Money.new(:USD, 200), Money.new(:USD, 300))
{:ok, Money.new(:USD, 200)}

iex> Money.min(Money.new(:USD, 200), Money.new(:AUD, 200))
{:error,
  {ArgumentError, "Cannot compare monies with different currencies. Received :USD and :AUD."}}
Link to this function

min!(money_1, money_2)

View Source (since 5.18.0)
@spec min!(money_1 :: t(), money_2 :: t()) :: t() | no_return()

Return the minimum of two Money.t/0 amounts or raises an exception.

Arguments

  • money_1 and money_2 are any valid Money.t/0 types returned by Money.new/2. money_1 and money_2 should be of the same currency.

Returns

  • minimum_money or

  • raises an exception.

Example

iex> Money.min!(Money.new(:USD, 200), Money.new(:USD, 300))
Money.new(:USD, 200)

iex> Money.min!(Money.new(:USD, 200), Money.new(:AUD, 200))
** (ArgumentError) Cannot compare monies with different currencies. Received :USD and :AUD.
@spec mult(t(), Cldr.Math.number_or_decimal()) ::
  {:ok, t()} | {:error, {module(), String.t()}}

Multiply a Money value by a number.

Arguments

Note that multipling one Money.t/0 by another is not supported.

Returns

  • {:ok, money} or

  • {:error, reason}

Example

iex> Money.mult(Money.new(:USD, 200), 2)
{:ok, Money.new(:USD, 400)}

iex> Money.mult(Money.new(:USD, 200), "xx")
{:error, {ArgumentError, "Cannot multiply money by \"xx\""}}
@spec mult!(t(), Cldr.Math.number_or_decimal()) :: t() | none()

Multiply a Money value by a number and raise on error.

Arguments

Returns

Examples

iex> Money.mult!(Money.new(:USD, 200), 2)
Money.new(:USD, "400")

Money.mult!(Money.new(:USD, 200), :invalid)
** (ArgumentError) Cannot multiply money by :invalid
Link to this function

negate(money)

View Source (since 5.18.0)
@spec negate(money :: t()) :: {:ok, t()}

Negate a Money.t/0 value.

Argument

Returns

  • {:ok, negated_money} with the amount negated.

Example

iex> Money.negate(Money.new(:USD, 200))
{:ok, Money.new(:USD, -200)}

iex> Money.negate(Money.new(:USD, -200))
{:ok, Money.new(:USD, 200)}
Link to this function

negate!(money)

View Source (since 5.18.0)
@spec negate!(money :: t()) :: t() | no_return()

Negate a Money.t/0 value or raises an exception.

Argument

Returns

  • negated_money with the amount negated or

  • raises an exception.

Example

iex> Money.negate!(Money.new(:USD, 200))
Money.new(:USD, -200)

iex> Money.negate!(Money.new(:USD, -200))
Money.new(:USD, 200)
Link to this function

negative?(value)

View Source (since 5.10.0)
@spec negative?(t()) :: boolean()

Returns a boolean indicating if Money.t/0 has a negative value.

Arguments

Example

iex> Money.negative?(Money.new(:USD, -1))
true

iex> Money.negative?(Money.new(:USD, 0))
false

iex> Money.negative?(Money.new(:USD, 1))
false
Link to this function

new(currency_code, amount, options \\ [])

View Source
@spec new(amount() | currency_code(), amount() | currency_code(), Keyword.t()) ::
  t() | {:error, {module(), String.t()}}

Returns a %Money{} struct from a currency code and a currency amount or an error tuple of the form {:error, {exception, message}}.

Arguments

  • currency_code is an ISO4217 binary or atom currency code or an ISO 24165 token identifier or shortname.

  • amount is an integer, string or Decimal money amount.

  • options is a keyword list of options.

Options

  • :locale is any known locale. The locale is used to normalize any binary (String) amounts to a form that can be consumed by Decimal.new/1. This consists of removing any localised grouping characters and replacing the localised decimal separator with a ".". The default is Cldr.get_locale/0.

  • :backend is any module() that includes use Cldr and therefore is a Cldr backend module(). The default is Money.default_backend/0.

  • Any other options are considered as formatting options to be applied by default when calling Money.to_string/2.

Note that the currency_code and amount arguments can be supplied in either order,

Examples

iex> Money.new(:USD, 100)
Money.new(:USD, "100")

iex> Money.new(100, :USD)
Money.new(:USD, "100")

iex> Money.new("USD", 100)
Money.new(:USD, "100")

iex> Money.new("thb", 500)
Money.new(:THB, "500")

iex> Money.new("EUR", Decimal.new(100))
Money.new(:EUR, "100")

iex> Money.new(:EUR, "100.30")
Money.new(:EUR, "100.30")

iex> Money.new(:EUR, "100.30", fractional_digits: 4)
Money.new(:EUR, "100.30", fractional_digits: 4)

iex> Money.new(:XYZZ, 100)
{:error, {Money.UnknownCurrencyError, "The currency :XYZZ is invalid"}}

iex> Money.new("1.000,99", :EUR, locale: "de")
Money.new(:EUR, "1000.99")

iex> Money.new 123.445, :USD
{:error,
 {Money.InvalidAmountError,
  "Float amounts are not supported in new/2 due to potenial " <>
  "rounding and precision issues.  If absolutely required, " <>
  "use Money.from_float/2"}}
Link to this function

new!(currency_code, amount, options \\ [])

View Source
@spec new!(amount() | currency_code(), amount() | currency_code(), Keyword.t()) ::
  t() | no_return()

Returns a %Money{} struct from a currency code and a currency amount. Raises an exception if the current code is invalid.

Arguments

  • currency_code is an ISO4217 binary or atom currency code or an ISO 24165 token identifier or shortname.

  • amount is an integer, float or Decimal

Examples

Money.new!(:XYZZ, 100)
** (Money.UnknownCurrencyError) Currency :XYZZ is not known
  (ex_money) lib/money.ex:177: Money.new!/2
Link to this function

normalize(money)

View Source (since 5.0.0)
@spec normalize(t()) :: t()

Normalizes the underlying decimal amount in a given Money.t/0.

This will normalize the coefficient and exponent of the decimal amount in a standard way that may aid in native comparison of Money.t/0 items.

Example

iex> x = %Money{currency: :USD, amount: %Decimal{sign: 1, coef: 42, exp: 0}}
Money.new(:USD, "42")
iex> y = %Money{currency: :USD, amount: %Decimal{sign: 1, coef: 4200000000, exp: -8}}
Money.new(:USD, "42.00000000")
iex> x == y
false
iex> y = Money.normalize(x)
Money.new(:USD, "42")
iex> x == y
true
Link to this function

parse(string, options \\ [])

View Source (since 3.2.0)
@spec parse(String.t(), Keyword.t()) :: t() | {:error, {module(), String.t()}}

Parse a string and return a Money.t/0 or an error.

The string to be parsed is required to have a currency code and an amount. The currency code may be placed before the amount or after, but not both.

Parsing is strict. Additional text surrounding the currency code and amount will cause the parse to fail.

Arguments

  • string is a string to be parsed

  • options is a keyword list of options that is passed to Money.new/3 with the exception of the options listed below

Options

  • :backend is any module() that includes use Cldr and therefore is a Cldr backend module(). The default is Money.default_backend()

  • :locale is any valid locale returned by Cldr.known_locale_names/1 or a Cldr.LanguageTag struct returned by Cldr.Locale.new!/2 The default is <backend>.get_locale()

  • :only is an atom or list of atoms representing the currencies or currency types to be considered for a match. The equates to a list of acceptable currencies for parsing. See the notes below for currency types.

  • :except is an atom or list of atoms representing the currencies or currency types to be not considered for a match. This equates to a list of unacceptable currencies for parsing. See the notes below for currency types.

  • :fuzzy is a float greater than 0.0 and less than or equal to 1.0 which is used as input to the String.jaro_distance/2 to determine is the provided currency string is close enough to a known currency string for it to identify definitively a currency code. It is recommended to use numbers greater than 0.8 in order to reduce false positives.

  • :default_currency is any valid currency code or false that will used if no currency code, symbol or description is indentified in the parsed string. The default is nil which means that the default currency associated with the :locale option will be used. If false then the currency assocated with the :locale option will not be used and an error will be returned if there is no currency in the string being parsed.

Returns

  • a Money.t/0 if parsing is successful or

  • {:error, {exception, reason}} if an error is detected.

Notes

The :only and :except options accept a list of currency codes and/or currency types. The following types are recognised.

If both :only and :except are specified, the :except entries take priority - that means any entries in :except are removed from the :only entries.

  • :all, the default, considers all currencies

  • :current considers those currencies that have a :to date of nil and which also is a known ISO4217 currency

  • :historic is the opposite of :current

  • :tender considers currencies that are legal tender

  • :unannotated considers currencies that don't have "(some string)" in their names. These are usually financial instruments.

Examples

iex> Money.parse("USD 100")
Money.new(:USD, "100")

iex> Money.parse "USD 100,00", locale: "de"
Money.new(:USD, "100.00")

iex> Money.parse("100 USD")
Money.new(:USD, "100")

iex> Money.parse("100 eurosports", fuzzy: 0.8)
Money.new(:EUR, "100")

iex> Money.parse("100", default_currency: :EUR)
Money.new(:EUR, "100")

iex> Money.parse("100 eurosports", fuzzy: 0.9)
{:error, {Money.UnknownCurrencyError, "The currency \"eurosports\" is unknown or not supported"}}

iex> Money.parse("100 afghan afghanis")
Money.new(:AFN, "100")

iex> Money.parse("100", default_currency: false)
{:error, {Money.Invalid,
  "A currency code, symbol or description must be specified but was not found in \"100\""}}

iex> Money.parse("USD 100 with trailing text")
{:error, {Money.ParseError, "Could not parse \"USD 100 with trailing text\"."}}
Link to this function

positive?(value)

View Source (since 5.10.0)
@spec positive?(t()) :: boolean()

Returns a boolean indicating if Money.t/0 has a positive value.

Arguments

Example

iex> Money.positive?(Money.new(:USD, 1))
true

iex> Money.positive?(Money.new(:USD, 0))
false

iex> Money.positive?(Money.new(:USD, -1))
false
Link to this function

put_format_options(money, options)

View Source (since 5.5.0)
@spec put_format_options(t(), Keyword.t()) :: t()

Add format options to a Money.t/0.

Arguments

Link to this function

put_fraction(money, fraction \\ 0)

View Source

Set the fractional part of a Money.

Arguments

  • money is any Money.t/0

  • fraction is an integer amount that will be set as the fraction of the money

Notes

The fraction can only be set if it matches the number of decimal digits for the currency associated with the money. Therefore, for a currency with 2 decimal digits, the maximum for fraction is 99.

Examples

iex> Money.put_fraction Money.new(:USD, "2.49"), 99
Money.new(:USD, "2.99")

iex> Money.put_fraction Money.new(:USD, "2.49"), 0
Money.new(:USD, "2.0")

iex> Money.put_fraction Money.new(:USD, "2.49"), 999
{:error,
 {Money.InvalidAmountError, "Rounding up to 999 is invalid for currency :USD"}}
This function is deprecated. Use Money.normalize/1 instead..
Link to this function

round(money, opts \\ [])

View Source
@spec round(t(), Keyword.t()) :: t() | {:error, {module(), binary()}}

Round a Money value into the acceptable range for the requested currency.

Arguments

  • money is any Money.t/0

  • opts is a keyword list of options

Options

  • :rounding_mode that defines how the number will be rounded. See Decimal.Context. The default is :half_even which is also known as "banker's rounding"

  • :currency_digits which determines the rounding increment. The valid options are :cash, :accounting and :iso or an integer value representing the rounding factor. The default is :iso.

Notes

There are two kinds of rounding applied:

  1. Round to the appropriate number of fractional digits

  2. Apply an appropriate rounding increment. Most currencies round to the same precision as the number of decimal digits, but some such as :CHF round to a minimum such as 0.05 when its a cash amount. The rounding increment is applied when the option :currency_digits is set to :cash

  3. Digital Tokens (crypto currencies) do not have formal definitions of decimal digits or rounding strategies. Therefore the money is returned unmodified.

Examples

iex> Money.round Money.new("123.73", :CHF), currency_digits: :cash
Money.new(:CHF, "123.75")

iex> Money.round Money.new("123.73", :CHF), currency_digits: 0
Money.new(:CHF, "124")

iex> Money.round Money.new("123.7456", :CHF)
Money.new(:CHF, "123.75")

iex> Money.round Money.new("123.7456", :JPY)
Money.new(:JPY, "124")
@spec split(t(), non_neg_integer()) :: {t(), t()}

Split a Money value into a number of parts maintaining the currency's precision and rounding and ensuring that the parts sum to the original amount.

Arguments

  • money is any Money.t/0

  • parts is an integer number of parts into which the money is split

Returns a tuple {dividend, remainder} as the function result derived as follows:

  1. Round the money amount to the required currency precision using Money.round/1

  2. Divide the result of step 1 by the integer divisor

  3. Round the result of the division to the precision of the currency using Money.round/1

  4. Return two numbers: the result of the division and any remainder that could not be applied given the precision of the currency.

Examples

Money.split Money.new(123.5, :JPY), 3
{¥41, ¥1}

Money.split Money.new(123.4, :JPY), 3
{¥41, ¥0}

Money.split Money.new(123.7, :USD), 9
{$13.74, $0.04}
@spec sub(money_1 :: t(), money_2 :: t()) ::
  {:ok, t()} | {:error, {module(), String.t()}}

Subtract one Money.t/0 value struct from another.

Options

Returns

  • {:ok, money} or

  • {:error, reason}.

Example

iex> Money.sub Money.new(:USD, 200), Money.new(:USD, 100)
{:ok, Money.new(:USD, 100)}
@spec sub!(money_1 :: t(), money_2 :: t()) :: t() | none()

Subtract one Money value struct from another and raise on error.

Returns either {:ok, money} or {:error, reason}.

Arguments

Returns

Examples

iex> Money.sub! Money.new(:USD, 200), Money.new(:USD, 100)
Money.new(:USD, "100")

Money.sub! Money.new(:USD, 200), Money.new(:CAD, 500)
** (ArgumentError) Cannot subtract monies with different currencies. Received :USD and :CAD.
Link to this function

sum(money_list, rates \\ latest_rates_or_empty_map())

View Source (since 5.3.0)
@spec sum(
  [t(), ...],
  Money.ExchangeRates.t()
  | {:ok, Money.ExchangeRates.t()}
  | {:error, {module(), String.t()}}
) :: {:ok, t()} | {:error, {module(), String.t()}}

Sum a list of monies that may be in different currencies.

Arguments

Returns

  • {:ok, money} representing the sum of the maybe converted money amounts. The currency of the sum is the currency of the first Money in the money_list.

  • {:error, {exception, reason}} describing an error.

Examples

iex> Money.sum([Money.new(:USD, 100), Money.new(:USD, 200), Money.new(:USD, 50)])
{:ok, Money.new(:USD, 350)}

iex> Money.sum([Money.new(:USD, 100), Money.new(:USD, 200), Money.new(:AUD, 50)], %{})
{:error,
 {Money.ExchangeRateError, "No exchange rate is available for currency :AUD"}}

iex> rates = %{AUD: Decimal.new(2), USD: Decimal.new(1)}
iex> Money.sum [Money.new(:USD, 100), Money.new(:USD, 200), Money.new(:AUD, 50)], rates
{:ok, Money.from_float(:USD, 325.0)}
Link to this function

to_currency(money, to_currency, rates \\ Money.ExchangeRates.latest_rates())

View Source
@spec to_currency(
  t(),
  currency_code(),
  Money.ExchangeRates.t()
  | {:ok, Money.ExchangeRates.t()}
  | {:error, {module(), String.t()}}
) :: {:ok, t()} | {:error, {module(), String.t()}}

Convert money from one currency to another.

Arguments

  • money is any Money.t/0 struct returned by Cldr.Currency.new/2.

  • to_currency is a valid currency code into which the money is converted.

  • rates is a Map of currency rates where the map key is an upcased atom or string and the value is a Decimal conversion factor. The default is the latest available exchange rates returned from Money.ExchangeRates.latest_rates/0.

Converting to a currency defined in a locale

To convert a Money to a currency defined by a locale, Cldr.Currency.currency_from_locale/1 can be called with a Cldr.LanguageTag.t/0 parameter. It will return the currency configured for that locale.

Examples

iex> Money.to_currency(Money.new(:USD, 100), :AUD,
...>   %{USD: Decimal.new(1), AUD: Decimal.from_float(0.7345)})
{:ok, Money.new(:AUD, "73.4500")}

iex> Money.to_currency(Money.new("USD", 100), "AUD",
...>   %{"USD" => Decimal.new(1), "AUD" => Decimal.from_float(0.7345)})
{:ok, Money.new(:AUD, "73.4500")}

iex> Money.to_currency(Money.new(:USD, 100), :AUDD,
...>   %{USD: Decimal.new(1), AUD: Decimal.from_float(0.7345)})
{:error, {Cldr.UnknownCurrencyError, "The currency :AUDD is invalid"}}

iex> Money.to_currency(Money.new(:USD, 100), :CHF,
...>   %{USD: Decimal.new(1), AUD: Decimal.from_float(0.7345)})
{:error, {Money.ExchangeRateError,
  "No exchange rate is available for currency :CHF"}}
Link to this function

to_currency!(money, to_currency, rates \\ Money.ExchangeRates.latest_rates())

View Source
@spec to_currency!(
  t(),
  currency_code(),
  Money.ExchangeRates.t()
  | {:ok, Money.ExchangeRates.t()}
  | {:error, {module(), String.t()}}
) :: t() | no_return()

Convert money from one currency to another or raises on error.

Arguments

  • money is any Money.t/0 struct returned by Cldr.Currency.new/2.

  • to_currency is a valid currency code into which the money is converted.

  • rates is a Map of currency rates where the map key is an upcased atom or string and the value is a Decimal conversion factor. The default is the latest available exchange rates returned from Money.ExchangeRates.latest_rates/0.

Examples

iex> Money.to_currency! Money.new(:USD, 100), :AUD,
...>   %{USD: Decimal.new(1), AUD: Decimal.from_float(0.7345)}
Money.new(:AUD, "73.4500")

iex> Money.to_currency! Money.new("USD", 100), "AUD",
...>   %{"USD" => Decimal.new(1), "AUD" => Decimal.from_float(0.7345)}
Money.new(:AUD, "73.4500")

=> Money.to_currency! Money.new(:USD, 100), :ZZZ,
     %{USD: Decimal.new(1), AUD: Decimal.from_float(0.7345)}
** (Cldr.UnknownCurrencyError) Currency :ZZZ is not known
Link to this function

to_currency_code(money)

View Source (since 5.6.0)
@spec to_currency_code(money :: t()) :: atom()

Returns the currecny code of a Money type as an atom.

Arguments

Returns

  • the currency code as an t:atom.

Example

iex> m = Money.new("USD", 100)
iex> Money.to_currency_code(m)
:USD
@spec to_decimal(money :: t()) :: Decimal.t()

Returns the amount part of a Money type as a Decimal

Arguments

Returns

  • a Decimal.t

Example

iex> m = Money.new("USD", 100)
iex> Money.to_decimal(m)
Decimal.new(100)
Link to this function

to_integer_exp(money, opts \\ [])

View Source

Returns a tuple comprising the currency code, integer amount, exponent and remainder.

Some services require submission of money items as an integer with an implied exponent that is appropriate to the currency.

Rather than return only the integer, Money.to_integer_exp returns the currency code, integer, exponent and remainder. The remainder is included because to return an integer money with an implied exponent the Money has to be rounded potentially leaving a remainder.

Options

Notes

  • Since the returned integer is expected to have the implied fractional digits the Money needs to be rounded which is what this function does.

Example

iex> m = Money.new(:USD, "200.012356")
Money.new(:USD, "200.012356")
iex> Money.to_integer_exp(m)
{:USD, 20001, -2, Money.new(:USD, "0.002356")}

iex> m = Money.new(:USD, "200.00")
Money.new(:USD, "200.00")
iex> Money.to_integer_exp(m)
{:USD, 20000, -2, Money.new(:USD, "0.00")}
Link to this function

to_string(money, options \\ [])

View Source
@spec to_string(t(), Keyword.t() | Cldr.Number.Format.Options.t()) ::
  {:ok, String.t()} | {:error, {module(), String.t()}}

Returns a formatted string representation of a Money.t/0.

Formatting is performed according to the rules defined by CLDR. See Cldr.Number.to_string/2 for formatting options. The default is to format as a currency which applies the appropriate rounding and fractional digits for the currency.

Arguments

  • money is any valid Money.t/0 type returned by Money.new/2

  • options is a keyword list of options or a %Cldr.Number.Format.Options{} struct

Returns

  • {:ok, string} or

  • {:error, reason}

Options

  • :backend is any CLDR backend module. The default is Money.default_backend().

  • currency_symbol: Allows overriding a currency symbol. The alternatives are:

    • :iso the ISO currency code will be used instead of the default currency symbol.
    • :narrow uses the narrow symbol defined for the locale. The same narrow symbol can be defined for more than one currency and therefore this should be used with care. If no narrow symbol is defined, the standard symbol is used.
    • :symbol uses the standard symbol defined in CLDR. A symbol is unique for each currency and can be safely used.
    • "string" uses string as the currency symbol
    • :standard (the default and recommended) uses the CLDR-defined symbol based upon the currency format for the locale.
  • :no_fraction_if_integer is a boolean which, if true, will set :fractional_digits to 0 if the money value is an integer value.

  • Any other options are passed to Cldr.Number.to_string/3

Examples

iex> Money.to_string Money.new(:USD, 1234)
{:ok, "$1,234.00"}

iex> Money.to_string Money.new(:USD, 1234), no_fraction_if_integer: true
{:ok, "$1,234"}

iex> Money.to_string Money.new(:JPY, 1234)
{:ok, "¥1,234"}

iex> Money.to_string Money.new(:THB, 1234)
{:ok, "THB 1,234.00"}

iex> Money.to_string Money.new(:THB, 1234, fractional_digits: 4)
{:ok, "THB 1,234.0000"}

iex> Money.to_string Money.new(:USD, 1234), format: :long
{:ok, "1,234 US dollars"}
Link to this function

to_string!(money, options \\ [])

View Source
@spec to_string!(t(), Keyword.t() | Cldr.Number.Format.Options.t()) ::
  String.t() | no_return()

Returns a formatted string representation of a Money.t/0 or raises if there is an error.

Formatting is performed according to the rules defined by CLDR. See Cldr.Number.to_string!/2 for formatting options. The default is to format as a currency which applies the appropriate rounding and fractional digits for the currency.

Arguments

  • money is any valid Money.t/0 type returned by Money.new/2

  • options is a keyword list of options or a %Cldr.Number.Format.Options{} struct

Options

  • :backend is any CLDR backend module. The default is Money.default_backend().

  • Any other options are passed to Cldr.Number.to_string/3

Examples

iex> Money.to_string! Money.new(:USD, 1234)
"$1,234.00"

iex> Money.to_string! Money.new(:JPY, 1234)
"¥1,234"

iex> Money.to_string! Money.new(:THB, 1234)
"THB 1,234.00"

iex> Money.to_string! Money.new(:USD, 1234), format: :long
"1,234 US dollars"
Link to this function

within?(money, minimum, maximum)

View Source (since 5.18.0)
@spec within?(money :: t(), minimum :: t(), maximum :: t()) :: boolean()

Returns a boolean indicating if the Money.t/0 is in the range minimum..maximum.

Arguments

  • money, minimum and maximum are any valid Money.t/0 types returned by Money.new/2. They should be of the same currency.

Returns

  • true or false.

Examples

iex> Money.within?(Money.new(:USD, 100), Money.new(:USD, 50), Money.new(:USD, 200))
true

iex> Money.within?(Money.new(:USD, 10), Money.new(:USD, 50), Money.new(:USD, 200))
false

iex> Money.within?(Money.new(:USD, 100), Money.new(:USD, 300), Money.new(:USD, 200))
** (ArgumentError) Minimum must be less than maximum. Found Money.new(:USD, "300") and Money.new(:USD, "200")

iex> Money.within?(Money.new(:USD, 10), Money.new(:AUD, 300), Money.new(:EUR, 200))
** (ArgumentError) Cannot compare monies with different currencies. Received :USD, :AUD and :EUR
Link to this function

zero(money_or_currency, options \\ [])

View Source

Return a zero amount Money.t/0 in the given currency.

Arguments

  • money_or_currency is either a Money.t/0 or a currency code.

  • options is a keyword list of options passed to Money.new/3. The default is [].

Example

iex> Money.zero(:USD)
Money.new(:USD, "0")

iex> money = Money.new(:USD, 200)
iex> Money.zero(money)
Money.new(:USD, "0")

iex> Money.zero :ZZZ
{:error, {Cldr.UnknownCurrencyError, "The currency :ZZZ is invalid"}}
Link to this function

zero?(value)

View Source (since 5.10.0)
@spec zero?(t()) :: boolean()

Returns a boolean indicating if Money.t/0 has a zero value.

Arguments

Example

iex> Money.zero?(Money.new(:USD, 0))
true

iex> Money.zero?(Money.new(:USD, 1))
false

iex> Money.zero?(Money.new(:USD, -1))
false