feat(investment): add portfolio allocation targets and interest receivable/post/receive lifecycle
Adds a Portfolio Allocation (Target vs Actual %) section to the Investment Dashboard, and reworks Investment Interest into the full accrual lifecycle: Interest Receivable, FD/Govt./Bond Interest Calculation & Post, and Interest Receive, plus the existing registers. Interest Calculation & Post now tracks cumulative posted/received amounts per holding instead of recomputing full accrued interest on every click (which previously double-counted on repeat posting). Holdings classified Non-Performing (Sub-Standard/Doubtful/Loss) are excluded from accrual posting per RBI norms — their interest accrues in memo/suspense only and is recognised solely on actual cash receipt via Interest Receive. Also bumps the production initial-bundle budget in angular.json (13/14mb -> 15/17mb) since the growing set of eagerly-loaded feature modules (Investment, NPA, Reconciliation, GL Reports, OSS Returns) pushed the build past the old limit.
This commit is contained in:
@@ -14,6 +14,7 @@ import {
|
||||
INSTRUMENT_LABELS,
|
||||
InstrumentType,
|
||||
InvestmentHolding,
|
||||
TARGET_ALLOCATION_PCT,
|
||||
accruedInterest,
|
||||
daysToMaturity,
|
||||
maturityAmount
|
||||
@@ -29,6 +30,16 @@ interface InstrumentSummary {
|
||||
maturityValue: number;
|
||||
}
|
||||
|
||||
interface AllocationRow {
|
||||
type: InstrumentType;
|
||||
label: string;
|
||||
targetPct: number;
|
||||
actualPct: number;
|
||||
actualValue: number;
|
||||
variancePct: number;
|
||||
statusLabel: 'Within Target' | 'Over-Allocated' | 'Under-Allocated';
|
||||
}
|
||||
|
||||
/** Cross-instrument portfolio dashboard — every figure is derived from ALL_HOLDINGS, never
|
||||
* hand-duplicated, so it can never drift from the per-instrument screens or Reports. */
|
||||
@Component({
|
||||
@@ -79,6 +90,30 @@ export class InvestmentDashboardComponent {
|
||||
});
|
||||
}
|
||||
|
||||
/** Board-approved policy target % per instrument type vs the portfolio's actual allocation
|
||||
* (by invested/face value) — a ±2 percentage-point band is treated as "Within Target" since
|
||||
* a treasury desk can't rebalance to the exact decimal every day. */
|
||||
get allocationVsTarget(): AllocationRow[] {
|
||||
const total = this.totalFaceValue;
|
||||
return this.types.map(({ type }) => {
|
||||
const value = this.holdingsOf(type).reduce((s, h) => s + h.faceValue, 0);
|
||||
const actualPct = total ? (value / total) * 100 : 0;
|
||||
const targetPct = TARGET_ALLOCATION_PCT[type];
|
||||
const variancePct = +(actualPct - targetPct).toFixed(1);
|
||||
const statusLabel: AllocationRow['statusLabel'] =
|
||||
Math.abs(variancePct) <= 2 ? 'Within Target' : variancePct > 0 ? 'Over-Allocated' : 'Under-Allocated';
|
||||
return {
|
||||
type,
|
||||
label: INSTRUMENT_LABELS[type],
|
||||
targetPct,
|
||||
actualPct: +actualPct.toFixed(1),
|
||||
actualValue: value,
|
||||
variancePct,
|
||||
statusLabel
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
get totalHoldings(): number {
|
||||
return ALL_HOLDINGS.length;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user