diff --git a/backend/src/modules/reports/reports.service.ts b/backend/src/modules/reports/reports.service.ts index cc9a393..9bb7918 100644 --- a/backend/src/modules/reports/reports.service.ts +++ b/backend/src/modules/reports/reports.service.ts @@ -1008,6 +1008,19 @@ export class ReportsService { WHERE is_active = true AND maturity_date IS NOT NULL AND maturity_date > CURRENT_DATE `); + // ── 5b) Get investment purchases (cash converts to an investment balance in the + // month the CD is bought). Only investments purchased on/after startYear-01-01 are + // indexed here — anything earlier is already counted in the opening investment + // balance below. Without this, point-in-time opening balances would silently drop + // every CD bought during the charted window. + const purchases = await this.tenant.query(` + SELECT fund_type, current_value, purchase_date + FROM investment_accounts + WHERE is_active = true + AND purchase_date IS NOT NULL + AND purchase_date >= $1::date + `, [`${startYear}-01-01`]); + // ── 6) Get capital project planned expenses ── const projectExpenses = await this.tenant.query(` SELECT estimated_cost, target_year, target_month, fund_source @@ -1077,6 +1090,19 @@ export class ReportsService { else maturityIndex[key].reserve += maturityTotal; } + // Index investment purchases by year-month — added to the running investment + // balance in the month the CD was bought (applies to both historical & forecast + // months, since a purchase is a real event regardless of where "now" falls). + const purchaseIndex: Record = {}; + for (const inv of purchases) { + const d = new Date(inv.purchase_date); + const key = `${d.getFullYear()}-${d.getMonth() + 1}`; + if (!purchaseIndex[key]) purchaseIndex[key] = { operating: 0, reserve: 0 }; + const val = parseFloat(inv.current_value) || 0; + if (inv.fund_type === 'operating') purchaseIndex[key].operating += val; + else purchaseIndex[key].reserve += val; + } + // Index project expenses by year-month const projectIndex: Record = {}; for (const p of projectExpenses) { @@ -1129,6 +1155,12 @@ export class ReportsService { const isHistorical = isPastMonth && hasActuals; const label = `${monthLabels[month - 1]} ${year}`; + // Apply investment purchases for this month before branching — a CD bought + // this month raises the investment balance whether the month is actual or forecast. + const purchased = purchaseIndex[key] || { operating: 0, reserve: 0 }; + runOpInv += purchased.operating; + runResInv += purchased.reserve; + if (isHistorical) { // Use actual journal entry changes from asset accounts const opChange = histIndex[`${year}-${month}-operating`] || 0;