Money (Money v5.23.0)
View SourceMoney 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:
Money must always have both a amount and a currency code.
The currency code must always be valid.
Money arithmetic can only be performed when both operands are of the same currency.
Money amounts are represented as a
Decimal.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.
All arithmetic functions work in fixed point decimal. No rounding occurs automatically (unless expressly called out for a function).
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.
Functions
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.
Returns the default rounding mode.
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.
Add format options to a Money.t/0.
Set the fractional part of a Money.
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.
Sum a list of monies that may be in different currencies or raise an exception on error.
Convert money from one currency to another.
Convert money from one currency to another or raises on error.
Returns the currecny code of a Money type
as an atom.
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
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.
@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
The absolute value of a Money.t/0 amount.
Returns a Money.t/0 type with a positive sign for the amount.
Arguments
moneyis any validMoney.t/0type returned byMoney.new/2.
Returns
- a
Money.t/0.
Example
iex> m = Money.new("USD", -100)
iex> Money.abs(m)
Money.new(:USD, "100")
Add two Money values.
Arguments
money_1andmoney_2are any validMoney.t/0types returned byMoney.new/2.
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."}}
Add two Money.t/0 values or raise on error.
Arguments
money_1andmoney_2are any validMoney.t/0types returned byMoney.new/2.
Returns
a
Money.t/0struct orraises an exception
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.
@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,minimumandmaximumare any validMoney.t/0types returned byMoney.new/2. They should be of the same currency.
Returns
{:ok, money]wheremoneyis clamped to theminimumormaximumif required.- If
moneyis within the rangeminimum..maximumthenmoneyis returned unchanged. - If
moneyis less thanminimumthenminimumis returned. - If
moneyis greater thanmaximumthenmaximumis returned.
- If
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"}}
Clamps a Money.t/0 to be in the range of minimum
to maximum or raises an exception.
Arguments
money,minimumandmaximumare any validMoney.t/0types returned byMoney.new/2. They should be of the same currency.
Returns
moneywheremoneyis clamped to theminimumormaximumif required.- If
moneyis within the rangeminimum..maximumthenmoneyis returned unchanged. - If
moneyis less thanminimumthenminimumis returned. - If
moneyis greater thanmaximumthenmaximumis returned.
- If
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
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
money_1andmoney_2are any validMoney.t/0types returned byMoney.new/2.
Returns
-1|0|1or{: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
money_1andmoney_2are any validMoney.t/0types returned byMoney.new/2
Returns
-1|0|1orraises an exception
Examples
Money.cmp! Money.new(:USD, 200), Money.new(:CAD, 500)
** (ArgumentError) Cannot compare monies with different currencies. Received :USD and :CAD.
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
money_1andmoney_2are any validMoney.t/0types returned byMoney.new/2
Returns
:gt|:eq|:ltor{: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."}}
Compares two Money values numerically and raises on error.
Arguments
money_1andmoney_2are any validMoney.t/0types returned byMoney.new/2.
Returns
:gt|:eq|:ltorraises an exception
Examples
Money.compare! Money.new(:USD, 200), Money.new(:CAD, 500)
** (ArgumentError) Cannot compare monies with different currencies. Received :USD and :CAD.
@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
fromis anyMoney.t/0struct returned byCldr.Currency.new/2or a valid currency code.to_currencyis a valid currency code into which themoneyis converted.ratesis aMapof 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 fromMoney.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
@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
fromis anyMoney.t/0struct returned byCldr.Currency.new/2or a valid currency code.to_currencyis a valid currency code into which themoneyis converted.ratesis aMapof 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 fromMoney.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.
Returns the default rounding mode.
@spec div(t(), Cldr.Math.number_or_decimal()) :: {:ok, t()} | {:error, {module(), String.t()}}
Divide a Money value by a number.
Arguments
moneyis any validMoney.t/0types returned byMoney.new/2numberis an integer, float orDecimal.t
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
moneyis any validMoney.t/0types returned byMoney.new/2numberis an integer, float orDecimal.t
Returns
a
Money.t/0struct orraises an exception
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"
Returns a boolean indicating if two Money values are equal
Arguments
money_1andmoney_2are any validMoney.t/0types returned byMoney.new/2
Returns
trueorfalse
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
@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_codeis an ISO4217 binary or atom currency code or an ISO 24165 token identifier or shortname.amountis a floatoptionsis a keyword list of options passed toMoney.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"}}
@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_codeis an ISO4217 binary or atom currency code or an ISO 24165 token identifier or shortname.amountis a float.optionsis a keyword list of options passed toMoney.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
@spec from_integer(integer(), currency_code(), Keyword.t()) :: t() | {:error, {module(), String.t()}}
Convert an integer representation of money into a Money struct.
Arguments
integeris an integer representation of a money amount including any decimal digits. ie.20000would be interpreted to mean$200.00if thecurrencyis:USDand no:currency_digitsoption was provided.currencyis the currency code for theinteger. The assumed decimal precision is derived from the currency code if nofractional_digitsoption is specified.optionsis a keyword list of options.
Options
:currency_digitswhich determines the currency precision implied by theinteger. The valid options are:cash,:accounting,:isoor a non-negative integer. The default is:isowhich uses the ISO 4217 definition of currency digits.
All other options are passed to Money.new/3.
Returns
A
Money.t/0struct 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
IQDas0whereas ISO 4217 defines3decimal 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_digitsparameter.
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, currency_digits: 3)
Money.new(:USD, "20.012")
iex> Money.from_integer(20012, :IQD)
Money.new(:IQD, "20.012")
Returns a boolean indicating if Money.t/0
is an integer value (has no significant fractional
digits).
Arguments
moneyis any validMoney.t/0type returned byMoney.new/2
Example
iex> Money.integer?(Money.new(:USD, 0))
true
iex> Money.integer?(Money.new(:USD, "1.10"))
false
Localizes a Money by converting it to the currency
of the specified locale.
Arguments
moneyis anyMoney.t/0struct returned byCldr.Currency.new/2.optionsis a keyword list of options.
Options
:localeis any valid locale returned byCldr.known_locale_names/1or aCldr.LanguageTagstruct returned byCldr.Locale.new!/2The default is<backend>.get_locale():backendis any module() that includesuse Cldrand therefore is aCldrbackend module(). The default isMoney.default_backend!/0
Returns
{:ok, localized_money}or{:error, {exception, reason}}
Return the maximum of two Money.t/0 amounts.
Arguments
money_1andmoney_2are any validMoney.t/0types returned byMoney.new/2.money_1andmoney_2should 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."}}
Return the maximum of two Money.t/0 amounts or
raises an exception.
Arguments
money_1andmoney_2are any validMoney.t/0types returned byMoney.new/2.money_1andmoney_2should be of the same currency.
Returns
maximum_moneyorraises 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.
Return the minimum of two Money.t/0 amounts.
Arguments
money_1andmoney_2are any validMoney.t/0types returned byMoney.new/2.money_1andmoney_2should 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."}}
Return the minimum of two Money.t/0 amounts or
raises an exception.
Arguments
money_1andmoney_2are any validMoney.t/0types returned byMoney.new/2.money_1andmoney_2should be of the same currency.
Returns
minimum_moneyorraises 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
moneyis any validMoney.t/0type returned byMoney.new/2.numberis an integer, float orDecimal.t/0.
Note that multipling one
Money.t/0by 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
moneyis any validMoney.t/0type returned byMoney.new/2.numberis an integer, float orDecimal.t/0.
Returns
a
Money.t/0orraises an exception
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
Negate a Money.t/0 value.
Argument
money_1is any validMoney.t/0type.
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)}
Negate a Money.t/0 value or raises an
exception.
Argument
money_1is any validMoney.t/0type.
Returns
negated_moneywith the amount negated orraises 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)
Returns a boolean indicating if Money.t/0
has a negative value.
Arguments
moneyis any validMoney.t/0type returned byMoney.new/2
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
@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_codeis an ISO4217 binary or atom currency code or an ISO 24165 token identifier or shortname.amountis an integer, string or Decimal money amount.optionsis a keyword list of options.
Options
:localeis any known locale. The locale is used to normalize any binary (String) amounts to a form that can be consumed byDecimal.new/1. This consists of removing any localised grouping characters and replacing the localised decimal separator with a ".". The default isCldr.get_locale/0.:backendis any module that includesuse Cldrand therefore is aCldrbackend module. The default isMoney.default_backend!/0.:separatorsselects which of the available symbol sets should be used when attempting to parse a string into a number. The default is:standard. Some limited locales have an alternative:usvariant that can be used. SeeCldr.Number.Symbol.number_symbols_for/3for the symbols supported for a given locale and number system.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"}}
@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_codeis an ISO4217 binary or atom currency code or an ISO 24165 token identifier or shortname.amountis an integer, float or Decimaloptionsis a keyword list of options. SeeMoney.new/3.
Examples
Money.new!(:XYZZ, 100)
** (Money.UnknownCurrencyError) Currency :XYZZ is not known
(ex_money) lib/money.ex:177: Money.new!/2
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
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
stringis a string to be parsedoptionsis a keyword list of options that is passed toMoney.new/3with the exception of the options listed below
Options
:backendis any module() that includesuse Cldrand therefore is aCldrbackend module(). The default isMoney.default_backend!():localeis any valid locale returned byCldr.known_locale_names/1or aCldr.LanguageTagstruct returned byCldr.Locale.new!/2The default is<backend>.get_locale():onlyis anatomor list ofatomsrepresenting 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.:exceptis anatomor list ofatomsrepresenting 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.:fuzzyis a float greater than0.0and less than or equal to1.0which is used as input to theString.jaro_distance/2to 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 than0.8in order to reduce false positives.:default_currencyis any valid currency code orfalsethat will used if no currency code, symbol or description is indentified in the parsed string. The default isnilwhich means that the default currency associated with the:localeoption will be used. Iffalsethen the currency assocated with the:localeoption will not be used and an error will be returned if there is no currency in the string being parsed.
Returns
a
Money.t/0if 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.:currentconsiders those currencies that have a:todate of nil and which also is a known ISO4217 currency.:historicis the opposite of:current.:tenderconsiders currencies that are legal tender.:unannotatedconsiders 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\"."}}
Returns a boolean indicating if Money.t/0
has a positive value.
Arguments
moneyis any validMoney.t/0type returned byMoney.new/2
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
Add format options to a Money.t/0.
Arguments
moneyis any validMoney.t/0type returned byMoney.new/2.optionsis a keyword list of options. These options are used when callingMoney.to_string/2. The default is[].
Set the fractional part of a Money.
Arguments
moneyis anyMoney.t/0.fractionis an integer amount that will be set as the fraction of themoney.
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"}}
Round a Money value into the acceptable range for the requested currency.
Arguments
moneyis anyMoney.t/0.optionsis a keyword list of options.
Options
:rounding_modethat defines how the number will be rounded. SeeDecimal.Context. The default is:half_evenwhich is also known as "banker's rounding".:currency_digitswhich determines the rounding increment. The valid options are:cash,:accountingand:isoor an integer value representing the rounding factor. The default is:iso.
Notes
There are two kinds of rounding applied:
Round to the appropriate number of currency digits.
Apply an appropriate rounding increment. Most currencies round to the same precision as the number of decimal digits, but some such as
:CHFround to a minimum such as0.05when its a cash amount. The rounding increment is applied when the option:fractional_digitsis set to:cash.Digital Tokens (crypto currencies) do not have formal definitions of decimal digits or rounding strategies. Therefore the
moneyis 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(money :: t(), parts :: non_neg_integer(), options :: Keyword.t()) :: {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
moneyis anyMoney.t/0.partsis an integer number of parts into which themoneyis split.optionsis a keyword list of options.
Options
- See
Money.round/2; any options are passed to this function.
Returns
{split_amount, remainder}wheresplit_amountis the amount money allocated by the split andremainderis the amount left over that could not be allocated evenly.
Notes
Returns a tuple {dividend, remainder} as the function result
derived as follows:
Divide the money by the integer divisor.
Round the result of the division to the precision of the currency using
Money.round/2. If the rounding mode results in a negative remainder, the rounding is done again using rounding mode:down.Return two numbers: the result of the division and any remainder that could not be applied given the precision of the currency.
Examples
iex> Money.split(Money.new("123.5", :JPY), 3)
{Money.new(:JPY, "41"), Money.new(:JPY, "0.5")}
iex> Money.split(Money.new("123.4", :JPY), 3)
{Money.new(:JPY, "41"), Money.new(:JPY, "0.4")}
iex> Money.split(Money.new("123.7", :USD), 9)
{Money.new(:USD, "13.74"), Money.new(:USD, "0.04")}
iex> Money.split(Money.new(:USD, 200), 3)
{Money.new(:USD, "66.66"), Money.new(:USD, "0.02")}
Subtract one Money.t/0 value struct from another.
Options
money_1andmoney_2are any validMoney.t/0types returned byMoney.new/2.
Returns
{:ok, money}or{:error, reason}.
Example
iex> Money.sub Money.new(:USD, 200), Money.new(:USD, 100)
{:ok, Money.new(:USD, 100)}
Subtract one Money value struct from another and raise on error.
Returns either {:ok, money} or {:error, reason}.
Arguments
money_1andmoney_2are any validMoney.t/0types returned byMoney.new/2.
Returns
a
Money.t/0struct orraises an exception.
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.
@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
money_listis a list of any validMoney.t/0types returned byMoney.new/2.ratesis a map of exchange rates. The default is the rates returned byMoney.ExchangeRates.latest_rates/0. If the exchange rates retriever is not running, then the default is%{}.
Returns
{:ok, money}wheremoneyis aMoney.t/0representing the sum of the maybe converted money amounts. The currency of the sum is the currency of the firstMoneyin themoney_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.new(:USD, "325.0")}
@spec sum!( [t(), ...], Money.ExchangeRates.t() | {:ok, Money.ExchangeRates.t()} | {:error, {module(), String.t()}} ) :: t() | no_return()
Sum a list of monies that may be in different currencies or raise an exception on error.
Arguments
money_listis a list of any validMoney.t/0types returned byMoney.new/2.ratesis a map of exchange rates. The default is the rates returned byMoney.ExchangeRates.latest_rates/0. If the exchange rates retriever is not running, then the default is%{}.
Returns
A
Money.t/0representing the sum of the maybe converted money amounts. The currency of the sum is the currency of the firstMoneyin themoney_list.raises an exception.
Examples
iex> Money.sum!([Money.new(:USD, 100), Money.new(:USD, 200), Money.new(:USD, 50)])
Money.new(:USD, 350)
iex> Money.sum!([Money.new(:USD, 100), Money.new(:USD, 200), Money.new(:AUD, 50)], %{})
** (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
Money.new(:USD, "325.0")
@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
moneyis anyMoney.t/0struct returned byCldr.Currency.new/2.to_currencyis a valid currency code into which themoneyis converted.ratesis aMapof 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 fromMoney.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"}}
@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
moneyis anyMoney.t/0struct returned byCldr.Currency.new/2.to_currencyis a valid currency code into which themoneyis converted.ratesis aMapof 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 fromMoney.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
Returns the currecny code of a Money type
as an atom.
Arguments
moneyis any validMoney.t/0type returned byMoney.new/2.
Returns
- the currency code as an
t:atom.
Example
iex> m = Money.new("USD", 100)
iex> Money.to_currency_code(m)
:USD
Returns the amount part of a Money type as a Decimal.
Arguments
moneyis any validMoney.t/0type returned byMoney.new/2.
Returns
- a
Decimal.t.
Example
iex> m = Money.new("USD", 100)
iex> Money.to_decimal(m)
Decimal.new(100)
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
moneyis anyMoney.t/0struct returned byCldr.Currency.new/2.
Notes
- Since the returned integer is expected to have the implied fractional
digits the
Moneyneeds 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")}
@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
moneyis any validMoney.t/0type returned byMoney.new/2.optionsis a keyword list of options or aCldr.Number.Format.Options.t/0struct.
Returns
{:ok, string}or{:error, reason}.
Options
:backendis any CLDR backend module. The default isMoney.default_backend!/0.currency_symbol: Allows overriding a currency symbol. The alternatives are::isothe ISO currency code will be used instead of the default currency symbol.:narrowuses 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.:symboluses the standard symbol defined in CLDR. A symbol is unique for each currency and can be safely used.- "string" uses
stringas the currency symbol :standard(the default and recommended) uses the CLDR-defined symbol based upon the currency format for the locale.:nonemeans format the amount without any currency symbol.
:no_fraction_if_integeris a boolean which, iftrue, will set:fractional_digitsto0if 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"}
iex> Money.to_string(Money.new(:EUR, "100"), locale: "bn")
{:ok, "১০০.০০€"}
@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
moneyis any validMoney.t/0type returned byMoney.new/2.optionsis a keyword list of options or a%Cldr.Number.Format.Options{}struct.
Options
:backendis any CLDR backend module. The default isMoney.default_backend!/0.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"
Returns a boolean indicating if the Money.t/0 is in the
range minimum..maximum.
Arguments
money,minimumandmaximumare any validMoney.t/0types returned byMoney.new/2. They should be of the same currency.
Returns
trueorfalse.
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, 10), Money.new(:USD, 50), Money.new(:USD, 50))
false
iex> Money.within?(Money.new(:USD, 50), Money.new(:USD, 50), Money.new(:USD, 50))
true
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
Return a zero amount Money.t/0 in the given currency.
Arguments
money_or_currencyis either aMoney.t/0or a currency code.optionsis a keyword list of options passed toMoney.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"}}
Returns a boolean indicating if Money.t/0
has a zero value.
Arguments
moneyis any validMoney.t/0type returned byMoney.new/2
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