Skip to content

Commit

Permalink
Generate missing exchange rate error during entry normalization
Browse files Browse the repository at this point in the history
  • Loading branch information
jakubkottnauer committed May 26, 2024
1 parent 5d9cf3b commit a6c6653
Show file tree
Hide file tree
Showing 4 changed files with 29 additions and 18 deletions.
40 changes: 25 additions & 15 deletions app/models/account/balance/calculator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ def calculate

private
def convert_balances_to_family_currency
rates = ExchangeRate.get_rate_series(
rates = ExchangeRate.get_rates(
@account.currency,
@account.family.currency,
@calc_start_date..Date.current
Expand All @@ -54,28 +54,38 @@ def convert_balances_to_family_currency
return []
end

@daily_balances.map do |balance|
rate = rates.find { |rate| rate.date == balance[:date] }
raise "Rate for #{@account.currency} to #{@account.family.currency} on #{balance[:date]} not found" if rate.nil?
converted_balance = balance[:balance] * rate.rate
@daily_balances.map.with_index do |balance, index|
converted_balance = balance[:balance] * rates[index].rate
{ date: balance[:date], balance: converted_balance, currency: @account.family.currency, updated_at: Time.current }
end
end

# For calculation, all transactions and valuations need to be normalized to the same currency (the account's primary currency)
def normalize_entries_to_account_currency(entries, value_key)
entries.map do |entry|
currency = entry.currency
date = entry.date
value = entry.send(value_key)
grouped_entries = entries.group_by(&:currency)
normalized_entries = []

grouped_entries.each do |currency, entries|
if currency != @account.currency
value = ExchangeRate.convert(value:, from: currency, to: @account.currency, date:)
currency = @account.currency
dates = entries.map(&:date).uniq
rates = ExchangeRate.get_rates(currency, @account.currency, dates).to_a
if rates.length != dates.length
@errors << :sync_message_missing_rates
else
entries.each do |entry|
## There can be several entries on the same date so we cannot rely on indeces
rate = rates.find { |rate| rate.date == entry.date }
value = entry.send(value_key)
value *= rate.rate
normalized_entries << entry.attributes.merge(value_key.to_s => value, "currency" => currency)
end
end
else
normalized_entries.concat(entries)
end

entry.attributes.merge(value_key.to_s => value, "currency" => currency)
end

normalized_entries
end

def normalized_valuations
Expand All @@ -97,8 +107,8 @@ def implied_start_balance
return @account.balance_on(@calc_start_date)
end

oldest_valuation_date = normalized_valuations.first&.dig("date")
oldest_transaction_date = normalized_transactions.first&.dig("date")
oldest_valuation_date = normalized_valuations.first&.date
oldest_transaction_date = normalized_transactions.first&.date
oldest_entry_date = [ oldest_valuation_date, oldest_transaction_date ].compact.min

if oldest_entry_date.present? && oldest_entry_date == oldest_valuation_date
Expand Down
2 changes: 1 addition & 1 deletion app/models/account/syncable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def sync(start_date = nil)

update!(status: "ok", last_sync_date: Date.today, balance: new_balance, sync_errors: calculator.errors, sync_warnings: calculator.warnings)
rescue => e
update!(status: "error")
update!(status: "error", sync_errors: [ :sync_message_unknown_error ])
logger.error("Failed to sync account #{id}: #{e.message}")
end

Expand Down
4 changes: 2 additions & 2 deletions app/models/exchange_rate.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ def find_rate_or_fetch(from:, to:, date:)
find_rate(from:, to:, date:) || fetch_rate_from_provider(from:, to:, date:)&.tap(&:save!)
end

def get_rate_series(from, to, date_range)
where(base_currency: from, converted_currency: to, date: date_range).order(:date)
def get_rates(from, to, dates)
where(base_currency: from, converted_currency: to, date: dates).order(:date)
end

def convert(value:, from:, to:, date:)
Expand Down
1 change: 1 addition & 0 deletions config/locales/views/account/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ en:
confirm_title: Delete account?
sync_message_missing_rates: Since exchange rates haven't been synced, balance
graphs may not reflect accurate values.
sync_message_unknown_error: An error has occurred during the sync.
summary:
new: New account
sync:
Expand Down

0 comments on commit a6c6653

Please sign in to comment.