Money v0.2.0 Money View Source
Money implements a set of functions to store, retrieve and perform arithmetic on a %Money{} type that is composed of a currency code and a currency amount.
Money is very opinionated in the interests of serving as a dependable library that can underpin accounting and financial applications. In its initial release it can be expected that this contract may not be fully met.
How is this opinion expressed:
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.
Link to this section Summary
Functions
Add two Money values
Add two Money values and raise 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
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
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
Calculates the future value for a list of cash flows and an interest rate
Calculates the future value for a present value, an interest rate and a number of periods
Calculates the effective interest rate for a given present value, a future value and a number of periods
Calculates the interal rate of return for a given list of cash flows
Multiply a Money value by a number
Multiply a Money value by a number and raise on error
Calculates the net present value of an initial investment, a list of cash flows and an interest rate
Calculates the net present value of an initial investment, a recurring payment, an interest rate and a number of periods
Returns a %Money{} struct from a tuple consistenting of a currency code and a currency amount. The format of the argument is a 2-tuple where
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 tuple consistenting of a currency code and a currency amount. Raises an exception if the currency code is invalid
Returns a %Money{} struct from a currency code and a currency amount. Raises an exception if the current code is invalid
Calculates the payment for a given loan or annuity given a present value, an interest rate and a number of periods
Calculates the number of periods between a present value and a future value with a given interest rate
Calculates the present value for a list of cash flows and an interest rate
Calculates the present value for future value, an interest rate and a number of periods
Round a Money value into the acceptable range for the defined 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
Called when an application is started
Subtract one Money value struct from another
Subtract one Money value struct from another and raise on error
Convert money from one currency to another
Convert money from one currency to another and raises on error
Returns a formatted string representation of a Money{}
Link to this section Types
Money is composed of an atom representation of an ISO4217 currency code and
a Decimal representation of an amount.
Link to this section Functions
Add two Money values.
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 values and raise on error.
Examples
iex> Money.add! Money.new(:USD, 200), Money.new(:USD, 100)
#Money<:USD, 300>
Money.add! Money.new(:USD, 200), Money.new(:CAD, 500)
** (ArgumentError) Cannot add two %Money{} 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.
Examples
iex> Money.cmp Money.new(:USD, 200), Money.new(:USD, 100)
:gt
iex> Money.cmp Money.new(:USD, 200), Money.new(:USD, 200)
:eq
iex> Money.cmp Money.new(:USD, 200), Money.new(:USD, 500)
:lt
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.
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 #Integer<1> is returned, if less than Integer<-1> is
returned. Otherwise, if both numbers are equal Integer<0> is returned.
Examples
iex> Money.compare Money.new(:USD, 200), Money.new(:USD, 100)
1
iex> Money.compare Money.new(:USD, 200), Money.new(:USD, 200)
0
iex> Money.compare Money.new(:USD, 200), Money.new(:USD, 500)
-1
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.
Examples
Money.compare! Money.new(:USD, 200), Money.new(:CAD, 500)
** (ArgumentError) Cannot compare monies with different currencies. Received :USD and :CAD.
Divide a Money value by a number.
moneyis a %Money{} structnumberis an integer or float
Note that dividing one %Money{} by another is not supported.
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\""}}
Divide a Money value by a number and raise on error.
Examples
iex> Money.div Money.new(:USD, 200), 2
{:ok, Money.new(:USD, 100)}
Money.div(Money.new(:USD, 200), "xx")
** (ArgumentError) "Cannot divide money by \"xx\""]}}
Returns a boolean indicating if two Money values are equal
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
Calculates the future value for a list of cash flows and an interest rate.
flowsis a list of tuples representing a cash flow. Each flow is represented as a tuple of the form{period, %Money{}}interest_rateis a float representation of an interest rate. For example, 12% would be represented as0.12
Example
iex> Money.future_value([{4, Money.new(:USD, 10000)}, {5, Money.new(:USD, 10000)}, {6, Money.new(:USD, 10000)}], 0.13)
#Money<:USD, 34068.99999999999999999999999>
iex> Money.future_value [{0, Money.new(:USD, 5000)},{1, Money.new(:USD, 2000)}], 0.12
#Money<:USD, 7600.000000000000000000000000>
Calculates the future value for a present value, an interest rate and a number of periods.
present_valueis a %Money{} representation of the present valueinterest_rateis a float representation of an interest rate. For example, 12% would be represented as0.12periodsin an integer number of periods
Examples
iex> Money.future_value Money.new(:USD, 10000), 0.08, 1
#Money<:USD, 10800.00>
iex> Money.future_value Money.new(:USD, 10000), 0.04, 2
#Money<:USD, 10816.0000>
iex> Money.future_value Money.new(:USD, 10000), 0.02, 4
#Money<:USD, 10824.32160000>
Calculates the effective interest rate for a given present value, a future value and a number of periods.
present_valueis a %Money{} representation of the present valuefuture_valueis a %Money{} representation of the future valueperiodsis an integer number of a period
Examples
iex> Money.interest_rate Money.new(:USD, 10000), Money.new(:USD, 10816), 2
#Decimal<0.04>
iex> Money.interest_rate Money.new(:USD, 10000), Money.new(:USD, 10824.3216), 4
#Decimal<0.02>
Calculates the interal rate of return for a given list of cash flows.
flowsis a list of tuples representing a cash flow. Each flow is represented as a tuple of the form{period, %Money{}}
Multiply a Money value by a number.
moneyis a %Money{} structnumberis an integer or float
Note that multipling one %Money{} by another is not supported.
Returns either {: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\""}}
Multiply a Money value by a number and raise on error.
Examples
iex> Money.mult!(Money.new(:USD, 200), 2)
#Money<:USD, 400>
Money.mult!(Money.new(:USD, 200), :invalid)
** (ArgumentError) Cannot multiply money by :invalid
Calculates the net present value of an initial investment, a list of cash flows and an interest rate.
flowsis a list of tuples representing a cash flow. Each flow is represented as a tuple of the form{period, %Money{}}interest_rateis a float representation of an interest rate. For example, 12% would be represented as0.12investmentis a %Money{} struct representing the initial investment
Example
iex> flows = [{0, Money.new(:USD, 5000)},{1, Money.new(:USD, 2000)},{2, Money.new(:USD, 500)},{3, Money.new(:USD,10_000)}]
iex> Money.net_present_value flows, 0.08, Money.new(:USD, 100)
#Money<:USD, 15118.84367220444038002337042>
iex> Money.net_present_value flows, 0.08
#Money<:USD, 15218.84367220444038002337042>
Calculates the net present value of an initial investment, a recurring payment, an interest rate and a number of periods
investmentis a %Money{} struct representing the initial investmentfuture_valueis a %Money{} representation of the future valueinterest_rateis a float representation of an interest rate. For example, 12% would be represented as0.12periodsin an integer number of a period
Example
iex> Money.net_present_value Money.new(:USD, 10000), 0.13, 2
#Money<:USD, 7831.466833737959119743127888>
iex> Money.net_present_value Money.new(:USD, 10000), 0.13, 2, Money.new(:USD, 100)
#Money<:USD, 7731.466833737959119743127888>
Returns a %Money{} struct from a tuple consistenting of a currency code and a currency amount. The format of the argument is a 2-tuple where:
currency_codeis an ISO4217 three-character upcased binaryamountis an integer, float or Decimal
This function is typically called from Ecto when it’s loading a %Money{} struct from the database.
Example
iex> Money.new({"USD", 100})
#Money<:USD, 100>
Returns a %Money{} struct from a currency code and a currency amount or
an error tuple of the form {:error, {exception, message}}.
currency_codeis an ISO4217 three-character upcased binary or atomamountis an integer, float or Decimal
Examples
iex> Money.new(:USD, 100)
#Money<:USD, 100>
iex> Money.new("USD", 100)
#Money<:USD, 100>
iex> Money.new("thb", 500)
#Money<:THB, 500>
iex> Money.new(500, "thb")
#Money<:THB, 500>
iex> Money.new("EUR", Decimal.new(100))
#Money<:EUR, 100>
iex> Money.new(:XYZZ, 100)
{:error, {Money.UnknownCurrencyError, "Currency :XYZZ is not known"}}
Returns a %Money{} struct from a tuple consistenting of a currency code and a currency amount. Raises an exception if the currency code is invalid.
currency_codeis an ISO4217 three-character upcased binaryamountis an integer, float or Decimal
This function is typically called from Ecto when it’s loading a %Money{} struct from the database.
Example
iex> Money.new!({"USD", 100})
#Money<:USD, 100>
Money.new!({"NO!", 100})
** (Money.UnknownCurrencyError) Currency "NO!" is not known
(ex_money) lib/money.ex:130: Money.new!/1
Returns a %Money{} struct from a currency code and a currency amount. Raises an exception if the current code is invalid.
currency_codeis an ISO4217 three-character upcased binary or atomamountis 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
Calculates the payment for a given loan or annuity given a present value, an interest rate and a number of periods.
present_valueis a %Money{} representation of the present valueinterest_rateis a float representation of an interest rate. For example, 12% would be represented as0.12periodsis an integer number of periods
Example
iex> Money.payment Money.new(:USD, 100), 0.12, 20
#Money<:USD, 13.38787800396606622792492299>
Calculates the number of periods between a present value and a future value with a given interest rate.
present_valueis a %Money{} representation of the present valuefuture_valueis a %Money{} representation of the future valueinterest_rateis a float representation of an interest rate. For example, 12% would be represented as0.12
Example
iex> Money.periods Money.new(:USD, 1500), Money.new(:USD, 2000), 0.005
#Decimal<57.68013595323872502502238648>
Calculates the present value for a list of cash flows and an interest rate.
flowsis a list of tuples representing a cash flow. Each flow is represented as a tuple of the form{period, %Money{}}interest_rateis a float representation of an interest rate. For example, 12% would be represented as0.12
Example
iex> Money.present_value([{4, Money.new(:USD, 10000)}, {5, Money.new(:USD, 10000)}, {6, Money.new(:USD, 10000)}], 0.13)
#Money<:USD, 16363.97191111964880256655144>
iex> Money.present_value [{0, Money.new(:USD, -1000)},{1, Money.new(:USD, -4000)}], 0.1
#Money<:USD, -4636.363636363636363636363636>
Calculates the present value for future value, an interest rate and a number of periods
future_valueis a %Money{} representation of the future valueinterest_rateis a float representation of an interest rate. For example, 12% would be represented as0.12periodsin an integer number of periods
Examples
iex> Money.present_value Money.new(:USD, 100), 0.08, 2
#Money<:USD, 85.73388203017832647462277092>
iex> Money.present_value Money.new(:USD, 1000), 0.10, 20
#Money<:USD, 148.6436280241436864020760472>
Round a Money value into the acceptable range for the defined currency.
moneyis a%Money{}structoptsis a keyword list with the following keys::rounding_modethat defines how the number will be rounded. SeeDecimal.Context. The default is:half_evenwhich is also known as “banker’s rounding”:cashwhich determines whether the rounding is being applied to an accounting amount or a cash amount. Some currencies, such as the :AUD and :CHF have a cash unit increment minimum which requires a different rounding increment to an arbitrary accounting amount. The default isfalse.
There are two kinds of rounding applied:
Round to the appropriate number of fractional digits
Apply an appropriate rounding increment. Most currencies round to the same precision as the number of decimal digits, but some such as :AUD and :CHF round to a minimum such as 0.05 when its a cash amount.
Examples
iex> Money.round Money.new(123.7456, :CHF), cash: true
#Money<:CHF, 125>
iex> Money.round Money.new(123.7456, :CHF)
#Money<:CHF, 123.75>
Money.round Money.new(123.7456, :JPY)
#Money<:JPY, 124>
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.
moneyis a%Money{}structpartsis an integer number of parts into which themoneyis split
Returns a tuple {dividend, remainder} as the function result
derived as follows:
Round the money amount to the required currency precision using
Money.round/1Divide the result of step 1 by the integer divisor
Round the result of the division to the precision of the currency using
Money.round/1Return 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}
Called when an application is started.
This function is called when an the application is started using
Application.start/2 (and functions on top of that, such as
Application.ensure_started/2). This function should start the top-level
process of the application (which should be the top supervisor of the
application’s supervision tree if the application follows the OTP design
principles around supervision).
start_type defines how the application is started:
:normal- used if the startup is a normal startup or if the application is distributed and is started on the current node because of a failover from another mode and the application specification key:start_phasesis:undefined.{:takeover, node}- used if the application is distributed and is started on the current node because of a failover on the nodenode.{:failover, node}- used if the application is distributed and is started on the current node because of a failover on nodenode, and the application specification key:start_phasesis not:undefined.
start_args are the arguments passed to the application in the :mod
specification key (e.g., mod: {MyApp, [:my_args]}).
This function should either return {:ok, pid} or {:ok, pid, state} if
startup is successful. pid should be the PID of the top supervisor. state
can be an arbitrary term, and if omitted will default to []; if the
application is later stopped, state is passed to the stop/1 callback (see
the documentation for the c:stop/1 callback for more information).
use Application provides no default implementation for the start/2
callback.
Callback implementation for Application.start/2.
Subtract one Money value struct from another.
Returns either {: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}.
Examaples
iex> Money.sub! Money.new(:USD, 200), Money.new(:USD, 100)
#Money<:USD, 100>
Money.sub! Money.new(:USD, 200), Money.new(:CAD, 500)
** (ArgumentError) Cannot subtract monies with different currencies. Received :USD and :CAD.
Convert money from one currency to another.
moneyis a %Money{} structto_currencyis a valid currency code into which themoneyis convertedratesis aMapof currency rates where the map key is an upcase atom and the value is a Decimal conversion factor. The default is the latest available exchange rates returned fromMoney.ExchangeRates.latest_rates()
Examples
Money.to_currency(Money.new(:USD, 100), :AUD, %{USD: Decimal.new(1), AUD: Decimal.new(0.7345)})
{:ok, #Money<:AUD, 73.4500>}
iex> Money.to_currency Money.new(:USD, 100) , :AUDD, %{USD: Decimal.new(1), AUD: Decimal.new(0.7345)}
{:error, {Cldr.UnknownCurrencyError, "Currency :AUDD is not known"}}
iex> Money.to_currency Money.new(:USD, 100) , :CHF, %{USD: Decimal.new(1), AUD: Decimal.new(0.7345)}
{:error, "No exchange rate is available for currency :CHF"}
Convert money from one currency to another and raises on error
Examples
iex> Money.to_currency! Money.new(:USD, 100) , :AUD, %{USD: Decimal.new(1), AUD: Decimal.new(0.7345)}
#Money<:AUD, 73.4500>
Money.to_currency! Money.new(:USD, 100) , :ZZZ, %{USD: Decimal.new(1), AUD: Decimal.new(0.7345)}
** (Cldr.UnknownCurrencyError) Currency :ZZZ is not known
Returns the amount part of a Money type as a Decimal
Example
iex> m = Money.new("USD", 100)
iex> Money.to_decimal(m)
#Decimal<100>
Returns a formatted string representation of a Money{}.
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.
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)
"THB1,234.00"
iex> Money.to_string Money.new(:USD, 1234), format: :long
"1,234 US dollars"