Files
cbsnexora/src/app/sft/sft.component.html
T
AdityaandClaude Opus 4.7 12bfc81219 feat: add 11 banking compliance & accounting report modules
Adds dialog components and feature modules for RBI/banking compliance,
KYC, and accounting reports. Wires them into the shell menu (RBI,
General Ledger, CKYC Mgmt, Others, Insurance) and dashboard cards.

Dialog components (lazy-loaded MatDialog):
- PSL Returns (Form III) — dashboard card + RBI menu
- ALM Statement of Structural Liquidity (Form ALM-1) — RBI menu
- CIMS / XBRL Returns (OSS-2 / PSA / RAL / RCP-UCB) — RBI menu, shared
  dialog with form-pill switcher
- CIC DQR (CIBIL / Experian / Equifax / CRIF, 72-col TUDF) — Others menu
  + dashboard card
- CKYC Compliance Reports (Re-KYC / Risk Review / CERSAI) — CKYC Mgmt
- Accounting Reports (P&L / Balance Sheet / Comparative B/S / GL DR/CR
  / Misc Expense Ledger) — General Ledger menu

Feature modules (Route.withShell):
- DEAF (/deaf): Form I, Form II, Annex 4, accounts register
- DICGC (/dicgc): Slab Report, SAHAY Depositor List
- FIU-IND (/fiu): FINnet 2.0 Statement of Financial Transactions
- SFT (/sft): Income Tax Section 285BA SFT
- CKYC Reports (/ckyc/ckyc-reports): standalone dashboard

UI:
- Theme-colored icons on 22 wired menu links across 5 menus —
  visually distinguishes wired (colored) from placeholder (gray) links.
- Backdrop classes per dialog in main.scss.

All using dummy data (Bharat Urban Bank Ltd, Karthik Kamath as Principal
Officer, dummy customer names) — no real bank or customer references.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 18:59:50 +05:30

398 lines
16 KiB
HTML

<!--
Copyright since 2025 Mifos Initiative
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at http://mozilla.org/MPL/2.0/.
-->
<div class="sft-root">
<!-- HEADER -->
<div class="sft-head">
<div class="sft-head-left">
<fa-icon icon="file-invoice" class="sft-head-ic"></fa-icon>
<div>
<h2 class="sft-head-t">Income Tax — Statement of Financial Transactions (SFT)</h2>
<div class="sft-head-s">
{{ bank.name }} &middot; {{ bank.branch }} &middot; FY <strong>{{ bank.fy }}</strong> &middot; IT Act §285BA /
Rule 114E &middot; Due <strong>{{ bank.filingDueDate }}</strong>
</div>
</div>
</div>
<div class="sft-head-meta">
<div>
<span class="sft-meta-l">Filer PAN</span><span class="sft-meta-v mono">{{ bank.filerPan }}</span>
</div>
<div>
<span class="sft-meta-l">TAN</span><span class="sft-meta-v mono">{{ bank.filerTan }}</span>
</div>
<div>
<span class="sft-meta-l">Principal Officer</span><span class="sft-meta-v">{{ bank.principalOfficer }}</span>
</div>
</div>
</div>
<!-- TABS -->
<div class="sft-tabs">
<button class="sft-tab" [class.active]="activeTab === 'dashboard'" (click)="showTab('dashboard')">
<fa-icon icon="chart-pie"></fa-icon> Dashboard
</button>
<button class="sft-tab" [class.active]="activeTab === 'person'" (click)="showTab('person')">
<fa-icon icon="users"></fa-icon> Person-wise (001 / 002 / 004)
</button>
<button class="sft-tab" [class.active]="activeTab === 'account'" (click)="showTab('account')">
<fa-icon icon="university"></fa-icon> Account-wise (003)
</button>
<button class="sft-tab" [class.active]="activeTab === 'intdiv'" (click)="showTab('intdiv')">
<fa-icon icon="coins"></fa-icon> Interest &amp; Dividend (015 / 016)
</button>
</div>
<!-- DASHBOARD -->
@if (activeTab === 'dashboard') {
<div class="sft-section">
<div class="sft-kpis">
<div class="sft-kpi sft-kpi--blue">
<div class="sft-kpi-ic"><fa-icon icon="file-alt"></fa-icon></div>
<div>
<div class="sft-kpi-n">{{ totalRecords | number }}</div>
<div class="sft-kpi-l">Total Records</div>
<div class="sft-kpi-sub">all SFT codes combined</div>
</div>
</div>
<div class="sft-kpi sft-kpi--teal">
<div class="sft-kpi-ic"><fa-icon icon="coins"></fa-icon></div>
<div>
<div class="sft-kpi-n">&#8377;{{ totalReportableAmount | number: '1.0-0' }}</div>
<div class="sft-kpi-l">Reportable Amount</div>
<div class="sft-kpi-sub">aggregate per FY {{ bank.fy }}</div>
</div>
</div>
<div class="sft-kpi sft-kpi--amber">
<div class="sft-kpi-ic"><fa-icon icon="users"></fa-icon></div>
<div>
<div class="sft-kpi-n">{{ sft001Count + sft002Count + sft004Count | number }}</div>
<div class="sft-kpi-l">Person-wise Records</div>
<div class="sft-kpi-sub">
{{ sft001Count }} ·001 &middot; {{ sft002Count }} ·002 &middot; {{ sft004Count }} ·004
</div>
</div>
</div>
<div class="sft-kpi sft-kpi--purple">
<div class="sft-kpi-ic"><fa-icon icon="university"></fa-icon></div>
<div>
<div class="sft-kpi-n">{{ sft003Count | number }}</div>
<div class="sft-kpi-l">SFT-003 Accounts</div>
<div class="sft-kpi-sub">cash CA ≥ &#8377;50 L per FY</div>
</div>
</div>
<div class="sft-kpi sft-kpi--green">
<div class="sft-kpi-ic"><fa-icon icon="coins"></fa-icon></div>
<div>
<div class="sft-kpi-n">{{ sft015Count + sft016Count | number }}</div>
<div class="sft-kpi-l">Int / Dividend</div>
<div class="sft-kpi-sub">{{ sft015Count }} ·015 &middot; {{ sft016Count }} ·016</div>
</div>
</div>
</div>
<!-- SFT code summary cards -->
<div class="sft-codes">
<div class="sft-code-card">
<div class="sft-code-h">
<span class="sft-code-tag t-001">SFT-001</span><span>Cash Drafts / Pay Orders</span>
</div>
<p>
Cash purchase of bank drafts, pay orders or banker's cheques aggregating ≥ <strong>&#8377;10 L</strong> per
person/FY
</p>
<div class="sft-code-meta">{{ sft001Count }} record{{ sft001Count === 1 ? '' : 's' }}</div>
</div>
<div class="sft-code-card">
<div class="sft-code-h">
<span class="sft-code-tag t-002">SFT-002</span><span>Time Deposits (FD/RD)</span>
</div>
<p>Time-deposit opening with cash ≥ <strong>&#8377;10 L</strong> per person/FY (excluding renewals)</p>
<div class="sft-code-meta">{{ sft002Count }} record{{ sft002Count === 1 ? '' : 's' }}</div>
</div>
<div class="sft-code-card">
<div class="sft-code-h"><span class="sft-code-tag t-003">SFT-003</span><span>Current Account Cash</span></div>
<p>
Cash deposits / withdrawals — <strong>current account</strong> aggregating ≥
<strong>&#8377;50 L</strong> per FY
</p>
<div class="sft-code-meta">{{ sft003Count }} account{{ sft003Count === 1 ? '' : 's' }}</div>
</div>
<div class="sft-code-card">
<div class="sft-code-h"><span class="sft-code-tag t-004">SFT-004</span><span>Savings Bank Cash</span></div>
<p>Cash deposits — <strong>savings account</strong> aggregating ≥ <strong>&#8377;10 L</strong> per FY</p>
<div class="sft-code-meta">{{ sft004Count }} record{{ sft004Count === 1 ? '' : 's' }}</div>
</div>
<div class="sft-code-card">
<div class="sft-code-h"><span class="sft-code-tag t-015">SFT-015</span><span>Dividend Payments</span></div>
<p>Dividend payments to shareholders — any amount, aggregated per PAN/FY</p>
<div class="sft-code-meta">{{ sft015Count }} record{{ sft015Count === 1 ? '' : 's' }}</div>
</div>
<div class="sft-code-card">
<div class="sft-code-h">
<span class="sft-code-tag t-016">SFT-016</span><span>Interest Paid on Deposits</span>
</div>
<p>Interest paid on deposits — any amount, aggregated per PAN/FY</p>
<div class="sft-code-meta">{{ sft016Count }} record{{ sft016Count === 1 ? '' : 's' }}</div>
</div>
</div>
<div class="sft-toolbar">
<button class="sft-btn sft-btn-xls" (click)="exportAll()">
<fa-icon icon="file-csv"></fa-icon> Download All SFT Files
</button>
</div>
</div>
}
<!-- PERSON-WISE -->
@if (activeTab === 'person') {
<div class="sft-section">
<div class="sft-form-meta">
<div class="sft-form-title">
<h3>Person-wise Records — SFT-001 / 002 / 004</h3>
<p>One record per person per SFT code per FY (aggregate)</p>
</div>
<div class="sft-action-group">
<select class="sft-inp sft-inp-narrow" [(ngModel)]="personSftFilter">
<option value="ALL">All Codes</option>
<option value="SFT-001">SFT-001 only</option>
<option value="SFT-002">SFT-002 only</option>
<option value="SFT-004">SFT-004 only</option>
</select>
<button class="sft-btn sft-btn-csv" (click)="exportPersonCsv('SFT-001')">
<fa-icon icon="file-csv"></fa-icon> SFT_001.csv
</button>
<button class="sft-btn sft-btn-csv" (click)="exportPersonCsv('SFT-002')">
<fa-icon icon="file-csv"></fa-icon> SFT_002.csv
</button>
<button class="sft-btn sft-btn-csv" (click)="exportPersonCsv('SFT-004')">
<fa-icon icon="file-csv"></fa-icon> SFT_004.csv
</button>
</div>
</div>
<div class="sft-tbl-wrap">
<table class="sft-tbl">
<thead>
<tr>
<th class="ta-c">RSN</th>
<th>Code</th>
<th>Person Name</th>
<th class="ta-c">Type</th>
<th>PAN</th>
<th>DOB</th>
<th>Mobile</th>
<th>City</th>
<th>Product</th>
<th class="ta-r">Aggregate</th>
<th class="ta-r">Cash</th>
<th>Last Txn</th>
<th>Account</th>
</tr>
</thead>
<tbody>
@for (r of filteredPersons; track r.reportSerialNumber + '-' + r.sftCode) {
<tr>
<td class="ta-c">{{ r.reportSerialNumber }}</td>
<td>
<span class="sft-code-tag" [class]="'t-' + r.sftCode.replace('SFT-', '')">{{ r.sftCode }}</span>
</td>
<td>{{ r.personName }}</td>
<td class="ta-c">{{ r.personType }}</td>
<td class="mono">{{ r.pan }}</td>
<td>{{ r.dobOrIncorporation }}</td>
<td class="mono">{{ r.primaryMobileNo }}</td>
<td>{{ r.city }}, {{ r.state }}</td>
<td>
<span class="muted">{{ productLabel(r.productType) }}</span>
</td>
<td class="ta-r mono">&#8377;{{ r.aggGrossReceived | number: '1.0-0' }}</td>
<td class="ta-r mono">&#8377;{{ r.aggGrossReceivedCash | number: '1.0-0' }}</td>
<td>{{ r.lastDateOfTransaction }}</td>
<td class="mono">{{ r.relatedAccountNumber }}</td>
</tr>
} @empty {
<tr>
<td colspan="13" class="sft-empty">No records for the selected SFT code.</td>
</tr>
}
</tbody>
</table>
</div>
</div>
}
<!-- ACCOUNT-WISE (SFT-003) -->
@if (activeTab === 'account') {
<div class="sft-section">
<div class="sft-form-meta">
<div class="sft-form-title">
<h3>SFT-003 — Cash Deposits/Withdrawals in Current Accounts</h3>
<p>Account-wise schema with embedded Person Card; aggregate ≥ &#8377;50 L cash per FY</p>
</div>
<button class="sft-btn sft-btn-csv" (click)="exportAccountCsv()">
<fa-icon icon="file-csv"></fa-icon> Download SFT_003.csv
</button>
</div>
<div class="sft-acc-list">
@for (r of accountRecords; track r.reportSerialNumber) {
<div class="acc-card">
<div class="acc-card-h">
<div class="acc-card-id">
<span class="acc-rsn">RSN-{{ r.reportSerialNumber }}</span>
<span class="acc-type-pill">{{ r.accountType }}</span>
<span class="acc-status-pill" [class.act]="r.accountStatus === 'A'">{{
r.accountStatus === 'A' ? 'Active' : r.accountStatus === 'C' ? 'Closed' : 'Dormant'
}}</span>
</div>
<div class="acc-card-amt">
<span class="muted">Cash credited</span>
<strong>&#8377;{{ r.aggGrossCashCredited | number: '1.0-0' }}</strong>
<span class="muted">/ debited</span>
<strong>&#8377;{{ r.aggGrossCashDebited | number: '1.0-0' }}</strong>
</div>
</div>
<div class="acc-card-body">
<div class="acc-meta">
<div>
<label>Account No.</label><span class="mono">{{ r.accountNumber }}</span>
</div>
<div>
<label>Holder</label><span>{{ r.accountHolderName }}</span>
</div>
<div>
<label>Branch</label><span>{{ r.branchName }} ({{ r.branchReferenceNumber }})</span>
</div>
<div>
<label>Branch Address</label><span>{{ r.branchAddress }}</span>
</div>
<div>
<label>Branch Phone</label><span class="mono">{{ r.branchStdCode }}-{{ r.branchPhone }}</span>
</div>
<div>
<label>Branch Email</label><span>{{ r.branchEmail }}</span>
</div>
</div>
<div class="acc-pc-block">
<div class="acc-pc-h"><fa-icon icon="user"></fa-icon> Person Card</div>
<div class="acc-meta">
<div>
<label>Name</label><span>{{ r.pcPersonName }}</span>
</div>
<div>
<label>Type</label><span>{{ r.pcPersonType }}</span>
</div>
<div>
<label>PAN</label><span class="mono">{{ r.pcPan }}</span>
</div>
<div>
<label>DOB / Incorp.</label><span>{{ r.pcDob }}</span>
</div>
<div>
<label>Business</label><span>{{ productLabel(r.pcBusiness) }}</span>
</div>
<div>
<label>Mobile</label><span class="mono">{{ r.pcPrimaryMobile }}</span>
</div>
<div class="acc-pc-addr">
<label>Address</label><span>{{ r.pcAddress }}, {{ r.pcCity }}, {{ r.pcState }} {{ r.pcPin }}</span>
</div>
</div>
</div>
</div>
</div>
} @empty {
<div class="sft-empty-card">No SFT-003 records this FY.</div>
}
</div>
</div>
}
<!-- INTEREST & DIVIDEND -->
@if (activeTab === 'intdiv') {
<div class="sft-section">
<div class="sft-form-meta">
<div class="sft-form-title">
<h3>SFT-015 (Dividend) &amp; SFT-016 (Interest Paid)</h3>
<p>Pipe-delimited compact format submitted to Income Tax Reporting Portal</p>
</div>
<div class="sft-action-group">
<select class="sft-inp sft-inp-narrow" [(ngModel)]="intDivFilter">
<option value="ALL">Both</option>
<option value="SFT-015">SFT-015 (Dividend)</option>
<option value="SFT-016">SFT-016 (Interest)</option>
</select>
<button class="sft-btn sft-btn-csv" (click)="exportIntDivCsv('SFT-015')">
<fa-icon icon="file-csv"></fa-icon> SFT15.csv
</button>
<button class="sft-btn sft-btn-csv" (click)="exportIntDivCsv('SFT-016')">
<fa-icon icon="file-csv"></fa-icon> SFT16.csv
</button>
</div>
</div>
<div class="sft-tbl-wrap">
<table class="sft-tbl">
<thead>
<tr>
<th class="ta-c">RSN</th>
<th>Code</th>
<th>FY</th>
<th>Name</th>
<th>PAN</th>
<th>Aadhaar (mask)</th>
<th>Mobile</th>
<th>Account</th>
<th class="ta-c">Type</th>
<th class="ta-r">Amount</th>
</tr>
</thead>
<tbody>
@for (r of filteredIntDiv; track r.rsn + '-' + r.sftCode) {
<tr>
<td class="ta-c">{{ r.rsn }}</td>
<td>
<span class="sft-code-tag" [class]="'t-' + r.sftCode.replace('SFT-', '')">{{ r.sftCode }}</span>
</td>
<td>{{ r.fy }}</td>
<td>{{ r.name }}</td>
<td class="mono">{{ r.pan || '—' }}</td>
<td class="mono">{{ r.aadhaar || '—' }}</td>
<td class="mono">{{ r.mobile }}</td>
<td class="mono">{{ r.accountNumber || '—' }}</td>
<td class="ta-c">{{ r.typeOfAccount || (r.sftCode === 'SFT-015' ? 'DIV' : '—') }}</td>
<td class="ta-r mono">
<strong>&#8377;{{ r.amount | number: '1.0-0' }}</strong>
</td>
</tr>
} @empty {
<tr>
<td colspan="10" class="sft-empty">No records for the selected SFT code.</td>
</tr>
}
</tbody>
</table>
</div>
<div class="sft-note">
<fa-icon icon="info-circle"></fa-icon>
<span
><strong>Note:</strong> SFT-015 (Dividend) and SFT-016 (Interest) are pipe-delimited (`|`) files, one row per
PAN per FY with aggregated amounts. Submit via the IT Reporting Portal under {{ bank.principalOfficer }}'s
digital signature.</span
>
</div>
</div>
}
<!-- TOAST -->
<div class="sft-toast" [class.show]="toastVisible">{{ toastMsg }}</div>
</div>