feat: add database export, welcome kit dialog, and DIP/sanctions updates
build-run / Run Lint, Build and Deploy (push) Canceled after 0s
Publish Image in Docker Hub / build (push) Canceled after 0s
Playwright E2E Tests / Run Playwright Tests (push) Canceled after 0s
Tests / testRigor (push) Canceled after 0s

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-17 17:52:28 +05:30
co-authored by Claude Opus 5
parent c18219fce5
commit 7ef75c902d
33 changed files with 3042 additions and 208 deletions
@@ -168,58 +168,78 @@
<div class="cv-cell__value">{{ clientViewData.occupation.name }}</div>
</div>
}
@if (clientViewData.mobileNo && clientViewData.dipVerified !== null) {
<!--
dipLiveStatus reflects the LATEST lookup, not the flag frozen at onboarding. A customer
cleared when they joined can have their number reported for fraud or reassigned later —
this cell has to show that, otherwise the page keeps claiming "Verified" indefinitely.
-->
@if (clientViewData.mobileNo && (clientViewData.dipVerified !== null || clientViewData.dipLiveStatus)) {
<div class="cv-cell">
<div class="cv-cell__label">DIP Status</div>
<div class="cv-cell__value">
<span
class="cv-badge"
[class.cv-badge--green]="
clientViewData.dipVerified === true ||
clientViewData.dipVerified === 'true' ||
clientViewData.dipVerified === 1
"
[class.cv-badge--yellow]="
clientViewData.dipVerified !== true &&
clientViewData.dipVerified !== 'true' &&
clientViewData.dipVerified !== 1
"
[class.cv-badge--red]="isDipFlagged(clientViewData.dipLiveStatus)"
[class.cv-badge--green]="!isDipFlagged(clientViewData.dipLiveStatus) && isDipClear(clientViewData)"
[class.cv-badge--yellow]="!isDipFlagged(clientViewData.dipLiveStatus) && !isDipClear(clientViewData)"
>
{{
clientViewData.dipVerified === true ||
clientViewData.dipVerified === 'true' ||
clientViewData.dipVerified === 1
? 'Verified'
: 'Pending'
}}
{{ dipStatusLabel(clientViewData) }}
</span>
</div>
</div>
}
@if (clientViewData.nameVerified !== null) {
@if (isDipFlagged(clientViewData.dipLiveStatus)) {
<div class="cv-cell cv-cell--full">
<div class="dip-alert">
<fa-icon icon="exclamation-triangle" class="dip-alert__icon"></fa-icon>
<div>
<strong>This mobile number is flagged on the DoT Digital Intelligence Platform.</strong>
<div class="dip-alert__detail">
OTPs and SMS alerts to this number are blocked. Contact the customer through an alternate channel and
obtain a new number. Account operations are not restricted.
</div>
</div>
</div>
</div>
}
<!--
A frozen customer must be obvious the moment anyone opens them, not something a teller
discovers when a withdrawal is refused at the counter.
-->
@if (clientViewData.sanctionsAlertStatus === 'CONFIRMED_MATCH') {
<div class="cv-cell cv-cell--full">
<div class="dip-alert">
<fa-icon icon="ban" class="dip-alert__icon"></fa-icon>
<div>
<strong>Confirmed UN Security Council sanctions match — accounts frozen.</strong>
<div class="dip-alert__detail">
Debits are blocked on this customer's deposit accounts and lending is barred. Do not discuss the
reason with the customer. See Reports &rarr; Sanctions Screening &amp; Alerts.
</div>
</div>
</div>
</div>
}
<!--
Driven by sanctionsAlertStatus (the live alert) rather than nameVerified, which records
the outcome at onboarding and never changes. A client confirmed against the UNSC list and
frozen afterwards was still reading "Clear" here — the single worst place to be wrong,
since this header is what anyone opening the customer sees first.
-->
@if (clientViewData.nameVerified !== null || clientViewData.sanctionsAlertStatus) {
<div class="cv-cell">
<div class="cv-cell__label">Sanctions Screening</div>
<div class="cv-cell__value">
<span
class="cv-badge"
[class.cv-badge--green]="
clientViewData.nameVerified === true ||
clientViewData.nameVerified === 'true' ||
clientViewData.nameVerified === 1
"
[class.cv-badge--red]="
clientViewData.nameVerified === false ||
clientViewData.nameVerified === 'false' ||
clientViewData.nameVerified === 0
[class.cv-badge--green]="!clientViewData.sanctionsAlertStatus && isNameCleared(clientViewData)"
[class.cv-badge--yellow]="
clientViewData.sanctionsAlertStatus === 'PENDING_REVIEW' ||
(!clientViewData.sanctionsAlertStatus && !isNameCleared(clientViewData))
"
[class.cv-badge--red]="clientViewData.sanctionsAlertStatus === 'CONFIRMED_MATCH'"
>
{{
clientViewData.nameVerified === true ||
clientViewData.nameVerified === 'true' ||
clientViewData.nameVerified === 1
? 'Clear'
: 'Pending'
}}
{{ sanctionsHeaderLabel(clientViewData) }}
</span>
</div>
</div>
@@ -410,9 +430,11 @@
<button mat-menu-item (click)="doAction('Add Charge')" *mifosxHasPermission="'CREATE_CLIENTCHARGE'">
{{ 'labels.buttons.Add Charge' | translate }}
</button>
<button mat-menu-item (click)="doAction('Welcome Kit')" *mifosxHasPermission="'READ_WELCOMEKIT'">
Welcome Kit
</button>
@if (isActive()) {
<button mat-menu-item (click)="doAction('Welcome Kit')" *mifosxHasPermission="'READ_WELCOMEKIT'">
Welcome Kit
</button>
}
<button mat-menu-item (click)="doAction('Create Collateral')">
{{ 'labels.buttons.Create Collateral' | translate }}
</button>