580 lines
24 KiB
HTML
580 lines
24 KiB
HTML
<!--
|
|
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="rr-root">
|
|
<!-- HEADER -->
|
|
<div class="rr-head">
|
|
<div class="rr-head-left">
|
|
<fa-icon icon="user-shield" class="rr-head-ic"></fa-icon>
|
|
<div>
|
|
<h2 class="rr-head-t">Risk Review Report</h2>
|
|
<div class="rr-head-s">
|
|
Customers whose transactions tripped an AML rule and whose risk profile therefore needs a look. For each case
|
|
the reviewer decides one of four things — keep the rating, move it, call for a KYC update, or refer it to the
|
|
Principal Officer for an STR.
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="rr-head-actions">
|
|
<button class="rr-btn rr-btn--primary" [disabled]="generating || loading" (click)="exportExcel()">
|
|
<fa-icon icon="file-excel"></fa-icon> {{ generating ? 'Generating…' : 'Download Excel' }}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- FILTERS -->
|
|
<div class="rr-filters">
|
|
<div class="rr-filter-row">
|
|
<div class="rr-modes">
|
|
@for (m of periodModes; track m.key) {
|
|
<button class="rr-chip" [class.active]="periodMode === m.key" (click)="periodMode = m.key">
|
|
{{ m.label }}
|
|
</button>
|
|
}
|
|
</div>
|
|
|
|
@switch (periodMode) {
|
|
@case ('day') {
|
|
<label class="rr-field">
|
|
<span>Date</span>
|
|
<input type="date" [(ngModel)]="filterDay" />
|
|
</label>
|
|
}
|
|
@case ('week') {
|
|
<label class="rr-field">
|
|
<span>Any date in week</span>
|
|
<input type="date" [(ngModel)]="filterWeek" />
|
|
</label>
|
|
<span class="rr-resolved">Week: {{ rangeLabel }}</span>
|
|
}
|
|
@case ('month') {
|
|
<label class="rr-field">
|
|
<span>Month</span>
|
|
<input type="month" [(ngModel)]="filterMonth" />
|
|
</label>
|
|
}
|
|
@default {
|
|
<label class="rr-field">
|
|
<span>Alerts from</span>
|
|
<input type="date" [(ngModel)]="filterFrom" />
|
|
</label>
|
|
<label class="rr-field">
|
|
<span>To</span>
|
|
<input type="date" [(ngModel)]="filterTo" />
|
|
</label>
|
|
}
|
|
}
|
|
</div>
|
|
|
|
<div class="rr-filter-row">
|
|
<label class="rr-field">
|
|
<span>Branch</span>
|
|
<select [(ngModel)]="branchCode" [disabled]="!canSelectBranch">
|
|
@if (canSelectBranch) {
|
|
<option value="">All Branches</option>
|
|
}
|
|
@for (b of branches; track b.code) {
|
|
<option [value]="b.code">{{ b.code }} — {{ b.name }}</option>
|
|
}
|
|
</select>
|
|
</label>
|
|
|
|
<label class="rr-field">
|
|
<span>Current risk</span>
|
|
<select [(ngModel)]="currentRisk">
|
|
<option value="">Any rating</option>
|
|
<option value="LOW">Low</option>
|
|
<option value="MEDIUM">Medium</option>
|
|
<option value="HIGH">High</option>
|
|
</select>
|
|
</label>
|
|
|
|
<label class="rr-field">
|
|
<span>AML rule triggered</span>
|
|
<select [(ngModel)]="ruleCode">
|
|
<option value="">All rules</option>
|
|
@for (r of rules; track r.code) {
|
|
<option [value]="r.code">{{ r.label }}</option>
|
|
}
|
|
</select>
|
|
</label>
|
|
|
|
<label class="rr-field">
|
|
<span>Review status</span>
|
|
<select [(ngModel)]="status">
|
|
<option value="">Any status</option>
|
|
@for (s of reviewStatuses; track s) {
|
|
<option [value]="s">{{ statusMeta[s].label }}</option>
|
|
}
|
|
</select>
|
|
</label>
|
|
|
|
<label class="rr-field">
|
|
<span>Rating outcome</span>
|
|
<select [(ngModel)]="direction">
|
|
<option value="">Any outcome</option>
|
|
<option value="up">Review upward</option>
|
|
<option value="down">Review downward</option>
|
|
<option value="same">Within current rating</option>
|
|
</select>
|
|
</label>
|
|
|
|
<label class="rr-field rr-field--grow">
|
|
<span>Search</span>
|
|
<input type="text" [(ngModel)]="search" placeholder="Customer name, customer ID, account number or alert ID…" />
|
|
</label>
|
|
|
|
<label class="rr-check">
|
|
<input type="checkbox" [(ngModel)]="openOnly" />
|
|
Only cases awaiting review
|
|
</label>
|
|
|
|
<button class="rr-btn" (click)="resetFilters()"><fa-icon icon="undo"></fa-icon> Reset</button>
|
|
</div>
|
|
|
|
@if (!canSelectBranch) {
|
|
<div class="rr-scope-note">
|
|
<fa-icon icon="lock"></fa-icon>
|
|
Showing {{ branchLabel }} only. Head Office logins can select any branch.
|
|
</div>
|
|
}
|
|
</div>
|
|
|
|
@if (loading) {
|
|
<div class="rr-loading"><fa-icon icon="shield-alt"></fa-icon> Loading AML alerts…</div>
|
|
} @else {
|
|
<!-- SUMMARY -->
|
|
<div class="rr-kpis">
|
|
<!-- Each tile reads as a question, so each one answers it by narrowing the table to the rows
|
|
it counted. They were plain text before, which invited a click that did nothing and left
|
|
the reviewer to rebuild the same filter by hand from the dropdowns below. -->
|
|
<button type="button" class="rr-kpi" (click)="focusAllCustomers()" title="Show every customer in the period">
|
|
<div class="rr-kpi-n">{{ summary.customers }}</div>
|
|
<div class="rr-kpi-l">Customers for review</div>
|
|
<div class="rr-kpi-sub">
|
|
{{ summary.byRisk.LOW }} Low · {{ summary.byRisk.MEDIUM }} Medium · {{ summary.byRisk.HIGH }} High
|
|
</div>
|
|
</button>
|
|
<button
|
|
type="button"
|
|
class="rr-kpi rr-kpi--blue"
|
|
[class.rr-kpi--on]="openOnly"
|
|
(click)="focusOpenAlerts()"
|
|
title="Show only the cases still awaiting a decision"
|
|
>
|
|
<div class="rr-kpi-n">{{ summary.alerts }}</div>
|
|
<div class="rr-kpi-l">AML alerts triggered</div>
|
|
<div class="rr-kpi-sub">on {{ summary.txns }} transactions · {{ summary.openAlerts }} awaiting a decision</div>
|
|
</button>
|
|
<button
|
|
type="button"
|
|
class="rr-kpi rr-kpi--amber"
|
|
[class.rr-kpi--dim]="summary.upgradeCandidates + summary.downgradeCandidates === 0"
|
|
[class.rr-kpi--on]="direction !== ''"
|
|
(click)="focusRatingsToMove()"
|
|
[title]="
|
|
summary.upgradeCandidates + summary.downgradeCandidates === 0
|
|
? 'No rating needs moving in this period'
|
|
: 'Show the customers whose rating should move'
|
|
"
|
|
>
|
|
<div class="rr-kpi-n">{{ summary.upgradeCandidates + summary.downgradeCandidates }}</div>
|
|
<div class="rr-kpi-l">Ratings to be moved</div>
|
|
<div class="rr-kpi-sub">
|
|
{{ summary.upgradeCandidates }} upward · {{ summary.downgradeCandidates }} downward
|
|
</div>
|
|
</button>
|
|
<button
|
|
type="button"
|
|
class="rr-kpi"
|
|
[class.rr-kpi--red]="summary.escalatedCustomers > 0"
|
|
[class.rr-kpi--dim]="summary.escalatedCustomers === 0"
|
|
[class.rr-kpi--on]="status === 'ESCALATED_STR'"
|
|
(click)="focusEscalated()"
|
|
[title]="
|
|
summary.escalatedCustomers === 0
|
|
? 'No case has gone to the Principal Officer in this period'
|
|
: 'Show only the cases with the Principal Officer'
|
|
"
|
|
>
|
|
<div class="rr-kpi-n">{{ summary.escalatedCustomers }}</div>
|
|
<div class="rr-kpi-l">Escalated to STR</div>
|
|
<div class="rr-kpi-sub">₹{{ summary.totalAmount | number: '1.0-0' }} under review</div>
|
|
</button>
|
|
</div>
|
|
|
|
<!-- RULE MIX — doubles as a one-click filter -->
|
|
@if (summary.byRule.length) {
|
|
<div class="rr-mix">
|
|
<span class="rr-mix-t">Rules triggered</span>
|
|
@for (r of summary.byRule; track r.code) {
|
|
<button class="rr-mix-item" [class.active]="ruleCode === r.code" (click)="toggleRule(r.code)">
|
|
{{ r.label }} <strong>{{ r.count }}</strong>
|
|
</button>
|
|
}
|
|
</div>
|
|
}
|
|
|
|
<!-- VIEW SWITCH -->
|
|
<div class="rr-views">
|
|
<button class="rr-chip" [class.active]="view === 'customer'" (click)="view = 'customer'">
|
|
<fa-icon icon="users"></fa-icon> Customer wise
|
|
</button>
|
|
<button class="rr-chip" [class.active]="view === 'alert'" (click)="view = 'alert'">
|
|
<fa-icon icon="list"></fa-icon> Alert wise
|
|
</button>
|
|
<button class="rr-chip" [class.active]="view === 'txn'" (click)="view = 'txn'">
|
|
<fa-icon icon="filter"></fa-icon> Transaction wise
|
|
</button>
|
|
<span class="rr-spacer"></span>
|
|
<span class="rr-count">
|
|
{{
|
|
view === 'customer'
|
|
? customerRows.length + ' customers'
|
|
: view === 'alert'
|
|
? alertRows.length + ' alerts'
|
|
: txnRows.length + ' transactions'
|
|
}}
|
|
</span>
|
|
</div>
|
|
|
|
<!-- CUSTOMER WISE -->
|
|
@if (view === 'customer') {
|
|
<!-- Grouped by verdict: the section heading answers "what do I do about these?" once, so the
|
|
row does not have to repeat it in a Move To and a Position column. -->
|
|
@for (g of customerGroups; track g.key) {
|
|
<div class="rr-group" [class]="'rr-group--' + g.tone">
|
|
<button type="button" class="rr-group-head" (click)="toggleGroup(g.key)">
|
|
<fa-icon [icon]="collapsedGroups[g.key] ? 'caret-right' : 'caret-down'"></fa-icon>
|
|
<span class="rr-group-t">{{ g.title }}</span>
|
|
<span class="rr-group-n">{{ g.rows.length }}</span>
|
|
<span class="rr-group-h">{{ g.hint }}</span>
|
|
</button>
|
|
|
|
@if (!collapsedGroups[g.key]) {
|
|
<div class="rr-table-wrap">
|
|
<table class="rr-table">
|
|
<thead>
|
|
<tr>
|
|
<th></th>
|
|
<th>Customer ID</th>
|
|
<th>Customer Name</th>
|
|
<th>Account Number</th>
|
|
<th>Branch</th>
|
|
<th>Rating on file</th>
|
|
<th>Review says</th>
|
|
<th class="num">Alerts</th>
|
|
<th>AML Rules Triggered</th>
|
|
<th class="num">Amount under review</th>
|
|
<th>Last Alert</th>
|
|
<th>Action</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@for (c of g.rows; track c.clientId) {
|
|
<tr
|
|
class="rr-cust"
|
|
[class.open]="expanded === c.clientId"
|
|
[class.rr-row--escalated]="c.escalated"
|
|
(click)="toggle(c.clientId)"
|
|
>
|
|
<td>
|
|
<fa-icon [icon]="expanded === c.clientId ? 'caret-down' : 'caret-right'"></fa-icon>
|
|
</td>
|
|
<td class="mono">{{ c.clientId }}</td>
|
|
<td>
|
|
<strong>{{ c.customerName }}</strong>
|
|
@if (c.openCount > 0) {
|
|
<span class="rr-tag">{{ c.openCount }} open</span>
|
|
}
|
|
</td>
|
|
<td class="mono">{{ c.accountNo || '—' }}</td>
|
|
<td>{{ c.branchCode || '—' }}</td>
|
|
<td>
|
|
<span [class]="riskClass(c.currentRisk)">{{ riskText(c.currentRisk) }}</span>
|
|
</td>
|
|
<!-- The verdict itself, on the row. The section heading says it once for the
|
|
whole group, but a reviewer reading a single row - or an exported sheet -
|
|
could not tell whether the rating was to be raised, lowered or left. The
|
|
reason sits under it rather than under the button, because it explains
|
|
this conclusion and not the act of opening the KYC screen. -->
|
|
<td class="rr-move-cell">
|
|
<span class="rr-move" [class]="'rr-move--' + c.direction">
|
|
<fa-icon [icon]="directionIcon(c)"></fa-icon>
|
|
{{ directionText(c) }}
|
|
</span>
|
|
@if (c.directionReason) {
|
|
<div class="rr-verdict-why">{{ c.directionReason }}</div>
|
|
}
|
|
</td>
|
|
<td class="num">{{ c.alertCount }}</td>
|
|
<td class="rr-rules-cell">
|
|
@for (label of c.ruleLabels; track label) {
|
|
<span class="rr-rule">{{ label }}</span>
|
|
}
|
|
</td>
|
|
<td class="num strong">{{ c.totalAmount | number: '1.0-0' }}</td>
|
|
<td class="mono">{{ c.lastAlertDate }}</td>
|
|
<!-- Only the control. The verdict and its reason moved to their own column,
|
|
so this no longer wraps to two lines under the button. -->
|
|
<td class="rr-action-cell">
|
|
<button
|
|
type="button"
|
|
class="rr-kyc-link"
|
|
[class.rr-kyc-link--act]="c.direction !== 'same' && !c.escalated"
|
|
(click)="openKyc(c, $event)"
|
|
[attr.aria-label]="kycActionText(c) + ' for ' + c.customerName"
|
|
>
|
|
<fa-icon icon="id-card"></fa-icon> {{ kycActionText(c) }}
|
|
</button>
|
|
</td>
|
|
</tr>
|
|
|
|
@if (expanded === c.clientId) {
|
|
<tr class="rr-detail">
|
|
<td colspan="12">
|
|
<!-- One block per alert: what the rule is, then the entries it fired on. -->
|
|
@for (a of c.alerts; track a.alertId) {
|
|
<div class="rr-case">
|
|
<div class="rr-case-head">
|
|
<span class="rr-rule">{{ a.rule.label }}</span>
|
|
<span class="rr-rule-cat">{{ a.rule.category }}</span>
|
|
<span class="rr-case-id mono">{{ a.alertId }} · raised {{ a.alertDate }}</span>
|
|
<span class="rr-spacer"></span>
|
|
<span class="rr-case-amt mono">₹{{ a.amount | number: '1.0-0' }}</span>
|
|
<span [class]="statusClass(a.status)">{{ statusMeta[a.status].label }}</span>
|
|
</div>
|
|
<div class="rr-case-why">
|
|
<fa-icon icon="exclamation-triangle"></fa-icon>
|
|
<span
|
|
><strong>Why it triggered:</strong> {{ a.rule.description }} —
|
|
{{ txnDetail(a) }}</span
|
|
>
|
|
</div>
|
|
|
|
<table class="rr-subtable">
|
|
<thead>
|
|
<tr>
|
|
<th>Txn Date</th>
|
|
<th>Txn ID</th>
|
|
<th>Channel</th>
|
|
<th>Dr/Cr</th>
|
|
<th class="num">Amount</th>
|
|
<th class="num">Balance After</th>
|
|
<th>Narration</th>
|
|
<th>Counterparty</th>
|
|
<th>AML Rule Triggered</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@for (t of a.txns; track t.txnId) {
|
|
<tr [class.rr-leg--ctr]="t.ctrReportable">
|
|
<td class="mono">{{ t.date }}</td>
|
|
<td class="mono">{{ t.txnId }}</td>
|
|
<td>
|
|
<span class="rr-chan">{{ channelLabel(t.channel) }}</span>
|
|
</td>
|
|
<td [class.cr]="t.drCr === 'CR'" [class.dr]="t.drCr === 'DR'">{{ t.drCr }}</td>
|
|
<td class="num strong">
|
|
{{ t.amount | number: '1.0-0' }}
|
|
@if (t.ctrReportable) {
|
|
<span class="rr-tag rr-tag--ctr">CTR</span>
|
|
}
|
|
</td>
|
|
<td class="num">
|
|
{{ t.balanceAfter ? (t.balanceAfter | number: '1.0-0') : '—' }}
|
|
</td>
|
|
<td>{{ t.narration || '—' }}</td>
|
|
<td>{{ t.counterparty || '—' }}</td>
|
|
<td>
|
|
<span class="rr-rule">{{ a.rule.label }}</span>
|
|
@if (a.txns.length > 1) {
|
|
<span class="rr-leg">leg {{ $index + 1 }} of {{ a.txns.length }}</span>
|
|
}
|
|
</td>
|
|
</tr>
|
|
}
|
|
</tbody>
|
|
</table>
|
|
|
|
<div class="rr-case-foot">
|
|
<div class="rr-suggest">
|
|
<fa-icon icon="clipboard-check"></fa-icon> {{ a.rule.suggestedAction }}
|
|
</div>
|
|
<div class="rr-case-remark">
|
|
<strong>Reviewer:</strong> {{ a.reviewedBy || 'not yet assigned' }} —
|
|
{{ a.remarks || 'no remarks recorded' }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
}
|
|
</td>
|
|
</tr>
|
|
}
|
|
}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
}
|
|
</div>
|
|
} @empty {
|
|
<div class="rr-empty">No customer tripped an AML rule for {{ rangeLabel }} at {{ branchLabel }}.</div>
|
|
}
|
|
}
|
|
|
|
<!-- ALERT WISE -->
|
|
@if (view === 'alert') {
|
|
<div class="rr-table-wrap">
|
|
<table class="rr-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Alert ID</th>
|
|
<th>Alert Date</th>
|
|
<th>Customer ID</th>
|
|
<th>Customer Name</th>
|
|
<th>Account Number</th>
|
|
<th>Branch</th>
|
|
<th>Current Risk</th>
|
|
<th>Transaction Details</th>
|
|
<th>AML Rule Triggered</th>
|
|
<th class="num">Amount</th>
|
|
<th>Review Status</th>
|
|
<th>Reviewer Remarks</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@for (a of alertRows; track a.alertId) {
|
|
<tr [class.rr-row--escalated]="a.status === 'ESCALATED_STR' || a.status === 'STR_FILED'">
|
|
<td class="mono">{{ a.alertId }}</td>
|
|
<td class="mono">{{ a.alertDate }}</td>
|
|
<td class="mono">{{ a.clientId }}</td>
|
|
<td>
|
|
<strong>{{ a.customerName }}</strong>
|
|
</td>
|
|
<td class="mono">{{ a.accountNo || '—' }}</td>
|
|
<td>{{ a.branchCode || '—' }}</td>
|
|
<td>
|
|
<span [class]="riskClass(a.currentRisk)">{{ riskText(a.currentRisk) }}</span>
|
|
</td>
|
|
<td>{{ txnDetail(a) }}</td>
|
|
<td class="rr-rules-cell">
|
|
<span class="rr-rule">{{ a.rule.label }}</span>
|
|
<span class="rr-rule-cat">{{ a.rule.category }}</span>
|
|
<div class="rr-rule-desc">{{ a.rule.description }}</div>
|
|
</td>
|
|
<td class="num strong">{{ a.amount | number: '1.0-0' }}</td>
|
|
<td>
|
|
<span [class]="statusClass(a.status)">{{ statusMeta[a.status].label }}</span>
|
|
@if (a.reviewedBy) {
|
|
<div class="rr-by">by {{ a.reviewedBy }}</div>
|
|
}
|
|
</td>
|
|
<td>
|
|
{{ a.remarks || '—' }}
|
|
<div class="rr-suggest"><fa-icon icon="clipboard-check"></fa-icon> {{ a.rule.suggestedAction }}</div>
|
|
</td>
|
|
</tr>
|
|
} @empty {
|
|
<tr>
|
|
<td colspan="12" class="rr-empty">
|
|
No AML rule was triggered for {{ rangeLabel }} at {{ branchLabel }}.
|
|
</td>
|
|
</tr>
|
|
}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
}
|
|
|
|
<!-- TRANSACTION WISE — every entry, and the rule it tripped -->
|
|
@if (view === 'txn') {
|
|
<div class="rr-table-wrap">
|
|
<table class="rr-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Txn Date</th>
|
|
<th>Txn ID</th>
|
|
<th>Customer ID</th>
|
|
<th>Customer Name</th>
|
|
<th>Account Number</th>
|
|
<th>Branch</th>
|
|
<th>Current Risk</th>
|
|
<th>Channel</th>
|
|
<th>Dr/Cr</th>
|
|
<th class="num">Amount</th>
|
|
<th class="num">Balance After</th>
|
|
<th>Narration</th>
|
|
<th>Counterparty</th>
|
|
<th>AML Rule Triggered</th>
|
|
<th>Alert</th>
|
|
<th>Review Status</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@for (t of txnRows; track t.txnId) {
|
|
<tr [class.rr-row--escalated]="t.status === 'ESCALATED_STR' || t.status === 'STR_FILED'">
|
|
<td class="mono">{{ t.date }}</td>
|
|
<td class="mono">{{ t.txnId }}</td>
|
|
<td class="mono">{{ t.clientId }}</td>
|
|
<td>
|
|
<strong>{{ t.customerName }}</strong>
|
|
</td>
|
|
<td class="mono">{{ t.accountNo || '—' }}</td>
|
|
<td>{{ t.branchCode || '—' }}</td>
|
|
<td>
|
|
<span [class]="riskClass(t.currentRisk)">{{ riskText(t.currentRisk) }}</span>
|
|
</td>
|
|
<td>
|
|
<span class="rr-chan">{{ channelLabel(t.channel) }}</span>
|
|
</td>
|
|
<td [class.cr]="t.drCr === 'CR'" [class.dr]="t.drCr === 'DR'">{{ t.drCr }}</td>
|
|
<td class="num strong">
|
|
{{ t.amount | number: '1.0-0' }}
|
|
@if (t.ctrReportable) {
|
|
<span class="rr-tag rr-tag--ctr">CTR</span>
|
|
}
|
|
</td>
|
|
<td class="num">{{ t.balanceAfter ? (t.balanceAfter | number: '1.0-0') : '—' }}</td>
|
|
<td>{{ t.narration || '—' }}</td>
|
|
<td>{{ t.counterparty || '—' }}</td>
|
|
<td class="rr-rules-cell">
|
|
<span class="rr-rule">{{ t.rule.label }}</span>
|
|
<span class="rr-rule-cat">{{ t.rule.category }}</span>
|
|
@if (t.legCount > 1) {
|
|
<span class="rr-leg">leg {{ t.legIndex }} of {{ t.legCount }}</span>
|
|
}
|
|
<div class="rr-rule-desc">{{ t.rule.description }}</div>
|
|
</td>
|
|
<td class="mono">{{ t.alertId }}</td>
|
|
<td>
|
|
<span [class]="statusClass(t.status)">{{ statusMeta[t.status].label }}</span>
|
|
</td>
|
|
</tr>
|
|
} @empty {
|
|
<tr>
|
|
<td colspan="16" class="rr-empty">
|
|
No transaction tripped an AML rule for {{ rangeLabel }} at {{ branchLabel }}.
|
|
</td>
|
|
</tr>
|
|
}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
}
|
|
|
|
<p class="rr-legend">
|
|
<span class="rr-status rr-status--open">Pending review</span> awaiting a reviewer ·
|
|
<span class="rr-status rr-status--ok">Risk retained</span> explained, rating unchanged ·
|
|
<span class="rr-status rr-status--warn">Risk upgraded / KYC update</span> profile changed ·
|
|
<span class="rr-status rr-status--danger">Escalated / STR filed</span> with the Principal Officer
|
|
</p>
|
|
}
|
|
|
|
<div class="rr-toast" [class.show]="toastVisible">{{ toastMsg }}</div>
|
|
</div>
|