feat(fiu): add Head Office / Branch-wise scoping; remove reconciliation nav dots
FIU: adds a branch selector (Head Office sees all/drills into one branch, a branch-level login is locked to its own branch) scoping the CTR/STR tabs, dashboard KPIs and header. A FIU_BRANCH_CODE_TO_CANONICAL map bridges the module's internal FINnet branch codes to the app-wide BranchMaster codes. Live backend-driven AML alerts/cases are unchanged (no branch field to scope by). Shell: removes the "working nav" green-dot indicator from the Reconciliation mega-menu's 17 report links per request.
This commit is contained in:
@@ -1400,27 +1400,27 @@
|
||||
<!-- Core / Books -->
|
||||
<div class="deposit-menu-group">
|
||||
<div class="deposit-group-title">Core & Books</div>
|
||||
<button mat-menu-item tabindex="0" class="menu-item-live" routerLink="/reconciliation/voucher">
|
||||
<button mat-menu-item tabindex="0" routerLink="/reconciliation/voucher">
|
||||
<fa-icon icon="receipt" class="menu-item-icon" style="color: #0d9488"></fa-icon>
|
||||
Voucher Reconciliation
|
||||
</button>
|
||||
<button mat-menu-item tabindex="0" class="menu-item-live" routerLink="/reconciliation/sundry-dr-cr">
|
||||
<button mat-menu-item tabindex="0" routerLink="/reconciliation/sundry-dr-cr">
|
||||
<fa-icon icon="random" class="menu-item-icon" style="color: #0d9488"></fa-icon>
|
||||
Sundry Dr / Cr Reconciliation
|
||||
</button>
|
||||
<button mat-menu-item tabindex="0" class="menu-item-live" routerLink="/reconciliation/pnl-impact">
|
||||
<button mat-menu-item tabindex="0" routerLink="/reconciliation/pnl-impact">
|
||||
<fa-icon icon="chart-line" class="menu-item-icon" style="color: #0d9488"></fa-icon>
|
||||
P&L Impact Reconciliation
|
||||
</button>
|
||||
<button mat-menu-item tabindex="0" class="menu-item-live" routerLink="/reconciliation/gl-reconciliation">
|
||||
<button mat-menu-item tabindex="0" routerLink="/reconciliation/gl-reconciliation">
|
||||
<fa-icon icon="book-open" class="menu-item-icon" style="color: #0d9488"></fa-icon>
|
||||
GL Reconciliation
|
||||
</button>
|
||||
<button mat-menu-item tabindex="0" class="menu-item-live" routerLink="/reconciliation/fixed-assets">
|
||||
<button mat-menu-item tabindex="0" routerLink="/reconciliation/fixed-assets">
|
||||
<fa-icon icon="cube" class="menu-item-icon" style="color: #0d9488"></fa-icon>
|
||||
Fixed Assets Reconciliation
|
||||
</button>
|
||||
<button mat-menu-item tabindex="0" class="menu-item-live" routerLink="/reconciliation/inter-company">
|
||||
<button mat-menu-item tabindex="0" routerLink="/reconciliation/inter-company">
|
||||
<fa-icon icon="sitemap" class="menu-item-icon" style="color: #0d9488"></fa-icon>
|
||||
Inter-Company Reconciliation
|
||||
</button>
|
||||
@@ -1429,19 +1429,19 @@
|
||||
<!-- Bank & Clearing -->
|
||||
<div class="deposit-menu-group">
|
||||
<div class="deposit-group-title">Bank & Clearing</div>
|
||||
<button mat-menu-item tabindex="0" class="menu-item-live" routerLink="/reconciliation/bank-reco">
|
||||
<button mat-menu-item tabindex="0" routerLink="/reconciliation/bank-reco">
|
||||
<fa-icon icon="university" class="menu-item-icon" style="color: #0d9488"></fa-icon>
|
||||
Bank Reconciliation
|
||||
</button>
|
||||
<button mat-menu-item tabindex="0" class="menu-item-live" routerLink="/reconciliation/api-bank-reco">
|
||||
<button mat-menu-item tabindex="0" routerLink="/reconciliation/api-bank-reco">
|
||||
<fa-icon icon="code-branch" class="menu-item-icon" style="color: #0d9488"></fa-icon>
|
||||
API Based Bank Reconciliation
|
||||
</button>
|
||||
<button mat-menu-item tabindex="0" class="menu-item-live" routerLink="/reconciliation/neft-rtgs">
|
||||
<button mat-menu-item tabindex="0" routerLink="/reconciliation/neft-rtgs">
|
||||
<fa-icon icon="exchange" class="menu-item-icon" style="color: #0d9488"></fa-icon>
|
||||
NEFT / RTGS Reconciliation
|
||||
</button>
|
||||
<button mat-menu-item tabindex="0" class="menu-item-live" routerLink="/reconciliation/clearing-reco">
|
||||
<button mat-menu-item tabindex="0" routerLink="/reconciliation/clearing-reco">
|
||||
<fa-icon icon="hand-holding-usd" class="menu-item-icon" style="color: #0d9488"></fa-icon>
|
||||
Clearing Reconciliation
|
||||
</button>
|
||||
@@ -1450,15 +1450,15 @@
|
||||
<!-- Digital / Payments -->
|
||||
<div class="deposit-menu-group">
|
||||
<div class="deposit-group-title">Digital & Payments</div>
|
||||
<button mat-menu-item tabindex="0" class="menu-item-live" routerLink="/reconciliation/udir">
|
||||
<button mat-menu-item tabindex="0" routerLink="/reconciliation/udir">
|
||||
<fa-icon icon="mobile-alt" class="menu-item-icon" style="color: #0d9488"></fa-icon>
|
||||
UDIR (IMPS / UPI / ATM)
|
||||
</button>
|
||||
<button mat-menu-item tabindex="0" class="menu-item-live" routerLink="/reconciliation/three-way-digital">
|
||||
<button mat-menu-item tabindex="0" routerLink="/reconciliation/three-way-digital">
|
||||
<fa-icon icon="project-diagram" class="menu-item-icon" style="color: #0d9488"></fa-icon>
|
||||
Three-way Digital Reconciliation
|
||||
</button>
|
||||
<button mat-menu-item tabindex="0" class="menu-item-live" routerLink="/reconciliation/nach-reco">
|
||||
<button mat-menu-item tabindex="0" routerLink="/reconciliation/nach-reco">
|
||||
<fa-icon icon="sync-alt" class="menu-item-icon" style="color: #0d9488"></fa-icon>
|
||||
NACH Reconciliation
|
||||
</button>
|
||||
@@ -1467,11 +1467,11 @@
|
||||
<!-- Instruments & Members -->
|
||||
<div class="deposit-menu-group">
|
||||
<div class="deposit-group-title">Instruments & Members</div>
|
||||
<button mat-menu-item [routerLink]="['/sponsor-dd-reconciliation']" tabindex="0" class="menu-item-live">
|
||||
<button mat-menu-item [routerLink]="['/sponsor-dd-reconciliation']" tabindex="0">
|
||||
<fa-icon icon="money-check-alt" class="menu-item-icon" style="color: #0d9488"></fa-icon>
|
||||
DD / Pay Order Reconciliation
|
||||
</button>
|
||||
<button mat-menu-item tabindex="0" class="menu-item-live" routerLink="/reconciliation/share-member">
|
||||
<button mat-menu-item tabindex="0" routerLink="/reconciliation/share-member">
|
||||
<fa-icon icon="coins" class="menu-item-icon" style="color: #0d9488"></fa-icon>
|
||||
Share Member Reconciliation
|
||||
</button>
|
||||
@@ -1480,11 +1480,11 @@
|
||||
<!-- Compliance & Financials -->
|
||||
<div class="deposit-menu-group">
|
||||
<div class="deposit-group-title">Compliance & Financials</div>
|
||||
<button mat-menu-item tabindex="0" class="menu-item-live" routerLink="/reconciliation/invoice-payment">
|
||||
<button mat-menu-item tabindex="0" routerLink="/reconciliation/invoice-payment">
|
||||
<fa-icon icon="file-invoice" class="menu-item-icon" style="color: #0d9488"></fa-icon>
|
||||
Invoice Payment
|
||||
</button>
|
||||
<button mat-menu-item tabindex="0" class="menu-item-live" routerLink="/reconciliation/tax-reco">
|
||||
<button mat-menu-item tabindex="0" routerLink="/reconciliation/tax-reco">
|
||||
<fa-icon icon="percentage" class="menu-item-icon" style="color: #0d9488"></fa-icon>
|
||||
Tax Reconciliation
|
||||
</button>
|
||||
|
||||
@@ -6,6 +6,10 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
import { BRANCHES, BranchMaster } from '../npa/npa-data';
|
||||
|
||||
export { BRANCHES, BranchMaster };
|
||||
|
||||
/**
|
||||
* Sample FIU-IND data — schema mirrors the FINnet 2.0 CSV submission templates
|
||||
* (TC1, TC2, KC1, KC2, Account_Detail, Account_Person_Relation).
|
||||
@@ -155,6 +159,25 @@ export const FIU_BANK = {
|
||||
cbwtrThreshold: 500000 // CBWTR threshold ₹5 L
|
||||
};
|
||||
|
||||
/**
|
||||
* CTR/STR records below use the bank's own internal numeric branch codes (as FINnet's TC2
|
||||
* schema expects), not the app-wide BranchMaster codes (BR01, BR02, ...) every other module
|
||||
* scopes Head-Office-vs-branch access by. This maps one to the other so a branch-level login's
|
||||
* officeName can be matched consistently, the same way NPA/Reconciliation/Loan Origination do.
|
||||
*/
|
||||
export const FIU_BRANCH_CODE_TO_CANONICAL: Record<string, string> = {
|
||||
'1': 'BR01',
|
||||
'2': 'BR02',
|
||||
'3': 'BR03',
|
||||
'4': 'BR04',
|
||||
'5': 'BR05',
|
||||
'6': 'BR06',
|
||||
'8': 'BR07',
|
||||
'9': 'BR08',
|
||||
'10': 'BR02',
|
||||
'12': 'BR04'
|
||||
};
|
||||
|
||||
/**
|
||||
* ── CTR transactions (FINnet TC2-style) ──
|
||||
* Only CASH transactions that breach the RBI/PMLA reporting limit of ₹10,00,000
|
||||
|
||||
@@ -14,12 +14,25 @@
|
||||
<div>
|
||||
<h2 class="fiu-head-t">Financial Intelligence Unit – India (FIU-IND)</h2>
|
||||
<div class="fiu-head-s">
|
||||
{{ bank.name }} · {{ bank.branch }} · Reporting Month <strong>{{ bank.reportingMonth }}</strong>
|
||||
{{ bank.name }} · {{ scopeName }} · Reporting Month <strong>{{ bank.reportingMonth }}</strong>
|
||||
· PMLA 2002 / FINnet 2.0
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="fiu-head-meta">
|
||||
<div>
|
||||
<span class="fiu-meta-l">Branch</span>
|
||||
@if (isHeadOffice) {
|
||||
<select class="fiu-inp" [ngModel]="branchFilter" (ngModelChange)="setBranch($event)">
|
||||
<option value="">All Branches</option>
|
||||
@for (b of branches; track b.code) {
|
||||
<option [value]="b.code">{{ b.name }}</option>
|
||||
}
|
||||
</select>
|
||||
} @else {
|
||||
<span class="fiu-meta-v">{{ scopeName }}</span>
|
||||
}
|
||||
</div>
|
||||
<div>
|
||||
<span class="fiu-meta-l">Principal Officer</span><span class="fiu-meta-v">{{ bank.principalOfficer }}</span>
|
||||
</div>
|
||||
@@ -339,7 +352,9 @@
|
||||
<td>
|
||||
{{ t.instrumentType }} <span class="muted">{{ t.instrumentId }}</span>
|
||||
</td>
|
||||
<td class="mono">{{ t.branchCode }}</td>
|
||||
<td class="mono">
|
||||
{{ t.branchCode }} <span class="muted">{{ branchNameFor(t.branchCode) }}</span>
|
||||
</td>
|
||||
<td class="ta-c">
|
||||
<span class="rel-pill" [class.non-cust]="t.relationshipFlag === 'Non-Customer'">{{
|
||||
t.relationshipFlag
|
||||
@@ -779,6 +794,9 @@
|
||||
<div>
|
||||
<label>Instrument</label><span>{{ s.instrumentType }} {{ s.instrumentId }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<label>Branch</label><span class="mono">{{ s.branchCode }} {{ branchNameFor(s.branchCode) }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="str-narrative">
|
||||
<label>Narrative</label>
|
||||
|
||||
@@ -13,9 +13,12 @@ import { FaIconComponent } from '@fortawesome/angular-fontawesome';
|
||||
import { AmlService } from 'app/aml/aml.service';
|
||||
import { AuthenticationService } from 'app/core/authentication/authentication.service';
|
||||
import {
|
||||
BRANCHES,
|
||||
BranchMaster,
|
||||
CtrTransaction,
|
||||
CTR_TXNS,
|
||||
FIU_BANK,
|
||||
FIU_BRANCH_CODE_TO_CANONICAL,
|
||||
KC1_INDIVIDUALS,
|
||||
KC2_ENTITIES,
|
||||
KycEntity,
|
||||
@@ -51,6 +54,19 @@ export class FiuComponent implements OnInit {
|
||||
kc1: KycIndividual[] = KC1_INDIVIDUALS;
|
||||
kc2: KycEntity[] = KC2_ENTITIES;
|
||||
|
||||
// -------------------- Head Office vs Branch scope --------------------
|
||||
// CTR/STR filing itself is a bank-wide Principal-Officer function (one filing for the whole
|
||||
// bank, not per branch), but the underlying cash transactions a branch's own staff work
|
||||
// (evidence capture, referral) are still branch-attributable — scoped the same way every other
|
||||
// report in the app splits Head Office (sees everything, can drill into one branch) vs a
|
||||
// branch-level login (locked to its own branch).
|
||||
readonly branches = BRANCHES;
|
||||
isHeadOffice = false;
|
||||
currentOfficeName = 'Branch Office';
|
||||
private ownBranchCode: string | null = null;
|
||||
/** '' = All Branches (Head Office consolidated view); otherwise a BranchMaster.code. */
|
||||
branchFilter = '';
|
||||
|
||||
/** CTR filters */
|
||||
ctrFilterMode: '' | 'Deposit' | 'Withdrawal' = '';
|
||||
ctrFilterAccount = '';
|
||||
@@ -223,6 +239,18 @@ export class FiuComponent implements OnInit {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
const creds = this.authenticationService.getCredentials();
|
||||
this.isHeadOffice = this.authenticationService.isHeadOfficeUser();
|
||||
this.currentOfficeName = creds?.officeName || 'Branch Office';
|
||||
if (this.isHeadOffice) {
|
||||
this.branchFilter = '';
|
||||
} else {
|
||||
this.ownBranchCode =
|
||||
this.branches.find((b: BranchMaster) => this.currentOfficeName.toLowerCase().includes(b.name.toLowerCase()))
|
||||
?.code || null;
|
||||
this.branchFilter = this.ownBranchCode || this.branches[0].code;
|
||||
}
|
||||
|
||||
this.loadAmlAlerts();
|
||||
this.loadAmlCtrReports();
|
||||
this.loadAmlStrCases();
|
||||
@@ -614,21 +642,21 @@ export class FiuComponent implements OnInit {
|
||||
|
||||
// -------------------- KPIs --------------------
|
||||
get totalReports(): number {
|
||||
return new Set(this.ctrTxns.map((t) => t.reportRefNo)).size;
|
||||
return new Set(this.scopedCtrTxns.map((t) => t.reportRefNo)).size;
|
||||
}
|
||||
get totalCtrTxns(): number {
|
||||
return this.ctrTxns.length;
|
||||
return this.scopedCtrTxns.length;
|
||||
}
|
||||
get totalCtrAmount(): number {
|
||||
return this.ctrTxns.reduce((s, t) => s + t.txnAmount, 0);
|
||||
return this.scopedCtrTxns.reduce((s, t) => s + t.txnAmount, 0);
|
||||
}
|
||||
get pendingStr(): number {
|
||||
return this.strTxns.filter(
|
||||
return this.scopedStrTxns.filter(
|
||||
(s) => s.status === 'draft' || s.status === 'po-review' || s.status === 'awaiting-filing'
|
||||
).length;
|
||||
}
|
||||
get filedStr(): number {
|
||||
return this.strTxns.filter((s) => s.status === 'filed').length;
|
||||
return this.scopedStrTxns.filter((s) => s.status === 'filed').length;
|
||||
}
|
||||
|
||||
// ── Live STR case counts (backend `amlStrCases`) — these are the cases the
|
||||
@@ -671,10 +699,48 @@ export class FiuComponent implements OnInit {
|
||||
return this.amlAlerts.filter((a) => !ctrRuleCodes.includes(a.ruleCode));
|
||||
}
|
||||
|
||||
// -------------------- Head Office vs Branch scope --------------------
|
||||
/** Maps a FINnet-style internal branch code to the app-wide canonical branch code. */
|
||||
private canonicalBranchOf(branchCode: string): string | undefined {
|
||||
return FIU_BRANCH_CODE_TO_CANONICAL[branchCode];
|
||||
}
|
||||
|
||||
/** Branch name for a row's raw FINnet branch code, for display alongside the code itself. */
|
||||
branchNameFor(branchCode: string): string {
|
||||
const canonical = this.canonicalBranchOf(branchCode);
|
||||
return this.branches.find((b) => b.code === canonical)?.name || '';
|
||||
}
|
||||
|
||||
setBranch(code: string): void {
|
||||
this.branchFilter = code;
|
||||
}
|
||||
|
||||
/** Name of the branch/scope currently being viewed, for display in the header. */
|
||||
get scopeName(): string {
|
||||
if (!this.isHeadOffice) {
|
||||
return this.currentOfficeName;
|
||||
}
|
||||
return this.branchFilter
|
||||
? this.branches.find((b) => b.code === this.branchFilter)?.name || ''
|
||||
: 'All Branches (Consolidated)';
|
||||
}
|
||||
|
||||
get scopedCtrTxns(): CtrTransaction[] {
|
||||
return this.branchFilter
|
||||
? this.ctrTxns.filter((t) => this.canonicalBranchOf(t.branchCode) === this.branchFilter)
|
||||
: this.ctrTxns;
|
||||
}
|
||||
|
||||
get scopedStrTxns(): StrTransaction[] {
|
||||
return this.branchFilter
|
||||
? this.strTxns.filter((s) => this.canonicalBranchOf(s.branchCode) === this.branchFilter)
|
||||
: this.strTxns;
|
||||
}
|
||||
|
||||
// -------------------- Filtered lists --------------------
|
||||
get filteredCtr(): CtrTransaction[] {
|
||||
const acc = this.ctrFilterAccount.trim();
|
||||
return this.ctrTxns.filter((t) => {
|
||||
return this.scopedCtrTxns.filter((t) => {
|
||||
if (this.ctrFilterMode && t.depositOrWithdrawal !== this.ctrFilterMode) return false;
|
||||
if (acc && !t.accountNumber.includes(acc)) return false;
|
||||
if (this.ctrFilterMinAmount > 0 && t.txnAmount < this.ctrFilterMinAmount) return false;
|
||||
@@ -683,7 +749,7 @@ export class FiuComponent implements OnInit {
|
||||
}
|
||||
|
||||
get filteredStr(): StrTransaction[] {
|
||||
return this.strTxns.filter((s) => {
|
||||
return this.scopedStrTxns.filter((s) => {
|
||||
if (this.strFilterStatus && s.status !== this.strFilterStatus) return false;
|
||||
if (this.strFilterRisk && s.riskCategory !== this.strFilterRisk) return false;
|
||||
return true;
|
||||
|
||||
Reference in New Issue
Block a user