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:
Aditya
2026-04-29 18:59:50 +05:30
co-authored by Claude Opus 4.7
parent 634003a75c
commit 12bfc81219
61 changed files with 22207 additions and 725 deletions
+485
View File
@@ -0,0 +1,485 @@
/**
* 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/.
*/
/**
* DICGC (Deposit Insurance and Credit Guarantee Corporation) sample data.
* Schema reproduces the actual report formats but bank/customer names are dummy.
*
* Two reports:
* Slab-wise A/C Report — accounts grouped by deposit-amount slabs
* (≤1L, 1L-2L, 2L-3L, >3L) for both deposits and loans
* SAHAY Depositor List — customer/account-wise CSV input template DICGC consumes
* when paying out claims after a bank failure
*/
/** Single product row in the slab-wise table */
export interface SlabRow {
sl: number;
description: string;
upto1Lakh: { amount: number; accounts: number };
oneTo2Lakh: { amount: number; accounts: number };
twoTo3Lakh: { amount: number; accounts: number };
above3Lakh: { amount: number; accounts: number };
total: { amount: number; accounts: number };
}
/** SAHAY depositor input record (19 columns) */
export interface SahayDepositor {
inputSerialNumber: number;
customerIdUcic: string;
accountNumber: string;
typeOfAccount: string;
natureOfAccount: string;
numberOfHolders: number;
nameFirst: string;
nameSecond: string;
nameThird: string;
dateOfBirthOrIncorporation: string;
amountOfDeposit: number;
insuredAmount: number;
loanAgainstDeposit: 'LAD' | 'LAFD' | '';
panNumber: string;
aadhaarNumber: string;
otherKycType: string;
otherKycNumber: string;
mobileNumber: string;
typeOfDeposit: string;
lastCustomerInducedTxnDate: string;
}
export const DICGC_BANK = {
name: 'Bharat Urban Bank Ltd',
branch: 'Head Office',
reportAsOn: '29-01-2026',
printDate: '29-01-2026 04:19 PM',
reportRefNo: '1290/2',
userCode: 'JTU',
insuranceLimit: 500000, // ₹5 lakh per depositor
premiumRatePer100: 0.12, // 12 paise per ₹100 of deposits
registrationNo: 'REG-CO-1290'
};
/** ── DEPOSITS — Section 1 (Credit Balance) ── */
export const DEPOSIT_SLABS: SlabRow[] = [
{
sl: 1,
description: 'CURRENT DEPOSIT INDIVIDUAL A/C',
upto1Lakh: { amount: 4161663.56, accounts: 231 },
oneTo2Lakh: { amount: 1104137.57, accounts: 7 },
twoTo3Lakh: { amount: 953186.92, accounts: 4 },
above3Lakh: { amount: 8451113.76, accounts: 12 },
total: { amount: 14670101.81, accounts: 254 }
},
{
sl: 2,
description: 'FIX DEPOSIT DOUBLE A/C',
upto1Lakh: { amount: 38612382.0, accounts: 824 },
oneTo2Lakh: { amount: 50661835.0, accounts: 371 },
twoTo3Lakh: { amount: 41999156.0, accounts: 175 },
above3Lakh: { amount: 204955057.0, accounts: 324 },
total: { amount: 336228430.0, accounts: 1694 }
},
{
sl: 3,
description: 'FIXED DEPOSIT SINGLE A/C',
upto1Lakh: { amount: 5488157.0, accounts: 694 },
oneTo2Lakh: { amount: 689874.0, accounts: 6 },
twoTo3Lakh: { amount: 250000.0, accounts: 1 },
above3Lakh: { amount: 1018485.0, accounts: 2 },
total: { amount: 7446516.0, accounts: 703 }
},
{
sl: 4,
description: 'FIXED DEPOSIT MONTHLY',
upto1Lakh: { amount: 445000.0, accounts: 6 },
oneTo2Lakh: { amount: 400000.0, accounts: 2 },
twoTo3Lakh: { amount: 1400000.0, accounts: 5 },
above3Lakh: { amount: 14500000.0, accounts: 14 },
total: { amount: 16745000.0, accounts: 27 }
},
{
sl: 5,
description: 'FIXED DEPOSIT QUARTERLY',
upto1Lakh: { amount: 0, accounts: 0 },
oneTo2Lakh: { amount: 0, accounts: 0 },
twoTo3Lakh: { amount: 0, accounts: 0 },
above3Lakh: { amount: 3250000.0, accounts: 3 },
total: { amount: 3250000.0, accounts: 3 }
},
{
sl: 6,
description: 'GENERAL LEDGER',
upto1Lakh: { amount: 0, accounts: 0 },
oneTo2Lakh: { amount: 0, accounts: 0 },
twoTo3Lakh: { amount: 0, accounts: 0 },
above3Lakh: { amount: 0, accounts: 0 },
total: { amount: 0, accounts: 0 }
},
{
sl: 7,
description: 'LINKING SHARE',
upto1Lakh: { amount: 11600908.0, accounts: 937 },
oneTo2Lakh: { amount: 8580300.0, accounts: 61 },
twoTo3Lakh: { amount: 3290000.0, accounts: 13 },
above3Lakh: { amount: 2876800.0, accounts: 7 },
total: { amount: 26348008.0, accounts: 1018 }
},
{
sl: 8,
description: 'MANGAL PARINAY A/C',
upto1Lakh: { amount: 197496.0, accounts: 2 },
oneTo2Lakh: { amount: 0, accounts: 0 },
twoTo3Lakh: { amount: 0, accounts: 0 },
above3Lakh: { amount: 0, accounts: 0 },
total: { amount: 197496.0, accounts: 2 }
},
{
sl: 9,
description: 'RECURRING DEPOSIT',
upto1Lakh: { amount: 558352.0, accounts: 22 },
oneTo2Lakh: { amount: 206756.0, accounts: 2 },
twoTo3Lakh: { amount: 0, accounts: 0 },
above3Lakh: { amount: 0, accounts: 0 },
total: { amount: 765108.0, accounts: 24 }
},
{
sl: 10,
description: 'SUNDRY CREDITORS A/C',
upto1Lakh: { amount: 46000.0, accounts: 2 },
oneTo2Lakh: { amount: 0, accounts: 0 },
twoTo3Lakh: { amount: 0, accounts: 0 },
above3Lakh: { amount: 607913.3, accounts: 1 },
total: { amount: 653913.3, accounts: 3 }
},
{
sl: 11,
description: 'SAVINGS DEPOSIT INDIVIDUAL A/C',
upto1Lakh: { amount: 37172591.62, accounts: 3954 },
oneTo2Lakh: { amount: 28097261.58, accounts: 199 },
twoTo3Lakh: { amount: 19583645.69, accounts: 84 },
above3Lakh: { amount: 108860739.06, accounts: 191 },
total: { amount: 193714237.95, accounts: 4428 }
}
];
/** ── LOANS — Section A (Credit Balance Loan A/c) ── */
export const LOAN_SLABS: SlabRow[] = [
{
sl: 1,
description: 'CC AGAINST DEPOSIT',
upto1Lakh: { amount: 10214.45, accounts: 4 },
oneTo2Lakh: { amount: 0, accounts: 0 },
twoTo3Lakh: { amount: 0, accounts: 0 },
above3Lakh: { amount: 0, accounts: 0 },
total: { amount: 10214.45, accounts: 4 }
},
{
sl: 2,
description: 'CASH CREDIT LOAN A/C',
upto1Lakh: { amount: 37223.99, accounts: 5 },
oneTo2Lakh: { amount: 0, accounts: 0 },
twoTo3Lakh: { amount: 257039.67, accounts: 1 },
above3Lakh: { amount: 3869523.24, accounts: 3 },
total: { amount: 4163786.9, accounts: 9 }
},
{
sl: 3,
description: 'OVER DRAFT BMC',
upto1Lakh: { amount: 0, accounts: 0 },
oneTo2Lakh: { amount: 0, accounts: 0 },
twoTo3Lakh: { amount: 0, accounts: 0 },
above3Lakh: { amount: 0, accounts: 0 },
total: { amount: 0, accounts: 0 }
},
{
sl: 4,
description: 'LOAN AGAINST GODOWN PLEDGE',
upto1Lakh: { amount: 0, accounts: 0 },
oneTo2Lakh: { amount: 0, accounts: 0 },
twoTo3Lakh: { amount: 0, accounts: 0 },
above3Lakh: { amount: 0, accounts: 0 },
total: { amount: 0, accounts: 0 }
},
{
sl: 5,
description: 'KISHAN CREDIT CARD',
upto1Lakh: { amount: 0, accounts: 0 },
oneTo2Lakh: { amount: 0, accounts: 0 },
twoTo3Lakh: { amount: 0, accounts: 0 },
above3Lakh: { amount: 0, accounts: 0 },
total: { amount: 0, accounts: 0 }
},
{
sl: 6,
description: 'LOAN AGAINST SECURITIES',
upto1Lakh: { amount: 0, accounts: 0 },
oneTo2Lakh: { amount: 0, accounts: 0 },
twoTo3Lakh: { amount: 0, accounts: 0 },
above3Lakh: { amount: 0, accounts: 0 },
total: { amount: 0, accounts: 0 }
},
{
sl: 7,
description: 'LOAN AGAINST DEPOSIT',
upto1Lakh: { amount: 0, accounts: 0 },
oneTo2Lakh: { amount: 0, accounts: 0 },
twoTo3Lakh: { amount: 0, accounts: 0 },
above3Lakh: { amount: 0, accounts: 0 },
total: { amount: 0, accounts: 0 }
},
{
sl: 8,
description: 'LOAN AGAINST GOLD',
upto1Lakh: { amount: 0, accounts: 0 },
oneTo2Lakh: { amount: 0, accounts: 0 },
twoTo3Lakh: { amount: 0, accounts: 0 },
above3Lakh: { amount: 0, accounts: 0 },
total: { amount: 0, accounts: 0 }
},
{
sl: 9,
description: 'LOAN AGAINST WAREHOUSE',
upto1Lakh: { amount: 13265.0, accounts: 1 },
oneTo2Lakh: { amount: 0, accounts: 0 },
twoTo3Lakh: { amount: 0, accounts: 0 },
above3Lakh: { amount: 0, accounts: 0 },
total: { amount: 13265.0, accounts: 1 }
},
{
sl: 10,
description: 'SUNDRY DEBTORS',
upto1Lakh: { amount: 0, accounts: 0 },
oneTo2Lakh: { amount: 0, accounts: 0 },
twoTo3Lakh: { amount: 0, accounts: 0 },
above3Lakh: { amount: 0, accounts: 0 },
total: { amount: 0, accounts: 0 }
},
{
sl: 11,
description: 'ADVANCE TO EMPLOYEES',
upto1Lakh: { amount: 0, accounts: 0 },
oneTo2Lakh: { amount: 0, accounts: 0 },
twoTo3Lakh: { amount: 0, accounts: 0 },
above3Lakh: { amount: 0, accounts: 0 },
total: { amount: 0, accounts: 0 }
},
{
sl: 12,
description: 'LONG TERM LOAN A/C',
upto1Lakh: { amount: 0, accounts: 0 },
oneTo2Lakh: { amount: 0, accounts: 0 },
twoTo3Lakh: { amount: 0, accounts: 0 },
above3Lakh: { amount: 0, accounts: 0 },
total: { amount: 0, accounts: 0 }
},
{
sl: 13,
description: 'PROPERTY MORTGAGE LIMIT',
upto1Lakh: { amount: 37564.07, accounts: 2 },
oneTo2Lakh: { amount: 0, accounts: 0 },
twoTo3Lakh: { amount: 0, accounts: 0 },
above3Lakh: { amount: 0, accounts: 0 },
total: { amount: 37564.07, accounts: 2 }
},
{
sl: 14,
description: 'MEDIUM TERM LOAN',
upto1Lakh: { amount: 0, accounts: 0 },
oneTo2Lakh: { amount: 0, accounts: 0 },
twoTo3Lakh: { amount: 0, accounts: 0 },
above3Lakh: { amount: 0, accounts: 0 },
total: { amount: 0, accounts: 0 }
}
];
/** Section D: Final summary */
export const SUMMARY_D = [
{ sl: 1, description: 'CREDIT BALANCE (1 to 16)', amount: 600018811.06, accounts: 8156 },
{ sl: 2, description: 'CREDIT BALANCE (LOAN A/C)', amount: 4224830.42, accounts: 16 },
{ sl: 3, description: 'OTHER LIABILITY', amount: 3436255.94, accounts: 18 }
];
/** SAHAY depositor list — sample customers (same dummy set used in CKYC + DEAF) */
export const SAHAY_DEPOSITORS: SahayDepositor[] = [
{
inputSerialNumber: 1,
customerIdUcic: 'UCIC0010078',
accountNumber: '110001302000312',
typeOfAccount: 'SAVINGS',
natureOfAccount: 'INDIVIDUAL',
numberOfHolders: 1,
nameFirst: 'RAVI KUMAR SHARMA',
nameSecond: '',
nameThird: '',
dateOfBirthOrIncorporation: '10-08-1985',
amountOfDeposit: 425000,
insuredAmount: 425000,
loanAgainstDeposit: '',
panNumber: 'AAQPS8560J',
aadhaarNumber: 'XXXXXXXX1234',
otherKycType: '',
otherKycNumber: '',
mobileNumber: '9892011001',
typeOfDeposit: 'SB',
lastCustomerInducedTxnDate: '05-04-2026'
},
{
inputSerialNumber: 2,
customerIdUcic: 'UCIC0010079',
accountNumber: '110001302000418',
typeOfAccount: 'FIXED',
natureOfAccount: 'INDIVIDUAL',
numberOfHolders: 1,
nameFirst: 'PRIYA PATEL',
nameSecond: '',
nameThird: '',
dateOfBirthOrIncorporation: '22-03-1990',
amountOfDeposit: 320000,
insuredAmount: 320000,
loanAgainstDeposit: '',
panNumber: 'AKLPS9933P',
aadhaarNumber: 'XXXXXXXX2210',
otherKycType: '',
otherKycNumber: '',
mobileNumber: '9822055002',
typeOfDeposit: 'FD',
lastCustomerInducedTxnDate: '15-03-2026'
},
{
inputSerialNumber: 3,
customerIdUcic: 'UCIC0010080',
accountNumber: '110001303000522',
typeOfAccount: 'RECURRING',
natureOfAccount: 'JOINT',
numberOfHolders: 2,
nameFirst: 'ARJUN DESHMUKH',
nameSecond: 'REKHA DESHMUKH',
nameThird: '',
dateOfBirthOrIncorporation: '15-01-1978',
amountOfDeposit: 148500,
insuredAmount: 148500,
loanAgainstDeposit: '',
panNumber: 'AGTPD1144K',
aadhaarNumber: 'XXXXXXXX5544',
otherKycType: '',
otherKycNumber: '',
mobileNumber: '9823033003',
typeOfDeposit: 'RD',
lastCustomerInducedTxnDate: '10-04-2026'
},
{
inputSerialNumber: 4,
customerIdUcic: 'UCIC0020101',
accountNumber: '110001302000711',
typeOfAccount: 'FIXED',
natureOfAccount: 'INDIVIDUAL',
numberOfHolders: 1,
nameFirst: 'VIKRAM REDDY',
nameSecond: '',
nameThird: '',
dateOfBirthOrIncorporation: '07-07-1982',
amountOfDeposit: 600000,
insuredAmount: 500000,
loanAgainstDeposit: 'LAFD',
panNumber: 'AAEPR9352L',
aadhaarNumber: 'XXXXXXXX6622',
otherKycType: '',
otherKycNumber: '',
mobileNumber: '9845022004',
typeOfDeposit: 'FD',
lastCustomerInducedTxnDate: '20-02-2026'
},
{
inputSerialNumber: 5,
customerIdUcic: 'UCIC0020102',
accountNumber: '110001301000814',
typeOfAccount: 'SAVINGS',
natureOfAccount: 'INDIVIDUAL',
numberOfHolders: 1,
nameFirst: 'LAKSHMI IYER',
nameSecond: '',
nameThird: '',
dateOfBirthOrIncorporation: '14-09-1986',
amountOfDeposit: 280000,
insuredAmount: 280000,
loanAgainstDeposit: '',
panNumber: '',
aadhaarNumber: 'XXXXXXXX5511',
otherKycType: 'VOTER_ID',
otherKycNumber: 'KA09KL5544',
mobileNumber: '9845066005',
typeOfDeposit: 'SB',
lastCustomerInducedTxnDate: '01-04-2026'
},
{
inputSerialNumber: 6,
customerIdUcic: 'UCIC0040301',
accountNumber: '110001302001012',
typeOfAccount: 'FIXED',
natureOfAccount: 'JOINT',
numberOfHolders: 2,
nameFirst: 'NIRAV SHAH',
nameSecond: 'RITA SHAH',
nameThird: '',
dateOfBirthOrIncorporation: '18-05-1992',
amountOfDeposit: 750000,
insuredAmount: 500000,
loanAgainstDeposit: '',
panNumber: 'AHKPS5544Z',
aadhaarNumber: 'XXXXXXXX9933',
otherKycType: 'PASSPORT',
otherKycNumber: 'M5544321',
mobileNumber: '9824012010',
typeOfDeposit: 'FD',
lastCustomerInducedTxnDate: '20-12-2025'
},
{
inputSerialNumber: 7,
customerIdUcic: 'UCIC0050401',
accountNumber: '110001301001145',
typeOfAccount: 'SAVINGS',
natureOfAccount: 'INDIVIDUAL',
numberOfHolders: 1,
nameFirst: 'KAVITA VERMA',
nameSecond: '',
nameThird: '',
dateOfBirthOrIncorporation: '01-04-1988',
amountOfDeposit: 95000,
insuredAmount: 95000,
loanAgainstDeposit: '',
panNumber: 'AKHPV2244R',
aadhaarNumber: 'XXXXXXXX1144',
otherKycType: '',
otherKycNumber: '',
mobileNumber: '9415055014',
typeOfDeposit: 'SB',
lastCustomerInducedTxnDate: '15-03-2026'
},
{
inputSerialNumber: 8,
customerIdUcic: 'UCIC0070601',
accountNumber: '110001304001458',
typeOfAccount: 'TERM_LOAN',
natureOfAccount: 'INDIVIDUAL',
numberOfHolders: 1,
nameFirst: 'SAMEER KAPOOR',
nameSecond: '',
nameThird: '',
dateOfBirthOrIncorporation: '03-02-1987',
amountOfDeposit: 1200000,
insuredAmount: 500000,
loanAgainstDeposit: 'LAD',
panNumber: 'AHKPK7788Q',
aadhaarNumber: 'XXXXXXXX8877',
otherKycType: '',
otherKycNumber: '',
mobileNumber: '9811022019',
typeOfDeposit: 'TL',
lastCustomerInducedTxnDate: '12-04-2026'
}
];
+29
View File
@@ -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 { DicgcComponent } from './dicgc.component';
const routes: Routes = [
Route.withShell([
{
path: 'dicgc',
component: DicgcComponent,
data: { title: 'DICGC', breadcrumb: 'DICGC' }
}
])
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class DicgcRoutingModule {}
+425
View File
@@ -0,0 +1,425 @@
<!--
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="dic-root">
<!-- HEADER -->
<div class="dic-head">
<div class="dic-head-left">
<fa-icon icon="shield-alt" class="dic-head-ic"></fa-icon>
<div>
<h2 class="dic-head-t">Deposit Insurance and Credit Guarantee (DICGC)</h2>
<div class="dic-head-s">
{{ bank.name }} &middot; {{ bank.branch }} &middot; As on <strong>{{ bank.reportAsOn }}</strong>
</div>
</div>
</div>
<div class="dic-head-meta">
<div>
<span class="dic-meta-l">Insurance Limit</span
><span class="dic-meta-v">&#8377;{{ bank.insuranceLimit | number }}</span>
</div>
<div>
<span class="dic-meta-l">Premium Rate</span><span class="dic-meta-v">{{ bank.premiumRatePer100 }}% p.a.</span>
</div>
<div>
<span class="dic-meta-l">Reg. No.</span><span class="dic-meta-v mono">{{ bank.registrationNo }}</span>
</div>
</div>
</div>
<!-- TABS -->
<div class="dic-tabs">
<button class="dic-tab" [class.active]="activeTab === 'dashboard'" (click)="showTab('dashboard')">
<fa-icon icon="chart-pie"></fa-icon> Dashboard
</button>
<button class="dic-tab" [class.active]="activeTab === 'slab'" (click)="showTab('slab')">
<fa-icon icon="file-invoice"></fa-icon> A/C-Wise Slab Report
</button>
<button class="dic-tab" [class.active]="activeTab === 'sahay'" (click)="showTab('sahay')">
<fa-icon icon="users"></fa-icon> SAHAY Depositor List
</button>
</div>
<!-- DASHBOARD -->
@if (activeTab === 'dashboard') {
<div class="dic-section">
<div class="dic-kpis">
<div class="dic-kpi dic-kpi--blue">
<div class="dic-kpi-ic"><fa-icon icon="piggy-bank"></fa-icon></div>
<div>
<div class="dic-kpi-n">&#8377;{{ depositTotal.amount | number: '1.0-0' }}</div>
<div class="dic-kpi-l">Total Deposits</div>
<div class="dic-kpi-sub">{{ depositTotal.accounts | number }} accounts</div>
</div>
</div>
<div class="dic-kpi dic-kpi--green">
<div class="dic-kpi-ic"><fa-icon icon="check-circle"></fa-icon></div>
<div>
<div class="dic-kpi-n">{{ fullyInsuredAccounts | number }}</div>
<div class="dic-kpi-l">Fully Insured A/cs</div>
<div class="dic-kpi-sub">balance &le; &#8377;{{ bank.insuranceLimit | number }}</div>
</div>
</div>
<div class="dic-kpi dic-kpi--amber">
<div class="dic-kpi-ic"><fa-icon icon="exclamation-triangle"></fa-icon></div>
<div>
<div class="dic-kpi-n">{{ above3LakhAccounts | number }}</div>
<div class="dic-kpi-l">Above &#8377;3L A/cs</div>
<div class="dic-kpi-sub">partial / above-cap exposure</div>
</div>
</div>
<div class="dic-kpi dic-kpi--teal">
<div class="dic-kpi-ic"><fa-icon icon="hand-holding-usd"></fa-icon></div>
<div>
<div class="dic-kpi-n">&#8377;{{ loanTotal.amount | number: '1.0-0' }}</div>
<div class="dic-kpi-l">Loans Against Deposits</div>
<div class="dic-kpi-sub">{{ loanTotal.accounts | number }} accounts</div>
</div>
</div>
<div class="dic-kpi dic-kpi--red">
<div class="dic-kpi-ic"><fa-icon icon="coins"></fa-icon></div>
<div>
<div class="dic-kpi-n">&#8377;{{ premiumDue | number: '1.0-0' }}</div>
<div class="dic-kpi-l">DICGC Premium (Half-Yearly)</div>
<div class="dic-kpi-sub">{{ bank.premiumRatePer100 }}% of deposits</div>
</div>
</div>
</div>
<!-- Compliance / shortcuts -->
<div class="dic-compliance">
<div class="dc-card">
<div class="dc-card-h">
<fa-icon icon="check-circle" class="dc-ok"></fa-icon><span>A/C-Wise Slab Report</span>
</div>
<div class="dc-meta">
As on: <strong>{{ bank.reportAsOn }}</strong>
</div>
<div class="dc-meta">
Total deposits: <strong>&#8377;{{ depositTotal.amount | number: '1.0-0' }}</strong> across
{{ depositTotal.accounts | number }} A/cs
</div>
<button class="dc-btn" (click)="showTab('slab')">
<fa-icon icon="external-link-alt"></fa-icon> Open Report
</button>
</div>
<div class="dc-card">
<div class="dc-card-h"><fa-icon icon="users" class="dc-info"></fa-icon><span>SAHAY Depositor List</span></div>
<div class="dc-meta">Format: <strong>DICGC SAHAY 2.0</strong></div>
<div class="dc-meta">
Total entries: <strong>{{ depositors.length }}</strong>
</div>
<button class="dc-btn" (click)="showTab('sahay')">
<fa-icon icon="external-link-alt"></fa-icon> Open Register
</button>
</div>
<div class="dc-card">
<div class="dc-card-h">
<fa-icon icon="info-circle" class="dc-info"></fa-icon><span>Premium Schedule</span>
</div>
<div class="dc-meta">
Half-yearly assessment as of <strong>{{ bank.reportAsOn }}</strong>
</div>
<div class="dc-meta">Next due: <strong>31 May 2026</strong></div>
</div>
</div>
</div>
}
<!-- A/C-WISE SLAB REPORT -->
@if (activeTab === 'slab') {
<div class="dic-section">
<div class="dic-form-meta">
<div class="dic-form-title">
<h3>A/C-Wise Deposit Insurance &amp; Credit Guarantee Report</h3>
<p>
{{ bank.name }} · {{ bank.branch }} &middot; As On {{ bank.reportAsOn }} &middot; Ref {{ bank.reportRefNo }}
</p>
</div>
<button class="dic-btn dic-btn-xls" (click)="exportSlabReport()">
<fa-icon icon="file-excel"></fa-icon> Download Excel
</button>
</div>
<!-- Deposits -->
<div class="dic-tbl-wrap">
<div class="dic-tbl-h">CREDIT BALANCE — DEPOSITS</div>
<table class="dic-tbl">
<thead>
<tr class="hd-1">
<th rowspan="2" class="ta-c">Sr.No</th>
<th rowspan="2">Description</th>
<th colspan="2" class="ta-c">Up to &#8377;1,00,000</th>
<th colspan="2" class="ta-c">&#8377;1,00,001 – 2,00,000</th>
<th colspan="2" class="ta-c">&#8377;2,00,001 – 3,00,000</th>
<th colspan="2" class="ta-c">Above &#8377;3,00,000</th>
<th colspan="2" class="ta-c">Total</th>
</tr>
<tr class="hd-2">
<th class="ta-r">Amount</th>
<th class="ta-r">#A/c</th>
<th class="ta-r">Amount</th>
<th class="ta-r">#A/c</th>
<th class="ta-r">Amount</th>
<th class="ta-r">#A/c</th>
<th class="ta-r">Amount</th>
<th class="ta-r">#A/c</th>
<th class="ta-r">Amount</th>
<th class="ta-r">#A/c</th>
</tr>
</thead>
<tbody>
@for (r of deposits; track r.sl) {
<tr>
<td class="ta-c">{{ r.sl }}</td>
<td>{{ r.description }}</td>
<td class="ta-r mono">{{ r.upto1Lakh.amount | number: '1.2-2' }}</td>
<td class="ta-r">{{ r.upto1Lakh.accounts | number }}</td>
<td class="ta-r mono">{{ r.oneTo2Lakh.amount | number: '1.2-2' }}</td>
<td class="ta-r">{{ r.oneTo2Lakh.accounts | number }}</td>
<td class="ta-r mono">{{ r.twoTo3Lakh.amount | number: '1.2-2' }}</td>
<td class="ta-r">{{ r.twoTo3Lakh.accounts | number }}</td>
<td class="ta-r mono">{{ r.above3Lakh.amount | number: '1.2-2' }}</td>
<td class="ta-r">{{ r.above3Lakh.accounts | number }}</td>
<td class="ta-r mono">
<strong>{{ r.total.amount | number: '1.2-2' }}</strong>
</td>
<td class="ta-r">
<strong>{{ r.total.accounts | number }}</strong>
</td>
</tr>
}
<tr class="row-total">
<td></td>
<td>TOTAL</td>
<td class="ta-r mono">600018811.06</td>
<td class="ta-r">{{ depositTotal.accounts | number }}</td>
<td class="ta-r mono">—</td>
<td class="ta-r">—</td>
<td class="ta-r mono">—</td>
<td class="ta-r">—</td>
<td class="ta-r mono">—</td>
<td class="ta-r">—</td>
<td class="ta-r mono">
<strong>{{ depositTotal.amount | number: '1.2-2' }}</strong>
</td>
<td class="ta-r">
<strong>{{ depositTotal.accounts | number }}</strong>
</td>
</tr>
</tbody>
</table>
</div>
<!-- Loans -->
<div class="dic-tbl-wrap">
<div class="dic-tbl-h">CREDIT BALANCE (LOAN A/C) — Section A</div>
<table class="dic-tbl">
<thead>
<tr class="hd-1">
<th rowspan="2" class="ta-c">Sr.No</th>
<th rowspan="2">Description</th>
<th colspan="2" class="ta-c">Up to &#8377;1,00,000</th>
<th colspan="2" class="ta-c">&#8377;1,00,001 – 2,00,000</th>
<th colspan="2" class="ta-c">&#8377;2,00,001 – 3,00,000</th>
<th colspan="2" class="ta-c">Above &#8377;3,00,000</th>
<th colspan="2" class="ta-c">Total</th>
</tr>
<tr class="hd-2">
<th class="ta-r">Amount</th>
<th class="ta-r">#A/c</th>
<th class="ta-r">Amount</th>
<th class="ta-r">#A/c</th>
<th class="ta-r">Amount</th>
<th class="ta-r">#A/c</th>
<th class="ta-r">Amount</th>
<th class="ta-r">#A/c</th>
<th class="ta-r">Amount</th>
<th class="ta-r">#A/c</th>
</tr>
</thead>
<tbody>
@for (r of loans; track r.sl) {
<tr>
<td class="ta-c">{{ r.sl }}</td>
<td>{{ r.description }}</td>
<td class="ta-r mono">{{ r.upto1Lakh.amount | number: '1.2-2' }}</td>
<td class="ta-r">{{ r.upto1Lakh.accounts | number }}</td>
<td class="ta-r mono">{{ r.oneTo2Lakh.amount | number: '1.2-2' }}</td>
<td class="ta-r">{{ r.oneTo2Lakh.accounts | number }}</td>
<td class="ta-r mono">{{ r.twoTo3Lakh.amount | number: '1.2-2' }}</td>
<td class="ta-r">{{ r.twoTo3Lakh.accounts | number }}</td>
<td class="ta-r mono">{{ r.above3Lakh.amount | number: '1.2-2' }}</td>
<td class="ta-r">{{ r.above3Lakh.accounts | number }}</td>
<td class="ta-r mono">
<strong>{{ r.total.amount | number: '1.2-2' }}</strong>
</td>
<td class="ta-r">
<strong>{{ r.total.accounts | number }}</strong>
</td>
</tr>
}
<tr class="row-total">
<td></td>
<td>TOTAL</td>
<td class="ta-r mono">—</td>
<td class="ta-r">—</td>
<td class="ta-r mono">—</td>
<td class="ta-r">—</td>
<td class="ta-r mono">—</td>
<td class="ta-r">—</td>
<td class="ta-r mono">—</td>
<td class="ta-r">—</td>
<td class="ta-r mono">
<strong>{{ loanTotal.amount | number: '1.2-2' }}</strong>
</td>
<td class="ta-r">
<strong>{{ loanTotal.accounts | number }}</strong>
</td>
</tr>
</tbody>
</table>
</div>
<!-- Section D summary -->
<div class="dic-tbl-wrap">
<div class="dic-tbl-h">Section D — Final Summary</div>
<table class="dic-tbl dic-summary-tbl">
<thead>
<tr>
<th class="ta-c">Sr.No</th>
<th>Description</th>
<th class="ta-r">Amount</th>
<th class="ta-r">#A/c</th>
</tr>
</thead>
<tbody>
@for (s of summary; track s.sl) {
<tr>
<td class="ta-c">{{ s.sl }}</td>
<td>{{ s.description }}</td>
<td class="ta-r mono">{{ s.amount | number: '1.2-2' }}</td>
<td class="ta-r">{{ s.accounts | number }}</td>
</tr>
}
<tr class="row-total">
<td></td>
<td>TOTAL</td>
<td class="ta-r mono"><strong>607,679,897.42</strong></td>
<td class="ta-r"><strong>8,190</strong></td>
</tr>
</tbody>
</table>
</div>
</div>
}
<!-- SAHAY DEPOSITOR LIST -->
@if (activeTab === 'sahay') {
<div class="dic-section">
<div class="dic-form-meta">
<div class="dic-form-title">
<h3>SAHAY — Depositor-wise Input File</h3>
<p>DICGC claim payout format (CSV/Excel) submitted on bank failure under Section 18A</p>
</div>
<div class="dic-action-group">
<button class="dic-btn dic-btn-csv" (click)="exportSahayCsv()">
<fa-icon icon="file-csv"></fa-icon> Download CSV
</button>
<button class="dic-btn dic-btn-xls" (click)="exportSahay()">
<fa-icon icon="file-excel"></fa-icon> Download Excel
</button>
</div>
</div>
<div class="dic-filters">
<div class="dic-filter">
<label>Customer Name</label>
<input class="dic-inp" type="text" [(ngModel)]="filterName" placeholder="Search customer" />
</div>
<div class="dic-filter">
<label>Account Number</label>
<input class="dic-inp" type="text" [(ngModel)]="filterAccountNumber" placeholder="A/c contains…" />
</div>
<div class="dic-filter dic-filter-check">
<label class="check-row">
<input type="checkbox" [(ngModel)]="filterAboveLimit" />
<span>Only above &#8377;{{ bank.insuranceLimit | number }} (uninsured portion)</span>
</label>
</div>
<button class="dic-btn dic-btn-g" (click)="resetFilters()">Reset</button>
</div>
<div class="dic-tbl-wrap">
<table class="dic-tbl">
<thead>
<tr>
<th class="ta-c">SR</th>
<th>UCIC</th>
<th>A/c No</th>
<th>Type</th>
<th class="ta-c">Holders</th>
<th>Customer Name(s)</th>
<th>DOB</th>
<th class="ta-r">Deposit</th>
<th class="ta-r">Insured</th>
<th class="ta-c">LAD/LAFD</th>
<th>PAN</th>
<th>Aadhaar</th>
<th>Mobile</th>
<th>Last Txn</th>
</tr>
</thead>
<tbody>
@for (d of filteredDepositors; track d.inputSerialNumber) {
<tr [class.uninsured]="isUninsured(d)">
<td class="ta-c">{{ d.inputSerialNumber }}</td>
<td class="mono">{{ d.customerIdUcic }}</td>
<td class="mono">{{ d.accountNumber }}</td>
<td>{{ d.typeOfDeposit }}</td>
<td class="ta-c">{{ d.numberOfHolders }}</td>
<td>
{{ d.nameFirst }}
@if (d.nameSecond) {
<span class="cust-2"> &amp; {{ d.nameSecond }}</span>
}
@if (d.nameThird) {
<span class="cust-2"> &amp; {{ d.nameThird }}</span>
}
</td>
<td>{{ d.dateOfBirthOrIncorporation }}</td>
<td class="ta-r mono">{{ d.amountOfDeposit | number: '1.0-0' }}</td>
<td class="ta-r mono">{{ d.insuredAmount | number: '1.0-0' }}</td>
<td class="ta-c">{{ d.loanAgainstDeposit || '—' }}</td>
<td class="mono">{{ d.panNumber || '—' }}</td>
<td class="mono">{{ d.aadhaarNumber || '—' }}</td>
<td class="mono">{{ d.mobileNumber }}</td>
<td>{{ d.lastCustomerInducedTxnDate }}</td>
</tr>
} @empty {
<tr>
<td colspan="14" class="dic-empty">No depositors match the filters.</td>
</tr>
}
</tbody>
</table>
</div>
<div class="dic-note">
<fa-icon icon="info-circle"></fa-icon>
<span
><strong>SAHAY Note:</strong> Insured Amount is capped at &#8377;{{ bank.insuranceLimit | number }} per
depositor per bank. Rows highlighted are above the cap — DICGC pays the cap, residual is unsecured.</span
>
</div>
</div>
}
<!-- TOAST -->
<div class="dic-toast" [class.show]="toastVisible">{{ toastMsg }}</div>
</div>
+602
View File
@@ -0,0 +1,602 @@
/**
* 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 {
--dc-navy: #0b1e3d;
--dc-blue: #1d4ed8;
--dc-blue-l: #eff6ff;
--dc-teal: #0e7e6b;
--dc-teal-l: #e0f4f0;
--dc-green: #15803d;
--dc-green-l: #dcfce7;
--dc-amber: #d97706;
--dc-amber-l: #fef3c7;
--dc-red: #c0392b;
--dc-red-l: #fdecea;
--dc-purple: #6d28d9;
--dc-purple-l: #ede9fe;
--dc-g50: #f8fafc;
--dc-g100: #f1f5f9;
--dc-g200: #e2e8f0;
--dc-g300: #cbd5e1;
--dc-g500: #64748b;
--dc-g700: #334155;
--dc-g900: #0f172a;
display: block;
font-family:
'DM Sans',
system-ui,
-apple-system,
sans-serif;
background: var(--dc-g50);
color: var(--dc-g900);
font-size: 14px;
line-height: 1.5;
}
.dic-root {
padding: 18px 22px;
max-width: 1500px;
margin: 0 auto;
}
/* HEADER */
.dic-head {
display: flex;
justify-content: space-between;
align-items: center;
gap: 16px;
flex-wrap: wrap;
margin-bottom: 16px;
}
.dic-head-left {
display: flex;
align-items: center;
gap: 14px;
}
.dic-head-ic {
font-size: 28px;
color: var(--dc-blue);
}
.dic-head-t {
margin: 0;
font-size: 18px;
font-weight: 700;
color: var(--dc-g900);
}
.dic-head-s {
font-size: 12px;
color: var(--dc-g500);
}
.dic-head-meta {
display: flex;
gap: 22px;
> div {
display: flex;
flex-direction: column;
.dic-meta-l {
font-size: 10px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--dc-g500);
}
.dic-meta-v {
font-size: 14px;
font-weight: 600;
color: var(--dc-g900);
}
}
}
/* TABS */
.dic-tabs {
display: flex;
gap: 4px;
background: #fff;
border: 1px solid var(--dc-g200);
border-radius: 10px;
padding: 4px;
margin-bottom: 16px;
overflow-x: auto;
}
.dic-tab {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 9px 14px;
border: none;
background: transparent;
font-size: 13px;
font-weight: 500;
color: var(--dc-g500);
cursor: pointer;
border-radius: 7px;
white-space: nowrap;
transition: all 0.15s;
font-family: inherit;
&:hover {
color: var(--dc-g900);
}
&.active {
background: var(--dc-blue);
color: #fff;
box-shadow: 0 2px 6px rgb(29 78 216 / 25%);
}
}
.dic-section {
display: flex;
flex-direction: column;
gap: 16px;
}
/* KPI CARDS */
.dic-kpis {
display: grid;
grid-template-columns: repeat(5, 1fr);
gap: 12px;
}
.dic-kpi {
background: #fff;
border: 1px solid var(--dc-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%);
}
}
.dic-kpi-ic {
width: 42px;
height: 42px;
border-radius: 11px;
display: flex;
align-items: center;
justify-content: center;
font-size: 18px;
flex-shrink: 0;
}
.dic-kpi--blue .dic-kpi-ic {
background: var(--dc-blue-l);
color: var(--dc-blue);
}
.dic-kpi--green .dic-kpi-ic {
background: var(--dc-green-l);
color: var(--dc-green);
}
.dic-kpi--amber .dic-kpi-ic {
background: var(--dc-amber-l);
color: var(--dc-amber);
}
.dic-kpi--teal .dic-kpi-ic {
background: var(--dc-teal-l);
color: var(--dc-teal);
}
.dic-kpi--red .dic-kpi-ic {
background: var(--dc-red-l);
color: var(--dc-red);
}
.dic-kpi-n {
font-size: 18px;
font-weight: 700;
color: var(--dc-g900);
line-height: 1.1;
}
.dic-kpi-l {
font-size: 12px;
color: var(--dc-g700);
font-weight: 500;
margin-top: 2px;
}
.dic-kpi-sub {
font-size: 11px;
color: var(--dc-g500);
margin-top: 1px;
}
/* COMPLIANCE CARDS */
.dic-compliance {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: 12px;
}
.dc-card {
background: #fff;
border: 1px solid var(--dc-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(--dc-g900);
margin-bottom: 8px;
}
.dc-ok {
color: var(--dc-green);
}
.dc-info {
color: var(--dc-blue);
}
.dc-meta {
font-size: 12px;
color: var(--dc-g500);
margin: 2px 0;
strong {
color: var(--dc-g900);
font-weight: 600;
}
}
.dc-btn {
margin-top: 10px;
padding: 6px 12px;
border: 1px solid var(--dc-blue);
background: var(--dc-blue-l);
color: var(--dc-blue);
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(--dc-blue);
color: #fff;
}
}
/* FORM HEADER */
.dic-form-meta {
display: flex;
justify-content: space-between;
align-items: flex-start;
gap: 14px;
flex-wrap: wrap;
}
.dic-form-title {
h3 {
margin: 0;
font-size: 16px;
font-weight: 700;
color: var(--dc-g900);
}
p {
margin: 2px 0 0;
font-size: 12px;
color: var(--dc-g500);
}
}
.dic-action-group {
display: flex;
gap: 8px;
}
/* BUTTONS */
.dic-btn {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 8px 14px;
border: 1px solid var(--dc-g300);
background: #fff;
border-radius: 8px;
font-size: 13px;
font-weight: 500;
color: var(--dc-g700);
cursor: pointer;
font-family: inherit;
transition: all 0.15s;
&:hover {
background: var(--dc-g50);
border-color: var(--dc-g500);
}
}
.dic-btn-xls {
background: #16a34a;
border-color: #16a34a;
color: #fff;
&:hover {
background: #15803d;
border-color: #15803d;
color: #fff;
}
}
.dic-btn-csv {
background: #1d4ed8;
border-color: #1d4ed8;
color: #fff;
&:hover {
background: #1e40af;
border-color: #1e40af;
color: #fff;
}
}
.dic-btn-g {
align-self: end;
}
/* INPUTS */
.dic-inp {
width: 100%;
padding: 8px 12px;
border: 1px solid var(--dc-g200);
border-radius: 8px;
font-size: 13px;
background: #fff;
font-family: inherit;
&:focus {
outline: none;
border-color: var(--dc-blue);
box-shadow: 0 0 0 3px rgb(29 78 216 / 15%);
}
}
/* FILTERS */
.dic-filters {
background: #fff;
border: 1px solid var(--dc-g200);
border-radius: 12px;
padding: 14px;
display: grid;
grid-template-columns: 1fr 1fr 1.4fr auto;
gap: 12px;
align-items: end;
}
.dic-filter {
display: flex;
flex-direction: column;
gap: 4px;
label {
font-size: 11px;
font-weight: 600;
color: var(--dc-g500);
text-transform: uppercase;
letter-spacing: 0.05em;
}
}
.dic-filter-check .check-row {
display: flex;
align-items: center;
gap: 8px;
font-size: 13px;
color: var(--dc-g700);
cursor: pointer;
user-select: none;
margin-top: 14px;
input {
width: 16px;
height: 16px;
accent-color: var(--dc-blue);
}
}
/* TABLE */
.dic-tbl-wrap {
background: #fff;
border: 1px solid var(--dc-g200);
border-radius: 12px;
overflow: auto;
box-shadow: 0 1px 3px rgb(0 0 0 / 4%);
}
.dic-tbl-h {
background: var(--dc-blue-l);
color: var(--dc-blue);
padding: 10px 16px;
font-size: 12px;
font-weight: 700;
text-transform: uppercase;
letter-spacing: 0.05em;
border-bottom: 1px solid var(--dc-g200);
}
.dic-tbl {
width: 100%;
border-collapse: collapse;
th {
text-align: left;
padding: 9px 10px;
font-size: 11px;
font-weight: 600;
color: var(--dc-g500);
text-transform: uppercase;
letter-spacing: 0.04em;
background: var(--dc-g50);
border-bottom: 1px solid var(--dc-g200);
}
th.hd-1,
tr.hd-1 th {
background: #f0f4ff;
color: var(--dc-blue);
}
td {
padding: 9px 10px;
border-bottom: 1px solid var(--dc-g100);
font-size: 12px;
color: var(--dc-g700);
}
tr:last-child td {
border-bottom: none;
}
tr:hover td {
background: var(--dc-g50);
}
tr.row-total td {
background: #f0fdf4;
font-weight: 700;
color: var(--dc-g900);
border-top: 2px solid var(--dc-green);
}
tr.uninsured td {
background: #fff7ed;
}
tr.uninsured:hover td {
background: #ffedd5;
}
}
.dic-summary-tbl {
td,
th {
padding: 11px 14px;
font-size: 13px;
}
}
.ta-c {
text-align: center;
}
.ta-r {
text-align: right;
}
.mono {
font-family: 'DM Mono', monospace;
font-size: 11px;
letter-spacing: 0.02em;
}
.cust-2 {
color: var(--dc-g500);
font-size: 11px;
}
.dic-empty {
text-align: center;
padding: 30px;
color: var(--dc-g500);
font-style: italic;
}
/* NOTE */
.dic-note {
background: var(--dc-amber-l);
border: 1px solid #fed7aa;
border-radius: 10px;
padding: 12px 16px;
display: flex;
gap: 10px;
font-size: 12px;
color: #92400e;
line-height: 1.5;
fa-icon {
font-size: 14px;
flex-shrink: 0;
margin-top: 2px;
}
}
/* TOAST */
.dic-toast {
position: fixed;
bottom: 32px;
left: 50%;
transform: translateX(-50%) translateY(20px);
background: var(--dc-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);
}
}
@media (width <= 1100px) {
.dic-kpis {
grid-template-columns: repeat(3, 1fr);
}
.dic-compliance {
grid-template-columns: 1fr;
}
.dic-filters {
grid-template-columns: 1fr 1fr;
}
}
@media (width <= 720px) {
.dic-kpis {
grid-template-columns: 1fr 1fr;
}
}
+398
View File
@@ -0,0 +1,398 @@
/**
* 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 {
DEPOSIT_SLABS,
DICGC_BANK,
LOAN_SLABS,
SahayDepositor,
SAHAY_DEPOSITORS,
SlabRow,
SUMMARY_D
} from './dicgc-data';
@Component({
selector: 'mifosx-dicgc',
templateUrl: './dicgc.component.html',
styleUrls: ['./dicgc.component.scss'],
imports: [
...STANDALONE_SHARED_IMPORTS,
FaIconComponent,
FormsModule
]
})
export class DicgcComponent {
/** Active tab */
activeTab: 'dashboard' | 'slab' | 'sahay' = 'dashboard';
bank = DICGC_BANK;
deposits: SlabRow[] = DEPOSIT_SLABS;
loans: SlabRow[] = LOAN_SLABS;
summary = SUMMARY_D;
depositors: SahayDepositor[] = SAHAY_DEPOSITORS;
/** SAHAY filters */
filterName = '';
filterAccountNumber = '';
filterAboveLimit = false;
/** Toast */
toastMsg = '';
toastVisible = false;
private toastTimer: any;
showTab(tab: 'dashboard' | 'slab' | 'sahay'): void {
this.activeTab = tab;
}
// -------------------- KPI helpers --------------------
private sumSlab(
rows: SlabRow[],
slab: keyof Pick<SlabRow, 'upto1Lakh' | 'oneTo2Lakh' | 'twoTo3Lakh' | 'above3Lakh' | 'total'>
): { amount: number; accounts: number } {
let amount = 0;
let accounts = 0;
for (const r of rows) {
amount += r[slab].amount;
accounts += r[slab].accounts;
}
return { amount, accounts };
}
get depositTotal(): { amount: number; accounts: number } {
return this.sumSlab(this.deposits, 'total');
}
get loanTotal(): { amount: number; accounts: number } {
return this.sumSlab(this.loans, 'total');
}
/** Insured = full amount for ≤5L, capped at 5L for >5L (sum across slabs ≤3L is fully insured here) */
get fullyInsuredAccounts(): number {
const u1 = this.sumSlab(this.deposits, 'upto1Lakh').accounts;
const u2 = this.sumSlab(this.deposits, 'oneTo2Lakh').accounts;
const u3 = this.sumSlab(this.deposits, 'twoTo3Lakh').accounts;
return u1 + u2 + u3;
}
get above3LakhAccounts(): number {
return this.sumSlab(this.deposits, 'above3Lakh').accounts;
}
get insuredAmount(): number {
return this.depositors.reduce((s, d) => s + d.insuredAmount, 0);
}
/** DICGC premium = 0.12% of total assessable deposits per half year */
get premiumDue(): number {
return this.depositTotal.amount * (this.bank.premiumRatePer100 / 100);
}
// SAHAY filtered list
get filteredDepositors(): SahayDepositor[] {
const name = this.filterName.trim().toLowerCase();
const acc = this.filterAccountNumber.trim();
return this.depositors.filter((d) => {
if (name && !`${d.nameFirst} ${d.nameSecond} ${d.nameThird}`.toLowerCase().includes(name)) return false;
if (acc && !d.accountNumber.includes(acc)) return false;
if (this.filterAboveLimit && d.amountOfDeposit <= this.bank.insuranceLimit) return false;
return true;
});
}
resetFilters(): void {
this.filterName = '';
this.filterAccountNumber = '';
this.filterAboveLimit = false;
}
/** True if depositor's amount exceeds the DICGC ₹5L cap */
isUninsured(d: SahayDepositor): boolean {
return d.amountOfDeposit > this.bank.insuranceLimit;
}
// -------------------- Excel exports --------------------
exportSlabReport(): void {
const rows: string[][] = [];
rows.push([
this.bank.name,
this.bank.branch
]);
rows.push([`A/C-Wise Deposit Insurance and Credit Guarantee Report — As On ${this.bank.reportAsOn}`]);
rows.push([]);
rows.push([
`Report Ref: ${this.bank.reportRefNo}`,
`Print Date: ${this.bank.printDate}`,
`User Code: ${this.bank.userCode}`
]);
rows.push([]);
// Header section
rows.push(['CREDIT BALANCE — DEPOSITS']);
rows.push([
'Sr.No',
'Description',
'Up to 1L Amount',
'Up to 1L #A/c',
'1L-2L Amount',
'1L-2L #A/c',
'2L-3L Amount',
'2L-3L #A/c',
'Above 3L Amount',
'Above 3L #A/c',
'Total Amount',
'Total #A/c'
]);
for (const r of this.deposits) {
rows.push(this.flattenSlabRow(r));
}
const dt = this.depositTotal;
rows.push([
'',
'TOTAL',
this.sumSlab(this.deposits, 'upto1Lakh').amount.toFixed(2),
this.sumSlab(this.deposits, 'upto1Lakh').accounts.toString(),
this.sumSlab(this.deposits, 'oneTo2Lakh').amount.toFixed(2),
this.sumSlab(this.deposits, 'oneTo2Lakh').accounts.toString(),
this.sumSlab(this.deposits, 'twoTo3Lakh').amount.toFixed(2),
this.sumSlab(this.deposits, 'twoTo3Lakh').accounts.toString(),
this.sumSlab(this.deposits, 'above3Lakh').amount.toFixed(2),
this.sumSlab(this.deposits, 'above3Lakh').accounts.toString(),
dt.amount.toFixed(2),
dt.accounts.toString()
]);
rows.push([]);
rows.push(['CREDIT BALANCE (LOAN A/C) — Section A']);
rows.push([
'Sr.No',
'Description',
'Up to 1L Amount',
'Up to 1L #A/c',
'1L-2L Amount',
'1L-2L #A/c',
'2L-3L Amount',
'2L-3L #A/c',
'Above 3L Amount',
'Above 3L #A/c',
'Total Amount',
'Total #A/c'
]);
for (const r of this.loans) {
rows.push(this.flattenSlabRow(r));
}
const lt = this.loanTotal;
rows.push([
'',
'TOTAL',
this.sumSlab(this.loans, 'upto1Lakh').amount.toFixed(2),
this.sumSlab(this.loans, 'upto1Lakh').accounts.toString(),
this.sumSlab(this.loans, 'oneTo2Lakh').amount.toFixed(2),
this.sumSlab(this.loans, 'oneTo2Lakh').accounts.toString(),
this.sumSlab(this.loans, 'twoTo3Lakh').amount.toFixed(2),
this.sumSlab(this.loans, 'twoTo3Lakh').accounts.toString(),
this.sumSlab(this.loans, 'above3Lakh').amount.toFixed(2),
this.sumSlab(this.loans, 'above3Lakh').accounts.toString(),
lt.amount.toFixed(2),
lt.accounts.toString()
]);
rows.push([]);
rows.push(['Section D — Final Summary']);
rows.push([
'Sr.No',
'Description',
'Amount',
'#A/c'
]);
for (const s of this.summary) {
rows.push([
s.sl.toString(),
s.description,
s.amount.toFixed(2),
s.accounts.toString()
]);
}
const grandAmount = this.summary.reduce((a, x) => a + x.amount, 0);
const grandAcc = this.summary.reduce((a, x) => a + x.accounts, 0);
rows.push([
'',
'TOTAL',
grandAmount.toFixed(2),
grandAcc.toString()
]);
this.saveTsv(rows, `DICGC-SlabReport-${this.fileTag()}.xls`);
this.toast('DICGC slab report downloaded');
}
exportSahay(): void {
const headers = [
'Input Serial Number',
'Customer ID (UCIC) Number',
'Account Number',
'Type of account',
'Nature of account',
'Number of Acct. Holders (in case of Joint)',
'Name Of First Customer',
'Name Of Second Customer',
'Name Of Third Customer',
'Date of Birth (Primary Holder) or Date of incorporation in case of Entity',
'Amount of Deposit',
'Insured Amount',
'Loan against deposits only (LAD / LAFD)',
'PAN Number',
'Aadhaar Number',
'Any Other OVD / KYC Document Type',
'Any Other OVD / KYC Number',
'Mobile Number',
'Type of Deposit',
'Date of Last Customer inducted transaction'
];
const rows: string[][] = [headers];
for (const d of this.filteredDepositors) {
rows.push([
d.inputSerialNumber.toString(),
d.customerIdUcic,
d.accountNumber,
d.typeOfAccount,
d.natureOfAccount,
d.numberOfHolders.toString(),
d.nameFirst,
d.nameSecond,
d.nameThird,
d.dateOfBirthOrIncorporation,
d.amountOfDeposit.toFixed(2),
d.insuredAmount.toFixed(2),
d.loanAgainstDeposit,
d.panNumber,
d.aadhaarNumber,
d.otherKycType,
d.otherKycNumber,
d.mobileNumber,
d.typeOfDeposit,
d.lastCustomerInducedTxnDate
]);
}
this.saveTsv(rows, `DICGC-SAHAY-Depositors-${this.fileTag()}.xls`);
this.toast(`${this.filteredDepositors.length} depositors exported (SAHAY format)`);
}
exportSahayCsv(): void {
// CSV mirrors the Input File Template DICGC ships
const headers = [
'Input Serial Number',
'Customer ID (UCIC) Number',
'Account Number',
'Type of account',
'Nature of account',
'Number of Acct. Holders (in case of Joint)',
'Name Of First Customer',
'Name Of Second Customer',
'Name Of Third Customer',
'Date of Birth (Primary Holder) or Date of incorporation in case of Entity',
'Amount of Deposit',
'Insured Amount',
'Loan against deposits only (LAD / LAFD)',
'PAN Number',
'Aadhaar Number',
'Any Other OVD / KYC Document Type',
'Any Other OVD / KYC Number',
'Mobile Number',
'Type of Deposit',
'Date of Last Customer inducted transaction'
];
const escape = (v: string): string => {
const s = (v || '').replace(/"/g, '""');
if (s.includes(',') || s.includes('"') || s.includes('\n')) return `"${s}"`;
return s;
};
const lines: string[] = [headers.map(escape).join(',')];
for (const d of this.filteredDepositors) {
lines.push(
[
d.inputSerialNumber.toString(),
d.customerIdUcic,
d.accountNumber,
d.typeOfAccount,
d.natureOfAccount,
d.numberOfHolders.toString(),
d.nameFirst,
d.nameSecond,
d.nameThird,
d.dateOfBirthOrIncorporation,
d.amountOfDeposit.toFixed(2),
d.insuredAmount.toFixed(2),
d.loanAgainstDeposit,
d.panNumber,
d.aadhaarNumber,
d.otherKycType,
d.otherKycNumber,
d.mobileNumber,
d.typeOfDeposit,
d.lastCustomerInducedTxnDate
]
.map(escape)
.join(',')
);
}
const blob = new Blob([lines.join('\n')], { type: 'text/csv;charset=utf-8' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `DICGC-SAHAY-Depositors-${this.fileTag()}.csv`;
a.click();
URL.revokeObjectURL(url);
this.toast(`${this.filteredDepositors.length} depositors exported (CSV)`);
}
private flattenSlabRow(r: SlabRow): string[] {
return [
r.sl.toString(),
r.description,
r.upto1Lakh.amount.toFixed(2),
r.upto1Lakh.accounts.toString(),
r.oneTo2Lakh.amount.toFixed(2),
r.oneTo2Lakh.accounts.toString(),
r.twoTo3Lakh.amount.toFixed(2),
r.twoTo3Lakh.accounts.toString(),
r.above3Lakh.amount.toFixed(2),
r.above3Lakh.accounts.toString(),
r.total.amount.toFixed(2),
r.total.accounts.toString()
];
}
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(): 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()}`;
}
toast(msg: string): void {
this.toastMsg = msg;
this.toastVisible = true;
if (this.toastTimer) clearTimeout(this.toastTimer);
this.toastTimer = setTimeout(() => (this.toastVisible = false), 2800);
}
}
+22
View File
@@ -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 { DicgcRoutingModule } from './dicgc-routing.module';
import { DicgcComponent } from './dicgc.component';
@NgModule({
imports: [
SharedModule,
DicgcRoutingModule,
DicgcComponent
]
})
export class DicgcModule {}