form 91/98 report, min max value update in AML rule and whihc rule apply day, week, month and some more updates

This commit is contained in:
2026-08-02 11:46:40 +05:30
parent 2a9df828ca
commit 3030e2f34e
37 changed files with 9292 additions and 620 deletions
+552 -20
View File
@@ -79,17 +79,33 @@
<div class="glr-filter">
<label>Branch</label>
<select class="glr-inp" [(ngModel)]="branchCode">
<option value="">All Branches (Consolidated)</option>
@for (b of branches; track b.code) {
<option [value]="b.code">{{ b.code }} — {{ b.name }}</option>
}
</select>
@if (canSelectBranch) {
<select class="glr-inp" [(ngModel)]="branchCode">
<option value="">All Branches (Consolidated)</option>
@for (b of branches; track b.code) {
<option [value]="b.code">{{ b.code }} — {{ b.name }}</option>
}
</select>
} @else {
<span class="glr-chip" title="Your login is restricted to this branch">
<fa-icon icon="university"></fa-icon> {{ scopeName }}
</span>
}
</div>
<button class="glr-btn" (click)="resetFilters()">Reset</button>
</div>
@if (scopeIsUnresolved) {
<div class="glr-balance glr-balance--bad">
<fa-icon icon="exclamation-triangle"></fa-icon>
<span>
Your office <strong>{{ scopeName }}</strong> does not match any branch in the ledger, so no figures can be
shown. Ask an administrator to align your office name with a branch.
</span>
</div>
}
<!-- REPORT SELECTOR -->
<div class="glr-tabs">
@for (r of reports; track r.code) {
@@ -193,7 +209,9 @@
@for (r of pnlExpense; track r.code) {
<tr>
<td class="mono">{{ r.code }}</td>
<td>{{ r.name }}<span class="muted"> · {{ r.group }}</span></td>
<td>
{{ r.name }}<span class="muted"> · {{ r.group }}</span>
</td>
<td class="ta-r mono">{{ r.amount | number: '1.2-2' }}</td>
</tr>
} @empty {
@@ -229,7 +247,9 @@
@for (r of pnlIncome; track r.code) {
<tr>
<td class="mono">{{ r.code }}</td>
<td>{{ r.name }}<span class="muted"> · {{ r.group }}</span></td>
<td>
{{ r.name }}<span class="muted"> · {{ r.group }}</span>
</td>
<td class="ta-r mono">{{ r.amount | number: '1.2-2' }}</td>
</tr>
} @empty {
@@ -281,7 +301,9 @@
@for (r of bsLiabilities; track r.code) {
<tr>
<td class="mono">{{ r.code }}</td>
<td>{{ r.name }}<span class="muted"> · {{ r.group }}</span></td>
<td>
{{ r.name }}<span class="muted"> · {{ r.group }}</span>
</td>
<td class="ta-r mono">{{ r.amount | number: '1.2-2' }}</td>
</tr>
}
@@ -312,7 +334,9 @@
@for (r of bsAssets; track r.code) {
<tr>
<td class="mono">{{ r.code }}</td>
<td>{{ r.name }}<span class="muted"> · {{ r.group }}</span></td>
<td>
{{ r.name }}<span class="muted"> · {{ r.group }}</span>
</td>
<td class="ta-r mono">{{ r.amount | number: '1.2-2' }}</td>
</tr>
}
@@ -331,11 +355,17 @@
@if (activeReport === 'comparative-balance-sheet') {
<div class="glr-section">
<p class="glr-note">
Compares the closing position as at <strong>{{ range.to }}</strong> against the position immediately before
this period began. Change the filter above to compare a different span.
Compares the closing position as at <strong>{{ range.to }}</strong> against the position immediately before this
period began. Change the filter above to compare a different span.
</p>
@for (block of [{ title: 'Capital & Liabilities', rows: compLiabilities }, { title: 'Assets', rows: compAssets }]; track block.title) {
@for (
block of [
{ title: 'Capital & Liabilities', rows: compLiabilities },
{ title: 'Assets', rows: compAssets }
];
track block.title
) {
<div class="glr-tbl-wrap">
<div class="glr-tbl-h">{{ block.title }}</div>
<table class="glr-tbl">
@@ -353,7 +383,9 @@
@for (r of block.rows; track r.code) {
<tr>
<td class="mono">{{ r.code }}</td>
<td>{{ r.name }}<span class="muted"> · {{ r.group }}</span></td>
<td>
{{ r.name }}<span class="muted"> · {{ r.group }}</span>
</td>
<td class="ta-r mono">{{ r.current | number: '1.2-2' }}</td>
<td class="ta-r mono">{{ r.previous | number: '1.2-2' }}</td>
<td class="ta-r mono" [class.var-up]="r.variance > 0" [class.var-down]="r.variance < 0">
@@ -379,8 +411,8 @@
@if (activeReport === 'contingent-liabilities') {
<div class="glr-section">
<p class="glr-note">
Off-balance-sheet commitments outstanding as at <strong>{{ range.to }}</strong>. These are memoranda accounts
and are deliberately excluded from the Trial Balance and Balance Sheet totals.
Off-balance-sheet commitments outstanding as at <strong>{{ range.to }}</strong
>. These are memoranda accounts and are deliberately excluded from the Trial Balance and Balance Sheet totals.
</p>
<div class="glr-tbl-wrap">
<table class="glr-tbl">
@@ -419,8 +451,8 @@
@if (activeReport === 'gl-wise-dr-cr') {
<div class="glr-section">
<p class="glr-note">
Debit and credit turnover posted between <strong>{{ rangeLabel }}</strong> for {{ branchLabel }}. Every
voucher is double-entry, so the debit and credit totals below must match.
Debit and credit turnover posted between <strong>{{ rangeLabel }}</strong> for {{ branchLabel }}. Every voucher
is double-entry, so the debit and credit totals below must match.
</p>
<div class="glr-tbl-wrap">
<table class="glr-tbl">
@@ -474,8 +506,8 @@
@if (activeReport === 'misc-expense-ledger') {
<div class="glr-section">
<p class="glr-note">
Every miscellaneous-expense voucher posted between <strong>{{ rangeLabel }}</strong> for {{ branchLabel }}
&mdash; {{ miscRows.length | number }} entries.
Every miscellaneous-expense voucher posted between <strong>{{ rangeLabel }}</strong> for
{{ branchLabel }} &mdash; {{ miscRows.length | number }} entries.
</p>
<div class="glr-tbl-wrap glr-tbl-wrap--tall">
<table class="glr-tbl">
@@ -518,6 +550,506 @@
</div>
}
<!-- ══════════════ GL AVERAGE BALANCE ══════════════ -->
@if (activeReport === 'gl-average-balance') {
<div class="glr-section">
<p class="glr-note">
Average of each account's closing balance across every day in
<strong>{{ rangeLabel }}</strong> for {{ branchLabel }}. Banks work from average balances rather than a closing
snapshot for interest, CRR/SLR and profitability, because a single day's figure can be dressed up.
</p>
<div class="glr-tbl-wrap glr-tbl-wrap--tall">
<table class="glr-tbl">
<thead>
<tr>
<th>GL Code</th>
<th>Account</th>
<th>Group</th>
<th class="ta-r">Opening</th>
<th class="ta-r">Closing</th>
<th class="ta-r">Average Daily</th>
<th class="ta-r">Peak</th>
<th class="ta-r">Lowest</th>
<th class="ta-c">Active Days</th>
</tr>
</thead>
<tbody>
@for (r of averageRows; track r.code) {
<tr>
<td class="mono">{{ r.code }}</td>
<td>{{ r.name }}</td>
<td class="muted">{{ r.group }}</td>
<td class="ta-r mono">{{ r.opening | number: '1.2-2' }}</td>
<td class="ta-r mono">{{ r.closing | number: '1.2-2' }}</td>
<td class="ta-r mono">
<strong>{{ r.average | number: '1.2-2' }}</strong>
</td>
<td class="ta-r mono">{{ r.peak | number: '1.2-2' }}</td>
<td class="ta-r mono">{{ r.lowest | number: '1.2-2' }}</td>
<td class="ta-c mono">{{ r.activeDays }}</td>
</tr>
} @empty {
<tr>
<td colspan="9" class="glr-empty">No ledger activity for this period and branch.</td>
</tr>
}
</tbody>
<tfoot>
<tr class="total-row">
<td colspan="5">TOTAL ({{ averageRows.length }} accounts)</td>
<td class="ta-r mono">{{ avgTotalAverage | number: '1.2-2' }}</td>
<td colspan="3"></td>
</tr>
</tfoot>
</table>
</div>
</div>
}
<!-- ══════════════ GL MAPPING FOR REPORT ══════════════ -->
@if (activeReport === 'gl-mapping') {
<div class="glr-section">
<p class="glr-note">
Which General Ledger accounts feed each RBI return line. Mappings are created on the OSS 1, OSS 2 and OSS 3
screens using <strong>Add / Remove GLs</strong>; this is the consolidated view of them, with the value each
mapping currently produces from the ledger.
</p>
<div class="glr-tbl-wrap">
<div class="glr-tbl-h">Mapped return lines ({{ mappingRows.length }})</div>
<table class="glr-tbl">
<thead>
<tr>
<th>Return</th>
<th>Return line</th>
<th>Mapped GL accounts</th>
<th class="ta-r">Ledger value (&#8377; thousands)</th>
</tr>
</thead>
<tbody>
@for (r of mappingRows; track r.returnCode + r.lineKey) {
<tr>
<td>{{ r.returnLabel }}</td>
<td class="mono">{{ r.lineKey }}</td>
<td>
@for (c of r.codes; track c) {
<span class="glr-gl-chip mono">{{ c }}</span>
}
</td>
<td class="ta-r mono">{{ r.value | number: '1.2-2' }}</td>
</tr>
} @empty {
<tr>
<td colspan="4" class="glr-empty">
No return lines mapped yet. Open OSS 1, 2 or 3 and use “Add / Remove GLs” to pin accounts to a line.
</td>
</tr>
}
</tbody>
</table>
</div>
<div class="glr-tbl-wrap glr-tbl-wrap--tall">
<div class="glr-tbl-h">Unmapped GL accounts ({{ unmappedAccounts.length }}) — not feeding any return line</div>
<table class="glr-tbl">
<thead>
<tr>
<th>GL Code</th>
<th>Account</th>
<th>Group</th>
</tr>
</thead>
<tbody>
@for (a of unmappedAccounts; track a.code) {
<tr>
<td class="mono">{{ a.code }}</td>
<td>{{ a.name }}</td>
<td class="muted">{{ a.group }}</td>
</tr>
} @empty {
<tr>
<td colspan="3" class="glr-empty">Every GL account feeds at least one return line.</td>
</tr>
}
</tbody>
</table>
</div>
</div>
}
<!-- ══════════════ ACCOUNT WISE BALANCE LIST ══════════════ -->
@if (activeReport === 'account-wise-balance') {
<div class="glr-section">
<p class="glr-note">
Closing balance of every account as at <strong>{{ range.to }}</strong
>, broken out by branch — which branch is actually carrying each balance.
</p>
<div class="glr-tbl-wrap glr-tbl-wrap--tall">
<table class="glr-tbl">
<thead>
<tr>
<th>GL Code</th>
<th>Account</th>
<th>Group</th>
@for (c of branchColumns; track c) {
<th class="ta-r">{{ branchName(c) }}</th>
}
<th class="ta-r">Total</th>
</tr>
</thead>
<tbody>
@for (r of accountWiseRows; track r.code) {
<tr>
<td class="mono">{{ r.code }}</td>
<td>{{ r.name }}</td>
<td class="muted">{{ r.group }}</td>
@for (c of branchColumns; track c) {
<td class="ta-r mono">{{ r.byBranch[c] ? (r.byBranch[c] | number: '1.2-2') : '' }}</td>
}
<td class="ta-r mono">
<strong>{{ r.total | number: '1.2-2' }}</strong>
</td>
</tr>
} @empty {
<tr>
<td [attr.colspan]="branchColumns.length + 4" class="glr-empty">
No balances for this period and branch.
</td>
</tr>
}
</tbody>
<tfoot>
<tr class="total-row">
<td colspan="3">TOTAL ({{ accountWiseRows.length }} accounts)</td>
@for (c of branchColumns; track c) {
<td class="ta-r mono">{{ branchColumnTotal(c) | number: '1.2-2' }}</td>
}
<td class="ta-r mono">{{ accountWiseGrandTotal | number: '1.2-2' }}</td>
</tr>
</tfoot>
</table>
</div>
</div>
}
<!-- ══════════════ DISTRIBUTION OF BALANCE ══════════════ -->
@if (activeReport === 'distribution-of-balance') {
<div class="glr-section">
<p class="glr-note">
Composition of the book as at <strong>{{ range.to }}</strong> for {{ branchLabel }} — how concentrated each side
of the balance sheet is by account group.
</p>
<div class="glr-two-col">
@for (
block of [
{ title: 'Capital & Liabilities', rows: liabilityDistribution, total: liabilityDistTotal },
{ title: 'Assets', rows: assetDistribution, total: assetDistTotal }
];
track block.title
) {
<div class="glr-tbl-wrap">
<div class="glr-tbl-h">{{ block.title }}</div>
<table class="glr-tbl">
<thead>
<tr>
<th>Group</th>
<th class="ta-c">A/cs</th>
<th class="ta-r">Amount (&#8377;)</th>
<th class="ta-r">Share</th>
<th class="glr-bar-col">Distribution</th>
</tr>
</thead>
<tbody>
@for (r of block.rows; track r.group) {
<tr>
<td>{{ r.group }}</td>
<td class="ta-c mono">{{ r.accounts }}</td>
<td class="ta-r mono">{{ r.amount | number: '1.2-2' }}</td>
<td class="ta-r mono">
<strong>{{ r.share | number: '1.2-2' }}%</strong>
</td>
<td>
<div class="glr-bar">
<div class="glr-bar-fill" [style.width.%]="r.share"></div>
</div>
</td>
</tr>
} @empty {
<tr>
<td colspan="5" class="glr-empty">No balances on this side.</td>
</tr>
}
<tr class="total-row">
<td colspan="2">Total</td>
<td class="ta-r mono">{{ block.total | number: '1.2-2' }}</td>
<td class="ta-r mono">100.00%</td>
<td></td>
</tr>
</tbody>
</table>
</div>
}
</div>
</div>
}
<!-- ══════════════ CLIENT WISE BALANCE ══════════════ -->
@if (activeReport === 'client-wise-balance') {
<div class="glr-section">
<div class="glr-kpis">
<div class="glr-kpi glr-kpi--teal">
<div class="glr-kpi-n">&#8377;{{ clientDeposits | number: '1.2-2' }}</div>
<div class="glr-kpi-l">Customer Deposits</div>
</div>
<div class="glr-kpi glr-kpi--amber">
<div class="glr-kpi-n">&#8377;{{ clientAdvances | number: '1.2-2' }}</div>
<div class="glr-kpi-l">Customer Advances</div>
</div>
<div class="glr-kpi glr-kpi--green">
<div class="glr-kpi-n">{{ clientRows.length | number }}</div>
<div class="glr-kpi-l">Relationships</div>
<div class="glr-kpi-sub">as at {{ range.to }} · {{ branchLabel }}</div>
</div>
</div>
<p class="glr-note">
Customer balances are derived from the General Ledger — each relationship holds a share of its branch's balance
in that head — so this report always reconciles to the GL rather than drifting as a second source.
</p>
<div class="glr-tbl-wrap glr-tbl-wrap--tall">
<table class="glr-tbl">
<thead>
<tr>
<th>CIF</th>
<th>Customer</th>
<th>Branch</th>
<th>Account No</th>
<th>Product</th>
<th class="ta-c">Side</th>
<th class="ta-r">Balance (&#8377;)</th>
</tr>
</thead>
<tbody>
@for (r of clientRows; track r.cif) {
<tr>
<td class="mono">{{ r.cif }}</td>
<td>{{ r.name }}</td>
<td>{{ branchName(r.branchCode) }}</td>
<td class="mono">{{ r.accountNo }}</td>
<td class="muted">{{ r.product }}</td>
<td class="ta-c">
<span
class="type-pill"
[class.type-liability]="r.side === 'DEPOSIT'"
[class.type-asset]="r.side === 'ADVANCE'"
>
{{ r.side }}
</span>
</td>
<td class="ta-r mono">{{ r.balance | number: '1.2-2' }}</td>
</tr>
} @empty {
<tr>
<td colspan="7" class="glr-empty">No customer relationships for this period and branch.</td>
</tr>
}
</tbody>
</table>
</div>
</div>
}
<!-- ══════════════ BANKER HEAD REPORT ══════════════ -->
@if (activeReport === 'banker-head') {
<div class="glr-section">
<p class="glr-note">
Head-wise abstract for <strong>{{ rangeLabel }}</strong> — the trial balance rolled up to principal heads, with
opening, turnover and closing for each. Debit and credit turnover must agree.
</p>
<div class="glr-tbl-wrap">
<table class="glr-tbl">
<thead>
<tr>
<th>Principal Head</th>
<th class="ta-c">Accounts</th>
<th class="ta-r">Opening</th>
<th class="ta-r">Debit</th>
<th class="ta-r">Credit</th>
<th class="ta-r">Closing</th>
</tr>
</thead>
<tbody>
@for (r of bankerHeadRows; track r.head) {
<tr>
<td>
<strong>{{ r.head }}</strong>
</td>
<td class="ta-c mono">{{ r.accounts }}</td>
<td class="ta-r mono">{{ r.opening | number: '1.2-2' }}</td>
<td class="ta-r mono">{{ r.debit ? (r.debit | number: '1.2-2') : '' }}</td>
<td class="ta-r mono">{{ r.credit ? (r.credit | number: '1.2-2') : '' }}</td>
<td class="ta-r mono">
<strong>{{ r.closing | number: '1.2-2' }}</strong>
</td>
</tr>
} @empty {
<tr>
<td colspan="6" class="glr-empty">No activity for this period and branch.</td>
</tr>
}
<tr class="total-row">
<td colspan="2">TOTAL ({{ bankerHeadRows.length }} heads)</td>
<td></td>
<td class="ta-r mono">{{ headDebitTotal | number: '1.2-2' }}</td>
<td class="ta-r mono">{{ headCreditTotal | number: '1.2-2' }}</td>
<td></td>
</tr>
</tbody>
</table>
</div>
</div>
}
<!-- ══════════════ SUNDRY REGISTER ══════════════ -->
@if (activeReport === 'sundry-register') {
<div class="glr-section">
<p class="glr-note">
Outstanding items in the sundry, suspense and bills-payable heads as at <strong>{{ range.to }}</strong
>, aged from their posting date. These heads are where unreconciled entries collect, so ageing is the point of
the register.
</p>
@if (sundryBuckets.length) {
<div class="glr-kpis">
@for (b of sundryBuckets; track b.bucket) {
<div
class="glr-kpi"
[class.glr-kpi--green]="b.bucket === 'Up to 30 days'"
[class.glr-kpi--amber]="b.bucket === '31 to 90 days'"
[class.glr-kpi--red]="b.bucket === 'Over 180 days'"
>
<div class="glr-kpi-n">&#8377;{{ b.amount | number: '1.2-2' }}</div>
<div class="glr-kpi-l">{{ b.bucket }}</div>
<div class="glr-kpi-sub">{{ b.count }} item(s)</div>
</div>
}
</div>
}
<div class="glr-tbl-wrap glr-tbl-wrap--tall">
<table class="glr-tbl">
<thead>
<tr>
<th>Date</th>
<th>Voucher No</th>
<th>Branch</th>
<th>GL Code</th>
<th>Account</th>
<th>Narration</th>
<th class="ta-r">Amount (&#8377;)</th>
<th class="ta-c">Age</th>
</tr>
</thead>
<tbody>
@for (r of sundryRows; track r.voucherNo + r.code + r.date) {
<tr>
<td class="mono">{{ r.date }}</td>
<td class="mono">{{ r.voucherNo }}</td>
<td>{{ branchName(r.branchCode) }}</td>
<td class="mono">{{ r.code }}</td>
<td>{{ r.name }}</td>
<td class="muted">{{ r.narration }}</td>
<td class="ta-r mono">{{ r.amount | number: '1.2-2' }}</td>
<td class="ta-c">
<span
class="type-pill"
[class.type-income]="r.bucket === 'Up to 30 days'"
[class.type-expense]="r.bucket === '31 to 90 days'"
[class.type-contingent]="r.bucket === 'Over 180 days'"
>
{{ r.ageDays }}d
</span>
</td>
</tr>
} @empty {
<tr>
<td colspan="8" class="glr-empty">No sundry or suspense items outstanding for this selection.</td>
</tr>
}
</tbody>
<tfoot>
<tr class="total-row">
<td colspan="6">Total outstanding ({{ sundryRows.length }} items)</td>
<td class="ta-r mono">{{ sundryTotal | number: '1.2-2' }}</td>
<td></td>
</tr>
</tfoot>
</table>
</div>
</div>
}
<!-- ══════════════ VOUCHER REGISTER ══════════════ -->
@if (activeReport === 'voucher-register') {
<div class="glr-section">
<div class="glr-balance" [class.glr-balance--bad]="unbalancedVouchers > 0">
<fa-icon [icon]="unbalancedVouchers ? 'exclamation-triangle' : 'check-circle'"></fa-icon>
<span>
{{ voucherRows.length | number }} voucher(s) raised in {{ rangeLabel }} for {{ branchLabel }} —
{{
unbalancedVouchers
? unbalancedVouchers + ' voucher(s) do NOT balance and must be investigated'
: 'every voucher is double-entry and balances'
}}
</span>
</div>
<div class="glr-tbl-wrap glr-tbl-wrap--tall">
<table class="glr-tbl">
<thead>
<tr>
<th>Date</th>
<th>Voucher No</th>
<th>Branch</th>
<th>Narration</th>
<th>Debit account(s)</th>
<th>Credit account(s)</th>
<th class="ta-r">Amount (&#8377;)</th>
<th class="ta-c">Legs</th>
</tr>
</thead>
<tbody>
@for (r of voucherRows; track r.voucherNo) {
<tr [class.glr-unbalanced]="!r.balanced">
<td class="mono">{{ r.date }}</td>
<td class="mono">{{ r.voucherNo }}</td>
<td>{{ branchName(r.branchCode) }}</td>
<td class="muted">{{ r.narration }}</td>
<td class="mono">{{ r.debitAccounts }}</td>
<td class="mono">{{ r.creditAccounts }}</td>
<td class="ta-r mono">{{ r.amount | number: '1.2-2' }}</td>
<td class="ta-c mono">{{ r.legs }}</td>
</tr>
} @empty {
<tr>
<td colspan="8" class="glr-empty">No vouchers raised in this period for this branch.</td>
</tr>
}
</tbody>
<tfoot>
<tr class="total-row">
<td colspan="6">Total ({{ voucherRows.length }} vouchers)</td>
<td class="ta-r mono">{{ voucherTotal | number: '1.2-2' }}</td>
<td></td>
</tr>
</tfoot>
</table>
</div>
</div>
}
<!-- TOAST -->
<div class="glr-toast" [class.show]="toastVisible">{{ toastMsg }}</div>
</div>