1
0
Fork 0
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:
Zach Gollwitzer 2024-07-08 09:04:59 -04:00 committed by GitHub
parent bef335c631
commit 6767aaed1d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
20 changed files with 383 additions and 609 deletions

View file

@ -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

View file

@ -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)