feat: add KYC document renewal alerts, Aadhaar/PAN exceptions, and AML recurring alerts UI; remove old journal AML marking
This commit is contained in:
@@ -0,0 +1,151 @@
|
||||
/**
|
||||
* 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 { FormsModule } from '@angular/forms';
|
||||
import {
|
||||
MAT_DIALOG_DATA,
|
||||
MatDialogRef,
|
||||
MatDialogContent,
|
||||
MatDialogActions,
|
||||
MatDialogClose
|
||||
} from '@angular/material/dialog';
|
||||
import { MatIcon } from '@angular/material/icon';
|
||||
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||
|
||||
export interface AadhaarReceiptDialogData {
|
||||
/** Client name, shown so the officer can check the slip belongs to the right person. */
|
||||
clientName: string;
|
||||
/** Message the Aadhaar step came back with, or why the officer is recording a receipt. */
|
||||
reason: string;
|
||||
/** Existing receipt, when the officer re-opens one already taken. */
|
||||
existing?: AadhaarReceiptResult | null;
|
||||
}
|
||||
|
||||
export interface AadhaarReceiptResult {
|
||||
/** 14-digit enrolment number as printed on the slip, separators kept. */
|
||||
enrolmentId: string;
|
||||
enrolmentDate: Date | null;
|
||||
remarks: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Records the UIDAI enrolment receipt accepted in place of a verified Aadhaar.
|
||||
*
|
||||
* A customer who has applied for Aadhaar but has not been issued one holds only an enrolment slip.
|
||||
* There is no Aadhaar number to send to the OTP flow, so no amount of retrying will clear the
|
||||
* check — the same dead end the PAN declaration resolves. Recording the slip lets the client be
|
||||
* created and waives the Aadhaar exception, while Aadhaar itself stays unverified.
|
||||
*
|
||||
* Only the 14-digit enrolment number is taken. The date and time printed beside it on the slip are
|
||||
* captured by the enrolment-date field, so asking for them again in the same box would just be a
|
||||
* second chance to mistype them.
|
||||
*
|
||||
* The number is validated on digit count rather than an exact layout: slips print it with varying
|
||||
* separators, and rejecting one because of a slash or a space would block a customer over
|
||||
* formatting rather than substance.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'mifosx-aadhaar-receipt-dialog',
|
||||
templateUrl: './aadhaar-receipt-dialog.component.html',
|
||||
styleUrls: ['./aadhaar-receipt-dialog.component.scss'],
|
||||
imports: [
|
||||
...STANDALONE_SHARED_IMPORTS,
|
||||
FormsModule,
|
||||
MatIcon,
|
||||
MatDialogContent,
|
||||
MatDialogActions,
|
||||
MatDialogClose
|
||||
]
|
||||
})
|
||||
export class AadhaarReceiptDialogComponent {
|
||||
data = inject<AadhaarReceiptDialogData>(MAT_DIALOG_DATA);
|
||||
private dialogRef = inject(MatDialogRef<AadhaarReceiptDialogComponent>);
|
||||
|
||||
enrolmentId = '';
|
||||
enrolmentDate: Date | null = null;
|
||||
remarks = '';
|
||||
/** The officer confirms the original slip was sighted — nothing is saved without it. */
|
||||
sighted = false;
|
||||
|
||||
today = new Date();
|
||||
|
||||
constructor() {
|
||||
const existing = this.data.existing;
|
||||
if (existing) {
|
||||
this.enrolmentId = existing.enrolmentId || '';
|
||||
this.enrolmentDate = existing.enrolmentDate || null;
|
||||
this.remarks = existing.remarks || '';
|
||||
}
|
||||
}
|
||||
|
||||
/** Digits only — separators on the printed slip are cosmetic and vary between forms. */
|
||||
private get enrolmentDigits(): string {
|
||||
return (this.enrolmentId || '').replace(/\D/g, '');
|
||||
}
|
||||
|
||||
get enrolmentIdEntered(): boolean {
|
||||
return this.enrolmentDigits.length > 0;
|
||||
}
|
||||
|
||||
/** UIDAI's enrolment number is 14 digits — the timestamp beside it is not part of it. */
|
||||
get enrolmentIdValid(): boolean {
|
||||
return this.enrolmentDigits.length === 14;
|
||||
}
|
||||
|
||||
/** How many digits are still missing, so the officer is told what to fix, not just that it failed. */
|
||||
get enrolmentIdHint(): string {
|
||||
const count = this.enrolmentDigits.length;
|
||||
if (!count) {
|
||||
return 'The 14-digit enrolment number only, e.g. 1234/56789/01234';
|
||||
}
|
||||
return `${count} of 14 digits`;
|
||||
}
|
||||
|
||||
/** A slip dated in the future is a keying error, not a valid enrolment. */
|
||||
get enrolmentDateValid(): boolean {
|
||||
return !!this.enrolmentDate && this.enrolmentDate.getTime() <= this.today.getTime();
|
||||
}
|
||||
|
||||
/** Whole months since enrolment — shown because a receipt is temporary by nature. */
|
||||
get monthsSinceEnrolment(): number | null {
|
||||
if (!this.enrolmentDate) {
|
||||
return null;
|
||||
}
|
||||
const months =
|
||||
(this.today.getFullYear() - this.enrolmentDate.getFullYear()) * 12 +
|
||||
(this.today.getMonth() - this.enrolmentDate.getMonth()) -
|
||||
(this.today.getDate() < this.enrolmentDate.getDate() ? 1 : 0);
|
||||
return Math.max(0, months);
|
||||
}
|
||||
|
||||
/**
|
||||
* An enrolment normally completes well inside six months, so an older slip is a prompt to chase
|
||||
* the customer for the Aadhaar itself. It is a warning, not a block: the branch may have good
|
||||
* reason to accept it, and the record shows the age either way.
|
||||
*/
|
||||
get receiptIsStale(): boolean {
|
||||
const months = this.monthsSinceEnrolment;
|
||||
return months !== null && months >= 6;
|
||||
}
|
||||
|
||||
get canSubmit(): boolean {
|
||||
return this.enrolmentIdValid && this.enrolmentDateValid && !!this.remarks.trim() && this.sighted;
|
||||
}
|
||||
|
||||
submit(): void {
|
||||
if (!this.canSubmit) {
|
||||
return;
|
||||
}
|
||||
this.dialogRef.close({
|
||||
enrolmentId: this.enrolmentId.trim(),
|
||||
enrolmentDate: this.enrolmentDate,
|
||||
remarks: this.remarks.trim()
|
||||
} as AadhaarReceiptResult);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user