Packages
ex_money
6.1.1
6.1.1
6.1.0
6.0.0
6.0.0-rc.0
5.24.2
5.24.1
5.24.0
retired
5.23.0
5.22.0
5.21.0
5.20.0
5.19.2
5.19.1
5.19.0
5.18.0
5.17.2
5.17.1
5.17.0
5.16.1
5.16.0
5.15.4
5.15.3
5.15.2
5.15.1
5.15.0
5.14.1
5.13.0
5.12.4
5.12.3
5.12.2
5.12.1
5.12.0
5.11.0
5.10.0
5.9.0
5.8.0
5.7.4
5.7.3
5.7.2
5.7.1
5.7.0
5.6.0
5.5.5
5.5.4
5.5.3
5.5.2
5.5.1
5.5.0
5.4.1
5.4.0
5.4.0-rc.0
5.3.2
5.3.1
5.3.0
5.2.1
5.2.0
5.1.0
5.0.2
5.0.1
5.0.0
retired
4.4.3
4.4.2
retired
4.4.1
4.4.0
4.3.0
4.2.2
4.2.1
4.2.0
4.1.0
4.0.0
3.4.4
3.4.3
3.4.2
3.4.1
3.4.0
3.3.1
3.3.0
3.2.4
3.2.3
3.2.2
3.2.1
3.2.0
3.1.0
3.0.0
2.12.2
2.12.1
retired
2.12.0
retired
2.11.0
2.10.0
2.9.1
2.9.0
2.8.0
2.7.3
2.7.2
2.7.1
2.7.0
2.6.1
2.6.0
2.5.0
2.4.0
2.3.0
2.2.2
2.2.1
2.2.0
2.1.0
2.1.0-rc.1
retired
2.1.0-rc.0
retired
2.0.4
2.0.3
2.0.2
2.0.1
2.0.0
1.1.3
1.1.2
1.1.1
retired
1.1.0
1.0.0
1.0.0-rc.0
retired
0.9.0
retired
0.8.5
retired
0.8.4
retired
0.8.3
retired
0.8.2
retired
0.8.1
retired
0.8.0
retired
0.7.0
retired
0.6.2
retired
0.6.1
retired
0.6.0
retired
0.5.3
retired
0.5.2
retired
0.5.1
retired
0.5.0
retired
0.4.3
retired
0.4.2
retired
0.4.1
retired
0.4.0
retired
0.3.0
retired
0.2.0
retired
0.1.7
retired
0.1.6
retired
0.1.5
retired
0.1.4
retired
0.1.3
retired
0.1.2
retired
0.1.1
retired
0.1.0
retired
0.0.16
retired
0.0.15
retired
0.0.14
retired
0.0.13
retired
0.0.12
retired
0.0.11
retired
0.0.10
retired
0.0.9
retired
0.0.7
retired
0.0.6
retired
0.0.5
retired
0.0.4
retired
0.0.3
retired
0.0.2
retired
Money functions for operations on and localization of a money data type with support for ISO 4217 currencies and ISO 24165 digial tokens (crypto currencies).
Current section
Files
Jump to
Current section
Files
lib/money/exchange_rates/open_exchange_rates.ex
defmodule Money.ExchangeRates.OpenExchangeRates do
@moduledoc """
Implements the `Money.ExchangeRates` for the Open Exchange
Rates service.
## Required configuration:
The configuration key `:open_exchange_rates_app_id` should be
set to your `app_id`. For example:
config :ex_money,
open_exchange_rates_app_id: "your_app_id"
or configure it via environment variable:
config :ex_money,
open_exchange_rates_app_id: {:system, "OPEN_EXCHANGE_RATES_APP_ID"}
It is also possible to configure an alternative base url for this
service in case it changes in the future. For example:
config :ex_money,
open_exchange_rates_app_id: "your_app_id"
open_exchange_rates_url: "https://openexchangerates.org/alternative_api"
"""
alias Money.ExchangeRates.HTTP
@behaviour Money.ExchangeRates
@open_exchange_rate_url "https://openexchangerates.org/api"
@doc """
Update the retriever configuration to include the requirements
for Open Exchange Rates. This function is invoked when the
exchange rate service starts up, just after the ets table
:exchange_rates is created.
* `default_config` is the configuration returned by `Money.ExchangeRates.default_config/0`
Returns the configuration either unchanged or updated with
additional configuration specific to this exchange
rates retrieval module.
"""
@impl true
def init(default_config) do
url = Money.get_env(:open_exchange_rates_url, @open_exchange_rate_url)
app_id = Money.get_env(:open_exchange_rates_app_id, nil)
Map.put(default_config, :retriever_options, %{url: url, app_id: app_id})
end
@doc false
def decode_rates(body) when is_list(body) do
body
|> List.to_string()
|> decode_rates()
end
def decode_rates(body) when is_binary(body) do
%{"base" => _base, "rates" => rates} = :json.decode(body)
rates
|> Localize.Utils.Map.atomize_keys()
|> Enum.map(fn
{k, v} when is_float(v) -> {k, Decimal.from_float(v)}
{k, v} when is_integer(v) -> {k, Decimal.new(v)}
end)
|> Enum.into(%{})
end
@doc """
Retrieves the latest exchange rates from Open Exchange Rates site.
* `config` is the retrieval configuration. When invoked from the
exchange rates service this will be the config returned from
`Money.ExchangeRates.config/0`
Returns:
* `{:ok, rates}` if the rates can be retrieved
* `{:ok, :not_modified}` if the rates are unchanged since the last retrieval
* `{:error, reason}` if rates cannot be retrieved
Typically this function is called by the exchange rates retrieval
service although it can be called outside that context as
required.
"""
@impl true
def get_latest_rates(config) do
url = config.retriever_options.url
app_id = config.retriever_options.app_id
retrieve_latest_rates(url, app_id, config)
end
defp retrieve_latest_rates(_url, nil, _config) do
{:error, app_id_not_configured()}
end
@latest_rates "/latest.json"
defp retrieve_latest_rates(url, app_id, config) do
case HTTP.get(url <> @latest_rates <> "?app_id=" <> app_id, verify_peer: config.verify_peer) do
{:ok, :not_modified} -> {:ok, :not_modified}
{:ok, response} -> {:ok, decode_rates(response)}
error -> error
end
end
@doc """
Retrieves the historic exchange rates from Open Exchange Rates site.
* `date` is a `t:Date.t/0` or any date-compatible map or struct (`t:Calendar.date/0`).
* `config` is the retrieval configuration. When invoked from the
exchange rates service this will be the config returned from
`Money.ExchangeRates.config/0`
Returns:
* `{:ok, rates}` if the rates can be retrieved
* `{:ok, :not_modified}` if the rates are unchanged since the last retrieval
* `{:error, reason}` if rates cannot be retrieved
Typically this function is called by the exchange rates retrieval
service although it can be called outside that context as
required.
"""
@impl true
def get_historic_rates(date, config) do
url = config.retriever_options.url
app_id = config.retriever_options.app_id
retrieve_historic_rates(date, url, app_id, config)
end
defp retrieve_historic_rates(_date, _url, nil, _config) do
{:error, app_id_not_configured()}
end
@historic_rates "/historical/"
defp retrieve_historic_rates(date, url, app_id, config) do
date_string = Date.to_string(date)
case HTTP.get(
url <> @historic_rates <> "#{date_string}.json" <> "?app_id=" <> app_id,
verify_peer: config.verify_peer
) do
{:ok, :not_modified} -> {:ok, :not_modified}
{:ok, response} -> {:ok, decode_rates(response)}
error -> error
end
end
defp app_id_not_configured do
"Open Exchange Rates app_id is not configured. Rates are not retrieved."
end
end