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>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
634003a75c
commit
12bfc81219
@@ -0,0 +1,475 @@
|
||||
/**
|
||||
* 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/.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Sample DEAF data — schema and totals match the actual CIBIL/RBI return template.
|
||||
* Bank/customer/officer/auditor names are dummy placeholders.
|
||||
*
|
||||
* Three RBI-prescribed reports:
|
||||
* Form I — Monthly Return of unclaimed deposits transferred to DEAF (filed online by 15th)
|
||||
* Form II — Same return submitted as original hardcopy
|
||||
* Annex 4 — Refund Claim Form (when bank claims back from DEAF for paid-out customer refunds)
|
||||
*/
|
||||
|
||||
export interface DeafFormRow {
|
||||
/** 1=Opening, 2=Wrongly reported earlier, 3=Transferred this month, 4=Claims settled, 5=Net, 6=Total at end */
|
||||
sl: number;
|
||||
particulars: string;
|
||||
/** (a) Interest Bearing Deposits */
|
||||
ibdAccounts: number;
|
||||
ibdAmount: number;
|
||||
/** (b) Non-Interest Bearing Deposits */
|
||||
nibdAccounts: number;
|
||||
nibdAmount: number;
|
||||
/** (c) Other Credits (Non-Interest bearing) */
|
||||
ocAccounts: number;
|
||||
ocAmount: number;
|
||||
/** (d) Total = (a) + (b) + (c) */
|
||||
totalAccounts: number;
|
||||
totalAmount: number;
|
||||
}
|
||||
|
||||
export interface DeafForm {
|
||||
bankName: string;
|
||||
bankDeafCode: string;
|
||||
remittedThroughSponsor: 'Y' | 'N';
|
||||
sponsorBankName: string;
|
||||
monthYear: string;
|
||||
dateOfTransfer: string;
|
||||
rows: DeafFormRow[];
|
||||
/** Authorized officer + auditor (signature block) */
|
||||
officer: string;
|
||||
officerDesignation: string;
|
||||
auditor: string;
|
||||
auditorAddress: string;
|
||||
}
|
||||
|
||||
export interface DeafClaim {
|
||||
slNo: number;
|
||||
ibdPrincipal: number;
|
||||
ibdInterest: number;
|
||||
ibdTotal: number;
|
||||
nibdAccounts: number;
|
||||
nibdAmount: number;
|
||||
ocAccounts: number;
|
||||
ocAmount: number;
|
||||
grandTotalAccounts: number;
|
||||
grandTotalAmount: number;
|
||||
}
|
||||
|
||||
export interface DeafEligibleAccount {
|
||||
acNo: string;
|
||||
customerName: string;
|
||||
acType: 'SB' | 'CA' | 'FD' | 'RD' | 'BG' | 'DD' | 'PO';
|
||||
branch: string;
|
||||
openedDate: string;
|
||||
lastTxnDate: string;
|
||||
inactiveYears: number;
|
||||
/** IBD = Interest Bearing Deposit; NIBD = Non-Interest Bearing; OC = Other Credit */
|
||||
bucket: 'IBD' | 'NIBD' | 'OC';
|
||||
principal: number;
|
||||
interest: number;
|
||||
total: number;
|
||||
status: 'eligible-this-month' | 'transferred' | 'claim-pending' | 'refunded';
|
||||
transferredOn?: string;
|
||||
}
|
||||
|
||||
/** Form I — Dec 2025 cycle */
|
||||
export const FORM_I: DeafForm = {
|
||||
bankName: 'Bharat Urban Bank Ltd, Mumbai Main Branch',
|
||||
bankDeafCode: '1100',
|
||||
remittedThroughSponsor: 'Y',
|
||||
sponsorBankName: 'State Bank of India',
|
||||
monthYear: '12/2025',
|
||||
dateOfTransfer: '29-12-2025',
|
||||
officer: 'Anjali Mehta',
|
||||
officerDesignation: 'Chief Executive Officer',
|
||||
auditor: 'Karthik Kamath',
|
||||
auditorAddress: '12 MG Road, Worli, Mumbai 400018',
|
||||
rows: [
|
||||
{
|
||||
sl: 1,
|
||||
particulars: 'Opening balance of accounts transferred to the Fund at the beginning of the month',
|
||||
ibdAccounts: 1208,
|
||||
ibdAmount: 2571461.6,
|
||||
nibdAccounts: 138,
|
||||
nibdAmount: 177338.98,
|
||||
ocAccounts: 0,
|
||||
ocAmount: 0,
|
||||
totalAccounts: 1346,
|
||||
totalAmount: 2748800.58
|
||||
},
|
||||
{
|
||||
sl: 2,
|
||||
particulars: 'Accounts if any wrongly reported in past and rectified during this month',
|
||||
ibdAccounts: 10,
|
||||
ibdAmount: 7582.7,
|
||||
nibdAccounts: 0,
|
||||
nibdAmount: 0,
|
||||
ocAccounts: 0,
|
||||
ocAmount: 0,
|
||||
totalAccounts: 10,
|
||||
totalAmount: 7582.7
|
||||
},
|
||||
{
|
||||
sl: 3,
|
||||
particulars:
|
||||
'Accounts transferred to the DEA Fund during this month (incl. inadvertently omitted in previous month)',
|
||||
ibdAccounts: 0,
|
||||
ibdAmount: 0,
|
||||
nibdAccounts: 0,
|
||||
nibdAmount: 0,
|
||||
ocAccounts: 0,
|
||||
ocAmount: 0,
|
||||
totalAccounts: 0,
|
||||
totalAmount: 0
|
||||
},
|
||||
{
|
||||
sl: 4,
|
||||
particulars: 'Claims settled and refund received from the DEA Fund during this month (only the principal)',
|
||||
ibdAccounts: 2,
|
||||
ibdAmount: 9177.0,
|
||||
nibdAccounts: 0,
|
||||
nibdAmount: 0,
|
||||
ocAccounts: 0,
|
||||
ocAmount: 0,
|
||||
totalAccounts: 2,
|
||||
totalAmount: 9177.0
|
||||
},
|
||||
{
|
||||
sl: 5,
|
||||
particulars: 'Net amount transferred to the Fund during the month (2 + 3 − 4)',
|
||||
ibdAccounts: 8,
|
||||
ibdAmount: -1594.3,
|
||||
nibdAccounts: 0,
|
||||
nibdAmount: 0,
|
||||
ocAccounts: 0,
|
||||
ocAmount: 0,
|
||||
totalAccounts: 8,
|
||||
totalAmount: -1594.3
|
||||
},
|
||||
{
|
||||
sl: 6,
|
||||
particulars: 'Total amount with the Fund at the end of the month (1 + 5)',
|
||||
ibdAccounts: 1216,
|
||||
ibdAmount: 2569867.3,
|
||||
nibdAccounts: 138,
|
||||
nibdAmount: 177338.98,
|
||||
ocAccounts: 0,
|
||||
ocAmount: 0,
|
||||
totalAccounts: 1354,
|
||||
totalAmount: 2747206.28
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
/** Form II — Jan 2026 (head office consolidated) */
|
||||
export const FORM_II: DeafForm = {
|
||||
bankName: 'Bharat Urban Bank Ltd, Head Office',
|
||||
bankDeafCode: '1100',
|
||||
remittedThroughSponsor: 'Y',
|
||||
sponsorBankName: 'State Bank of India',
|
||||
monthYear: '01/2026',
|
||||
dateOfTransfer: '15-01-2026',
|
||||
officer: 'Anjali Mehta',
|
||||
officerDesignation: 'Chief Executive Officer',
|
||||
auditor: 'Karthik Kamath',
|
||||
auditorAddress: '12 MG Road, Worli, Mumbai 400018',
|
||||
rows: [
|
||||
{
|
||||
sl: 1,
|
||||
particulars: 'Opening balance at the beginning of the month',
|
||||
ibdAccounts: 699,
|
||||
ibdAmount: 2040493.18,
|
||||
nibdAccounts: 140,
|
||||
nibdAmount: 187649.0,
|
||||
ocAccounts: 0,
|
||||
ocAmount: 0,
|
||||
totalAccounts: 839,
|
||||
totalAmount: 2228142.18
|
||||
},
|
||||
{
|
||||
sl: 2,
|
||||
particulars: 'Accounts and amount inadvertently omitted in previous month return and transferred this month',
|
||||
ibdAccounts: 0,
|
||||
ibdAmount: 0,
|
||||
nibdAccounts: 0,
|
||||
nibdAmount: 0,
|
||||
ocAccounts: 0,
|
||||
ocAmount: 0,
|
||||
totalAccounts: 0,
|
||||
totalAmount: 0
|
||||
},
|
||||
{
|
||||
sl: 3,
|
||||
particulars: 'Accounts and amount due and transferred to the Fund during this month',
|
||||
ibdAccounts: 5,
|
||||
ibdAmount: 19956.75,
|
||||
nibdAccounts: 0,
|
||||
nibdAmount: 0,
|
||||
ocAccounts: 0,
|
||||
ocAmount: 0,
|
||||
totalAccounts: 5,
|
||||
totalAmount: 19956.75
|
||||
},
|
||||
{
|
||||
sl: 4,
|
||||
particulars: 'Accounts and amount claimed during the previous month and paid from the Fund during this month',
|
||||
ibdAccounts: 0,
|
||||
ibdAmount: 0,
|
||||
nibdAccounts: 0,
|
||||
nibdAmount: 0,
|
||||
ocAccounts: 0,
|
||||
ocAmount: 0,
|
||||
totalAccounts: 0,
|
||||
totalAmount: 0
|
||||
},
|
||||
{
|
||||
sl: 5,
|
||||
particulars: 'Total amount transferred less amount paid from the Fund during the month (2 + 3 − 4)',
|
||||
ibdAccounts: 5,
|
||||
ibdAmount: 19956.75,
|
||||
nibdAccounts: 0,
|
||||
nibdAmount: 0,
|
||||
ocAccounts: 0,
|
||||
ocAmount: 0,
|
||||
totalAccounts: 5,
|
||||
totalAmount: 19956.75
|
||||
},
|
||||
{
|
||||
sl: 6,
|
||||
particulars: 'Total amount with the Fund at the end of the month (1 + 5)',
|
||||
ibdAccounts: 704,
|
||||
ibdAmount: 2060449.93,
|
||||
nibdAccounts: 140,
|
||||
nibdAmount: 187649.0,
|
||||
ocAccounts: 0,
|
||||
ocAmount: 0,
|
||||
totalAccounts: 844,
|
||||
totalAmount: 2248098.93
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
/** Annex 4 — Refund claim form (Jan 2026) */
|
||||
export const REFUND_CLAIMS: {
|
||||
bankName: string;
|
||||
bankDeafCode: string;
|
||||
currentAcWithRbi: string;
|
||||
sponsorBank: string;
|
||||
month: string;
|
||||
year: string;
|
||||
firstSignatory: string;
|
||||
firstDesignation: string;
|
||||
secondSignatory: string;
|
||||
secondDesignation: string;
|
||||
auditor: string;
|
||||
rows: DeafClaim[];
|
||||
} = {
|
||||
bankName: 'Bharat Urban Bank Ltd',
|
||||
bankDeafCode: '1100',
|
||||
currentAcWithRbi: '03010200099001',
|
||||
sponsorBank: 'State Bank of India',
|
||||
month: 'January',
|
||||
year: '2026',
|
||||
firstSignatory: 'Vikram Singh',
|
||||
firstDesignation: 'IT Manager',
|
||||
secondSignatory: 'Rohan Malhotra',
|
||||
secondDesignation: 'Clerk / Cashier',
|
||||
auditor: 'Karthik Kamath',
|
||||
rows: [
|
||||
{
|
||||
slNo: 4,
|
||||
ibdPrincipal: 5754.0,
|
||||
ibdInterest: 457,
|
||||
ibdTotal: 6211.0,
|
||||
nibdAccounts: 0,
|
||||
nibdAmount: 0,
|
||||
ocAccounts: 0,
|
||||
ocAmount: 0,
|
||||
grandTotalAccounts: 4,
|
||||
grandTotalAmount: 6211.0
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
/** Eligible / transferred / claimed accounts list (dummy customers across multiple branches) */
|
||||
export const ELIGIBLE_ACCOUNTS: DeafEligibleAccount[] = [
|
||||
{
|
||||
acNo: '110001301002013',
|
||||
customerName: 'RAVI KUMAR SHARMA',
|
||||
acType: 'SB',
|
||||
branch: 'Mumbai Main',
|
||||
openedDate: '12-04-2010',
|
||||
lastTxnDate: '15-03-2016',
|
||||
inactiveYears: 10,
|
||||
bucket: 'IBD',
|
||||
principal: 4250.0,
|
||||
interest: 312.5,
|
||||
total: 4562.5,
|
||||
status: 'eligible-this-month'
|
||||
},
|
||||
{
|
||||
acNo: '110001301004221',
|
||||
customerName: 'PRIYA PATEL',
|
||||
acType: 'SB',
|
||||
branch: 'Pune FC Road',
|
||||
openedDate: '08-09-2009',
|
||||
lastTxnDate: '20-01-2016',
|
||||
inactiveYears: 10,
|
||||
bucket: 'IBD',
|
||||
principal: 1850.75,
|
||||
interest: 132.0,
|
||||
total: 1982.75,
|
||||
status: 'eligible-this-month'
|
||||
},
|
||||
{
|
||||
acNo: '110001302001145',
|
||||
customerName: 'ARJUN DESHMUKH',
|
||||
acType: 'FD',
|
||||
branch: 'Nagpur Dharampeth',
|
||||
openedDate: '01-01-2011',
|
||||
lastTxnDate: '01-01-2016',
|
||||
inactiveYears: 10,
|
||||
bucket: 'IBD',
|
||||
principal: 25000.0,
|
||||
interest: 4180.0,
|
||||
total: 29180.0,
|
||||
status: 'eligible-this-month'
|
||||
},
|
||||
{
|
||||
acNo: '110001301005612',
|
||||
customerName: 'VIKRAM REDDY',
|
||||
acType: 'SB',
|
||||
branch: 'Bengaluru Jayanagar',
|
||||
openedDate: '25-07-2008',
|
||||
lastTxnDate: '12-12-2015',
|
||||
inactiveYears: 10,
|
||||
bucket: 'IBD',
|
||||
principal: 8350.5,
|
||||
interest: 654.0,
|
||||
total: 9004.5,
|
||||
status: 'eligible-this-month'
|
||||
},
|
||||
{
|
||||
acNo: '110001303002284',
|
||||
customerName: 'LAKSHMI IYER',
|
||||
acType: 'RD',
|
||||
branch: 'Bengaluru Indiranagar',
|
||||
openedDate: '15-06-2010',
|
||||
lastTxnDate: '15-06-2015',
|
||||
inactiveYears: 10,
|
||||
bucket: 'IBD',
|
||||
principal: 12500.0,
|
||||
interest: 1850.0,
|
||||
total: 14350.0,
|
||||
status: 'eligible-this-month'
|
||||
},
|
||||
{
|
||||
acNo: '110001305000412',
|
||||
customerName: 'NIRAV SHAH',
|
||||
acType: 'DD',
|
||||
branch: 'Ahmedabad Satellite',
|
||||
openedDate: '03-10-2014',
|
||||
lastTxnDate: '03-10-2014',
|
||||
inactiveYears: 11,
|
||||
bucket: 'NIBD',
|
||||
principal: 3450.0,
|
||||
interest: 0,
|
||||
total: 3450.0,
|
||||
status: 'eligible-this-month'
|
||||
},
|
||||
{
|
||||
acNo: '110001301001780',
|
||||
customerName: 'KAVITA VERMA',
|
||||
acType: 'SB',
|
||||
branch: 'Lucknow Gomti Nagar',
|
||||
openedDate: '11-02-2008',
|
||||
lastTxnDate: '11-09-2014',
|
||||
inactiveYears: 11,
|
||||
bucket: 'IBD',
|
||||
principal: 6240.0,
|
||||
interest: 478.0,
|
||||
total: 6718.0,
|
||||
status: 'transferred',
|
||||
transferredOn: '15-12-2025'
|
||||
},
|
||||
{
|
||||
acNo: '110001302002091',
|
||||
customerName: 'KARTHIK SUBRAMANIAN',
|
||||
acType: 'FD',
|
||||
branch: 'Chennai Valasaravakkam',
|
||||
openedDate: '04-08-2009',
|
||||
lastTxnDate: '04-08-2014',
|
||||
inactiveYears: 11,
|
||||
bucket: 'IBD',
|
||||
principal: 18500.0,
|
||||
interest: 2725.0,
|
||||
total: 21225.0,
|
||||
status: 'transferred',
|
||||
transferredOn: '15-11-2025'
|
||||
},
|
||||
{
|
||||
acNo: '110001301008764',
|
||||
customerName: 'SAMEER KAPOOR',
|
||||
acType: 'SB',
|
||||
branch: 'Delhi Greater Kailash',
|
||||
openedDate: '17-05-2009',
|
||||
lastTxnDate: '17-05-2014',
|
||||
inactiveYears: 11,
|
||||
bucket: 'IBD',
|
||||
principal: 4587.0,
|
||||
interest: 290.0,
|
||||
total: 4877.0,
|
||||
status: 'transferred',
|
||||
transferredOn: '15-09-2024'
|
||||
},
|
||||
{
|
||||
acNo: '110001302003145',
|
||||
customerName: 'ABHISHEK BANERJEE',
|
||||
acType: 'FD',
|
||||
branch: 'Kolkata Salt Lake',
|
||||
openedDate: '22-03-2010',
|
||||
lastTxnDate: '22-03-2015',
|
||||
inactiveYears: 10,
|
||||
bucket: 'IBD',
|
||||
principal: 15000.0,
|
||||
interest: 2150.0,
|
||||
total: 17150.0,
|
||||
status: 'claim-pending'
|
||||
},
|
||||
{
|
||||
acNo: '110001301010224',
|
||||
customerName: 'GAURAV THAKUR',
|
||||
acType: 'SB',
|
||||
branch: 'Shimla Sector 4',
|
||||
openedDate: '08-12-2008',
|
||||
lastTxnDate: '08-06-2014',
|
||||
inactiveYears: 11,
|
||||
bucket: 'IBD',
|
||||
principal: 3275.0,
|
||||
interest: 195.0,
|
||||
total: 3470.0,
|
||||
status: 'claim-pending'
|
||||
},
|
||||
{
|
||||
acNo: '110001302004088',
|
||||
customerName: 'MANMOHAN SINGH GILL',
|
||||
acType: 'FD',
|
||||
branch: 'Amritsar Model Town',
|
||||
openedDate: '19-09-2009',
|
||||
lastTxnDate: '19-09-2014',
|
||||
inactiveYears: 11,
|
||||
bucket: 'IBD',
|
||||
principal: 8500.0,
|
||||
interest: 1124.0,
|
||||
total: 9624.0,
|
||||
status: 'refunded',
|
||||
transferredOn: '15-04-2024'
|
||||
}
|
||||
];
|
||||
@@ -0,0 +1,29 @@
|
||||
/**
|
||||
* 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/.
|
||||
*/
|
||||
|
||||
import { NgModule } from '@angular/core';
|
||||
import { Routes, RouterModule } from '@angular/router';
|
||||
|
||||
import { Route } from '../core/route/route.service';
|
||||
import { DeafComponent } from './deaf.component';
|
||||
|
||||
const routes: Routes = [
|
||||
Route.withShell([
|
||||
{
|
||||
path: 'deaf',
|
||||
component: DeafComponent,
|
||||
data: { title: 'DEAF', breadcrumb: 'DEAF' }
|
||||
}
|
||||
])
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class DeafRoutingModule {}
|
||||
@@ -0,0 +1,416 @@
|
||||
<!--
|
||||
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="deaf-root">
|
||||
<!-- HEADER -->
|
||||
<div class="deaf-head">
|
||||
<div class="deaf-head-left">
|
||||
<fa-icon icon="university" class="deaf-head-ic"></fa-icon>
|
||||
<div>
|
||||
<h2 class="deaf-head-t">Depositor Education and Awareness Fund (DEAF)</h2>
|
||||
<div class="deaf-head-s">RBI Master Direction on DEAF, 2014 · Returns & refund register</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="deaf-head-meta">
|
||||
<div>
|
||||
<span class="deaf-meta-l">Bank DEAF Code</span><span class="deaf-meta-v">{{ formII.bankDeafCode }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span class="deaf-meta-l">Sponsor Bank</span><span class="deaf-meta-v">{{ formII.sponsorBankName }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- TABS -->
|
||||
<div class="deaf-tabs">
|
||||
<button class="deaf-tab" [class.active]="activeTab === 'dashboard'" (click)="showTab('dashboard')">
|
||||
<fa-icon icon="chart-pie"></fa-icon> Dashboard
|
||||
</button>
|
||||
<button class="deaf-tab" [class.active]="activeTab === 'form1'" (click)="showTab('form1')">
|
||||
<fa-icon icon="file-invoice"></fa-icon> Form I (Transfer Return)
|
||||
</button>
|
||||
<button class="deaf-tab" [class.active]="activeTab === 'form2'" (click)="showTab('form2')">
|
||||
<fa-icon icon="file-invoice"></fa-icon> Form II (Position with Fund)
|
||||
</button>
|
||||
<button class="deaf-tab" [class.active]="activeTab === 'refund'" (click)="showTab('refund')">
|
||||
<fa-icon icon="hand-holding-usd"></fa-icon> Annex 4 (Refund Claim)
|
||||
</button>
|
||||
<button class="deaf-tab" [class.active]="activeTab === 'eligible'" (click)="showTab('eligible')">
|
||||
<fa-icon icon="users"></fa-icon> Accounts Register
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- DASHBOARD -->
|
||||
@if (activeTab === 'dashboard') {
|
||||
<div class="deaf-section">
|
||||
<div class="deaf-kpis">
|
||||
<div class="deaf-kpi deaf-kpi--blue">
|
||||
<div class="deaf-kpi-ic"><fa-icon icon="piggy-bank"></fa-icon></div>
|
||||
<div>
|
||||
<div class="deaf-kpi-n">₹{{ totalWithFund | number: '1.2-2' }}</div>
|
||||
<div class="deaf-kpi-l">Total with Fund</div>
|
||||
<div class="deaf-kpi-sub">{{ totalAccountsWithFund | number }} accounts</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="deaf-kpi deaf-kpi--teal">
|
||||
<div class="deaf-kpi-ic"><fa-icon icon="upload"></fa-icon></div>
|
||||
<div>
|
||||
<div class="deaf-kpi-n">₹{{ transferredThisMonth | number: '1.2-2' }}</div>
|
||||
<div class="deaf-kpi-l">Transferred this Month</div>
|
||||
<div class="deaf-kpi-sub">{{ accountsTransferredThisMonth | number }} accounts</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="deaf-kpi deaf-kpi--green">
|
||||
<div class="deaf-kpi-ic"><fa-icon icon="hand-holding-usd"></fa-icon></div>
|
||||
<div>
|
||||
<div class="deaf-kpi-n">₹{{ refundedThisCycle | number: '1.2-2' }}</div>
|
||||
<div class="deaf-kpi-l">Claims Paid (refunded)</div>
|
||||
<div class="deaf-kpi-sub">{{ refundAccountsThisCycle | number }} accounts</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="deaf-kpi deaf-kpi--amber">
|
||||
<div class="deaf-kpi-ic"><fa-icon icon="exclamation-triangle"></fa-icon></div>
|
||||
<div>
|
||||
<div class="deaf-kpi-n">{{ accountsCrossing10Y | number }}</div>
|
||||
<div class="deaf-kpi-l">Crossing 10y this Cycle</div>
|
||||
<div class="deaf-kpi-sub">eligible to transfer</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="deaf-kpi deaf-kpi--red">
|
||||
<div class="deaf-kpi-ic"><fa-icon icon="clock"></fa-icon></div>
|
||||
<div>
|
||||
<div class="deaf-kpi-n">{{ pendingClaims | number }}</div>
|
||||
<div class="deaf-kpi-l">Refund Claims Pending</div>
|
||||
<div class="deaf-kpi-sub">awaiting RBI settlement</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Compliance summary -->
|
||||
<div class="deaf-compliance">
|
||||
<div class="dc-card">
|
||||
<div class="dc-card-h">
|
||||
<fa-icon icon="check-circle" class="dc-ok"></fa-icon><span>Form I — Online Submission</span>
|
||||
</div>
|
||||
<div class="dc-meta">Last filed: <strong>15 Jan 2026</strong> · Cycle: {{ formI.monthYear }}</div>
|
||||
<div class="dc-meta">Next due: <strong>15 Feb 2026</strong></div>
|
||||
<button class="dc-btn" (click)="showTab('form1')"><fa-icon icon="external-link-alt"></fa-icon> Open</button>
|
||||
</div>
|
||||
<div class="dc-card">
|
||||
<div class="dc-card-h">
|
||||
<fa-icon icon="check-circle" class="dc-ok"></fa-icon><span>Form II — Physical Hardcopy</span>
|
||||
</div>
|
||||
<div class="dc-meta">Last filed: <strong>15 Jan 2026</strong> · Cycle: {{ formII.monthYear }}</div>
|
||||
<div class="dc-meta">Next due: <strong>15 Feb 2026</strong></div>
|
||||
<button class="dc-btn" (click)="showTab('form2')"><fa-icon icon="external-link-alt"></fa-icon> Open</button>
|
||||
</div>
|
||||
<div class="dc-card">
|
||||
<div class="dc-card-h">
|
||||
<fa-icon icon="hand-holding-usd" class="dc-info"></fa-icon><span>Annex 4 — Refund Claim</span>
|
||||
</div>
|
||||
<div class="dc-meta">
|
||||
Cycle: <strong>{{ refund.month }} {{ refund.year }}</strong>
|
||||
</div>
|
||||
<div class="dc-meta">
|
||||
Pending claims: <strong>{{ pendingClaims }}</strong>
|
||||
</div>
|
||||
<button class="dc-btn" (click)="showTab('refund')"><fa-icon icon="external-link-alt"></fa-icon> Open</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
<!-- FORM I / FORM II — shared template -->
|
||||
@if (activeTab === 'form1' || activeTab === 'form2') {
|
||||
@let _form = activeTab === 'form1' ? formI : formII;
|
||||
<div class="deaf-section">
|
||||
<div class="deaf-form-meta">
|
||||
<div class="deaf-form-title">
|
||||
@if (activeTab === 'form1') {
|
||||
<h3>Form I — Monthly Return of Unclaimed Deposits Transferred to DEAF</h3>
|
||||
<p>Filed online with RBI by 15th of the succeeding month</p>
|
||||
} @else {
|
||||
<h3>Form II — Position with the Fund (snapshot)</h3>
|
||||
<p>Original hardcopy submitted to RBI by 15th of the succeeding month</p>
|
||||
}
|
||||
</div>
|
||||
<button class="deaf-btn deaf-btn-xls" (click)="activeTab === 'form1' ? exportFormI() : exportFormII()">
|
||||
<fa-icon icon="file-excel"></fa-icon> Download Excel
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="deaf-meta-grid">
|
||||
<div>
|
||||
<label>Name of the Bank</label><span>{{ _form.bankName }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<label>DEAF Code (RBI)</label><span>{{ _form.bankDeafCode }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<label>Remitted via Sponsor</label><span>{{ _form.remittedThroughSponsor === 'Y' ? 'Yes' : 'No' }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<label>Sponsor Bank</label><span>{{ _form.sponsorBankName }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<label>Month / Year</label><span>{{ _form.monthYear }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<label>Date of Transfer</label><span>{{ _form.dateOfTransfer }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="deaf-tbl-wrap">
|
||||
<table class="deaf-tbl">
|
||||
<thead>
|
||||
<tr class="hd-1">
|
||||
<th rowspan="2" class="ta-c">Sr.No</th>
|
||||
<th rowspan="2">Particulars</th>
|
||||
<th colspan="2" class="ta-c">Interest Bearing Deposits (a)</th>
|
||||
<th colspan="2" class="ta-c">Non-Interest Bearing Deposits (b)</th>
|
||||
<th colspan="2" class="ta-c">Other Credits (c)</th>
|
||||
<th colspan="2" class="ta-c">Total (d) = (a)+(b)+(c)</th>
|
||||
</tr>
|
||||
<tr class="hd-2">
|
||||
<th class="ta-r">No. of A/c</th>
|
||||
<th class="ta-r">Amount</th>
|
||||
<th class="ta-r">No. of A/c</th>
|
||||
<th class="ta-r">Amount</th>
|
||||
<th class="ta-r">No. of A/c</th>
|
||||
<th class="ta-r">Amount</th>
|
||||
<th class="ta-r">No. of A/c</th>
|
||||
<th class="ta-r">Amount</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@for (r of _form.rows; track r.sl) {
|
||||
<tr [class]="amountClass(r)">
|
||||
<td class="ta-c">{{ r.sl }}</td>
|
||||
<td>{{ r.particulars }}</td>
|
||||
<td class="ta-r">{{ r.ibdAccounts | number }}</td>
|
||||
<td class="ta-r mono">{{ r.ibdAmount | number: '1.2-2' }}</td>
|
||||
<td class="ta-r">{{ r.nibdAccounts | number }}</td>
|
||||
<td class="ta-r mono">{{ r.nibdAmount | number: '1.2-2' }}</td>
|
||||
<td class="ta-r">{{ r.ocAccounts | number }}</td>
|
||||
<td class="ta-r mono">{{ r.ocAmount | number: '1.2-2' }}</td>
|
||||
<td class="ta-r">{{ r.totalAccounts | number }}</td>
|
||||
<td class="ta-r mono">{{ r.totalAmount | number: '1.2-2' }}</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="deaf-sign">
|
||||
<div class="deaf-sign-block">
|
||||
<label>Authorised Officer</label>
|
||||
<div class="sign-name">{{ _form.officer }}</div>
|
||||
<div class="sign-desg">{{ _form.officerDesignation }}</div>
|
||||
</div>
|
||||
<div class="deaf-sign-block">
|
||||
<label>Concurrent Auditor</label>
|
||||
<div class="sign-name">{{ _form.auditor }}</div>
|
||||
<div class="sign-desg">{{ _form.auditorAddress }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
<!-- ANNEX 4 — REFUND CLAIM -->
|
||||
@if (activeTab === 'refund') {
|
||||
<div class="deaf-section">
|
||||
<div class="deaf-form-meta">
|
||||
<div class="deaf-form-title">
|
||||
<h3>Annex 4 — Monthly Return claiming refund from DEA Fund</h3>
|
||||
<p>Submitted by 15th of succeeding month for the cycle to which the claim pertains</p>
|
||||
</div>
|
||||
<button class="deaf-btn deaf-btn-xls" (click)="exportRefund()">
|
||||
<fa-icon icon="file-excel"></fa-icon> Download Excel
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="deaf-meta-grid">
|
||||
<div>
|
||||
<label>Name of the Bank</label><span>{{ refund.bankName }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<label>DEAF Code (RBI)</label><span>{{ refund.bankDeafCode }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<label>Current A/c with RBI</label><span class="mono">{{ refund.currentAcWithRbi }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<label>Maintained with</label><span>{{ refund.sponsorBank }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<label>Month / Year</label><span>{{ refund.month }} {{ refund.year }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="deaf-tbl-wrap">
|
||||
<table class="deaf-tbl">
|
||||
<thead>
|
||||
<tr class="hd-1">
|
||||
<th rowspan="2" class="ta-c">Sr.No</th>
|
||||
<th colspan="3" class="ta-c">Interest Bearing Deposits</th>
|
||||
<th colspan="2" class="ta-c">Non-Interest Bearing Deposits</th>
|
||||
<th colspan="2" class="ta-c">Other Credits</th>
|
||||
<th colspan="2" class="ta-c">Grand Total</th>
|
||||
</tr>
|
||||
<tr class="hd-2">
|
||||
<th class="ta-r">Principal</th>
|
||||
<th class="ta-r">Interest</th>
|
||||
<th class="ta-r">Total</th>
|
||||
<th class="ta-r">No. of A/c</th>
|
||||
<th class="ta-r">Amount</th>
|
||||
<th class="ta-r">No. of A/c</th>
|
||||
<th class="ta-r">Amount</th>
|
||||
<th class="ta-r">No. of A/c</th>
|
||||
<th class="ta-r">Amount</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@for (r of refund.rows; track r.slNo) {
|
||||
<tr>
|
||||
<td class="ta-c">{{ r.slNo }}</td>
|
||||
<td class="ta-r mono">{{ r.ibdPrincipal | number: '1.2-2' }}</td>
|
||||
<td class="ta-r mono">{{ r.ibdInterest | number: '1.2-2' }}</td>
|
||||
<td class="ta-r mono">{{ r.ibdTotal | number: '1.2-2' }}</td>
|
||||
<td class="ta-r">{{ r.nibdAccounts | number }}</td>
|
||||
<td class="ta-r mono">{{ r.nibdAmount | number: '1.2-2' }}</td>
|
||||
<td class="ta-r">{{ r.ocAccounts | number }}</td>
|
||||
<td class="ta-r mono">{{ r.ocAmount | number: '1.2-2' }}</td>
|
||||
<td class="ta-r">{{ r.grandTotalAccounts | number }}</td>
|
||||
<td class="ta-r mono">{{ r.grandTotalAmount | number: '1.2-2' }}</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div class="deaf-note">
|
||||
<fa-icon icon="info-circle"></fa-icon>
|
||||
<span
|
||||
><strong>Note:</strong> No individual customer/depositor wise details should be furnished. In case of refund
|
||||
of part amount by the depositor whose unclaimed amount/inoperative deposit had been transferred to the Fund,
|
||||
the bank shall claim the entire amount transferred to the Fund in respect of such depositor, along with
|
||||
interest payable, if any.</span
|
||||
>
|
||||
</div>
|
||||
|
||||
<div class="deaf-sign">
|
||||
<div class="deaf-sign-block">
|
||||
<label>First Authorised Signatory</label>
|
||||
<div class="sign-name">{{ refund.firstSignatory }}</div>
|
||||
<div class="sign-desg">{{ refund.firstDesignation }}</div>
|
||||
</div>
|
||||
<div class="deaf-sign-block">
|
||||
<label>Second Authorised Signatory</label>
|
||||
<div class="sign-name">{{ refund.secondSignatory }}</div>
|
||||
<div class="sign-desg">{{ refund.secondDesignation }}</div>
|
||||
</div>
|
||||
<div class="deaf-sign-block">
|
||||
<label>Concurrent Auditor</label>
|
||||
<div class="sign-name">{{ refund.auditor }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
<!-- ELIGIBLE / TRANSFERRED ACCOUNTS REGISTER -->
|
||||
@if (activeTab === 'eligible') {
|
||||
<div class="deaf-section">
|
||||
<div class="deaf-form-meta">
|
||||
<div class="deaf-form-title">
|
||||
<h3>Accounts Register</h3>
|
||||
<p>Inoperative / unclaimed accounts crossing 10y, transferred, claimed and refunded</p>
|
||||
</div>
|
||||
<button class="deaf-btn deaf-btn-xls" (click)="exportEligible()">
|
||||
<fa-icon icon="file-excel"></fa-icon> Download Excel
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="deaf-filters">
|
||||
<div class="deaf-filter">
|
||||
<label>Status</label>
|
||||
<select class="deaf-inp" [(ngModel)]="filterStatus">
|
||||
<option value="">All</option>
|
||||
<option value="eligible-this-month">Eligible (≥10y)</option>
|
||||
<option value="transferred">Transferred</option>
|
||||
<option value="claim-pending">Claim Pending</option>
|
||||
<option value="refunded">Refunded</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="deaf-filter">
|
||||
<label>Bucket</label>
|
||||
<select class="deaf-inp" [(ngModel)]="filterBucket">
|
||||
<option value="">All</option>
|
||||
<option value="IBD">Interest Bearing</option>
|
||||
<option value="NIBD">Non-Interest Bearing</option>
|
||||
<option value="OC">Other Credits</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="deaf-filter">
|
||||
<label>Branch</label>
|
||||
<input class="deaf-inp" type="text" [(ngModel)]="filterBranch" placeholder="Branch" />
|
||||
</div>
|
||||
<button class="deaf-btn deaf-btn-g" (click)="resetFilters()">Reset</button>
|
||||
</div>
|
||||
|
||||
<div class="deaf-tbl-wrap">
|
||||
<table class="deaf-tbl">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>A/c No</th>
|
||||
<th>Customer</th>
|
||||
<th class="ta-c">Type</th>
|
||||
<th>Branch</th>
|
||||
<th>Opened</th>
|
||||
<th>Last Txn</th>
|
||||
<th class="ta-c">Inactive</th>
|
||||
<th class="ta-c">Bucket</th>
|
||||
<th class="ta-r">Principal</th>
|
||||
<th class="ta-r">Interest</th>
|
||||
<th class="ta-r">Total</th>
|
||||
<th class="ta-c">Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@for (a of filteredAccounts; track a.acNo) {
|
||||
<tr>
|
||||
<td class="mono">{{ a.acNo }}</td>
|
||||
<td>{{ a.customerName }}</td>
|
||||
<td class="ta-c">{{ a.acType }}</td>
|
||||
<td>{{ a.branch }}</td>
|
||||
<td>{{ a.openedDate }}</td>
|
||||
<td>{{ a.lastTxnDate }}</td>
|
||||
<td class="ta-c">{{ a.inactiveYears }}y</td>
|
||||
<td class="ta-c">
|
||||
<span class="bucket-pill" [class]="'bk-' + a.bucket.toLowerCase()">{{ a.bucket }}</span>
|
||||
</td>
|
||||
<td class="ta-r mono">{{ a.principal | number: '1.2-2' }}</td>
|
||||
<td class="ta-r mono">{{ a.interest | number: '1.2-2' }}</td>
|
||||
<td class="ta-r mono">{{ a.total | number: '1.2-2' }}</td>
|
||||
<td class="ta-c">
|
||||
<span class="status-pill" [class]="'st-' + a.status">{{ statusLabel(a.status) }}</span>
|
||||
</td>
|
||||
</tr>
|
||||
} @empty {
|
||||
<tr>
|
||||
<td colspan="12" class="deaf-empty">No accounts match the filters.</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
<!-- TOAST -->
|
||||
<div class="deaf-toast" [class.show]="toastVisible">{{ toastMsg }}</div>
|
||||
</div>
|
||||
@@ -0,0 +1,672 @@
|
||||
/**
|
||||
* 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/.
|
||||
*/
|
||||
|
||||
:host {
|
||||
--d-navy: #0b1e3d;
|
||||
--d-blue: #1d4ed8;
|
||||
--d-blue-l: #eff6ff;
|
||||
--d-teal: #0e7e6b;
|
||||
--d-teal-l: #e0f4f0;
|
||||
--d-green: #15803d;
|
||||
--d-green-l: #dcfce7;
|
||||
--d-amber: #d97706;
|
||||
--d-amber-l: #fef3c7;
|
||||
--d-red: #c0392b;
|
||||
--d-red-l: #fdecea;
|
||||
--d-purple: #6d28d9;
|
||||
--d-purple-l: #ede9fe;
|
||||
--d-g50: #f8fafc;
|
||||
--d-g100: #f1f5f9;
|
||||
--d-g200: #e2e8f0;
|
||||
--d-g300: #cbd5e1;
|
||||
--d-g500: #64748b;
|
||||
--d-g700: #334155;
|
||||
--d-g900: #0f172a;
|
||||
|
||||
display: block;
|
||||
font-family:
|
||||
'DM Sans',
|
||||
system-ui,
|
||||
-apple-system,
|
||||
sans-serif;
|
||||
background: var(--d-g50);
|
||||
color: var(--d-g900);
|
||||
font-size: 14px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.deaf-root {
|
||||
padding: 18px 22px;
|
||||
max-width: 1400px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
/* HEADER */
|
||||
.deaf-head {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.deaf-head-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 14px;
|
||||
}
|
||||
|
||||
.deaf-head-ic {
|
||||
font-size: 28px;
|
||||
color: var(--d-purple);
|
||||
}
|
||||
|
||||
.deaf-head-t {
|
||||
margin: 0;
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
color: var(--d-g900);
|
||||
}
|
||||
|
||||
.deaf-head-s {
|
||||
font-size: 12px;
|
||||
color: var(--d-g500);
|
||||
}
|
||||
|
||||
.deaf-head-meta {
|
||||
display: flex;
|
||||
gap: 22px;
|
||||
|
||||
> div {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.deaf-meta-l {
|
||||
font-size: 10px;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
color: var(--d-g500);
|
||||
}
|
||||
|
||||
.deaf-meta-v {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: var(--d-g900);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* TABS */
|
||||
.deaf-tabs {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
background: #fff;
|
||||
border: 1px solid var(--d-g200);
|
||||
border-radius: 10px;
|
||||
padding: 4px;
|
||||
margin-bottom: 16px;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.deaf-tab {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 9px 14px;
|
||||
border: none;
|
||||
background: transparent;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: var(--d-g500);
|
||||
cursor: pointer;
|
||||
border-radius: 7px;
|
||||
white-space: nowrap;
|
||||
transition: all 0.15s;
|
||||
font-family: inherit;
|
||||
|
||||
&:hover {
|
||||
color: var(--d-g900);
|
||||
}
|
||||
|
||||
&.active {
|
||||
background: var(--d-purple);
|
||||
color: #fff;
|
||||
box-shadow: 0 2px 6px rgb(109 40 217 / 25%);
|
||||
}
|
||||
}
|
||||
|
||||
.deaf-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
}
|
||||
|
||||
/* KPIs */
|
||||
.deaf-kpis {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(5, 1fr);
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.deaf-kpi {
|
||||
background: #fff;
|
||||
border: 1px solid var(--d-g200);
|
||||
border-radius: 12px;
|
||||
padding: 14px 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
box-shadow: 0 1px 3px rgb(0 0 0 / 5%);
|
||||
|
||||
&:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 4px 14px rgb(0 0 0 / 10%);
|
||||
}
|
||||
}
|
||||
|
||||
.deaf-kpi-ic {
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
border-radius: 11px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 18px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.deaf-kpi--blue .deaf-kpi-ic {
|
||||
background: var(--d-blue-l);
|
||||
color: var(--d-blue);
|
||||
}
|
||||
|
||||
.deaf-kpi--teal .deaf-kpi-ic {
|
||||
background: var(--d-teal-l);
|
||||
color: var(--d-teal);
|
||||
}
|
||||
|
||||
.deaf-kpi--green .deaf-kpi-ic {
|
||||
background: var(--d-green-l);
|
||||
color: var(--d-green);
|
||||
}
|
||||
|
||||
.deaf-kpi--amber .deaf-kpi-ic {
|
||||
background: var(--d-amber-l);
|
||||
color: var(--d-amber);
|
||||
}
|
||||
|
||||
.deaf-kpi--red .deaf-kpi-ic {
|
||||
background: var(--d-red-l);
|
||||
color: var(--d-red);
|
||||
}
|
||||
|
||||
.deaf-kpi-n {
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
color: var(--d-g900);
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
.deaf-kpi-l {
|
||||
font-size: 12px;
|
||||
color: var(--d-g700);
|
||||
margin-top: 2px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.deaf-kpi-sub {
|
||||
font-size: 11px;
|
||||
color: var(--d-g500);
|
||||
margin-top: 1px;
|
||||
}
|
||||
|
||||
/* COMPLIANCE CARDS */
|
||||
.deaf-compliance {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.dc-card {
|
||||
background: #fff;
|
||||
border: 1px solid var(--d-g200);
|
||||
border-radius: 12px;
|
||||
padding: 14px 18px;
|
||||
box-shadow: 0 1px 3px rgb(0 0 0 / 4%);
|
||||
}
|
||||
|
||||
.dc-card-h {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: var(--d-g900);
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.dc-ok {
|
||||
color: var(--d-green);
|
||||
}
|
||||
|
||||
.dc-info {
|
||||
color: var(--d-blue);
|
||||
}
|
||||
|
||||
.dc-meta {
|
||||
font-size: 12px;
|
||||
color: var(--d-g500);
|
||||
margin: 2px 0;
|
||||
|
||||
strong {
|
||||
color: var(--d-g900);
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
.dc-btn {
|
||||
margin-top: 10px;
|
||||
padding: 6px 12px;
|
||||
border: 1px solid var(--d-purple);
|
||||
background: var(--d-purple-l);
|
||||
color: var(--d-purple);
|
||||
border-radius: 8px;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
font-family: inherit;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
|
||||
&:hover {
|
||||
background: var(--d-purple);
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
/* FORM HEADER ROW */
|
||||
.deaf-form-meta {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
gap: 14px;
|
||||
}
|
||||
|
||||
.deaf-form-title {
|
||||
h3 {
|
||||
margin: 0;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
color: var(--d-g900);
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 2px 0 0;
|
||||
font-size: 12px;
|
||||
color: var(--d-g500);
|
||||
}
|
||||
}
|
||||
|
||||
.deaf-meta-grid {
|
||||
background: #fff;
|
||||
border: 1px solid var(--d-g200);
|
||||
border-radius: 12px;
|
||||
padding: 14px 18px;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 12px 24px;
|
||||
box-shadow: 0 1px 3px rgb(0 0 0 / 4%);
|
||||
|
||||
> div {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
label {
|
||||
font-size: 10px;
|
||||
font-weight: 600;
|
||||
color: var(--d-g500);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.06em;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
span {
|
||||
font-size: 13px;
|
||||
color: var(--d-g900);
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* BUTTONS */
|
||||
.deaf-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 8px 14px;
|
||||
border: 1px solid var(--d-g300);
|
||||
background: #fff;
|
||||
border-radius: 8px;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: var(--d-g700);
|
||||
cursor: pointer;
|
||||
font-family: inherit;
|
||||
transition: all 0.15s;
|
||||
|
||||
&:hover {
|
||||
background: var(--d-g50);
|
||||
border-color: var(--d-g500);
|
||||
}
|
||||
}
|
||||
|
||||
.deaf-btn-xls {
|
||||
background: #16a34a;
|
||||
border-color: #16a34a;
|
||||
color: #fff;
|
||||
|
||||
&:hover {
|
||||
background: #15803d;
|
||||
border-color: #15803d;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.deaf-btn-g {
|
||||
align-self: end;
|
||||
}
|
||||
|
||||
/* INPUTS */
|
||||
.deaf-inp {
|
||||
width: 100%;
|
||||
padding: 8px 12px;
|
||||
border: 1px solid var(--d-g200);
|
||||
border-radius: 8px;
|
||||
font-size: 13px;
|
||||
background: #fff;
|
||||
font-family: inherit;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
border-color: var(--d-purple);
|
||||
box-shadow: 0 0 0 3px rgb(109 40 217 / 15%);
|
||||
}
|
||||
}
|
||||
|
||||
/* FILTERS */
|
||||
.deaf-filters {
|
||||
background: #fff;
|
||||
border: 1px solid var(--d-g200);
|
||||
border-radius: 12px;
|
||||
padding: 14px;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr) auto;
|
||||
gap: 12px;
|
||||
align-items: end;
|
||||
}
|
||||
|
||||
.deaf-filter {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
|
||||
label {
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
color: var(--d-g500);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
}
|
||||
|
||||
/* TABLE */
|
||||
.deaf-tbl-wrap {
|
||||
background: #fff;
|
||||
border: 1px solid var(--d-g200);
|
||||
border-radius: 12px;
|
||||
overflow: auto;
|
||||
box-shadow: 0 1px 3px rgb(0 0 0 / 4%);
|
||||
}
|
||||
|
||||
.deaf-tbl {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
|
||||
th {
|
||||
text-align: left;
|
||||
padding: 10px 12px;
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
color: var(--d-g500);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.04em;
|
||||
background: var(--d-g50);
|
||||
border-bottom: 1px solid var(--d-g200);
|
||||
}
|
||||
|
||||
th.hd-1,
|
||||
tr.hd-1 th {
|
||||
background: #f0f4ff;
|
||||
color: var(--d-blue);
|
||||
}
|
||||
|
||||
td {
|
||||
padding: 10px 12px;
|
||||
border-bottom: 1px solid var(--d-g100);
|
||||
font-size: 13px;
|
||||
color: var(--d-g700);
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
tr:last-child td {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
tr:hover td {
|
||||
background: var(--d-g50);
|
||||
}
|
||||
|
||||
tr.amt-bold td {
|
||||
background: #f0fdf4;
|
||||
font-weight: 600;
|
||||
color: var(--d-g900);
|
||||
}
|
||||
|
||||
tr.amt-neg td {
|
||||
color: var(--d-red);
|
||||
}
|
||||
}
|
||||
|
||||
.ta-c {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.ta-r {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.mono {
|
||||
font-family: 'DM Mono', monospace;
|
||||
font-size: 12px;
|
||||
letter-spacing: 0.02em;
|
||||
}
|
||||
|
||||
.deaf-empty {
|
||||
text-align: center;
|
||||
padding: 30px;
|
||||
color: var(--d-g500);
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/* SIGNATURE BLOCKS */
|
||||
.deaf-sign {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 14px;
|
||||
}
|
||||
|
||||
.deaf-sign-block {
|
||||
background: #fff;
|
||||
border: 1px solid var(--d-g200);
|
||||
border-radius: 12px;
|
||||
padding: 14px 16px;
|
||||
box-shadow: 0 1px 3px rgb(0 0 0 / 4%);
|
||||
|
||||
label {
|
||||
font-size: 10px;
|
||||
font-weight: 600;
|
||||
color: var(--d-g500);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.06em;
|
||||
margin-bottom: 6px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.sign-name {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: var(--d-g900);
|
||||
}
|
||||
|
||||
.sign-desg {
|
||||
font-size: 12px;
|
||||
color: var(--d-g500);
|
||||
margin-top: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
/* NOTE / INFO */
|
||||
.deaf-note {
|
||||
background: var(--d-blue-l);
|
||||
border: 1px solid #bfdbfe;
|
||||
border-radius: 10px;
|
||||
padding: 12px 16px;
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
font-size: 12px;
|
||||
color: #1e3a8a;
|
||||
line-height: 1.5;
|
||||
|
||||
fa-icon {
|
||||
font-size: 14px;
|
||||
flex-shrink: 0;
|
||||
margin-top: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
/* PILLS */
|
||||
.bucket-pill {
|
||||
display: inline-block;
|
||||
padding: 2px 9px;
|
||||
border-radius: 999px;
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
|
||||
&.bk-ibd {
|
||||
background: var(--d-blue-l);
|
||||
color: var(--d-blue);
|
||||
}
|
||||
|
||||
&.bk-nibd {
|
||||
background: var(--d-teal-l);
|
||||
color: var(--d-teal);
|
||||
}
|
||||
|
||||
&.bk-oc {
|
||||
background: var(--d-purple-l);
|
||||
color: var(--d-purple);
|
||||
}
|
||||
}
|
||||
|
||||
.status-pill {
|
||||
display: inline-block;
|
||||
padding: 2px 10px;
|
||||
border-radius: 999px;
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
|
||||
&.st-eligible-this-month {
|
||||
background: var(--d-amber-l);
|
||||
color: var(--d-amber);
|
||||
}
|
||||
|
||||
&.st-transferred {
|
||||
background: var(--d-green-l);
|
||||
color: var(--d-green);
|
||||
}
|
||||
|
||||
&.st-claim-pending {
|
||||
background: var(--d-red-l);
|
||||
color: var(--d-red);
|
||||
}
|
||||
|
||||
&.st-refunded {
|
||||
background: var(--d-blue-l);
|
||||
color: var(--d-blue);
|
||||
}
|
||||
}
|
||||
|
||||
/* TOAST */
|
||||
.deaf-toast {
|
||||
position: fixed;
|
||||
bottom: 32px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%) translateY(20px);
|
||||
background: var(--d-navy);
|
||||
color: #fff;
|
||||
padding: 12px 22px;
|
||||
border-radius: 10px;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
box-shadow: 0 6px 20px rgb(0 0 0 / 25%);
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
transition: all 0.25s;
|
||||
z-index: 1500;
|
||||
|
||||
&.show {
|
||||
opacity: 1;
|
||||
transform: translateX(-50%) translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* RESPONSIVE */
|
||||
@media (width <= 1100px) {
|
||||
.deaf-kpis {
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
}
|
||||
|
||||
.deaf-compliance {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.deaf-meta-grid {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
}
|
||||
|
||||
.deaf-sign {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.deaf-filters {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
@media (width <= 720px) {
|
||||
.deaf-kpis {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
}
|
||||
|
||||
.deaf-meta-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,358 @@
|
||||
/**
|
||||
* 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/.
|
||||
*/
|
||||
|
||||
import { Component } from '@angular/core';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
|
||||
import {
|
||||
DeafEligibleAccount,
|
||||
DeafForm,
|
||||
DeafFormRow,
|
||||
ELIGIBLE_ACCOUNTS,
|
||||
FORM_I,
|
||||
FORM_II,
|
||||
REFUND_CLAIMS
|
||||
} from './deaf-data';
|
||||
|
||||
@Component({
|
||||
selector: 'mifosx-deaf',
|
||||
templateUrl: './deaf.component.html',
|
||||
styleUrls: ['./deaf.component.scss'],
|
||||
imports: [
|
||||
...STANDALONE_SHARED_IMPORTS,
|
||||
FaIconComponent,
|
||||
FormsModule
|
||||
]
|
||||
})
|
||||
export class DeafComponent {
|
||||
/** Active tab */
|
||||
activeTab: 'dashboard' | 'form1' | 'form2' | 'refund' | 'eligible' = 'dashboard';
|
||||
|
||||
formI: DeafForm = FORM_I;
|
||||
formII: DeafForm = FORM_II;
|
||||
refund = REFUND_CLAIMS;
|
||||
accounts: DeafEligibleAccount[] = ELIGIBLE_ACCOUNTS;
|
||||
|
||||
/** Eligible-list filters */
|
||||
filterStatus: '' | DeafEligibleAccount['status'] = '';
|
||||
filterBranch = '';
|
||||
filterBucket: '' | DeafEligibleAccount['bucket'] = '';
|
||||
|
||||
/** Toast */
|
||||
toastMsg = '';
|
||||
toastVisible = false;
|
||||
private toastTimer: any;
|
||||
|
||||
// -------------------- Tabs --------------------
|
||||
showTab(tab: 'dashboard' | 'form1' | 'form2' | 'refund' | 'eligible'): void {
|
||||
this.activeTab = tab;
|
||||
}
|
||||
|
||||
// -------------------- KPIs --------------------
|
||||
/** Total amount currently with the DEAF Fund (closing balance from Form II row 6) */
|
||||
get totalWithFund(): number {
|
||||
return this.formII.rows[5]?.totalAmount || 0;
|
||||
}
|
||||
get totalAccountsWithFund(): number {
|
||||
return this.formII.rows[5]?.totalAccounts || 0;
|
||||
}
|
||||
get transferredThisMonth(): number {
|
||||
return this.formII.rows[2]?.totalAmount || 0;
|
||||
}
|
||||
get accountsTransferredThisMonth(): number {
|
||||
return this.formII.rows[2]?.totalAccounts || 0;
|
||||
}
|
||||
get refundedThisCycle(): number {
|
||||
return this.refund.rows.reduce((s, r) => s + r.grandTotalAmount, 0);
|
||||
}
|
||||
get refundAccountsThisCycle(): number {
|
||||
return this.refund.rows.reduce((s, r) => s + r.grandTotalAccounts, 0);
|
||||
}
|
||||
get accountsCrossing10Y(): number {
|
||||
return this.accounts.filter((a) => a.status === 'eligible-this-month').length;
|
||||
}
|
||||
get pendingClaims(): number {
|
||||
return this.accounts.filter((a) => a.status === 'claim-pending').length;
|
||||
}
|
||||
|
||||
// -------------------- Eligible filter --------------------
|
||||
get filteredAccounts(): DeafEligibleAccount[] {
|
||||
const branch = this.filterBranch.trim().toLowerCase();
|
||||
return this.accounts.filter((a) => {
|
||||
if (this.filterStatus && a.status !== this.filterStatus) return false;
|
||||
if (this.filterBucket && a.bucket !== this.filterBucket) return false;
|
||||
if (branch && !a.branch.toLowerCase().includes(branch)) return false;
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
resetFilters(): void {
|
||||
this.filterStatus = '';
|
||||
this.filterBranch = '';
|
||||
this.filterBucket = '';
|
||||
}
|
||||
|
||||
statusLabel(s: DeafEligibleAccount['status']): string {
|
||||
switch (s) {
|
||||
case 'eligible-this-month':
|
||||
return 'Eligible';
|
||||
case 'transferred':
|
||||
return 'Transferred';
|
||||
case 'claim-pending':
|
||||
return 'Claim Pending';
|
||||
case 'refunded':
|
||||
return 'Refunded';
|
||||
}
|
||||
}
|
||||
|
||||
// -------------------- Excel export --------------------
|
||||
/** Builds Form I / Form II rows as a 2-D array — same layout as the RBI return */
|
||||
private buildFormRows(form: DeafForm, label: 'Form I' | 'Form II'): string[][] {
|
||||
const rows: string[][] = [];
|
||||
rows.push([
|
||||
label,
|
||||
'Monthly Return of Unclaimed Deposits Transferred to DEAF Fund'
|
||||
]);
|
||||
rows.push([]);
|
||||
rows.push([
|
||||
'Name of the Bank',
|
||||
form.bankName
|
||||
]);
|
||||
rows.push([
|
||||
'Bank DEAF Code allotted by RBI',
|
||||
form.bankDeafCode
|
||||
]);
|
||||
rows.push([
|
||||
'If remitted through Sponsor Bank',
|
||||
form.remittedThroughSponsor
|
||||
]);
|
||||
rows.push([
|
||||
'Name of the Sponsor Bank',
|
||||
form.sponsorBankName
|
||||
]);
|
||||
rows.push([
|
||||
'Month / Year',
|
||||
form.monthYear
|
||||
]);
|
||||
rows.push([
|
||||
'Date of Transfer to the Fund',
|
||||
form.dateOfTransfer
|
||||
]);
|
||||
rows.push([]);
|
||||
rows.push(['Particulars (Amount in Rupees)']);
|
||||
rows.push([
|
||||
'Sr.No',
|
||||
'Particulars',
|
||||
'IBD No. of A/c',
|
||||
'IBD Amount',
|
||||
'NIBD No. of A/c',
|
||||
'NIBD Amount',
|
||||
'OC No. of A/c',
|
||||
'OC Amount',
|
||||
'Total No. of A/c',
|
||||
'Total Amount'
|
||||
]);
|
||||
for (const r of form.rows) {
|
||||
rows.push([
|
||||
r.sl.toString(),
|
||||
r.particulars,
|
||||
r.ibdAccounts.toString(),
|
||||
r.ibdAmount.toFixed(2),
|
||||
r.nibdAccounts.toString(),
|
||||
r.nibdAmount.toFixed(2),
|
||||
r.ocAccounts.toString(),
|
||||
r.ocAmount.toFixed(2),
|
||||
r.totalAccounts.toString(),
|
||||
r.totalAmount.toFixed(2)
|
||||
]);
|
||||
}
|
||||
rows.push([]);
|
||||
rows.push([
|
||||
'Authorised Officer',
|
||||
form.officer
|
||||
]);
|
||||
rows.push([
|
||||
'Designation',
|
||||
form.officerDesignation
|
||||
]);
|
||||
rows.push([
|
||||
'Concurrent Auditor',
|
||||
form.auditor
|
||||
]);
|
||||
rows.push([
|
||||
'Auditor Address',
|
||||
form.auditorAddress
|
||||
]);
|
||||
return rows;
|
||||
}
|
||||
|
||||
private buildRefundRows(): string[][] {
|
||||
const c = this.refund;
|
||||
const rows: string[][] = [];
|
||||
rows.push([
|
||||
'Annex 4',
|
||||
'Monthly Return claiming refund from DEA Fund'
|
||||
]);
|
||||
rows.push([]);
|
||||
rows.push([
|
||||
'Name of the Bank',
|
||||
c.bankName
|
||||
]);
|
||||
rows.push([
|
||||
'Bank DEAF Code allotted by RBI',
|
||||
c.bankDeafCode
|
||||
]);
|
||||
rows.push([
|
||||
'Current A/c with RBI',
|
||||
`${c.currentAcWithRbi} via ${c.sponsorBank}`
|
||||
]);
|
||||
rows.push([
|
||||
'Month / Year',
|
||||
`${c.month} ${c.year}`
|
||||
]);
|
||||
rows.push([]);
|
||||
rows.push(['Details of claims made during the month (Amount in Rupees)']);
|
||||
rows.push([
|
||||
'Sr.No',
|
||||
'IBD Principal',
|
||||
'IBD Interest',
|
||||
'IBD Total',
|
||||
'NIBD No. of A/c',
|
||||
'NIBD Amount',
|
||||
'OC No. of A/c',
|
||||
'OC Amount',
|
||||
'Grand Total No. of A/c',
|
||||
'Grand Total Amount'
|
||||
]);
|
||||
for (const r of c.rows) {
|
||||
rows.push([
|
||||
r.slNo.toString(),
|
||||
r.ibdPrincipal.toFixed(2),
|
||||
r.ibdInterest.toFixed(2),
|
||||
r.ibdTotal.toFixed(2),
|
||||
r.nibdAccounts.toString(),
|
||||
r.nibdAmount.toFixed(2),
|
||||
r.ocAccounts.toString(),
|
||||
r.ocAmount.toFixed(2),
|
||||
r.grandTotalAccounts.toString(),
|
||||
r.grandTotalAmount.toFixed(2)
|
||||
]);
|
||||
}
|
||||
rows.push([]);
|
||||
rows.push([
|
||||
'Note',
|
||||
'No individual customer/depositor wise details should be furnished.'
|
||||
]);
|
||||
rows.push([
|
||||
'First Authorised Signatory',
|
||||
`${c.firstSignatory} (${c.firstDesignation})`
|
||||
]);
|
||||
rows.push([
|
||||
'Second Authorised Signatory',
|
||||
`${c.secondSignatory} (${c.secondDesignation})`
|
||||
]);
|
||||
rows.push([
|
||||
'Concurrent Auditor',
|
||||
c.auditor
|
||||
]);
|
||||
return rows;
|
||||
}
|
||||
|
||||
private buildEligibleRows(): string[][] {
|
||||
const rows: string[][] = [];
|
||||
rows.push(['DEAF — Accounts Register']);
|
||||
rows.push([]);
|
||||
rows.push([
|
||||
'A/c No',
|
||||
'Customer Name',
|
||||
'A/c Type',
|
||||
'Branch',
|
||||
'Opened',
|
||||
'Last Txn',
|
||||
'Inactive (yrs)',
|
||||
'Bucket',
|
||||
'Principal',
|
||||
'Interest',
|
||||
'Total',
|
||||
'Status',
|
||||
'Transferred On'
|
||||
]);
|
||||
for (const a of this.filteredAccounts) {
|
||||
rows.push([
|
||||
a.acNo,
|
||||
a.customerName,
|
||||
a.acType,
|
||||
a.branch,
|
||||
a.openedDate,
|
||||
a.lastTxnDate,
|
||||
a.inactiveYears.toString(),
|
||||
a.bucket,
|
||||
a.principal.toFixed(2),
|
||||
a.interest.toFixed(2),
|
||||
a.total.toFixed(2),
|
||||
this.statusLabel(a.status),
|
||||
a.transferredOn || ''
|
||||
]);
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
|
||||
exportFormI(): void {
|
||||
this.saveTsv(this.buildFormRows(this.formI, 'Form I'), `DEAF-FormI-${this.fileTag(this.formI.monthYear)}.xls`);
|
||||
this.toast('Form I downloaded');
|
||||
}
|
||||
exportFormII(): void {
|
||||
this.saveTsv(this.buildFormRows(this.formII, 'Form II'), `DEAF-FormII-${this.fileTag(this.formII.monthYear)}.xls`);
|
||||
this.toast('Form II downloaded');
|
||||
}
|
||||
exportRefund(): void {
|
||||
this.saveTsv(this.buildRefundRows(), `DEAF-Annex4-${this.refund.month}-${this.refund.year}.xls`);
|
||||
this.toast('Annex 4 (Refund Claim) downloaded');
|
||||
}
|
||||
exportEligible(): void {
|
||||
this.saveTsv(this.buildEligibleRows(), `DEAF-Accounts-${this.dateStamp()}.xls`);
|
||||
this.toast(`${this.filteredAccounts.length} accounts exported`);
|
||||
}
|
||||
|
||||
private saveTsv(rows: string[][], filename: string): void {
|
||||
const tsv = rows.map((r) => r.map((v) => (v || '').replace(/\t/g, ' ')).join('\t')).join('\n');
|
||||
const blob = new Blob([tsv], { type: 'application/vnd.ms-excel;charset=utf-8' });
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = filename;
|
||||
a.click();
|
||||
URL.revokeObjectURL(url);
|
||||
}
|
||||
|
||||
private fileTag(monthYear: string): string {
|
||||
return monthYear.replace('/', '-');
|
||||
}
|
||||
|
||||
private dateStamp(): string {
|
||||
const d = new Date();
|
||||
const dd = String(d.getDate()).padStart(2, '0');
|
||||
const mm = String(d.getMonth() + 1).padStart(2, '0');
|
||||
return `${dd}${mm}${d.getFullYear()}`;
|
||||
}
|
||||
|
||||
/** Coerce a row's raw amounts for display — handles negatives in Form I row 5 */
|
||||
amountClass(r: DeafFormRow): string {
|
||||
if (r.sl === 5 && r.totalAmount < 0) return 'amt-neg';
|
||||
if (r.sl === 6) return 'amt-bold';
|
||||
return '';
|
||||
}
|
||||
|
||||
toast(msg: string): void {
|
||||
this.toastMsg = msg;
|
||||
this.toastVisible = true;
|
||||
if (this.toastTimer) clearTimeout(this.toastTimer);
|
||||
this.toastTimer = setTimeout(() => (this.toastVisible = false), 2800);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* 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/.
|
||||
*/
|
||||
|
||||
import { NgModule } from '@angular/core';
|
||||
|
||||
import { SharedModule } from '../shared/shared.module';
|
||||
import { DeafRoutingModule } from './deaf-routing.module';
|
||||
import { DeafComponent } from './deaf.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
SharedModule,
|
||||
DeafRoutingModule,
|
||||
DeafComponent
|
||||
]
|
||||
})
|
||||
export class DeafModule {}
|
||||
Reference in New Issue
Block a user