mirror of
https://github.com/we-promise/sure.git
synced 2026-04-19 03:54:08 +00:00
* Placeholder logic for missing prices * Generate holdings properly for "offline" securities * Separate forward and reverse calculators for holdings and balances * Remove unnecessary currency conversion during sync * Clearer sync process * Move price caching logic to dedicated model * Base holding calculator * Base calculator for balances * Finish balance calculators * Better naming * Logs cleanup * Remove stale data type * Remove stale test * Fix price lookup logic for holdings sync * Fix Plaid item sync regression * Remove temp logging * Calculate cash and holdings series * Add holdings, cash, and balance series dropdown for investments
70 lines
1.9 KiB
Ruby
70 lines
1.9 KiB
Ruby
class Account::Balance::Syncer
|
|
attr_reader :account, :strategy
|
|
|
|
def initialize(account, strategy:)
|
|
@account = account
|
|
@strategy = strategy
|
|
end
|
|
|
|
def sync_balances
|
|
Account::Balance.transaction do
|
|
sync_holdings
|
|
calculate_balances
|
|
|
|
Rails.logger.info("Persisting #{@balances.size} balances")
|
|
persist_balances
|
|
|
|
purge_stale_balances
|
|
|
|
if strategy == :forward
|
|
update_account_info
|
|
end
|
|
end
|
|
end
|
|
|
|
private
|
|
def sync_holdings
|
|
@holdings = Account::Holding::Syncer.new(account, strategy: strategy).sync_holdings
|
|
end
|
|
|
|
def update_account_info
|
|
calculated_balance = @balances.sort_by(&:date).last&.balance || 0
|
|
calculated_holdings_value = @holdings.select { |h| h.date == Date.current }.sum(&:amount) || 0
|
|
calculated_cash_balance = calculated_balance - calculated_holdings_value
|
|
|
|
Rails.logger.info("Balance update: cash=#{calculated_cash_balance}, total=#{calculated_balance}")
|
|
|
|
account.update!(
|
|
balance: calculated_balance,
|
|
cash_balance: calculated_cash_balance
|
|
)
|
|
end
|
|
|
|
def calculate_balances
|
|
@balances = calculator.calculate
|
|
end
|
|
|
|
def persist_balances
|
|
current_time = Time.now
|
|
account.balances.upsert_all(
|
|
@balances.map { |b| b.attributes
|
|
.slice("date", "balance", "cash_balance", "currency")
|
|
.merge("updated_at" => current_time) },
|
|
unique_by: %i[account_id date currency]
|
|
)
|
|
end
|
|
|
|
def purge_stale_balances
|
|
deleted_count = account.balances.delete_by("date < ?", account.start_date)
|
|
Rails.logger.info("Purged #{deleted_count} stale balances") if deleted_count > 0
|
|
end
|
|
|
|
def calculator
|
|
if strategy == :reverse
|
|
Account::Balance::ReverseCalculator.new(account)
|
|
else
|
|
Account::Balance::ForwardCalculator.new(account)
|
|
end
|
|
end
|
|
end
|