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,260 @@
|
||||
<!--
|
||||
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="cims-dlg">
|
||||
<!-- HEADER -->
|
||||
<div class="cims-head">
|
||||
<div class="cims-head-left">
|
||||
<div class="cims-head-ic"><fa-icon icon="code"></fa-icon></div>
|
||||
<div>
|
||||
<h2 class="cims-title">CIMS / XBRL Returns — {{ currentForm.name }}</h2>
|
||||
<p class="cims-sub" [innerHTML]="currentForm.fullName"></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cims-head-actions">
|
||||
<span class="cims-status" [ngClass]="validation.status">
|
||||
<fa-icon [icon]="validation.status === 'valid' ? 'check-double' : 'exclamation-triangle'"></fa-icon>
|
||||
{{ validation.populated }}/{{ validation.total }} populated
|
||||
</span>
|
||||
<button class="cims-close" (click)="close()" matTooltip="Close" aria-label="Close">✕</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- FORM SELECTOR -->
|
||||
<div class="cims-form-bar">
|
||||
<span class="cims-form-bar-l">Active Form:</span>
|
||||
<button
|
||||
*ngFor="let code of formCodes"
|
||||
class="cims-form-pill"
|
||||
[class.active]="activeForm === code"
|
||||
(click)="setForm(code)"
|
||||
[matTooltip]="forms[code].fullName"
|
||||
>
|
||||
{{ forms[code].name }}
|
||||
</button>
|
||||
<span class="cims-form-meta mono"> <fa-icon icon="hashtag"></fa-icon> {{ currentForm.cimsCode }} </span>
|
||||
<span class="cims-form-meta"> <fa-icon icon="calendar-alt"></fa-icon> {{ currentForm.periodicity }} </span>
|
||||
<span class="cims-form-meta">
|
||||
<fa-icon icon="clock"></fa-icon> Next due: <strong>{{ currentForm.nextDue }}</strong>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<!-- TABS -->
|
||||
<div class="cims-tabs">
|
||||
<button class="cims-tab" [class.active]="activeTab === 'filing'" (click)="setTab('filing')">
|
||||
<fa-icon icon="address-card"></fa-icon> Filing Information
|
||||
</button>
|
||||
<button class="cims-tab" [class.active]="activeTab === 'data'" (click)="setTab('data')">
|
||||
<fa-icon icon="layer-group"></fa-icon> Form Data & Facts
|
||||
</button>
|
||||
<button class="cims-tab" [class.active]="activeTab === 'preview'" (click)="setTab('preview')">
|
||||
<fa-icon icon="code"></fa-icon> XBRL XML Preview
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="cims-body">
|
||||
<!-- ════════════ FILING INFO ════════════ -->
|
||||
<ng-container *ngIf="activeTab === 'filing'">
|
||||
<div class="cims-section">
|
||||
<div class="cims-sec-h">
|
||||
<h3 class="cims-sec-t">Reporting Entity</h3>
|
||||
</div>
|
||||
<div class="cims-info-grid">
|
||||
<div class="cims-info">
|
||||
<div class="cims-info-l">Bank Name</div>
|
||||
<div class="cims-info-v">{{ bank.name }}</div>
|
||||
</div>
|
||||
<div class="cims-info">
|
||||
<div class="cims-info-l">Branch</div>
|
||||
<div class="cims-info-v">{{ bank.branch }}</div>
|
||||
</div>
|
||||
<div class="cims-info">
|
||||
<div class="cims-info-l">BSR Code</div>
|
||||
<div class="cims-info-v mono">{{ bank.bsrCode }}</div>
|
||||
</div>
|
||||
<div class="cims-info">
|
||||
<div class="cims-info-l">IFSC</div>
|
||||
<div class="cims-info-v mono">{{ bank.ifsc }}</div>
|
||||
</div>
|
||||
<div class="cims-info">
|
||||
<div class="cims-info-l">Legal Entity ID</div>
|
||||
<div class="cims-info-v mono">{{ bank.legalEntityId }}</div>
|
||||
</div>
|
||||
<div class="cims-info">
|
||||
<div class="cims-info-l">PAN</div>
|
||||
<div class="cims-info-v mono">{{ bank.pan }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="cims-section">
|
||||
<div class="cims-sec-h">
|
||||
<h3 class="cims-sec-t">Return Particulars</h3>
|
||||
</div>
|
||||
<div class="cims-info-grid">
|
||||
<div class="cims-info">
|
||||
<div class="cims-info-l">CIMS Form Code</div>
|
||||
<div class="cims-info-v mono">{{ currentForm.cimsCode }}</div>
|
||||
</div>
|
||||
<div class="cims-info">
|
||||
<div class="cims-info-l">Taxonomy Version</div>
|
||||
<div class="cims-info-v mono">{{ currentForm.taxonomy }}</div>
|
||||
</div>
|
||||
<div class="cims-info">
|
||||
<div class="cims-info-l">Periodicity</div>
|
||||
<div class="cims-info-v">{{ currentForm.periodicity }}</div>
|
||||
</div>
|
||||
<div class="cims-info">
|
||||
<div class="cims-info-l">Reporting Period</div>
|
||||
<div class="cims-info-v">{{ bank.quarter }}</div>
|
||||
</div>
|
||||
<div class="cims-info">
|
||||
<div class="cims-info-l">As On Date</div>
|
||||
<div class="cims-info-v">{{ bank.asOnDate }}</div>
|
||||
</div>
|
||||
<div class="cims-info">
|
||||
<div class="cims-info-l">Last Filed</div>
|
||||
<div class="cims-info-v">{{ currentForm.lastFiled }}</div>
|
||||
</div>
|
||||
<div class="cims-info">
|
||||
<div class="cims-info-l">Next Due</div>
|
||||
<div class="cims-info-v">
|
||||
<strong>{{ currentForm.nextDue }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cims-info">
|
||||
<div class="cims-info-l">CIMS Portal</div>
|
||||
<div class="cims-info-v mono">{{ bank.cimsPortal }}</div>
|
||||
</div>
|
||||
<div class="cims-info">
|
||||
<div class="cims-info-l">CIMS User ID</div>
|
||||
<div class="cims-info-v mono">{{ bank.cimsUserId }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cims-desc" [innerHTML]="currentForm.description"></div>
|
||||
</div>
|
||||
|
||||
<div class="cims-section">
|
||||
<div class="cims-sec-h">
|
||||
<h3 class="cims-sec-t">Principal Officer</h3>
|
||||
</div>
|
||||
<div class="cims-info-grid">
|
||||
<div class="cims-info">
|
||||
<div class="cims-info-l">Name</div>
|
||||
<div class="cims-info-v">{{ bank.principalOfficer }}</div>
|
||||
</div>
|
||||
<div class="cims-info">
|
||||
<div class="cims-info-l">Designation</div>
|
||||
<div class="cims-info-v">{{ bank.poDesignation }}</div>
|
||||
</div>
|
||||
<div class="cims-info">
|
||||
<div class="cims-info-l">Email</div>
|
||||
<div class="cims-info-v mono">{{ bank.poEmail }}</div>
|
||||
</div>
|
||||
<div class="cims-info">
|
||||
<div class="cims-info-l">Mobile</div>
|
||||
<div class="cims-info-v mono">{{ bank.poMobile }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<!-- ════════════ FORM DATA ════════════ -->
|
||||
<ng-container *ngIf="activeTab === 'data'">
|
||||
<div class="cims-section" *ngFor="let sec of sections">
|
||||
<div class="cims-sec-h">
|
||||
<h3 class="cims-sec-t">{{ sec }}</h3>
|
||||
</div>
|
||||
<div class="cims-tbl-wrap">
|
||||
<table class="cims-tbl">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>XBRL Element</th>
|
||||
<th>Label</th>
|
||||
<th class="ta-r">Value</th>
|
||||
<th class="ta-c">Unit</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr *ngFor="let f of fieldsBySection(sec)">
|
||||
<td class="mono cell-ref">{{ f.ref }}</td>
|
||||
<td [innerHTML]="f.label"></td>
|
||||
<td class="ta-r">
|
||||
<strong>{{ f.value }}</strong>
|
||||
<span *ngIf="f.type === 'percent'" class="muted"> %</span>
|
||||
</td>
|
||||
<td class="ta-c">
|
||||
<span class="unit-pill">{{ f.unit }}</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<!-- ════════════ XBRL PREVIEW ════════════ -->
|
||||
<ng-container *ngIf="activeTab === 'preview'">
|
||||
<div class="cims-section">
|
||||
<div class="cims-sec-h">
|
||||
<h3 class="cims-sec-t">XBRL Instance Document Preview</h3>
|
||||
<div class="cims-sec-actions">
|
||||
<button mat-stroked-button class="cims-btn-ghost" (click)="copyXbrl()" matTooltip="Copy XML to clipboard">
|
||||
<fa-icon icon="copy"></fa-icon> Copy
|
||||
</button>
|
||||
<button mat-stroked-button class="cims-btn-xls" (click)="exportXbrl()">
|
||||
<fa-icon icon="file-export"></fa-icon> Download .xml
|
||||
</button>
|
||||
<button mat-stroked-button class="cims-btn-xls cims-btn-excel" (click)="exportExcel()">
|
||||
<fa-icon icon="file-excel"></fa-icon> Download Excel
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="cims-validation" [ngClass]="validation.status">
|
||||
<fa-icon [icon]="validation.status === 'valid' ? 'check-double' : 'exclamation-triangle'"></fa-icon>
|
||||
<div>
|
||||
<div class="cims-val-t">
|
||||
<ng-container *ngIf="validation.status === 'valid'"
|
||||
>XBRL Document Valid — ready to upload</ng-container
|
||||
>
|
||||
<ng-container *ngIf="validation.status === 'warning'"
|
||||
>{{ validation.empty }} field(s) need attention</ng-container
|
||||
>
|
||||
</div>
|
||||
<div class="cims-val-d">
|
||||
{{ validation.populated }} of {{ validation.total }} elements populated · Taxonomy
|
||||
<span class="mono">{{ currentForm.taxonomy }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<pre class="xbrl-preview"><code>{{ generateXbrlXml() }}</code></pre>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
|
||||
<!-- FOOTER ACTIONS -->
|
||||
<div class="cims-foot">
|
||||
<div class="cims-foot-l">
|
||||
<fa-icon icon="shield-alt"></fa-icon>
|
||||
<span
|
||||
>Submitted to RBI CIMS Portal under <strong>{{ currentForm.cimsCode }}</strong> by
|
||||
{{ bank.principalOfficer }}</span
|
||||
>
|
||||
</div>
|
||||
<div class="cims-foot-actions">
|
||||
<button mat-stroked-button class="cims-btn-ghost" (click)="exportExcel()">
|
||||
<fa-icon icon="file-excel"></fa-icon> Excel
|
||||
</button>
|
||||
<button mat-stroked-button class="cims-btn-xls" (click)="exportXbrl()">
|
||||
<fa-icon icon="file-export"></fa-icon> Generate XBRL
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,514 @@
|
||||
/**
|
||||
* 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 {
|
||||
--cims-good: #15803d;
|
||||
--cims-good-l: #dcfce7;
|
||||
--cims-mid: #d97706;
|
||||
--cims-mid-l: #fef3c7;
|
||||
--cims-low: #c0392b;
|
||||
--cims-low-l: #fdecea;
|
||||
--cims-cyan: #0891b2;
|
||||
--cims-cyan-l: #cffafe;
|
||||
--cims-teal: #0d9488;
|
||||
--cims-teal-l: #ccfbf1;
|
||||
--cims-g50: #f8fafc;
|
||||
--cims-g100: #f1f5f9;
|
||||
--cims-g200: #e2e8f0;
|
||||
--cims-g300: #cbd5e1;
|
||||
--cims-g500: #64748b;
|
||||
--cims-g700: #334155;
|
||||
--cims-g900: #0f172a;
|
||||
|
||||
display: block;
|
||||
font-family:
|
||||
'DM Sans',
|
||||
system-ui,
|
||||
-apple-system,
|
||||
sans-serif;
|
||||
color: var(--cims-g900);
|
||||
}
|
||||
|
||||
.cims-dlg {
|
||||
background: #fff;
|
||||
border-radius: 14px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
max-height: 92vh;
|
||||
}
|
||||
|
||||
/* HEADER */
|
||||
.cims-head {
|
||||
padding: 18px 22px;
|
||||
border-bottom: 1px solid var(--cims-g200);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
flex-shrink: 0;
|
||||
background: linear-gradient(135deg, #ecfeff 0%, #fff 100%);
|
||||
}
|
||||
|
||||
.cims-head-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 14px;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.cims-head-ic {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
border-radius: 11px;
|
||||
background: var(--cims-cyan-l);
|
||||
color: var(--cims-cyan);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 18px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.cims-title {
|
||||
margin: 0;
|
||||
font-size: 17px;
|
||||
font-weight: 700;
|
||||
color: var(--cims-g900);
|
||||
}
|
||||
|
||||
.cims-sub {
|
||||
margin: 2px 0 0;
|
||||
font-size: 12px;
|
||||
color: var(--cims-g500);
|
||||
}
|
||||
|
||||
.cims-head-actions {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.cims-status {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
padding: 6px 12px;
|
||||
border-radius: 999px;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
|
||||
&.valid {
|
||||
background: var(--cims-good-l);
|
||||
color: var(--cims-good);
|
||||
}
|
||||
|
||||
&.warning {
|
||||
background: var(--cims-mid-l);
|
||||
color: var(--cims-mid);
|
||||
}
|
||||
}
|
||||
|
||||
.cims-close {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid var(--cims-g200);
|
||||
background: #fff;
|
||||
font-size: 14px;
|
||||
color: var(--cims-g500);
|
||||
cursor: pointer;
|
||||
transition: all 0.15s;
|
||||
|
||||
&:hover {
|
||||
background: var(--cims-g100);
|
||||
color: var(--cims-g900);
|
||||
}
|
||||
}
|
||||
|
||||
/* FORM SELECTOR BAR */
|
||||
.cims-form-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
padding: 10px 22px;
|
||||
background: var(--cims-g50);
|
||||
border-bottom: 1px solid var(--cims-g200);
|
||||
flex-shrink: 0;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.cims-form-bar-l {
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
color: var(--cims-g500);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
|
||||
.cims-form-pill {
|
||||
padding: 6px 14px;
|
||||
border-radius: 999px;
|
||||
border: 1px solid var(--cims-g200);
|
||||
background: #fff;
|
||||
cursor: pointer;
|
||||
font-family: inherit;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
color: var(--cims-g700);
|
||||
transition: all 0.15s;
|
||||
|
||||
&:hover {
|
||||
background: var(--cims-cyan-l);
|
||||
border-color: var(--cims-cyan);
|
||||
color: var(--cims-cyan);
|
||||
}
|
||||
|
||||
&.active {
|
||||
background: var(--cims-cyan);
|
||||
border-color: var(--cims-cyan);
|
||||
color: #fff;
|
||||
box-shadow: 0 2px 6px rgb(8 145 178 / 25%);
|
||||
}
|
||||
}
|
||||
|
||||
.cims-form-meta {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
font-size: 11px;
|
||||
color: var(--cims-g500);
|
||||
padding: 4px 10px;
|
||||
background: #fff;
|
||||
border: 1px solid var(--cims-g200);
|
||||
border-radius: 6px;
|
||||
|
||||
fa-icon {
|
||||
color: var(--cims-cyan);
|
||||
margin-right: 2px;
|
||||
}
|
||||
|
||||
strong {
|
||||
color: var(--cims-g900);
|
||||
margin-left: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
/* TABS */
|
||||
.cims-tabs {
|
||||
display: flex;
|
||||
background: #fff;
|
||||
border-bottom: 1px solid var(--cims-g200);
|
||||
padding: 0 22px;
|
||||
overflow-x: auto;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.cims-tab {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 12px 18px;
|
||||
border: none;
|
||||
background: transparent;
|
||||
cursor: pointer;
|
||||
font-family: inherit;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: var(--cims-g500);
|
||||
border-bottom: 2px solid transparent;
|
||||
transition: all 0.15s;
|
||||
white-space: nowrap;
|
||||
|
||||
&:hover {
|
||||
color: var(--cims-g700);
|
||||
background: var(--cims-g50);
|
||||
}
|
||||
|
||||
&.active {
|
||||
background: #fff;
|
||||
color: var(--cims-cyan);
|
||||
border-bottom-color: var(--cims-cyan);
|
||||
}
|
||||
}
|
||||
|
||||
/* BODY */
|
||||
.cims-body {
|
||||
padding: 18px 22px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
overflow: auto;
|
||||
flex: 1;
|
||||
background: var(--cims-g50);
|
||||
}
|
||||
|
||||
.cims-section {
|
||||
background: #fff;
|
||||
border: 1px solid var(--cims-g200);
|
||||
border-radius: 12px;
|
||||
padding: 16px 18px;
|
||||
box-shadow: 0 1px 3px rgb(0 0 0 / 4%);
|
||||
}
|
||||
|
||||
.cims-sec-h {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
margin-bottom: 14px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.cims-sec-t {
|
||||
margin: 0;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
color: var(--cims-g700);
|
||||
}
|
||||
|
||||
.cims-sec-actions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.cims-btn-xls {
|
||||
font-size: 12px !important;
|
||||
height: 34px !important;
|
||||
color: #fff !important;
|
||||
background: var(--cims-cyan) !important;
|
||||
}
|
||||
|
||||
.cims-btn-excel {
|
||||
background: #16a34a !important;
|
||||
}
|
||||
|
||||
.cims-btn-ghost {
|
||||
font-size: 12px !important;
|
||||
height: 34px !important;
|
||||
color: var(--cims-g700) !important;
|
||||
background: #fff !important;
|
||||
border: 1px solid var(--cims-g200) !important;
|
||||
}
|
||||
|
||||
/* INFO GRID */
|
||||
.cims-info-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 12px 24px;
|
||||
}
|
||||
|
||||
.cims-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.cims-info-l {
|
||||
font-size: 10px;
|
||||
font-weight: 600;
|
||||
color: var(--cims-g500);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
}
|
||||
|
||||
.cims-info-v {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: var(--cims-g900);
|
||||
}
|
||||
|
||||
.cims-desc {
|
||||
margin-top: 12px;
|
||||
padding: 10px 14px;
|
||||
background: var(--cims-g50);
|
||||
border-left: 3px solid var(--cims-cyan);
|
||||
border-radius: 4px;
|
||||
font-size: 12px;
|
||||
color: var(--cims-g700);
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
/* TABLE */
|
||||
.cims-tbl-wrap {
|
||||
border: 1px solid var(--cims-g200);
|
||||
border-radius: 8px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.cims-tbl {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
|
||||
th {
|
||||
text-align: left;
|
||||
padding: 10px 14px;
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
color: var(--cims-g500);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
background: var(--cims-g50);
|
||||
border-bottom: 1px solid var(--cims-g200);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
td {
|
||||
padding: 10px 14px;
|
||||
border-bottom: 1px solid var(--cims-g100);
|
||||
font-size: 13px;
|
||||
color: var(--cims-g700);
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
tr:last-child td {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
tr:hover td {
|
||||
background: var(--cims-g50);
|
||||
}
|
||||
}
|
||||
|
||||
.cell-ref {
|
||||
color: var(--cims-cyan);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.unit-pill {
|
||||
display: inline-block;
|
||||
padding: 2px 8px;
|
||||
border-radius: 6px;
|
||||
background: var(--cims-teal-l);
|
||||
color: var(--cims-teal);
|
||||
font-family: 'DM Mono', monospace;
|
||||
font-size: 10px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.ta-c {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.ta-r {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.mono {
|
||||
font-family: 'DM Mono', monospace;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.muted {
|
||||
color: var(--cims-g500);
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
/* VALIDATION BANNER */
|
||||
.cims-validation {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 12px 16px;
|
||||
border-radius: 8px;
|
||||
margin-bottom: 12px;
|
||||
|
||||
fa-icon {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
&.valid {
|
||||
background: var(--cims-good-l);
|
||||
color: var(--cims-good);
|
||||
}
|
||||
|
||||
&.warning {
|
||||
background: var(--cims-mid-l);
|
||||
color: var(--cims-mid);
|
||||
}
|
||||
}
|
||||
|
||||
.cims-val-t {
|
||||
font-size: 13px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.cims-val-d {
|
||||
font-size: 11px;
|
||||
margin-top: 2px;
|
||||
opacity: 0.85;
|
||||
}
|
||||
|
||||
/* XBRL PREVIEW */
|
||||
.xbrl-preview {
|
||||
background: #0f172a;
|
||||
color: #e2e8f0;
|
||||
padding: 16px;
|
||||
border-radius: 8px;
|
||||
font-family: 'DM Mono', 'Cascadia Code', monospace;
|
||||
font-size: 11.5px;
|
||||
line-height: 1.6;
|
||||
overflow: auto;
|
||||
max-height: 480px;
|
||||
margin: 0;
|
||||
white-space: pre;
|
||||
border: 1px solid var(--cims-g200);
|
||||
|
||||
code {
|
||||
font-family: inherit;
|
||||
background: transparent;
|
||||
color: inherit;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* FOOTER */
|
||||
.cims-foot {
|
||||
padding: 12px 22px;
|
||||
border-top: 1px solid var(--cims-g200);
|
||||
background: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 12px;
|
||||
flex-shrink: 0;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.cims-foot-l {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
font-size: 12px;
|
||||
color: var(--cims-g500);
|
||||
|
||||
fa-icon {
|
||||
color: var(--cims-cyan);
|
||||
}
|
||||
}
|
||||
|
||||
.cims-foot-actions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
/* RESPONSIVE */
|
||||
@media (width <= 1100px) {
|
||||
.cims-info-grid {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
@media (width <= 720px) {
|
||||
.cims-info-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.cims-head,
|
||||
.cims-form-bar,
|
||||
.cims-foot {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,840 @@
|
||||
/**
|
||||
* 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, inject } from '@angular/core';
|
||||
import { CommonModule, DecimalPipe } from '@angular/common';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef, MatDialogModule } from '@angular/material/dialog';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
|
||||
|
||||
export type CimsFormCode = 'OSS-2' | 'PSA' | 'RAL' | 'RCP-UCB';
|
||||
|
||||
export interface CimsXbrlDialogData {
|
||||
initialForm?: CimsFormCode;
|
||||
}
|
||||
|
||||
interface CimsField {
|
||||
ref: string;
|
||||
label: string;
|
||||
section: string;
|
||||
value: number | string;
|
||||
unit?: 'INR-Lakh' | 'INR-Cr' | 'Pure' | 'Percent' | 'Number';
|
||||
type?: 'monetary' | 'numeric' | 'string' | 'percent';
|
||||
}
|
||||
|
||||
interface CimsForm {
|
||||
code: CimsFormCode;
|
||||
name: string;
|
||||
fullName: string;
|
||||
description: string;
|
||||
cimsCode: string;
|
||||
taxonomy: string;
|
||||
periodicity: 'Daily' | 'Monthly' | 'Quarterly' | 'Half-Yearly' | 'Annual';
|
||||
lastFiled: string;
|
||||
nextDue: string;
|
||||
fields: CimsField[];
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'mifosx-cims-xbrl-dialog',
|
||||
standalone: true,
|
||||
templateUrl: './cims-xbrl-dialog.component.html',
|
||||
styleUrls: ['./cims-xbrl-dialog.component.scss'],
|
||||
imports: [
|
||||
CommonModule,
|
||||
DecimalPipe,
|
||||
FormsModule,
|
||||
MatDialogModule,
|
||||
MatButtonModule,
|
||||
MatTooltipModule,
|
||||
FaIconComponent
|
||||
]
|
||||
})
|
||||
export class CimsXbrlDialogComponent {
|
||||
private dialogRef = inject(MatDialogRef<CimsXbrlDialogComponent>);
|
||||
|
||||
activeForm: CimsFormCode;
|
||||
activeTab: 'filing' | 'data' | 'preview' = 'filing';
|
||||
|
||||
bank = {
|
||||
name: 'Bharat Urban Bank Ltd',
|
||||
branch: 'Head Office',
|
||||
bsrCode: 'BUBL0000123',
|
||||
ifsc: 'BUBL0000123',
|
||||
legalEntityId: 'BUBL-LEI-2025',
|
||||
pan: 'AAACB1234L',
|
||||
asOnDate: '31-03-2026',
|
||||
quarter: 'Q4 FY 2025-26',
|
||||
fiscalYear: '2025-26',
|
||||
principalOfficer: 'Karthik Kamath',
|
||||
poDesignation: 'Chief Compliance Officer',
|
||||
poEmail: 'compliance@bharaturbanbank.in',
|
||||
poMobile: '+91-9988002211',
|
||||
cimsUserId: 'BUBL_CIMS_001',
|
||||
cimsPortal: 'https://cims.rbi.org.in/'
|
||||
};
|
||||
|
||||
forms: Record<CimsFormCode, CimsForm> = {
|
||||
'OSS-2': {
|
||||
code: 'OSS-2',
|
||||
name: 'OSS-2',
|
||||
fullName: 'Off-site Surveillance — Statement of Asset Quality & Capital Adequacy',
|
||||
description: 'Quarterly return on asset classification, NPA, capital adequacy and profitability indicators.',
|
||||
cimsCode: 'CIMS_OSS_002',
|
||||
taxonomy: 'rbi-cims-oss-2024-04-01',
|
||||
periodicity: 'Quarterly',
|
||||
lastFiled: '15-01-2026',
|
||||
nextDue: '15-04-2026',
|
||||
fields: [
|
||||
{
|
||||
ref: 'oss2:CapAdq.CRAR',
|
||||
section: 'Capital Adequacy',
|
||||
label: 'CRAR (Total)',
|
||||
value: 14.82,
|
||||
unit: 'Percent',
|
||||
type: 'percent'
|
||||
},
|
||||
{
|
||||
ref: 'oss2:CapAdq.Tier1',
|
||||
section: 'Capital Adequacy',
|
||||
label: 'Tier-I CRAR',
|
||||
value: 12.18,
|
||||
unit: 'Percent',
|
||||
type: 'percent'
|
||||
},
|
||||
{
|
||||
ref: 'oss2:CapAdq.Tier2',
|
||||
section: 'Capital Adequacy',
|
||||
label: 'Tier-II CRAR',
|
||||
value: 2.64,
|
||||
unit: 'Percent',
|
||||
type: 'percent'
|
||||
},
|
||||
{
|
||||
ref: 'oss2:Asset.Total',
|
||||
section: 'Asset Classification',
|
||||
label: 'Total Advances (₹ Lakh)',
|
||||
value: 416265,
|
||||
unit: 'INR-Lakh',
|
||||
type: 'monetary'
|
||||
},
|
||||
{
|
||||
ref: 'oss2:Asset.Standard',
|
||||
section: 'Asset Classification',
|
||||
label: 'Standard Assets (₹ Lakh)',
|
||||
value: 401820,
|
||||
unit: 'INR-Lakh',
|
||||
type: 'monetary'
|
||||
},
|
||||
{
|
||||
ref: 'oss2:Asset.SubStd',
|
||||
section: 'Asset Classification',
|
||||
label: 'Sub-Standard (₹ Lakh)',
|
||||
value: 6220,
|
||||
unit: 'INR-Lakh',
|
||||
type: 'monetary'
|
||||
},
|
||||
{
|
||||
ref: 'oss2:Asset.Doubtful',
|
||||
section: 'Asset Classification',
|
||||
label: 'Doubtful (₹ Lakh)',
|
||||
value: 5840,
|
||||
unit: 'INR-Lakh',
|
||||
type: 'monetary'
|
||||
},
|
||||
{
|
||||
ref: 'oss2:Asset.Loss',
|
||||
section: 'Asset Classification',
|
||||
label: 'Loss (₹ Lakh)',
|
||||
value: 2385,
|
||||
unit: 'INR-Lakh',
|
||||
type: 'monetary'
|
||||
},
|
||||
{
|
||||
ref: 'oss2:Asset.GNPA',
|
||||
section: 'NPA Position',
|
||||
label: 'Gross NPA (₹ Lakh)',
|
||||
value: 14445,
|
||||
unit: 'INR-Lakh',
|
||||
type: 'monetary'
|
||||
},
|
||||
{
|
||||
ref: 'oss2:Asset.NNPA',
|
||||
section: 'NPA Position',
|
||||
label: 'Net NPA (₹ Lakh)',
|
||||
value: 5212,
|
||||
unit: 'INR-Lakh',
|
||||
type: 'monetary'
|
||||
},
|
||||
{
|
||||
ref: 'oss2:Asset.GNPAPct',
|
||||
section: 'NPA Position',
|
||||
label: 'GNPA %',
|
||||
value: 3.47,
|
||||
unit: 'Percent',
|
||||
type: 'percent'
|
||||
},
|
||||
{
|
||||
ref: 'oss2:Asset.NNPAPct',
|
||||
section: 'NPA Position',
|
||||
label: 'NNPA %',
|
||||
value: 1.27,
|
||||
unit: 'Percent',
|
||||
type: 'percent'
|
||||
},
|
||||
{
|
||||
ref: 'oss2:Asset.PCR',
|
||||
section: 'NPA Position',
|
||||
label: 'Provision Coverage Ratio',
|
||||
value: 64.13,
|
||||
unit: 'Percent',
|
||||
type: 'percent'
|
||||
},
|
||||
{
|
||||
ref: 'oss2:Profit.NIM',
|
||||
section: 'Profitability',
|
||||
label: 'Net Interest Margin',
|
||||
value: 3.21,
|
||||
unit: 'Percent',
|
||||
type: 'percent'
|
||||
},
|
||||
{
|
||||
ref: 'oss2:Profit.ROA',
|
||||
section: 'Profitability',
|
||||
label: 'Return on Assets',
|
||||
value: 0.92,
|
||||
unit: 'Percent',
|
||||
type: 'percent'
|
||||
},
|
||||
{
|
||||
ref: 'oss2:Profit.ROE',
|
||||
section: 'Profitability',
|
||||
label: 'Return on Equity',
|
||||
value: 11.48,
|
||||
unit: 'Percent',
|
||||
type: 'percent'
|
||||
},
|
||||
{
|
||||
ref: 'oss2:Liq.CRR',
|
||||
section: 'Liquidity',
|
||||
label: 'CRR Maintained',
|
||||
value: 4.52,
|
||||
unit: 'Percent',
|
||||
type: 'percent'
|
||||
},
|
||||
{
|
||||
ref: 'oss2:Liq.SLR',
|
||||
section: 'Liquidity',
|
||||
label: 'SLR Maintained',
|
||||
value: 19.24,
|
||||
unit: 'Percent',
|
||||
type: 'percent'
|
||||
}
|
||||
]
|
||||
},
|
||||
PSA: {
|
||||
code: 'PSA',
|
||||
name: 'PSA',
|
||||
fullName: 'Priority Sector Advances — Annual Achievement Statement',
|
||||
description: 'Annual return on priority sector lending, sub-targets and weaker section coverage.',
|
||||
cimsCode: 'CIMS_PSA_001',
|
||||
taxonomy: 'rbi-cims-psa-2024-04-01',
|
||||
periodicity: 'Annual',
|
||||
lastFiled: '30-04-2025',
|
||||
nextDue: '30-04-2026',
|
||||
fields: [
|
||||
{
|
||||
ref: 'psa:Reference.ANBC',
|
||||
section: 'Reference',
|
||||
label: 'Adjusted Net Bank Credit (₹ Lakh)',
|
||||
value: 600000,
|
||||
unit: 'INR-Lakh',
|
||||
type: 'monetary'
|
||||
},
|
||||
{
|
||||
ref: 'psa:Reference.OBE',
|
||||
section: 'Reference',
|
||||
label: 'Credit Equivalent of OBE (₹ Lakh)',
|
||||
value: 25000,
|
||||
unit: 'INR-Lakh',
|
||||
type: 'monetary'
|
||||
},
|
||||
{
|
||||
ref: 'psa:PSL.Total',
|
||||
section: 'PSL Achievement',
|
||||
label: 'Total PSL Outstanding (₹ Lakh)',
|
||||
value: 241700,
|
||||
unit: 'INR-Lakh',
|
||||
type: 'monetary'
|
||||
},
|
||||
{
|
||||
ref: 'psa:PSL.TotalPct',
|
||||
section: 'PSL Achievement',
|
||||
label: 'Total PSL % of ANBC',
|
||||
value: 40.28,
|
||||
unit: 'Percent',
|
||||
type: 'percent'
|
||||
},
|
||||
{
|
||||
ref: 'psa:PSL.Agri',
|
||||
section: 'Sub-targets',
|
||||
label: 'Agriculture (₹ Lakh)',
|
||||
value: 124000,
|
||||
unit: 'INR-Lakh',
|
||||
type: 'monetary'
|
||||
},
|
||||
{
|
||||
ref: 'psa:PSL.AgriPct',
|
||||
section: 'Sub-targets',
|
||||
label: 'Agriculture % of ANBC',
|
||||
value: 20.67,
|
||||
unit: 'Percent',
|
||||
type: 'percent'
|
||||
},
|
||||
{
|
||||
ref: 'psa:PSL.SMF',
|
||||
section: 'Sub-targets',
|
||||
label: 'Small & Marginal Farmers (₹ Lakh)',
|
||||
value: 72000,
|
||||
unit: 'INR-Lakh',
|
||||
type: 'monetary'
|
||||
},
|
||||
{
|
||||
ref: 'psa:PSL.SMFPct',
|
||||
section: 'Sub-targets',
|
||||
label: 'SMF % of ANBC',
|
||||
value: 12.0,
|
||||
unit: 'Percent',
|
||||
type: 'percent'
|
||||
},
|
||||
{
|
||||
ref: 'psa:PSL.MicroEnt',
|
||||
section: 'Sub-targets',
|
||||
label: 'Micro Enterprises (₹ Lakh)',
|
||||
value: 51000,
|
||||
unit: 'INR-Lakh',
|
||||
type: 'monetary'
|
||||
},
|
||||
{
|
||||
ref: 'psa:PSL.MicroPct',
|
||||
section: 'Sub-targets',
|
||||
label: 'Micro Enterprises % of ANBC',
|
||||
value: 8.5,
|
||||
unit: 'Percent',
|
||||
type: 'percent'
|
||||
},
|
||||
{
|
||||
ref: 'psa:PSL.Weaker',
|
||||
section: 'Sub-targets',
|
||||
label: 'Weaker Sections (₹ Lakh)',
|
||||
value: 85500,
|
||||
unit: 'INR-Lakh',
|
||||
type: 'monetary'
|
||||
},
|
||||
{
|
||||
ref: 'psa:PSL.WeakerPct',
|
||||
section: 'Sub-targets',
|
||||
label: 'Weaker Sections % of ANBC',
|
||||
value: 14.25,
|
||||
unit: 'Percent',
|
||||
type: 'percent'
|
||||
},
|
||||
{
|
||||
ref: 'psa:PSL.Housing',
|
||||
section: 'Other Categories',
|
||||
label: 'Housing (₹ Lakh)',
|
||||
value: 9200,
|
||||
unit: 'INR-Lakh',
|
||||
type: 'monetary'
|
||||
},
|
||||
{
|
||||
ref: 'psa:PSL.Education',
|
||||
section: 'Other Categories',
|
||||
label: 'Education (₹ Lakh)',
|
||||
value: 4200,
|
||||
unit: 'INR-Lakh',
|
||||
type: 'monetary'
|
||||
},
|
||||
{
|
||||
ref: 'psa:PSL.Export',
|
||||
section: 'Other Categories',
|
||||
label: 'Export Credit (₹ Lakh)',
|
||||
value: 3800,
|
||||
unit: 'INR-Lakh',
|
||||
type: 'monetary'
|
||||
},
|
||||
{
|
||||
ref: 'psa:PSL.RenEnergy',
|
||||
section: 'Other Categories',
|
||||
label: 'Renewable Energy (₹ Lakh)',
|
||||
value: 2400,
|
||||
unit: 'INR-Lakh',
|
||||
type: 'monetary'
|
||||
}
|
||||
]
|
||||
},
|
||||
RAL: {
|
||||
code: 'RAL',
|
||||
name: 'RAL',
|
||||
fullName: 'Return on Assets & Liabilities (Half-Yearly)',
|
||||
description: 'Half-yearly statement of bank-wide assets and liabilities composition for cooperative banks.',
|
||||
cimsCode: 'CIMS_RAL_004',
|
||||
taxonomy: 'rbi-cims-ral-2024-04-01',
|
||||
periodicity: 'Half-Yearly',
|
||||
lastFiled: '30-10-2025',
|
||||
nextDue: '30-04-2026',
|
||||
fields: [
|
||||
{
|
||||
ref: 'ral:Liab.Capital',
|
||||
section: 'Liabilities',
|
||||
label: 'Capital (₹ Lakh)',
|
||||
value: 22000,
|
||||
unit: 'INR-Lakh',
|
||||
type: 'monetary'
|
||||
},
|
||||
{
|
||||
ref: 'ral:Liab.Reserves',
|
||||
section: 'Liabilities',
|
||||
label: 'Reserves & Surplus (₹ Lakh)',
|
||||
value: 32400,
|
||||
unit: 'INR-Lakh',
|
||||
type: 'monetary'
|
||||
},
|
||||
{
|
||||
ref: 'ral:Liab.DepDemand',
|
||||
section: 'Liabilities',
|
||||
label: 'Demand Deposits (₹ Lakh)',
|
||||
value: 84200,
|
||||
unit: 'INR-Lakh',
|
||||
type: 'monetary'
|
||||
},
|
||||
{
|
||||
ref: 'ral:Liab.DepSavings',
|
||||
section: 'Liabilities',
|
||||
label: 'Savings Deposits (₹ Lakh)',
|
||||
value: 218600,
|
||||
unit: 'INR-Lakh',
|
||||
type: 'monetary'
|
||||
},
|
||||
{
|
||||
ref: 'ral:Liab.DepTerm',
|
||||
section: 'Liabilities',
|
||||
label: 'Term Deposits (₹ Lakh)',
|
||||
value: 462800,
|
||||
unit: 'INR-Lakh',
|
||||
type: 'monetary'
|
||||
},
|
||||
{
|
||||
ref: 'ral:Liab.Borrow',
|
||||
section: 'Liabilities',
|
||||
label: 'Borrowings (₹ Lakh)',
|
||||
value: 24180,
|
||||
unit: 'INR-Lakh',
|
||||
type: 'monetary'
|
||||
},
|
||||
{
|
||||
ref: 'ral:Liab.Other',
|
||||
section: 'Liabilities',
|
||||
label: 'Other Liabilities & Provisions (₹ Lakh)',
|
||||
value: 18420,
|
||||
unit: 'INR-Lakh',
|
||||
type: 'monetary'
|
||||
},
|
||||
{
|
||||
ref: 'ral:Asset.Cash',
|
||||
section: 'Assets',
|
||||
label: 'Cash on Hand (₹ Lakh)',
|
||||
value: 8420,
|
||||
unit: 'INR-Lakh',
|
||||
type: 'monetary'
|
||||
},
|
||||
{
|
||||
ref: 'ral:Asset.RBI',
|
||||
section: 'Assets',
|
||||
label: 'Balances with RBI (₹ Lakh)',
|
||||
value: 38400,
|
||||
unit: 'INR-Lakh',
|
||||
type: 'monetary'
|
||||
},
|
||||
{
|
||||
ref: 'ral:Asset.Banks',
|
||||
section: 'Assets',
|
||||
label: 'Balances with Banks (₹ Lakh)',
|
||||
value: 24800,
|
||||
unit: 'INR-Lakh',
|
||||
type: 'monetary'
|
||||
},
|
||||
{
|
||||
ref: 'ral:Asset.Money',
|
||||
section: 'Assets',
|
||||
label: 'Money at Call & Short Notice (₹ Lakh)',
|
||||
value: 12400,
|
||||
unit: 'INR-Lakh',
|
||||
type: 'monetary'
|
||||
},
|
||||
{
|
||||
ref: 'ral:Asset.Invest',
|
||||
section: 'Assets',
|
||||
label: 'Investments (₹ Lakh)',
|
||||
value: 184600,
|
||||
unit: 'INR-Lakh',
|
||||
type: 'monetary'
|
||||
},
|
||||
{
|
||||
ref: 'ral:Asset.Adv',
|
||||
section: 'Assets',
|
||||
label: 'Advances (₹ Lakh)',
|
||||
value: 416265,
|
||||
unit: 'INR-Lakh',
|
||||
type: 'monetary'
|
||||
},
|
||||
{
|
||||
ref: 'ral:Asset.Fixed',
|
||||
section: 'Assets',
|
||||
label: 'Fixed Assets (₹ Lakh)',
|
||||
value: 14200,
|
||||
unit: 'INR-Lakh',
|
||||
type: 'monetary'
|
||||
},
|
||||
{
|
||||
ref: 'ral:Asset.Other',
|
||||
section: 'Assets',
|
||||
label: 'Other Assets (₹ Lakh)',
|
||||
value: 12480,
|
||||
unit: 'INR-Lakh',
|
||||
type: 'monetary'
|
||||
},
|
||||
{
|
||||
ref: 'ral:OBE.Guar',
|
||||
section: 'Off-Balance Sheet',
|
||||
label: 'Bank Guarantees (₹ Lakh)',
|
||||
value: 18420,
|
||||
unit: 'INR-Lakh',
|
||||
type: 'monetary'
|
||||
},
|
||||
{
|
||||
ref: 'ral:OBE.LC',
|
||||
section: 'Off-Balance Sheet',
|
||||
label: 'Letters of Credit (₹ Lakh)',
|
||||
value: 6580,
|
||||
unit: 'INR-Lakh',
|
||||
type: 'monetary'
|
||||
}
|
||||
]
|
||||
},
|
||||
'RCP-UCB': {
|
||||
code: 'RCP-UCB',
|
||||
name: 'RCP (UCB)',
|
||||
fullName: 'Return on Cash Position — Urban Cooperative Banks',
|
||||
description: 'Fortnightly statement of CRR/SLR maintenance, NDTL composition and reserve position.',
|
||||
cimsCode: 'CIMS_RCP_UCB_007',
|
||||
taxonomy: 'rbi-cims-rcp-ucb-2024-04-01',
|
||||
periodicity: 'Monthly',
|
||||
lastFiled: '14-04-2026',
|
||||
nextDue: '28-04-2026',
|
||||
fields: [
|
||||
{
|
||||
ref: 'rcp:Liab.DemandDep',
|
||||
section: 'NDTL Composition',
|
||||
label: 'Demand Liabilities (₹ Lakh)',
|
||||
value: 84200,
|
||||
unit: 'INR-Lakh',
|
||||
type: 'monetary'
|
||||
},
|
||||
{
|
||||
ref: 'rcp:Liab.TimeDep',
|
||||
section: 'NDTL Composition',
|
||||
label: 'Time Liabilities (₹ Lakh)',
|
||||
value: 681400,
|
||||
unit: 'INR-Lakh',
|
||||
type: 'monetary'
|
||||
},
|
||||
{
|
||||
ref: 'rcp:Liab.NDTL',
|
||||
section: 'NDTL Composition',
|
||||
label: 'Net Demand & Time Liabilities (NDTL)',
|
||||
value: 740000,
|
||||
unit: 'INR-Lakh',
|
||||
type: 'monetary'
|
||||
},
|
||||
{
|
||||
ref: 'rcp:CRR.Required',
|
||||
section: 'CRR Maintenance',
|
||||
label: 'CRR Required (4.5%)',
|
||||
value: 33300,
|
||||
unit: 'INR-Lakh',
|
||||
type: 'monetary'
|
||||
},
|
||||
{
|
||||
ref: 'rcp:CRR.Maintained',
|
||||
section: 'CRR Maintenance',
|
||||
label: 'CRR Maintained (avg)',
|
||||
value: 33448,
|
||||
unit: 'INR-Lakh',
|
||||
type: 'monetary'
|
||||
},
|
||||
{
|
||||
ref: 'rcp:CRR.MaintainedPct',
|
||||
section: 'CRR Maintenance',
|
||||
label: 'CRR % Maintained',
|
||||
value: 4.52,
|
||||
unit: 'Percent',
|
||||
type: 'percent'
|
||||
},
|
||||
{
|
||||
ref: 'rcp:CRR.Surplus',
|
||||
section: 'CRR Maintenance',
|
||||
label: 'CRR Surplus / Shortfall (₹ Lakh)',
|
||||
value: 148,
|
||||
unit: 'INR-Lakh',
|
||||
type: 'monetary'
|
||||
},
|
||||
{
|
||||
ref: 'rcp:SLR.Required',
|
||||
section: 'SLR Maintenance',
|
||||
label: 'SLR Required (18%)',
|
||||
value: 133200,
|
||||
unit: 'INR-Lakh',
|
||||
type: 'monetary'
|
||||
},
|
||||
{
|
||||
ref: 'rcp:SLR.Maintained',
|
||||
section: 'SLR Maintenance',
|
||||
label: 'SLR Maintained (avg)',
|
||||
value: 142376,
|
||||
unit: 'INR-Lakh',
|
||||
type: 'monetary'
|
||||
},
|
||||
{
|
||||
ref: 'rcp:SLR.MaintainedPct',
|
||||
section: 'SLR Maintenance',
|
||||
label: 'SLR % Maintained',
|
||||
value: 19.24,
|
||||
unit: 'Percent',
|
||||
type: 'percent'
|
||||
},
|
||||
{
|
||||
ref: 'rcp:SLR.Surplus',
|
||||
section: 'SLR Maintenance',
|
||||
label: 'SLR Surplus / Shortfall (₹ Lakh)',
|
||||
value: 9176,
|
||||
unit: 'INR-Lakh',
|
||||
type: 'monetary'
|
||||
},
|
||||
{
|
||||
ref: 'rcp:Cash.OnHand',
|
||||
section: 'Cash Position',
|
||||
label: 'Cash on Hand (₹ Lakh)',
|
||||
value: 8420,
|
||||
unit: 'INR-Lakh',
|
||||
type: 'monetary'
|
||||
},
|
||||
{
|
||||
ref: 'rcp:Cash.AtRBI',
|
||||
section: 'Cash Position',
|
||||
label: 'Cash at RBI (₹ Lakh)',
|
||||
value: 33448,
|
||||
unit: 'INR-Lakh',
|
||||
type: 'monetary'
|
||||
},
|
||||
{
|
||||
ref: 'rcp:Cash.AtBanks',
|
||||
section: 'Cash Position',
|
||||
label: 'Cash at other Banks (₹ Lakh)',
|
||||
value: 24800,
|
||||
unit: 'INR-Lakh',
|
||||
type: 'monetary'
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
formCodes: CimsFormCode[] = [
|
||||
'OSS-2',
|
||||
'PSA',
|
||||
'RAL',
|
||||
'RCP-UCB'
|
||||
];
|
||||
|
||||
data = inject<CimsXbrlDialogData | null>(MAT_DIALOG_DATA, { optional: true });
|
||||
|
||||
constructor() {
|
||||
this.activeForm = this.data?.initialForm ?? 'OSS-2';
|
||||
}
|
||||
|
||||
get currentForm(): CimsForm {
|
||||
return this.forms[this.activeForm];
|
||||
}
|
||||
|
||||
get sections(): string[] {
|
||||
const s: string[] = [];
|
||||
for (const f of this.currentForm.fields) {
|
||||
if (!s.includes(f.section)) s.push(f.section);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
fieldsBySection(section: string): CimsField[] {
|
||||
return this.currentForm.fields.filter((f) => f.section === section);
|
||||
}
|
||||
|
||||
setForm(code: CimsFormCode): void {
|
||||
this.activeForm = code;
|
||||
this.activeTab = 'filing';
|
||||
}
|
||||
setTab(tab: 'filing' | 'data' | 'preview'): void {
|
||||
this.activeTab = tab;
|
||||
}
|
||||
close(): void {
|
||||
this.dialogRef.close();
|
||||
}
|
||||
|
||||
/** Format a number for XBRL output (no commas, 2 dp for monetary/percent) */
|
||||
private fmtXbrl(f: CimsField): string {
|
||||
if (typeof f.value === 'string') return f.value;
|
||||
if (f.type === 'monetary' || f.type === 'percent') return f.value.toFixed(2);
|
||||
return f.value.toString();
|
||||
}
|
||||
|
||||
/** Build XBRL XML document for a form (representative; real CIMS taxonomy differs) */
|
||||
generateXbrlXml(): string {
|
||||
const f = this.currentForm;
|
||||
const period = `${this.bank.fiscalYear} (${this.bank.quarter})`;
|
||||
const ctxId = `ctx_${f.code.replace('-', '_')}`;
|
||||
const startDate = '2026-01-01';
|
||||
const endDate = '2026-03-31';
|
||||
const lines: string[] = [];
|
||||
lines.push('<?xml version="1.0" encoding="UTF-8"?>');
|
||||
lines.push('<xbrl');
|
||||
lines.push(' xmlns="http://www.xbrl.org/2003/instance"');
|
||||
lines.push(' xmlns:link="http://www.xbrl.org/2003/linkbase"');
|
||||
lines.push(' xmlns:xbrli="http://www.xbrl.org/2003/instance"');
|
||||
lines.push(' xmlns:iso4217="http://www.xbrl.org/2003/iso4217"');
|
||||
lines.push(' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"');
|
||||
lines.push(` xmlns:${f.code.replace('-', '').toLowerCase()}="${f.taxonomy}">`);
|
||||
lines.push(` <link:schemaRef xlink:type="simple" xlink:href="${f.taxonomy}.xsd"/>`);
|
||||
lines.push(` <!-- Period: ${period} -->`);
|
||||
lines.push(` <context id="${ctxId}">`);
|
||||
lines.push(' <entity>');
|
||||
lines.push(` <identifier scheme="http://www.rbi.org.in/cims">${this.bank.legalEntityId}</identifier>`);
|
||||
lines.push(' </entity>');
|
||||
lines.push(' <period>');
|
||||
lines.push(` <startDate>${startDate}</startDate>`);
|
||||
lines.push(` <endDate>${endDate}</endDate>`);
|
||||
lines.push(' </period>');
|
||||
lines.push(' </context>');
|
||||
lines.push(' <unit id="INR_Lakh"><measure>iso4217:INR</measure></unit>');
|
||||
lines.push(' <unit id="Pure"><measure>xbrli:pure</measure></unit>');
|
||||
lines.push(' <!-- Filing -->');
|
||||
lines.push(` <cims:bankName contextRef="${ctxId}">${this.bank.name}</cims:bankName>`);
|
||||
lines.push(` <cims:bsrCode contextRef="${ctxId}">${this.bank.bsrCode}</cims:bsrCode>`);
|
||||
lines.push(` <cims:cimsFormCode contextRef="${ctxId}">${f.cimsCode}</cims:cimsFormCode>`);
|
||||
lines.push(' <!-- Facts -->');
|
||||
for (const fld of f.fields) {
|
||||
const unitRef = fld.type === 'monetary' ? 'INR_Lakh' : 'Pure';
|
||||
const decimals = fld.type === 'monetary' || fld.type === 'percent' ? '2' : '0';
|
||||
lines.push(
|
||||
` <${fld.ref} contextRef="${ctxId}" unitRef="${unitRef}" decimals="${decimals}">${this.fmtXbrl(
|
||||
fld
|
||||
)}</${fld.ref}>`
|
||||
);
|
||||
}
|
||||
lines.push('</xbrl>');
|
||||
return lines.join('\n');
|
||||
}
|
||||
|
||||
/** Validation summary — counts fields, flags any zero/missing */
|
||||
get validation(): { total: number; populated: number; empty: number; status: 'valid' | 'warning' } {
|
||||
const fields = this.currentForm.fields;
|
||||
const populated = fields.filter((f) => f.value !== '' && f.value !== 0).length;
|
||||
const empty = fields.length - populated;
|
||||
return {
|
||||
total: fields.length,
|
||||
populated,
|
||||
empty,
|
||||
status: empty === 0 ? 'valid' : 'warning'
|
||||
};
|
||||
}
|
||||
|
||||
// -------------------- Exports --------------------
|
||||
exportXbrl(): void {
|
||||
const xml = this.generateXbrlXml();
|
||||
this.saveBlob(xml, `${this.currentForm.cimsCode}-${this.dateTag()}.xml`, 'application/xml');
|
||||
}
|
||||
copyXbrl(): void {
|
||||
const xml = this.generateXbrlXml();
|
||||
if (navigator.clipboard) navigator.clipboard.writeText(xml);
|
||||
}
|
||||
exportExcel(): void {
|
||||
const f = this.currentForm;
|
||||
const rows: string[][] = [];
|
||||
rows.push([
|
||||
this.bank.name,
|
||||
this.bank.branch
|
||||
]);
|
||||
rows.push([
|
||||
f.fullName,
|
||||
`As On ${this.bank.asOnDate}`
|
||||
]);
|
||||
rows.push([
|
||||
`CIMS Code: ${f.cimsCode}`,
|
||||
`Taxonomy: ${f.taxonomy}`
|
||||
]);
|
||||
rows.push([
|
||||
`Periodicity: ${f.periodicity}`,
|
||||
`Quarter: ${this.bank.quarter}`
|
||||
]);
|
||||
rows.push([
|
||||
`Principal Officer: ${this.bank.principalOfficer}`,
|
||||
`Email: ${this.bank.poEmail}`
|
||||
]);
|
||||
rows.push([]);
|
||||
rows.push([
|
||||
'Section',
|
||||
'Element Ref',
|
||||
'Label',
|
||||
'Value',
|
||||
'Unit'
|
||||
]);
|
||||
for (const fld of f.fields) {
|
||||
rows.push([
|
||||
fld.section,
|
||||
fld.ref,
|
||||
fld.label.replace(/&/g, '&'),
|
||||
this.fmtXbrl(fld),
|
||||
fld.unit ?? ''
|
||||
]);
|
||||
}
|
||||
rows.push([]);
|
||||
rows.push([
|
||||
'Certified by',
|
||||
this.bank.principalOfficer + ' — ' + this.bank.poDesignation
|
||||
]);
|
||||
this.saveTsv(rows, `${f.cimsCode}-${this.dateTag()}.xls`);
|
||||
}
|
||||
|
||||
// ---- helpers ----
|
||||
private dateTag(): string {
|
||||
const d = new Date();
|
||||
return `${String(d.getDate()).padStart(2, '0')}${String(d.getMonth() + 1).padStart(2, '0')}${d.getFullYear()}`;
|
||||
}
|
||||
private saveTsv(rows: string[][], filename: string): void {
|
||||
const tsv = rows.map((r) => r.map((v) => (v || '').replace(/\t/g, ' ')).join('\t')).join('\n');
|
||||
this.saveBlob(tsv, filename, 'application/vnd.ms-excel');
|
||||
}
|
||||
private saveBlob(content: string, filename: string, mime: string): void {
|
||||
const blob = new Blob([content], { type: `${mime};charset=utf-8` });
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = filename;
|
||||
a.click();
|
||||
URL.revokeObjectURL(url);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user