Skip to content
This repository was archived by the owner on Jul 27, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 5 additions & 66 deletions app/components/UI/account/activity_date.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -17,81 +17,20 @@

<div class="flex items-center gap-4">
<div class="flex items-center gap-2">
<span class="font-medium"><%= balance_trend.current.format %></span>
<span class="font-medium"><%= end_balance_money.format %></span>
<%= render DS::Tooltip.new(text: "The end of day balance, after all transactions and adjustments", placement: "left", size: "sm") %>
</div>
<%= helpers.icon "chevron-down", class: "group-open:rotate-180" %>
</div>
</div>
</summary>

<div class="p-4 space-y-3">
<dl class="flex gap-4 items-center text-sm text-primary">
<dt class="flex items-center gap-2">
Start of day balance
<%= render DS::Tooltip.new(text: "The account balance at the beginning of this day, before any transactions or value changes", placement: "left", size: "sm") %>
</dt>
<hr class="grow border-dashed border-secondary">
<dd class="font-bold"><%= start_balance_money.format %></dd>
</dl>

<% if account.balance_type == :investment %>
<dl class="flex gap-4 items-center text-sm text-primary">
<dt class="flex items-center gap-2">
&#916; Cash
<%= render DS::Tooltip.new(text: "Net change in cash from deposits, withdrawals, and other cash transactions during the day", placement: "left", size: "sm") %>
</dt>
<hr class="grow border-dashed border-secondary">
<dd><%= cash_change_money.format %></dd>
</dl>

<dl class="flex gap-4 items-center text-sm text-primary">
<dt class="flex items-center gap-2">
&#916; Holdings
<%= render DS::Tooltip.new(text: "Net change in investment holdings value from buying, selling, or market price movements", placement: "left", size: "sm") %>
</dt>
<hr class="grow border-dashed border-secondary">
<dd><%= holdings_change_money.format %></dd>
</dl>
<div class="p-4">
<% if balance %>
<%= render UI::Account::BalanceReconciliation.new(balance: balance, account: account) %>
<% else %>
<dl class="flex gap-4 items-center text-sm text-primary">
<dt class="flex items-center gap-2">
&#916; Cash
<%= render DS::Tooltip.new(text: "Net change in cash balance from all transactions during the day", placement: "left", size: "sm") %>
</dt>
<hr class="grow border-dashed border-secondary">
<dd><%= cash_change_money.format %></dd>
</dl>
<p class="text-sm text-secondary">No balance data available for this date</p>
<% end %>

<dl class="flex gap-4 items-center text-sm text-primary">
<dt class="flex items-center gap-2">
End of day balance
<%= render DS::Tooltip.new(text: "The calculated balance after all transactions but before any manual adjustments or reconciliations", placement: "left", size: "sm") %>
</dt>
<hr class="grow border-dashed border-secondary">
<dd class="font-medium"><%= end_balance_before_adjustments_money.format %></dd>
</dl>

<hr class="border border-primary">

<dl class="flex gap-4 items-center text-sm text-primary">
<dt class="flex items-center gap-2">
&#916; Value adjustments
<%= render DS::Tooltip.new(text: "Adjustments are either manual reconciliations made by the user or adjustments due to market price changes throughout the day", placement: "left", size: "sm") %>
</dt>
<hr class="grow border-dashed border-secondary">
<dd><%= adjustments_money.format %></dd>
</dl>

<dl class="flex gap-4 items-center text-sm text-primary">
<dt class="flex items-center gap-2">
Closing balance
<%= render DS::Tooltip.new(text: "The final account balance for the day, after all transactions and adjustments have been applied", placement: "left", size: "sm") %>
</dt>
<hr class="grow border-dashed border-primary">
<dd class="font-bold"><%= end_balance_money.format %></dd>
</dl>
</div>
</details>

Expand Down
24 changes: 2 additions & 22 deletions app/components/UI/account/activity_date.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
class UI::Account::ActivityDate < ApplicationComponent
attr_reader :account, :data

delegate :date, :entries, :balance_trend, :cash_balance_trend, :holdings_value_trend, :transfers, to: :data
delegate :date, :entries, :balance, :transfers, to: :data

def initialize(account:, data:)
@account = account
Expand All @@ -16,28 +16,8 @@ def broadcast_channel
account
end

def start_balance_money
balance_trend.previous
end

def cash_change_money
cash_balance_trend.value
end

def holdings_change_money
holdings_value_trend.value
end

def end_balance_before_adjustments_money
balance_trend.previous + cash_change_money + holdings_change_money
end

def adjustments_money
end_balance_money - end_balance_before_adjustments_money
end

def end_balance_money
balance_trend.current
balance&.end_balance_money || Money.new(0, account.currency)
end

def broadcast_refresh!
Expand Down
22 changes: 22 additions & 0 deletions app/components/UI/account/balance_reconciliation.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<div class="space-y-3">
<% reconciliation_items.each_with_index do |item, index| %>
<% if item[:style] == :subtotal %>
<hr class="border border-primary">
<% end %>

<dl class="flex gap-4 items-center text-sm text-primary">
<dt class="flex items-center gap-2">
<%= item[:label] %>
<%= render DS::Tooltip.new(text: item[:tooltip], placement: "left", size: "sm") %>
</dt>
<hr class="grow border-dashed <%= item[:style] == :final ? "border-primary" : "border-secondary" %>">
<dd class="<%= item[:style] == :start || item[:style] == :final ? "font-bold" : item[:style] == :subtotal ? "font-medium" : "" %>">
<%= item[:value].format %>
</dd>
</dl>

<% if item[:style] == :adjustment %>
<hr class="border border-primary">
<% end %>
<% end %>
</div>
155 changes: 155 additions & 0 deletions app/components/UI/account/balance_reconciliation.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
class UI::Account::BalanceReconciliation < ApplicationComponent
attr_reader :balance, :account

def initialize(balance:, account:)
@balance = balance
@account = account
end

def reconciliation_items
case account.accountable_type
when "Depository", "OtherAsset", "OtherLiability"
default_items
when "CreditCard"
credit_card_items
when "Investment"
investment_items
when "Loan"
loan_items
when "Property", "Vehicle"
asset_items
when "Crypto"
crypto_items
else
default_items
end
end

private

def default_items
items = [
{ label: "Start balance", value: balance.start_balance_money, tooltip: "The account balance at the beginning of this day", style: :start },
{ label: "Net cash flow", value: net_cash_flow, tooltip: "Net change in balance from all transactions during the day", style: :flow }
]

if has_adjustments?
items << { label: "End balance", value: end_balance_before_adjustments, tooltip: "The calculated balance after all transactions", style: :subtotal }
items << { label: "Adjustments", value: total_adjustments, tooltip: "Manual reconciliations or other adjustments", style: :adjustment }
end

items << { label: "Final balance", value: balance.end_balance_money, tooltip: "The final account balance for the day", style: :final }
items
end

def credit_card_items
items = [
{ label: "Start balance", value: balance.start_balance_money, tooltip: "The balance owed at the beginning of this day", style: :start },
{ label: "Charges", value: balance.cash_outflows_money, tooltip: "New charges made during the day", style: :flow },
{ label: "Payments", value: balance.cash_inflows_money * -1, tooltip: "Payments made to the card during the day", style: :flow }
]

if has_adjustments?
items << { label: "End balance", value: end_balance_before_adjustments, tooltip: "The calculated balance after all transactions", style: :subtotal }
items << { label: "Adjustments", value: total_adjustments, tooltip: "Manual reconciliations or other adjustments", style: :adjustment }
end

items << { label: "Final balance", value: balance.end_balance_money, tooltip: "The final balance owed for the day", style: :final }
items
end

def investment_items
items = [
{ label: "Start balance", value: balance.start_balance_money, tooltip: "The total portfolio value at the beginning of this day", style: :start }
]

# Change in brokerage cash (includes deposits, withdrawals, and cash from trades)
items << { label: "Change in brokerage cash", value: net_cash_flow, tooltip: "Net change in cash from deposits, withdrawals, and trades", style: :flow }

# Change in holdings from trading activity
items << { label: "Change in holdings (buys/sells)", value: net_non_cash_flow, tooltip: "Impact on holdings from buying and selling securities", style: :flow }

# Market price changes
items << { label: "Change in holdings (market price activity)", value: balance.net_market_flows_money, tooltip: "Change in holdings value from market price movements", style: :flow }

if has_adjustments?
items << { label: "End balance", value: end_balance_before_adjustments, tooltip: "The calculated balance after all activity", style: :subtotal }
items << { label: "Adjustments", value: total_adjustments, tooltip: "Manual reconciliations or other adjustments", style: :adjustment }
end

items << { label: "Final balance", value: balance.end_balance_money, tooltip: "The final portfolio value for the day", style: :final }
items
end

def loan_items
items = [
{ label: "Start principal", value: balance.start_balance_money, tooltip: "The principal balance at the beginning of this day", style: :start },
{ label: "Net principal change", value: net_non_cash_flow, tooltip: "Principal payments and new borrowing during the day", style: :flow }
]

if has_adjustments?
items << { label: "End principal", value: end_balance_before_adjustments, tooltip: "The calculated principal after all transactions", style: :subtotal }
items << { label: "Adjustments", value: balance.non_cash_adjustments_money, tooltip: "Manual reconciliations or other adjustments", style: :adjustment }
end

items << { label: "Final principal", value: balance.end_balance_money, tooltip: "The final principal balance for the day", style: :final }
items
end

def asset_items # Property/Vehicle
items = [
{ label: "Start value", value: balance.start_balance_money, tooltip: "The asset value at the beginning of this day", style: :start },
{ label: "Net value change", value: net_total_flow, tooltip: "All value changes including improvements and depreciation", style: :flow }
]

if has_adjustments?
items << { label: "End value", value: end_balance_before_adjustments, tooltip: "The calculated value after all changes", style: :subtotal }
items << { label: "Adjustments", value: total_adjustments, tooltip: "Manual value adjustments or appraisals", style: :adjustment }
end

items << { label: "Final value", value: balance.end_balance_money, tooltip: "The final asset value for the day", style: :final }
items
end

def crypto_items
items = [
{ label: "Start balance", value: balance.start_balance_money, tooltip: "The crypto holdings value at the beginning of this day", style: :start }
]

items << { label: "Buys", value: balance.cash_outflows_money * -1, tooltip: "Crypto purchases during the day", style: :flow } if balance.cash_outflows != 0
items << { label: "Sells", value: balance.cash_inflows_money, tooltip: "Crypto sales during the day", style: :flow } if balance.cash_inflows != 0
items << { label: "Market changes", value: balance.net_market_flows_money, tooltip: "Value changes from market price movements", style: :flow } if balance.net_market_flows != 0

if has_adjustments?
items << { label: "End balance", value: end_balance_before_adjustments, tooltip: "The calculated balance after all activity", style: :subtotal }
items << { label: "Adjustments", value: total_adjustments, tooltip: "Manual reconciliations or other adjustments", style: :adjustment }
end

items << { label: "Final balance", value: balance.end_balance_money, tooltip: "The final crypto holdings value for the day", style: :final }
items
end

def net_cash_flow
balance.cash_inflows_money - balance.cash_outflows_money
end

def net_non_cash_flow
balance.non_cash_inflows_money - balance.non_cash_outflows_money
end

def net_total_flow
net_cash_flow + net_non_cash_flow + balance.net_market_flows_money
end

def total_adjustments
balance.cash_adjustments_money + balance.non_cash_adjustments_money
end

def has_adjustments?
balance.cash_adjustments != 0 || balance.non_cash_adjustments != 0
end

def end_balance_before_adjustments
balance.end_balance_money - total_adjustments
end
end
Loading