Show investments under Operating/Reserve tabs and include in fund totals

- Investment accounts now appear under their respective Operating/Reserve
  tabs in the Accounts page, with a compact sub-table showing name, type,
  institution, principal/value, rate, interest earned, and maturity info
- Investment values (current_value) are included in dashboard Total Cash KPI
- Reserve investment values are added to Reserve Fund Balance KPI and
  project funded percentage calculations
- Year-end report reserve status now includes reserve investment values
- Tab counts updated to include investment accounts per fund type
- Summary cards show separate "asset (investments)" total for visibility

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-20 08:33:00 -05:00
parent 112578672e
commit c68a7e21c3
3 changed files with 163 additions and 24 deletions

View File

@@ -374,9 +374,9 @@ export class ReportsService {
`, [year]);
// Reserve fund status from unified projects table
// Uses dynamic reserve balance computation (reserve equity accounts = fund balance)
// Uses dynamic reserve balance computation (reserve equity accounts + reserve investments)
const reserveStatus = await this.tenant.query(`
WITH reserve_balance AS (
WITH reserve_equity AS (
SELECT COALESCE(SUM(sub.balance), 0) as total FROM (
SELECT COALESCE(SUM(jel.credit), 0) - COALESCE(SUM(jel.debit), 0) as balance
FROM accounts a
@@ -386,6 +386,14 @@ export class ReportsService {
GROUP BY a.id
) sub
),
reserve_investments AS (
SELECT COALESCE(SUM(current_value), 0) as total
FROM investment_accounts WHERE fund_type = 'reserve' AND is_active = true
),
reserve_balance AS (
SELECT re.total + ri.total as total
FROM reserve_equity re, reserve_investments ri
),
reserve_total_cost AS (
SELECT COALESCE(SUM(estimated_cost), 0) as total
FROM projects
@@ -432,7 +440,12 @@ export class ReportsService {
GROUP BY a.id
) sub
`);
const totalCash = parseFloat(cash[0]?.total || '0');
// Also include investment account current_value in total cash
const investmentCash = await this.tenant.query(`
SELECT COALESCE(SUM(current_value), 0) as total
FROM investment_accounts WHERE is_active = true
`);
const totalCash = parseFloat(cash[0]?.total || '0') + parseFloat(investmentCash[0]?.total || '0');
// Receivables: sum of unpaid invoices
const ar = await this.tenant.query(`
@@ -453,6 +466,11 @@ export class ReportsService {
GROUP BY a.id
) sub
`);
// Add reserve investment account values to the reserve fund total
const reserveInvestments = await this.tenant.query(`
SELECT COALESCE(SUM(current_value), 0) as total
FROM investment_accounts WHERE fund_type = 'reserve' AND is_active = true
`);
// Delinquent count (overdue invoices)
const delinquent = await this.tenant.query(`
@@ -470,7 +488,7 @@ export class ReportsService {
return {
total_cash: totalCash.toFixed(2),
total_receivables: ar[0]?.total || '0.00',
reserve_fund_balance: parseFloat(reserves[0]?.total || '0').toFixed(2),
reserve_fund_balance: (parseFloat(reserves[0]?.total || '0') + parseFloat(reserveInvestments[0]?.total || '0')).toFixed(2),
delinquent_units: parseInt(delinquent[0]?.count || '0'),
recent_transactions: recentTx,
};