Skip to content
This repository was archived by the owner on Jul 27, 2025. It is now read-only.

Commit a0f7af8

Browse files
committed
Add Opening Balance manager, add tests to forward calculator
1 parent 240c11c commit a0f7af8

File tree

8 files changed

+322
-78
lines changed

8 files changed

+322
-78
lines changed

app/models/account.rb

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
class Account < ApplicationRecord
2-
include Syncable, Monetizable, Chartable, Linkable, Enrichable
3-
include AASM
2+
include AASM, Syncable, Monetizable, Chartable, Linkable, Enrichable, Anchorable
43

54
validates :name, :balance, :currency, presence: true
65

app/models/account/anchorable.rb

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# All accounts are "anchored" with start/end valuation records, with transactions,
2+
# trades, and reconciliations between them.
3+
module Account::Anchorable
4+
extend ActiveSupport::Concern
5+
6+
included do
7+
include Monetizable
8+
9+
monetize :opening_balance, :opening_cash_balance
10+
end
11+
12+
def set_opening_balance(**opts)
13+
opening_balance_manager.set_opening_balance(**opts)
14+
end
15+
16+
def opening_date
17+
opening_balance_manager.opening_date
18+
end
19+
20+
def opening_balance
21+
opening_balance_manager.opening_balance
22+
end
23+
24+
def opening_cash_balance
25+
opening_balance_manager.opening_cash_balance
26+
end
27+
28+
private
29+
def opening_balance_manager
30+
@opening_balance_manager ||= Account::OpeningBalanceManager.new(self)
31+
end
32+
end

app/models/account/opening_balance_manager.rb

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,19 @@ def initialize(account)
55
@account = account
66
end
77

8+
# Most accounts should have an opening anchor. If not, we derive the opening date from the oldest entry date
9+
def opening_date
10+
opening_anchor_valuation&.entry&.date || account.entries.order(:date).first&.date || Date.current
11+
end
12+
13+
def opening_balance
14+
opening_anchor_valuation&.balance || 0
15+
end
16+
17+
def opening_cash_balance
18+
opening_anchor_valuation&.cash_balance || 0
19+
end
20+
821
def set_opening_balance(balance:, cash_balance: nil, date: nil)
922
resolved_date = date || default_date
1023
resolved_cash_balance = cash_balance || default_cash_balance(balance)

app/models/balance/forward_calculator.rb

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,16 +13,18 @@ def calculate
1313

1414
private
1515
def calculate_balances
16-
current_cash_balance = 0
16+
current_cash_balance = account.opening_cash_balance
1717
next_cash_balance = nil
1818

1919
@balances = []
2020

21-
account.start_date.upto(Date.current).each do |date|
21+
end_date = [ account.entries.order(:date).last&.date, account.holdings.order(:date).last&.date ].compact.max || Date.current
22+
23+
account.opening_date.upto(end_date).each do |date|
2224
entries = sync_cache.get_entries(date)
2325
holdings = sync_cache.get_holdings(date)
2426
holdings_value = holdings.sum(&:amount)
25-
valuation = sync_cache.get_valuation(date)
27+
valuation = sync_cache.get_reconciliation_valuation(date)
2628

2729
next_cash_balance = if valuation
2830
valuation.amount - holdings_value

app/models/balance/sync_cache.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ def get_valuation(date)
77
converted_entries.find { |e| e.date == date && e.valuation? }
88
end
99

10+
def get_reconciliation_valuation(date)
11+
converted_entries.find { |e| e.date == date && e.valuation? && e.valuation.reconciliation? }
12+
end
13+
1014
def get_holdings(date)
1115
converted_holdings.select { |h| h.date == date }
1216
end

app/models/balance/trend_calculator.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ def trend_for(date)
1818
BalanceTrend.new(
1919
trend: Trend.new(
2020
current: Money.new(balance.balance, balance.currency),
21-
previous: Money.new(prior_balance.balance, balance.currency),
21+
previous: prior_balance.present? ? Money.new(prior_balance.balance, balance.currency) : nil,
2222
favorable_direction: balance.account.favorable_direction
2323
),
2424
cash: Money.new(balance.cash_balance, balance.currency),

0 commit comments

Comments
 (0)