KYC management: stage-wise notices, pagination, RD base chart

This commit is contained in:
2026-10-20 17:23:42 +05:30
parent 3e5cc26e49
commit 357f666421
108 changed files with 15001 additions and 2721 deletions
@@ -15,7 +15,7 @@
RBI Liabilities Register
</div>
<h2 class="dialog-title">Demand &amp; Time Liabilities</h2>
<p class="dialog-sub">NDTL &middot; CRR/SLR Computation Base &middot; As per RBI Master Circular</p>
<p class="dialog-sub">What the bank owes, and what it must hold against it</p>
</div>
<div class="header-right">
<!-- The close being reported, and under it the close the ratios are charged on. Two dates,
@@ -45,36 +45,39 @@
</div>
</div>
<!-- Summary Cards -->
<!-- What the liabilities are, and what they come to. Four cards rather than five: the CRR
requirement that used to sit here is on the compliance bar below, beside what is held
against it, where it answers a question rather than repeating one. -->
<div class="summary-row">
<div class="summary-card sc-demand">
<div class="sc-label">Total Demand Liabilities</div>
<div class="sc-value">{{ crore(totalDemand) }}<span class="cr" *ngIf="totalDemand !== null">Cr</span></div>
<div class="sc-sub">Payable on demand</div>
<div class="sc-label">Demand liabilities</div>
<div class="sc-value" [title]="money(totalDemand)">{{ tile(totalDemand) }}</div>
<div class="sc-sub">Repayable on demand</div>
</div>
<div class="summary-card sc-time">
<div class="sc-label">Total Time Liabilities</div>
<div class="sc-value">{{ crore(totalTime) }}<span class="cr" *ngIf="totalTime !== null">Cr</span></div>
<div class="sc-sub">Payable on maturity</div>
<div class="sc-label">Time liabilities</div>
<div class="sc-value" [title]="money(totalTime)">{{ tile(totalTime) }}</div>
<div class="sc-sub">Repayable on maturity</div>
</div>
<div class="summary-card sc-asset">
<div class="sc-label">Assets with Banking System</div>
<div class="sc-value">
{{ crore(totalBankingAssets) }}<span class="cr" *ngIf="totalBankingAssets !== null">Cr</span>
<div class="sc-label">Held with other banks</div>
<!-- Scaled on the tile, exact on hover: the card is read for order of magnitude, but the
figure behind it should never be more than a pointer away. -->
<div class="sc-value" [title]="money(totalBankingAssets)">
{{ tile(totalBankingAssets) }}
</div>
<!-- These assets net against what the bank OWES other banks, not against the whole base, and
the netting floors at zero — so where they exceed what is owed, nothing comes off at all.
Said plainly, because "deducted from NDTL" was being printed on a card where no
deduction had been made. -->
<div class="sc-sub" [class.dn]="bankingAssetsNet">
{{ bankingAssetsNet ? 'Reduces the base below' : 'More than we owe banks — base unchanged' }}
</div>
<div class="sc-change dn">&#8595; Deducted from NDTL</div>
</div>
<div class="summary-card sc-ndtl">
<div class="sc-label">Net Demand &amp; Time Liabilities (NDTL)</div>
<div class="sc-value">{{ crore(ndtl) }}<span class="cr" *ngIf="ndtl !== null">Cr</span></div>
<div class="sc-sub">After deducting banking assets</div>
</div>
<div class="summary-card sc-crr">
<!-- The rate is named from the configuration, not fixed here: a card headed "CRR Required
(3%)" while Admin holds 4% states a rate the bank is not on. -->
<div class="sc-label">CRR Required{{ crrRate === null ? '' : ' (' + crrRate + '%)' }}</div>
<div class="sc-value">{{ crore(crrRequired) }}<span class="cr" *ngIf="crrRequired !== null">Cr</span></div>
<div class="sc-sub">SLR Req: {{ crore(slrRequired) }}{{ slrRate === null ? '' : ' Cr (' + slrRate + '%)' }}</div>
<div class="sc-label">NDTL &mdash; the base</div>
<div class="sc-value" [title]="money(ndtl)">{{ tile(ndtl) }}</div>
<div class="sc-sub">Demand + time, net of bank balances</div>
</div>
</div>
@@ -94,26 +97,33 @@
<span class="tab-pill pill-time">02</span> Time Liabilities
</button>
<button class="tab-btn" [class.active]="activeTab === 'assets'" (click)="activeTab = 'assets'">
<span class="tab-pill pill-asset">03</span> Assets with Banking System
<span class="tab-pill pill-asset">03</span> Held with other banks
</button>
<button class="tab-btn" [class.active]="activeTab === 'slr'" (click)="activeTab = 'slr'">
<span class="tab-pill pill-slr">04</span> SLR &mdash; Liquid Assets
<span class="tab-pill pill-slr">04</span> SLR assets
</button>
<!-- Where the reserve is actually held, and what it holds TODAY. The four tabs above report the
fortnight close the return is made up to; this one answers the question a treasury desk
asks every morning — as things stand now, are we short, and which account do we cover it
into. A close two weeks old cannot say that, because the balances have since moved. -->
<button class="tab-btn" [class.active]="activeTab === 'held'" (click)="activeTab = 'held'">
<span class="tab-pill pill-held">05</span> Our accounts today
</button>
</div>
<!-- Demand Liabilities Table -->
@if (activeTab === 'demand') {
<div class="section-desc">Amounts payable on demand &mdash; RBI Schedule II</div>
<div class="section-desc">Money the bank must repay whenever a customer asks for it.</div>
<div class="table-wrap">
<table>
<thead>
<tr>
<th class="sl">#</th>
<th>Liability Item</th>
<th>Account Code</th>
<th class="right">Opening (&#8377; Cr)</th>
<th class="right">Current (&#8377; Cr)</th>
<th class="right">Change (&#8377; Cr)</th>
<th>Item</th>
<th class="right">Opening</th>
<th class="right">Current</th>
<th class="right">Change</th>
<th>Status</th>
</tr>
</thead>
@@ -167,17 +177,17 @@
<!-- Time Liabilities Table -->
@if (activeTab === 'time') {
<div class="section-desc">Amounts payable after a specified period &mdash; RBI Schedule III</div>
<div class="section-desc">Money the bank repays only when the deposit matures.</div>
<div class="table-wrap">
<table>
<thead>
<tr>
<th class="sl">#</th>
<th>Liability Item</th>
<th>Account Code</th>
<th class="right">Opening (&#8377; Cr)</th>
<th class="right">Current (&#8377; Cr)</th>
<th class="right">Change (&#8377; Cr)</th>
<th>Item</th>
<th class="right">Opening</th>
<th class="right">Current</th>
<th class="right">Change</th>
<th>Status</th>
</tr>
</thead>
@@ -231,17 +241,20 @@
<!-- Assets with Banking System Table -->
@if (activeTab === 'assets') {
<div class="section-desc">Deducted from gross liabilities to arrive at NDTL &mdash; RBI Master Circular</div>
<div class="section-desc">
What the bank keeps with other banks. This comes off what it owes them — and only off that, so where it is the
larger of the two the base is left as it is.
</div>
<div class="table-wrap">
<table>
<thead>
<tr>
<th class="sl">#</th>
<th>Asset Item</th>
<th>Account Code</th>
<th class="right">Opening (&#8377; Cr)</th>
<th class="right">Current (&#8377; Cr)</th>
<th class="right">Change (&#8377; Cr)</th>
<th>Item</th>
<th class="right">Opening</th>
<th class="right">Current</th>
<th class="right">Change</th>
<th>Status</th>
</tr>
</thead>
@@ -275,7 +288,12 @@
<tfoot>
<tr>
<td colspan="3">
<strong>Total Assets with Banking System</strong> <span class="deduct-tag">( Deducted from NDTL )</span>
<strong>Total Assets with Banking System</strong>
<span class="deduct-tag">{{
bankingAssetsNet
? '( Deducted from NDTL )'
: '( Netted against item I, which is smaller — no deduction )'
}}</span>
</td>
<td class="right foot-asset">{{ totalOf(bankingAssets, 'openingValue') }}</td>
<td class="right foot-asset">{{ totalOf(bankingAssets, 'currentValue') }}</td>
@@ -289,20 +307,18 @@
<!-- SLR - Liquid Assets Table -->
@if (activeTab === 'slr') {
<div class="section-desc">
SLR = (Liquid Assets / NDTL) &times; 100 &mdash; RBI Sec 24(2A) of Banking Regulation Act, 1949
</div>
<div class="section-desc">Cash, bank balances and securities the bank holds against its SLR requirement.</div>
<div class="table-wrap">
<table>
<thead>
<tr>
<th class="sl">#</th>
<th>Liquid Asset</th>
<th>Account Code</th>
<th>Item</th>
<th>Category</th>
<th class="right">Opening (&#8377; Cr)</th>
<th class="right">Current (&#8377; Cr)</th>
<th class="right">Change (&#8377; Cr)</th>
<th class="right">Opening</th>
<th class="right">Current</th>
<th class="right">Change</th>
<th>Status</th>
</tr>
</thead>
@@ -348,119 +364,141 @@
</table>
</div>
<!-- SLR Formula -->
<!-- How the ratio is struck. The "× 100" box that stood here was a term whose value was 100 and
whose label was 100 — it took a quarter of the row to say that a fraction is written as a
percentage. -->
<div class="formula-block slr-formula">
<div class="formula-title">SLR Computation &mdash; (Liquid Assets / NDTL) &times; 100</div>
<div class="formula-title">How the SLR ratio is worked out</div>
<div class="formula-row">
<div class="formula-term ft-slr">
<div class="formula-term-label">Liquid Assets</div>
<div class="formula-term-val">&#8377;13,238.80</div>
<div class="formula-term-sub">6 asset categories</div>
<div class="formula-term-label">Assets we hold</div>
<div class="formula-term-val">{{ money(totalLiquidAssets) }}</div>
<div class="formula-term-sub">{{ liquidAssets.length }} categories</div>
</div>
<div class="formula-op">&divide;</div>
<div class="formula-term ft-ndtl">
<div class="formula-term-label">NDTL</div>
<div class="formula-term-val">&#8377;69,221.30</div>
<div class="formula-term-sub">Net Demand &amp; Time</div>
</div>
<div class="formula-op">&times;</div>
<div class="formula-term" style="border-color: #e2e8f0; background: #f8fafc">
<div class="formula-term-label" style="color: #64748b">100</div>
<div class="formula-term-val" style="color: #334155">100</div>
<div class="formula-term-sub">&nbsp;</div>
<div class="formula-term-label">NDTL base</div>
<div class="formula-term-val">{{ money(baseNdtl) }}</div>
<div class="formula-term-sub">as at {{ baseDateStr || '—' }}</div>
</div>
<div class="formula-op equals">=</div>
<div class="formula-term ft-slr-result">
<div class="formula-term-label">Actual SLR</div>
<div class="formula-term-label">SLR held</div>
<div class="formula-term-val">{{ slrActualPercent }}%</div>
<div class="formula-term-sub">Min required: {{ slrRate }}%</div>
<div class="formula-term-sub">minimum {{ slrRate }}%</div>
</div>
</div>
</div>
<!-- SLR Status Bar -->
<div class="slr-status-bar">
<div class="slr-status-left">
<div class="slr-status-title">SLR Compliance Status</div>
<div class="slr-status-desc">
Actual: {{ slrActualPercent }}% &middot; Required: {{ slrRate }}.00% &middot; NDTL: &#8377;{{
ndtl | number: '1.2-2'
}}
Cr
</div>
</div>
<div class="slr-status-calcs">
<div class="slr-calc">
<div class="slr-calc-label">SLR Required ({{ slrRate }}%)</div>
<div class="slr-calc-val">&#8377;{{ slrRequired | number: '1.2-2' }} Cr</div>
</div>
<div class="slr-calc">
<div class="slr-calc-label">Liquid Assets Held</div>
<div class="slr-calc-val">&#8377;{{ totalLiquidAssets | number: '1.2-2' }} Cr</div>
</div>
<div class="slr-calc">
<div class="slr-calc-label">Surplus</div>
<div class="slr-calc-val surplus">&#8377;{{ slrSurplus | number: '1.2-2' }} Cr</div>
</div>
</div>
</div>
<!-- The SLR compliance bar that used to sit here said the same three figures as the row above
it and the bar below it — required, held, surplus, three times on one screen. It is gone;
the compliance bar at the foot carries both ratios for every tab. -->
}
<!-- NDTL Formula Block -->
<div class="formula-block">
<div class="formula-title">
NDTL Computation &mdash; Formula Breakdown &middot; Data as of {{ reportingDateStr }}
<!-- Required against held, for both ratios. Always on screen, under whichever tab is open:
whether the bank is short is the one thing a reader must not have to go looking for. -->
<div class="crr-bar">
<div class="crr-text">
<div class="crr-title">Are we meeting the requirement?</div>
<div class="crr-desc">
Charged on the NDTL of {{ money(baseNdtl) }} as at {{ baseDateStr || reportingDateStr }}
</div>
</div>
<div class="formula-row">
<div class="formula-term ft-demand">
<div class="formula-term-label">Demand Liabilities</div>
<div class="formula-term-val">&#8377;{{ totalDemand | number: '1.2-2' }}</div>
<div class="formula-term-sub">16 line items</div>
</div>
<div class="formula-op">+</div>
<div class="formula-term ft-time">
<div class="formula-term-label">Time Liabilities</div>
<div class="formula-term-val">&#8377;{{ totalTime | number: '1.2-2' }}</div>
<div class="formula-term-sub">13 line items</div>
</div>
<div class="formula-op minus">&minus;</div>
<div class="formula-term ft-asset">
<div class="formula-term-label">Assets with Banking</div>
<div class="formula-term-val">&#8377;{{ totalBankingAssets | number: '1.2-2' }}</div>
<div class="formula-term-sub">3 line items</div>
</div>
<div class="formula-op equals">=</div>
<div class="formula-term ft-ndtl">
<div class="formula-term-label">NDTL</div>
<div class="formula-term-val">&#8377;{{ ndtl | number: '1.2-2' }}</div>
<div class="formula-term-sub">CRR &amp; SLR base</div>
<!-- Required AND held, side by side. The requirement alone answers half the question: a screen
headed "Reserve Requirements" that states ₹2.10 Cr without saying what is against it sends
a reader to another tab to find out whether the bank is short — which is the one thing they
opened this bar to learn. -->
<div class="crr-calcs">
@for (r of positionRatios(); track r.name) {
<div class="crr-calc" [class.crr-calc--short]="!r.met">
<!-- A ratio with no rate on record is said to have none. It used to print "SLR @ null%" and
a surplus of nothing, which reads as a requirement met rather than one not set. -->
<div class="crr-calc-label">{{ r.name }}{{ r.rate === null ? ' — rate not set' : ' @ ' + r.rate + '%' }}</div>
<div class="crr-calc-val">{{ money(r.required) }}</div>
<div class="crr-calc-held">
held {{ money(r.maintained) }}
<span [class.crr-short]="!r.met">
&middot; {{ r.met ? '+' + money(r.surplus) : 'short ' + money(r.shortfall) }}
</span>
</div>
</div>
}
<div class="crr-calc">
<div class="crr-calc-label">Total Reserve</div>
<div class="crr-calc-val">{{ money(totalReserve) }}</div>
<div class="crr-calc-held">CRR + SLR required</div>
</div>
</div>
</div>
<!-- CRR/SLR Bar -->
<div class="crr-bar">
<div class="crr-text">
<div class="crr-title">CRR &amp; SLR Reserve Requirements &mdash; RBI Computation on NDTL</div>
<div class="crr-desc">
Based on NDTL of &#8377;{{ ndtl | number: '1.2-2' }} Cr &middot; Data as of {{ reportingDateStr }} (45-day lag)
</div>
<!-- Reserve accounts, as they stand today -->
@if (activeTab === 'held') {
<div class="section-desc">
Where the cash reserve is held, with each account's balance on the business date
<strong>{{ position?.onDate || '—' }}</strong
>. The requirement below is charged on <strong>{{ position?.baseDate || '—' }}</strong
>, a fortnight back — RBI's lag is a rule, so today's own liabilities settle nothing yet.
</div>
<div class="crr-calcs">
<div class="crr-calc">
<div class="crr-calc-label">CRR @ {{ crrRate }}.00%</div>
<div class="crr-calc-val">&#8377;{{ crrRequired | number: '1.2-2' }} Cr</div>
@if (position) {
<!-- Required against held, for each ratio. Stated before the accounts because a desk reads
the gap first and only then asks which account to move money into. -->
<div class="held-ratios">
@for (r of positionRatios(); track r.name) {
<div class="held-ratio" [class.held-ratio--short]="!r.met">
<div class="held-ratio__name">{{ r.name }}{{ r.rate === null ? '' : ' @ ' + r.rate + '%' }}</div>
<div class="held-ratio__grid">
<span>Required</span><strong>{{ money(r.required) }}</strong> <span>Maintained</span
><strong>{{ money(r.maintained) }}</strong>
<span>{{ r.met ? 'Surplus' : 'Shortfall' }}</span>
<strong [class.held-short]="!r.met">{{ money(r.met ? r.surplus : r.shortfall) }}</strong>
</div>
</div>
}
</div>
<div class="crr-calc">
<div class="crr-calc-label">SLR @ {{ slrRate }}.00%</div>
<div class="crr-calc-val">&#8377;{{ slrRequired | number: '1.2-2' }} Cr</div>
<div class="table-wrap">
<table>
<thead>
<tr>
<th class="sl">#</th>
<th>Account</th>
<th>Form 1 head</th>
<th class="right">Balance today</th>
<th>&nbsp;</th>
</tr>
</thead>
<tbody>
@for (a of position.accounts; track a.glAccountId) {
<tr>
<td class="sl">{{ $index + 1 }}</td>
<td>
<div class="item-name">{{ a.name }}</div>
<div class="item-sub mono">{{ a.glCode }}</div>
</td>
<td>
{{ a.item }} &middot; {{ a.head }}
<!-- An account the return does not read is named as such. It can still be moved
into — the money is real — but adding it to what is maintained would have
this screen claim a compliance the filed form does not. -->
@if (!a.countsTowardMaintained) {
<span class="held-chip">not counted on the return</span>
}
</td>
<td class="right amt">{{ money(a.balance) }}</td>
<td class="right">
<button class="held-move" (click)="openTransfer(a)">
<fa-icon icon="exchange-alt"></fa-icon>
Transfer
</button>
</td>
</tr>
}
</tbody>
</table>
</div>
<div class="crr-calc">
<div class="crr-calc-label">Total Reserve</div>
<div class="crr-calc-val">&#8377;{{ totalReserve | number: '1.2-2' }} Cr</div>
</div>
</div>
</div>
}
}
<!-- Footer -->
<div class="dialog-footer">