feat(aml,risk-review,accounting): update financial activity mapping options, AML flagged transactions filters, and risk review report
This commit is contained in:
@@ -220,13 +220,29 @@ export class FiuComponent implements OnInit {
|
||||
*/
|
||||
sanctionsStrCases: any[] = [];
|
||||
sanctionsStrFilter = '';
|
||||
amlAlertStatusFilter = '';
|
||||
amlReviewNotes: Record<number, string> = {};
|
||||
|
||||
amlCtrReports: any[] = [];
|
||||
ctrGenerateMonth = '';
|
||||
|
||||
amlStrCases: any[] = [];
|
||||
|
||||
/**
|
||||
* The cases still carrying work, which is what "Live" means here.
|
||||
*
|
||||
* <p>
|
||||
* A case that has been filed with FIU-IND is finished: the report is gone, the reference number is on it, and there
|
||||
* is nothing left for the Principal Officer to do. Leaving it in the live queue is how a working list stops being
|
||||
* one — every filed case stays on it for good, and an officer opening the tab has to tell the outstanding work from
|
||||
* the closed by reading a status column. Filed cases are listed below, where they can still be looked up.
|
||||
*/
|
||||
get liveStrCases(): any[] {
|
||||
return this.amlStrCases.filter((c) => c?.status !== 'FILED');
|
||||
}
|
||||
|
||||
/** Cases already filed with FIU-IND, kept for the record rather than as work. */
|
||||
get filedStrCases(): any[] {
|
||||
return this.amlStrCases.filter((c) => c?.status === 'FILED');
|
||||
}
|
||||
selectedStrCase: any = null;
|
||||
concludeConclusion: 'NOT_SUSPICIOUS' | 'SUSPICIOUS' = 'NOT_SUSPICIOUS';
|
||||
concludeInvestigationNotes = '';
|
||||
@@ -633,10 +649,9 @@ export class FiuComponent implements OnInit {
|
||||
}
|
||||
|
||||
/**
|
||||
* Always fetches every status. The triage table and the cleared register are two views of the
|
||||
* same set, so filtering server-side would empty one whenever the other was narrowed — and the
|
||||
* CTR tab reads this list too, which a status filter chosen on the STR tab should not touch.
|
||||
* amlAlertStatusFilter is applied client-side in {@link amlSuspiciousAlerts} instead.
|
||||
* Always fetches every status. This tab shows what was cleared and what became an STR case, which are two views of
|
||||
* the same set, and the CTR tab reads the list as well — so narrowing it server-side for one view would empty
|
||||
* another.
|
||||
*/
|
||||
loadAmlAlerts(): void {
|
||||
this.amlService.getAlerts().subscribe((data) => (this.amlAlerts = data || []));
|
||||
@@ -679,7 +694,8 @@ export class FiuComponent implements OnInit {
|
||||
this.ctrLinesLoading = false;
|
||||
this.ctrTxns = [];
|
||||
this.ctrLinesError =
|
||||
err?.error?.defaultUserMessage || 'Could not load the generated CTR lines. Generate a report for the month first.';
|
||||
err?.error?.defaultUserMessage ||
|
||||
'Could not load the generated CTR lines. Generate a report for the month first.';
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -779,48 +795,6 @@ export class FiuComponent implements OnInit {
|
||||
return (err: any) => this.toast(err?.error?.defaultUserMessage || `${action} failed — please retry`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clearing or escalating an alert has to carry a reason: review_notes is the only audit record of
|
||||
* why a flagged transaction was disposed of, and an empty string leaves no trace of the decision.
|
||||
*/
|
||||
private reviewNotesOf(alert: any): string | null {
|
||||
const notes = (this.amlReviewNotes[alert.id] || '').trim();
|
||||
if (!notes) {
|
||||
this.toast(`Enter review notes before disposing of alert #${alert.id}`);
|
||||
return null;
|
||||
}
|
||||
return notes;
|
||||
}
|
||||
|
||||
whitelistAlert(alert: any): void {
|
||||
const notes = this.reviewNotesOf(alert);
|
||||
if (!notes) {
|
||||
return;
|
||||
}
|
||||
this.amlService.reviewAlert(alert.id, 'WHITELIST', notes).subscribe({
|
||||
next: () => {
|
||||
this.toast(`Alert #${alert.id} whitelisted — no STR raised`);
|
||||
this.loadAmlAlerts();
|
||||
},
|
||||
error: this.apiError(`Whitelisting alert #${alert.id}`)
|
||||
});
|
||||
}
|
||||
|
||||
escalateAlert(alert: any): void {
|
||||
const notes = this.reviewNotesOf(alert);
|
||||
if (!notes) {
|
||||
return;
|
||||
}
|
||||
this.amlService.reviewAlert(alert.id, 'ESCALATE', notes).subscribe({
|
||||
next: () => {
|
||||
this.toast(`Alert #${alert.id} escalated — now an STR case for the Principal Officer`);
|
||||
this.loadAmlAlerts();
|
||||
this.loadAmlStrCases();
|
||||
},
|
||||
error: this.apiError(`Escalating alert #${alert.id}`)
|
||||
});
|
||||
}
|
||||
|
||||
generateCtrReport(): void {
|
||||
if (!this.ctrGenerateMonth) {
|
||||
this.toast('Pick a reporting month first');
|
||||
@@ -1039,12 +1013,6 @@ export class FiuComponent implements OnInit {
|
||||
* The STR triage queue: still to decide, or already escalated. Whitelisted alerts are closed
|
||||
* with no report, so they are not STR business — they live in {@link amlWhitelistedAlerts}.
|
||||
*/
|
||||
get amlSuspiciousAlerts(): any[] {
|
||||
return this.behaviouralAlerts.filter(
|
||||
(a) => a.status !== 'WHITELISTED' && (!this.amlAlertStatusFilter || a.status === this.amlAlertStatusFilter)
|
||||
);
|
||||
}
|
||||
|
||||
/** Cleared register: alerts closed as false positives, kept for audit with their evidence. */
|
||||
get amlWhitelistedAlerts(): any[] {
|
||||
return this.behaviouralAlerts.filter((a) => a.status === 'WHITELISTED');
|
||||
@@ -1707,7 +1675,9 @@ export class FiuComponent implements OnInit {
|
||||
private writeLiveStrXml(cases: any[], filename: string): void {
|
||||
const xml: string[] = [];
|
||||
xml.push('<?xml version="1.0" encoding="UTF-8"?>');
|
||||
xml.push(`<STR xmlns="http://fiuind.gov.in/finnet2/str" reportingMonth="${this.escapeXml(this.reportingMonthLabel)}">`);
|
||||
xml.push(
|
||||
`<STR xmlns="http://fiuind.gov.in/finnet2/str" reportingMonth="${this.escapeXml(this.reportingMonthLabel)}">`
|
||||
);
|
||||
xml.push(` <REBank name="${this.escapeXml(this.bank.name)}" />`);
|
||||
if (this.principalOfficerName) {
|
||||
xml.push(` <PrincipalOfficer name="${this.escapeXml(this.principalOfficerName)}" />`);
|
||||
|
||||
Reference in New Issue
Block a user