mirror of
https://github.com/maybe-finance/maybe.git
synced 2025-07-19 05:09:38 +02:00
Handle missing exchange rate provider, allow fallback for missing rates (#955)
* Clean up exchange rate logic * Remove stale method
This commit is contained in:
parent
bef335c631
commit
6767aaed1d
20 changed files with 383 additions and 609 deletions
24
lib/money.rb
24
lib/money.rb
|
@ -2,7 +2,10 @@ class Money
|
|||
include Comparable, Arithmetic
|
||||
include ActiveModel::Validations
|
||||
|
||||
attr_reader :amount, :currency
|
||||
class ConversionError < StandardError
|
||||
end
|
||||
|
||||
attr_reader :amount, :currency, :store
|
||||
|
||||
validate :source_must_be_of_known_type
|
||||
|
||||
|
@ -16,20 +19,27 @@ class Money
|
|||
end
|
||||
end
|
||||
|
||||
def initialize(obj, currency = Money.default_currency)
|
||||
def initialize(obj, currency = Money.default_currency, store: ExchangeRate)
|
||||
@source = obj
|
||||
@amount = obj.is_a?(Money) ? obj.amount : BigDecimal(obj.to_s)
|
||||
@currency = obj.is_a?(Money) ? obj.currency : Money::Currency.new(currency)
|
||||
@store = store
|
||||
|
||||
validate!
|
||||
end
|
||||
|
||||
# TODO: Replace with injected rate store
|
||||
def exchange_to(other_currency, date = Date.current)
|
||||
if currency == Money::Currency.new(other_currency)
|
||||
def exchange_to(other_currency, date: Date.current, fallback_rate: nil)
|
||||
iso_code = currency.iso_code
|
||||
other_iso_code = Money::Currency.new(other_currency).iso_code
|
||||
|
||||
if iso_code == other_iso_code
|
||||
self
|
||||
elsif rate = ExchangeRate.find_rate(from: currency, to: other_currency, date: date)
|
||||
Money.new(amount * rate.rate, other_currency)
|
||||
else
|
||||
exchange_rate = store.find_rate(from: iso_code, to: other_iso_code, date: date)&.rate || fallback_rate
|
||||
|
||||
raise ConversionError.new("Couldn't find exchange rate from #{iso_code} to #{other_iso_code} on #{date}") unless exchange_rate
|
||||
|
||||
Money.new(amount * exchange_rate, other_iso_code)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -45,8 +45,8 @@ namespace :demo_data do
|
|||
exchange_rates = (0..60).map do |days_ago|
|
||||
{
|
||||
date: Date.current - days_ago.days,
|
||||
base_currency: "EUR",
|
||||
converted_currency: "USD",
|
||||
from_currency: "EUR",
|
||||
to_currency: "USD",
|
||||
rate: rand(1.0840..1.0924).round(4)
|
||||
}
|
||||
end
|
||||
|
@ -54,18 +54,18 @@ namespace :demo_data do
|
|||
exchange_rates += (0..20).map do |days_ago|
|
||||
{
|
||||
date: Date.current - days_ago.days,
|
||||
base_currency: "BTC",
|
||||
converted_currency: "USD",
|
||||
from_currency: "BTC",
|
||||
to_currency: "USD",
|
||||
rate: rand(60000..65000).round(2)
|
||||
}
|
||||
end
|
||||
|
||||
# Multi-currency account needs a few USD:EUR rates
|
||||
exchange_rates += [
|
||||
{ date: Date.current - 45.days, base_currency: "USD", converted_currency: "EUR", rate: 0.89 },
|
||||
{ date: Date.current - 34.days, base_currency: "USD", converted_currency: "EUR", rate: 0.87 },
|
||||
{ date: Date.current - 28.days, base_currency: "USD", converted_currency: "EUR", rate: 0.88 },
|
||||
{ date: Date.current - 14.days, base_currency: "USD", converted_currency: "EUR", rate: 0.86 }
|
||||
{ date: Date.current - 45.days, from_currency: "USD", to_currency: "EUR", rate: 0.89 },
|
||||
{ date: Date.current - 34.days, from_currency: "USD", to_currency: "EUR", rate: 0.87 },
|
||||
{ date: Date.current - 28.days, from_currency: "USD", to_currency: "EUR", rate: 0.88 },
|
||||
{ date: Date.current - 14.days, from_currency: "USD", to_currency: "EUR", rate: 0.86 }
|
||||
]
|
||||
|
||||
ExchangeRate.insert_all(exchange_rates)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue