feat: add KYC document renewal alerts, Aadhaar/PAN exceptions, and AML recurring alerts UI; remove old journal AML marking
This commit is contained in:
@@ -10,11 +10,26 @@
|
||||
import { Component, OnInit, OnDestroy, inject } from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { UntypedFormBuilder, UntypedFormGroup, Validators, FormsModule } from '@angular/forms';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { catchError, of, Subject, takeUntil } from 'rxjs';
|
||||
|
||||
/** Custom Services */
|
||||
import { ClientsService } from '../../clients.service';
|
||||
import { deriveKycExceptionFields } from '../../kyc-exception.util';
|
||||
import {
|
||||
deriveKycDocumentRenewal,
|
||||
kycDocumentNeedsAttention,
|
||||
KycDocumentRenewalStatus,
|
||||
KYC_DOCUMENT_RENEWAL_YEARS
|
||||
} from '../../kyc-document-renewal.util';
|
||||
import {
|
||||
PanDeclarationDialogComponent,
|
||||
PanDeclarationResult
|
||||
} from '../../shared/pan-declaration-dialog/pan-declaration-dialog.component';
|
||||
import {
|
||||
AadhaarReceiptDialogComponent,
|
||||
AadhaarReceiptResult
|
||||
} from '../../shared/aadhaar-receipt-dialog/aadhaar-receipt-dialog.component';
|
||||
import { Dates } from 'app/core/utils/dates';
|
||||
import { jsPDF } from 'jspdf';
|
||||
import { MatIcon } from '@angular/material/icon';
|
||||
@@ -47,6 +62,7 @@ export class KycTabComponent implements OnInit, OnDestroy {
|
||||
private clientsService = inject(ClientsService);
|
||||
private formBuilder = inject(UntypedFormBuilder);
|
||||
private dateUtils = inject(Dates);
|
||||
private dialog = inject(MatDialog);
|
||||
|
||||
private destroy$ = new Subject<void>();
|
||||
|
||||
@@ -200,6 +216,127 @@ export class KycTabComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
}
|
||||
|
||||
/** True when the stored record carries a signed declaration standing in for the PAN check. */
|
||||
get panDeclarationTaken(): boolean {
|
||||
return this.kycData?.panDeclarationTaken === true;
|
||||
}
|
||||
|
||||
/** "Name", "Date of Birth", "Name and Date of Birth", or the not-checked-at-all case. */
|
||||
get panDeclarationMismatchLabel(): string {
|
||||
const fields: string = this.kycData?.panDeclarationMismatchFields;
|
||||
if (!fields || fields === 'NONE') {
|
||||
return 'PAN could not be verified';
|
||||
}
|
||||
return fields
|
||||
.split(',')
|
||||
.map((f) => (f === 'NAME' ? 'Name' : 'Date of Birth'))
|
||||
.join(' and ');
|
||||
}
|
||||
|
||||
/** True when the stored record carries a UIDAI enrolment slip standing in for the OTP check. */
|
||||
get aadhaarReceiptTaken(): boolean {
|
||||
return this.kycData?.aadhaarReceiptTaken === true;
|
||||
}
|
||||
|
||||
// ── KYC document renewal ──────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* Whether the OVD captured at onboarding is still current — see `deriveKycDocumentRenewal()`.
|
||||
*
|
||||
* The issue and expiry dates have always been captured on the KYC step but never read back, so
|
||||
* a client onboarded on a ten-year-old licence looked identical to one onboarded yesterday.
|
||||
*/
|
||||
get kycDocumentRenewal(): KycDocumentRenewalStatus {
|
||||
return deriveKycDocumentRenewal({
|
||||
issueDate: this.parseApiDate(this.kycData?.kycDocIssueDate),
|
||||
expiryDate: this.parseApiDate(this.kycData?.kycDocExpiryDate),
|
||||
today: new Date()
|
||||
});
|
||||
}
|
||||
|
||||
/** Only raise the banner for a document that actually exists and actually needs action. */
|
||||
get showKycDocumentAlert(): boolean {
|
||||
return !!this.kycData?.kycDocumentName && kycDocumentNeedsAttention(this.kycDocumentRenewal.state);
|
||||
}
|
||||
|
||||
/** Heading for the alert — the three states call for visibly different things. */
|
||||
get kycDocumentAlertTitle(): string {
|
||||
switch (this.kycDocumentRenewal.state) {
|
||||
case 'EXPIRED':
|
||||
return 'KYC Document Expired';
|
||||
case 'EXPIRING_SOON':
|
||||
return 'KYC Document Expires Soon';
|
||||
default:
|
||||
return 'KYC Document Due for Update';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The sentence staff act on. Each case names the date that triggered it, because "update the
|
||||
* document" without saying why leaves the officer checking the form to work out which clock ran
|
||||
* out.
|
||||
*/
|
||||
get kycDocumentAlertMessage(): string {
|
||||
const status = this.kycDocumentRenewal;
|
||||
const docName = this.kycData?.kycDocumentName || 'The KYC document';
|
||||
// `formatDate()` only understands Fineract's [y, m, d] arrays; these are real Date objects.
|
||||
const dueOn = status.dueOn ? this.dateUtils.formatDate(status.dueOn, 'dd MMMM yyyy') : '';
|
||||
const days = status.daysRemaining ?? 0;
|
||||
|
||||
switch (status.state) {
|
||||
case 'EXPIRED':
|
||||
return `${docName} expired on ${dueOn} and is no longer a valid officially valid document. Collect a renewed document from the customer and update the KYC record.`;
|
||||
case 'EXPIRING_SOON':
|
||||
return days === 0
|
||||
? `${docName} expires today (${dueOn}). Ask the customer for the renewed document before it lapses.`
|
||||
: `${docName} expires on ${dueOn} — ${days} day${days === 1 ? '' : 's'} from now. Ask the customer for the renewed document before it lapses.`;
|
||||
default:
|
||||
return `${docName} was issued more than ${KYC_DOCUMENT_RENEWAL_YEARS} years ago and fell due for update on ${dueOn}. Re-collect the document from the customer and update the KYC record.`;
|
||||
}
|
||||
}
|
||||
|
||||
/** Drives the banner's colour — an expired document is a harder failure than a stale one. */
|
||||
get kycDocumentAlertSeverity(): 'critical' | 'warning' {
|
||||
return this.kycDocumentRenewal.state === 'EXPIRED' ? 'critical' : 'warning';
|
||||
}
|
||||
|
||||
/**
|
||||
* The date the document stops counting as current, whether or not one is printed on it.
|
||||
*
|
||||
* A Voter ID or NREGA card carries no expiry, but it is not valid forever for KYC purposes —
|
||||
* the five-year rule is its expiry. Showing the derived date rather than a blank means every
|
||||
* document answers "valid until when?", and the officer sees the same date the alert will fire on
|
||||
* instead of having to add five years in their head.
|
||||
*/
|
||||
get kycDocumentExpiresOn(): string {
|
||||
const dueOn = this.kycDocumentRenewal.dueOn;
|
||||
return dueOn ? this.dateUtils.formatDate(dueOn, 'dd MMMM yyyy') : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* True when the date above was calculated from the issue date rather than read off the document.
|
||||
* Flagged in the UI so a derived date is never mistaken for one printed on the card.
|
||||
*/
|
||||
get kycDocumentExpiryIsDerived(): boolean {
|
||||
return this.kycDocumentRenewal.reason === 'AGE';
|
||||
}
|
||||
|
||||
/** Compact chip label for the document row in the verification table. */
|
||||
get kycDocumentStatusLabel(): string {
|
||||
switch (this.kycDocumentRenewal.state) {
|
||||
case 'EXPIRED':
|
||||
return 'Expired';
|
||||
case 'EXPIRING_SOON':
|
||||
return 'Expires Soon';
|
||||
case 'DUE':
|
||||
return 'Update Due';
|
||||
case 'OK':
|
||||
return 'Current';
|
||||
default:
|
||||
return '—';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Exception columns derived from verification status — see `deriveKycExceptionFields()`.
|
||||
*
|
||||
@@ -213,7 +350,11 @@ export class KycTabComponent implements OnInit, OnDestroy {
|
||||
|
||||
return deriveKycExceptionFields({
|
||||
panVerified,
|
||||
// A signed declaration closes the PAN item by paperwork when the API never can.
|
||||
panDeclarationTaken: this.panDeclarationTaken,
|
||||
aadhaarVerified,
|
||||
// An enrolment slip closes the Aadhaar item when there is no number to verify yet.
|
||||
aadhaarReceiptTaken: this.aadhaarReceiptTaken,
|
||||
aadhaarApplicable: !this.isNonIndividual,
|
||||
hadException: this.kycData?.isException === true,
|
||||
previousReason: this.kycData?.exceptionReason || null,
|
||||
@@ -326,7 +467,12 @@ export class KycTabComponent implements OnInit, OnDestroy {
|
||||
if (response?.changes?.panVerified) {
|
||||
this.verificationStatus.pan = 'VERIFIED';
|
||||
this.verificationDetails.pan = response.changes;
|
||||
this.loadKycData();
|
||||
// A PAN that now verifies makes any earlier declaration moot.
|
||||
if (this.panDeclarationTaken) {
|
||||
this.writePanDeclaration(null);
|
||||
} else {
|
||||
this.loadKycData();
|
||||
}
|
||||
} else {
|
||||
this.verificationStatus.pan = 'FAILED';
|
||||
this.verificationError.pan = 'PAN verification failed.';
|
||||
@@ -345,6 +491,283 @@ export class KycTabComponent implements OnInit, OnDestroy {
|
||||
}, 'pan');
|
||||
}
|
||||
|
||||
/**
|
||||
* Records the customer declaration that stands in for a PAN check the client cannot pass.
|
||||
*
|
||||
* Offered for any PAN failure, not just a name/DOB mismatch — an officer facing an unreachable
|
||||
* vendor is just as stuck as one facing a misspelt PAN card, and the same signed paperwork
|
||||
* resolves both. When the failure was not a comparable mismatch there is no PAN card to compare
|
||||
* against, so the dialog only asks why the declaration is being taken.
|
||||
*/
|
||||
takePanDeclaration(): void {
|
||||
if (!this.kycId) {
|
||||
this.verificationError.pan = 'KYC record not found. Save KYC details first.';
|
||||
return;
|
||||
}
|
||||
const failureMessage = this.verificationError.pan || 'PAN has not been verified.';
|
||||
const mismatch = failureMessage.toLowerCase().includes('does not match');
|
||||
|
||||
this.dialog
|
||||
.open(PanDeclarationDialogComponent, {
|
||||
width: '720px',
|
||||
maxWidth: '95vw',
|
||||
disableClose: true,
|
||||
data: {
|
||||
submittedName: this.kycData?.clientDisplayName || this.clientData?.displayName || '',
|
||||
submittedDob: this.clientDateOfBirth || '',
|
||||
panNumber: this.kycForm.value.panNumber || this.kycData?.panNumber || '',
|
||||
failureMessage,
|
||||
// Only a reported name/DOB mismatch gives the officer something to compare against.
|
||||
unverifiable: !mismatch,
|
||||
existing: this.panDeclarationTaken
|
||||
? {
|
||||
mismatchFields: this.kycData?.panDeclarationMismatchFields || 'NONE',
|
||||
nameOnPan: this.kycData?.panDeclarationNameOnPan || null,
|
||||
dobOnPan: this.parseApiDate(this.kycData?.panDeclarationDobOnPan),
|
||||
// The scan itself lives with the client's documents; the record keeps its name.
|
||||
file: null,
|
||||
fileName: this.kycData?.panDeclarationRemarks || ''
|
||||
}
|
||||
: null
|
||||
}
|
||||
})
|
||||
.afterClosed()
|
||||
.subscribe((result: PanDeclarationResult | undefined) => {
|
||||
if (!result) {
|
||||
return;
|
||||
}
|
||||
// The scan has to be filed against the client before the record says a declaration exists —
|
||||
// otherwise the PAN exception is waived by a document nobody can produce.
|
||||
if (result.file) {
|
||||
this.uploadPanDeclarationFile(result.file, () => this.writePanDeclaration(result));
|
||||
} else {
|
||||
this.writePanDeclaration(result);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** Files the signed declaration under the client's documents, then continues with `onDone`. */
|
||||
private uploadPanDeclarationFile(file: File, onDone: () => void): void {
|
||||
this.saving = true;
|
||||
this.errorMessage = null;
|
||||
|
||||
const formData = new FormData();
|
||||
formData.append('file', file);
|
||||
formData.append('name', 'PAN Declaration');
|
||||
formData.append(
|
||||
'description',
|
||||
`Signed PAN declaration for ${this.kycForm.value.panNumber || this.kycData?.panNumber || 'PAN'}`
|
||||
);
|
||||
|
||||
this.clientsService
|
||||
.uploadClientDocument(this.clientId, formData)
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe({
|
||||
next: () => {
|
||||
this.saving = false;
|
||||
onDone();
|
||||
},
|
||||
error: (err: any) => {
|
||||
this.saving = false;
|
||||
this.errorMessage =
|
||||
err?.error?.defaultUserMessage ||
|
||||
err?.error?.developerMessage ||
|
||||
err?.message ||
|
||||
'Could not upload the signed declaration. Please try again.';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** Officer-initiated removal — the PAN exception is raised again on this same save. */
|
||||
removePanDeclaration(): void {
|
||||
if (this.panDeclarationTaken) {
|
||||
this.writePanDeclaration(null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Persists (or clears) the declaration on the KYC record.
|
||||
*
|
||||
* `buildExceptionFields()` reads the declaration off `kycData`, so that has to be updated before
|
||||
* the payload is built — otherwise the save would carry the declaration and the PAN exception at
|
||||
* the same time, which is exactly the contradiction the declaration exists to prevent.
|
||||
*/
|
||||
private writePanDeclaration(declaration: PanDeclarationResult | null): void {
|
||||
this.saving = true;
|
||||
this.errorMessage = null;
|
||||
|
||||
const previous = {
|
||||
panDeclarationTaken: this.kycData?.panDeclarationTaken,
|
||||
panDeclarationMismatchFields: this.kycData?.panDeclarationMismatchFields,
|
||||
panDeclarationNameOnPan: this.kycData?.panDeclarationNameOnPan,
|
||||
panDeclarationDobOnPan: this.kycData?.panDeclarationDobOnPan,
|
||||
panDeclarationRemarks: this.kycData?.panDeclarationRemarks,
|
||||
panDeclarationTakenOn: this.kycData?.panDeclarationTakenOn
|
||||
};
|
||||
|
||||
const dateFormat = 'dd MMMM yyyy';
|
||||
const declarationFields = {
|
||||
panDeclarationTaken: !!declaration,
|
||||
panDeclarationMismatchFields: declaration?.mismatchFields || null,
|
||||
panDeclarationNameOnPan: declaration?.nameOnPan || null,
|
||||
panDeclarationDobOnPan: declaration?.dobOnPan
|
||||
? this.dateUtils.formatDate(declaration.dobOnPan, dateFormat)
|
||||
: null,
|
||||
// Names the uploaded declaration filed under the client's documents.
|
||||
panDeclarationRemarks: declaration?.fileName || null,
|
||||
panDeclarationTakenOn: declaration ? this.dateUtils.formatDate(new Date(), dateFormat) : null
|
||||
};
|
||||
|
||||
this.kycData = { ...(this.kycData || {}), ...declarationFields };
|
||||
|
||||
const payload: any = {
|
||||
locale: 'en',
|
||||
dateFormat,
|
||||
riskCategory: this.kycForm.value.riskCategory || 1,
|
||||
...declarationFields,
|
||||
...this.buildExceptionFields()
|
||||
};
|
||||
|
||||
this.clientsService
|
||||
.updateClientKyc(this.clientId, this.kycId, payload)
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe({
|
||||
next: () => {
|
||||
this.saving = false;
|
||||
this.loadKycData();
|
||||
},
|
||||
error: (err: any) => {
|
||||
this.saving = false;
|
||||
// Put the record back so the tab never shows a declaration the server did not accept.
|
||||
this.kycData = { ...(this.kycData || {}), ...previous };
|
||||
this.errorMessage =
|
||||
err?.error?.developerMessage ||
|
||||
err?.error?.defaultUserMessage ||
|
||||
err?.message ||
|
||||
'Failed to save the PAN declaration.';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 has no number to put through
|
||||
* the OTP flow, so the check can never pass. The slip closes the item instead.
|
||||
*/
|
||||
takeAadhaarReceipt(): void {
|
||||
if (!this.kycId) {
|
||||
this.verificationError.aadhaar = 'KYC record not found. Save KYC details first.';
|
||||
return;
|
||||
}
|
||||
this.dialog
|
||||
.open(AadhaarReceiptDialogComponent, {
|
||||
width: '560px',
|
||||
maxWidth: '95vw',
|
||||
disableClose: true,
|
||||
data: {
|
||||
clientName: this.kycData?.clientDisplayName || this.clientData?.displayName || '',
|
||||
reason:
|
||||
this.verificationError.aadhaar ||
|
||||
'Aadhaar has not been verified. Record the enrolment slip if the customer has applied but not yet received their Aadhaar.',
|
||||
existing: this.aadhaarReceiptTaken
|
||||
? {
|
||||
enrolmentId: this.kycData?.aadhaarEnrolmentId || '',
|
||||
enrolmentDate: this.parseApiDate(this.kycData?.aadhaarEnrolmentDate),
|
||||
remarks: this.kycData?.aadhaarReceiptRemarks || ''
|
||||
}
|
||||
: null
|
||||
}
|
||||
})
|
||||
.afterClosed()
|
||||
.subscribe((result: AadhaarReceiptResult | undefined) => {
|
||||
if (result) {
|
||||
this.writeAadhaarReceipt(result);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** Officer-initiated removal — the Aadhaar exception is raised again on this same save. */
|
||||
removeAadhaarReceipt(): void {
|
||||
if (this.aadhaarReceiptTaken) {
|
||||
this.writeAadhaarReceipt(null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Persists (or clears) the enrolment receipt on the KYC record.
|
||||
*
|
||||
* `buildExceptionFields()` reads the receipt off `kycData`, so that has to be updated before the
|
||||
* payload is built — otherwise the save would carry the receipt and the Aadhaar exception at the
|
||||
* same time, the contradiction the receipt exists to prevent.
|
||||
*/
|
||||
private writeAadhaarReceipt(receipt: AadhaarReceiptResult | null): void {
|
||||
this.saving = true;
|
||||
this.errorMessage = null;
|
||||
|
||||
const previous = {
|
||||
aadhaarReceiptTaken: this.kycData?.aadhaarReceiptTaken,
|
||||
aadhaarEnrolmentId: this.kycData?.aadhaarEnrolmentId,
|
||||
aadhaarEnrolmentDate: this.kycData?.aadhaarEnrolmentDate,
|
||||
aadhaarReceiptRemarks: this.kycData?.aadhaarReceiptRemarks,
|
||||
aadhaarReceiptTakenOn: this.kycData?.aadhaarReceiptTakenOn
|
||||
};
|
||||
|
||||
const dateFormat = 'dd MMMM yyyy';
|
||||
const receiptFields = {
|
||||
aadhaarReceiptTaken: !!receipt,
|
||||
aadhaarEnrolmentId: receipt?.enrolmentId || null,
|
||||
aadhaarEnrolmentDate: receipt?.enrolmentDate
|
||||
? this.dateUtils.formatDate(receipt.enrolmentDate, dateFormat)
|
||||
: null,
|
||||
aadhaarReceiptRemarks: receipt?.remarks || null,
|
||||
aadhaarReceiptTakenOn: receipt ? this.dateUtils.formatDate(new Date(), dateFormat) : null
|
||||
};
|
||||
|
||||
this.kycData = { ...(this.kycData || {}), ...receiptFields };
|
||||
|
||||
const payload: any = {
|
||||
locale: 'en',
|
||||
dateFormat,
|
||||
riskCategory: this.kycForm.value.riskCategory || 1,
|
||||
...receiptFields,
|
||||
...this.buildExceptionFields()
|
||||
};
|
||||
|
||||
this.clientsService
|
||||
.updateClientKyc(this.clientId, this.kycId, payload)
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe({
|
||||
next: () => {
|
||||
this.saving = false;
|
||||
this.verificationError.aadhaar = null;
|
||||
this.loadKycData();
|
||||
},
|
||||
error: (err: any) => {
|
||||
this.saving = false;
|
||||
// Put the record back so the tab never shows a receipt the server did not accept.
|
||||
this.kycData = { ...(this.kycData || {}), ...previous };
|
||||
this.errorMessage =
|
||||
err?.error?.developerMessage ||
|
||||
err?.error?.defaultUserMessage ||
|
||||
err?.message ||
|
||||
'Failed to save the Aadhaar enrolment receipt.';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/** Fineract serialises dates as `[yyyy, M, d]`; the same field can also arrive as a string. */
|
||||
private parseApiDate(raw: any): Date | null {
|
||||
if (!raw) {
|
||||
return null;
|
||||
}
|
||||
if (Array.isArray(raw) && raw.length >= 3) {
|
||||
return new Date(raw[0], raw[1] - 1, raw[2]);
|
||||
}
|
||||
const parsed = new Date(raw);
|
||||
return isNaN(parsed.getTime()) ? null : parsed;
|
||||
}
|
||||
|
||||
/** Show Aadhaar input in summary view for re-verification */
|
||||
startAadhaarReVerify(): void {
|
||||
this.showAadhaarReVerify = true;
|
||||
@@ -416,7 +839,13 @@ export class KycTabComponent implements OnInit, OnDestroy {
|
||||
this.verificationStatus.aadhaar = 'VERIFIED';
|
||||
this.verificationDetails.aadhaar = response.changes;
|
||||
this.resetOtpState();
|
||||
this.loadKycData();
|
||||
// Aadhaar has been issued and verified, so the enrolment slip has served its purpose —
|
||||
// drop it rather than leave the record claiming the customer is still waiting.
|
||||
if (this.aadhaarReceiptTaken) {
|
||||
this.writeAadhaarReceipt(null);
|
||||
} else {
|
||||
this.loadKycData();
|
||||
}
|
||||
} else {
|
||||
this.verificationStatus.aadhaar = 'FAILED';
|
||||
this.verificationError.aadhaar = 'OTP verification failed.';
|
||||
@@ -619,13 +1048,43 @@ export class KycTabComponent implements OnInit, OnDestroy {
|
||||
|
||||
// PAN
|
||||
y = addLine('PAN Number:', kyc.panNumber || '—', y);
|
||||
y = addLine('PAN Status:', kyc.panVerified ? 'Verified' : 'Pending', y);
|
||||
// "Pending" would misdescribe a PAN that was checked, failed, and was settled by declaration —
|
||||
// nothing is pending on that record, and the certificate has to say what actually happened.
|
||||
y = addLine(
|
||||
'PAN Status:',
|
||||
kyc.panVerified ? 'Verified' : this.panDeclarationTaken ? 'Not Verified — Declaration Taken' : 'Pending',
|
||||
y
|
||||
);
|
||||
if (kyc.panVerifiedOn) y = addLine('PAN Verified On:', this.formatDate(kyc.panVerifiedOn), y);
|
||||
if (!kyc.panVerified && this.panDeclarationTaken) {
|
||||
y = addLine('Declared Mismatch:', this.panDeclarationMismatchLabel, y);
|
||||
if (kyc.panDeclarationNameOnPan) y = addLine('Name on PAN:', kyc.panDeclarationNameOnPan, y);
|
||||
if (kyc.panDeclarationDobOnPan) {
|
||||
y = addLine('DOB on PAN:', this.formatDate(kyc.panDeclarationDobOnPan), y);
|
||||
}
|
||||
if (kyc.panDeclarationTakenOn) {
|
||||
y = addLine('Declaration Taken On:', this.formatDate(kyc.panDeclarationTakenOn), y);
|
||||
}
|
||||
}
|
||||
|
||||
// Aadhaar
|
||||
y = addLine('Aadhaar Number:', kyc.aadhaarNumberMasked || '—', y);
|
||||
y = addLine('Aadhaar Status:', kyc.aadhaarVerified ? 'Verified' : 'Pending', y);
|
||||
// As with PAN: "Pending" would misdescribe a client who holds only an enrolment slip.
|
||||
y = addLine(
|
||||
'Aadhaar Status:',
|
||||
kyc.aadhaarVerified ? 'Verified' : this.aadhaarReceiptTaken ? 'Not Verified — Enrolment Receipt' : 'Pending',
|
||||
y
|
||||
);
|
||||
if (kyc.aadhaarVerifiedOn) y = addLine('Aadhaar Verified On:', this.formatDate(kyc.aadhaarVerifiedOn), y);
|
||||
if (!kyc.aadhaarVerified && this.aadhaarReceiptTaken) {
|
||||
if (kyc.aadhaarEnrolmentId) y = addLine('Enrolment ID:', kyc.aadhaarEnrolmentId, y);
|
||||
if (kyc.aadhaarEnrolmentDate) {
|
||||
y = addLine('Enrolment Date:', this.formatDate(kyc.aadhaarEnrolmentDate), y);
|
||||
}
|
||||
if (kyc.aadhaarReceiptTakenOn) {
|
||||
y = addLine('Receipt Recorded On:', this.formatDate(kyc.aadhaarReceiptTakenOn), y);
|
||||
}
|
||||
}
|
||||
|
||||
// PAN-Aadhaar Link
|
||||
const seedingStatus =
|
||||
|
||||
Reference in New Issue
Block a user