fix: restore content silently dropped from the dev merge (KYC exception, TDS reports, Form 121)
The demo-backup merge's git 3-way auto-resolve dropped several hunks without flagging conflicts, wherever demo had independently touched adjacent lines: the KYC Exception feature (client-kyc-step, kyc-tab, create-client, clients.service — checkbox, derivation logic, banners, contact-log endpoints), TDS report routes/menu links (reports-routing, shell), the Form 121 client tab (clients-routing, clients-view), the kyc-management exceptions dashboard, and the Form 121/15G-H register's real-data view integration. Restored by diffing demo-backup against dev per file and re-applying each genuine gap while preserving demo-backup's own independent work (Approval Center tab style, Loan Origination/Investment menus, form-97-98/risk-review report routes).
This commit is contained in:
@@ -14,6 +14,7 @@ import { catchError, of, Subject, takeUntil } from 'rxjs';
|
||||
|
||||
/** Custom Services */
|
||||
import { ClientsService } from '../../clients.service';
|
||||
import { deriveKycExceptionFields } from '../../kyc-exception.util';
|
||||
import { Dates } from 'app/core/utils/dates';
|
||||
import { jsPDF } from 'jspdf';
|
||||
import { MatIcon } from '@angular/material/icon';
|
||||
@@ -121,7 +122,9 @@ export class KycTabComponent implements OnInit, OnDestroy {
|
||||
'',
|
||||
[Validators.pattern(/^[0-9]{2}[A-Z]{5}[0-9]{4}[A-Z]{1}[1-9A-Z]{1}Z[0-9A-Z]{1}$/)]
|
||||
],
|
||||
remarks: ['']
|
||||
remarks: [''],
|
||||
isException: [false],
|
||||
exceptionReason: [[]]
|
||||
});
|
||||
|
||||
ngOnInit(): void {
|
||||
@@ -157,7 +160,9 @@ export class KycTabComponent implements OnInit, OnDestroy {
|
||||
// the full 12-digit number to re-verify, so don't pre-fill.
|
||||
aadhaarNumber: '',
|
||||
gstinNumber: data.gstinNumber || '',
|
||||
remarks: data.remarks || ''
|
||||
remarks: data.remarks || '',
|
||||
isException: data.isException || false,
|
||||
exceptionReason: data.exceptionReason ? data.exceptionReason.split(', ') : []
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -195,6 +200,28 @@ export class KycTabComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Exception columns derived from verification status — see `deriveKycExceptionFields()`.
|
||||
*
|
||||
* A field counts as verified if it was verified in this session OR is already verified on the
|
||||
* stored record; either way the customer has cleared that check. Verifying one of two
|
||||
* outstanding items narrows the exception to the remaining one rather than closing it.
|
||||
*/
|
||||
private buildExceptionFields() {
|
||||
const panVerified = this.verificationStatus.pan === 'VERIFIED' || this.kycData?.panVerified === true;
|
||||
const aadhaarVerified = this.verificationStatus.aadhaar === 'VERIFIED' || this.kycData?.aadhaarVerified === true;
|
||||
|
||||
return deriveKycExceptionFields({
|
||||
panVerified,
|
||||
aadhaarVerified,
|
||||
aadhaarApplicable: !this.isNonIndividual,
|
||||
hadException: this.kycData?.isException === true,
|
||||
previousReason: this.kycData?.exceptionReason || null,
|
||||
manualReasons: Array.isArray(this.kycForm.value.exceptionReason) ? this.kycForm.value.exceptionReason : [],
|
||||
todayFormatted: this.dateUtils.formatDate(new Date(), 'dd MMMM yyyy')
|
||||
});
|
||||
}
|
||||
|
||||
saveKyc(): void {
|
||||
if (this.kycForm.invalid) {
|
||||
return;
|
||||
@@ -210,7 +237,10 @@ export class KycTabComponent implements OnInit, OnDestroy {
|
||||
panNumber: this.kycForm.value.panNumber || null,
|
||||
aadhaarNumberMasked: aadhaarMasked,
|
||||
gstinNumber: this.kycForm.value.gstinNumber || null,
|
||||
remarks: this.kycForm.value.remarks || null
|
||||
remarks: this.kycForm.value.remarks || null,
|
||||
// dateFormat is required so the backend can parse exceptionResolvedOn when an exception closes.
|
||||
dateFormat: 'dd MMMM yyyy',
|
||||
...this.buildExceptionFields()
|
||||
};
|
||||
|
||||
if (!this.kycId) {
|
||||
@@ -244,6 +274,38 @@ export class KycTabComponent implements OnInit, OnDestroy {
|
||||
});
|
||||
}
|
||||
|
||||
private saveKycBeforeVerify(callback: () => void, field: 'pan' | 'aadhaar' | 'gstin'): void {
|
||||
if (this.isEditMode) {
|
||||
const aadhaarRaw = this.kycForm.value.aadhaarNumber || '';
|
||||
const aadhaarMasked = aadhaarRaw.length === 12 ? 'XXXXXXXX' + aadhaarRaw.slice(-4) : aadhaarRaw || null;
|
||||
const payload: any = {
|
||||
locale: 'en',
|
||||
panNumber: this.kycForm.value.panNumber || null,
|
||||
aadhaarNumberMasked: aadhaarMasked,
|
||||
gstinNumber: this.kycForm.value.gstinNumber || null,
|
||||
remarks: this.kycForm.value.remarks || null,
|
||||
riskCategory: this.kycForm.value.riskCategory || 1,
|
||||
dateFormat: 'dd MMMM yyyy',
|
||||
...this.buildExceptionFields()
|
||||
};
|
||||
|
||||
this.clientsService.updateClientKyc(this.clientId, this.kycId, payload).subscribe({
|
||||
next: () => {
|
||||
this.loadKycData();
|
||||
callback();
|
||||
},
|
||||
error: (err: any) => {
|
||||
this.verifying[field] = false;
|
||||
this.verificationStatus[field] = 'FAILED';
|
||||
this.verificationError[field] =
|
||||
err?.error?.defaultUserMessage || `Failed to update ${field.toUpperCase()} number before verification.`;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
verifyPAN(): void {
|
||||
if (!this.kycId) {
|
||||
this.verificationError.pan = 'KYC record not found. Save KYC details first.';
|
||||
@@ -254,31 +316,33 @@ export class KycTabComponent implements OnInit, OnDestroy {
|
||||
this.verificationError.pan = null;
|
||||
this.verificationDetails.pan = null;
|
||||
|
||||
this.clientsService
|
||||
.verifyPAN(this.clientId, this.kycId)
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe({
|
||||
next: (response: any) => {
|
||||
this.verifying.pan = false;
|
||||
if (response?.changes?.panVerified) {
|
||||
this.verificationStatus.pan = 'VERIFIED';
|
||||
this.verificationDetails.pan = response.changes;
|
||||
this.loadKycData();
|
||||
} else {
|
||||
this.saveKycBeforeVerify(() => {
|
||||
this.clientsService
|
||||
.verifyPAN(this.clientId, this.kycId)
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe({
|
||||
next: (response: any) => {
|
||||
this.verifying.pan = false;
|
||||
if (response?.changes?.panVerified) {
|
||||
this.verificationStatus.pan = 'VERIFIED';
|
||||
this.verificationDetails.pan = response.changes;
|
||||
this.loadKycData();
|
||||
} else {
|
||||
this.verificationStatus.pan = 'FAILED';
|
||||
this.verificationError.pan = 'PAN verification failed.';
|
||||
}
|
||||
},
|
||||
error: (err: any) => {
|
||||
this.verifying.pan = false;
|
||||
this.verificationStatus.pan = 'FAILED';
|
||||
this.verificationError.pan = 'PAN verification failed.';
|
||||
this.verificationError.pan =
|
||||
err?.error?.developerMessage ||
|
||||
err?.error?.defaultUserMessage ||
|
||||
err?.message ||
|
||||
'PAN verification failed. Please try again.';
|
||||
}
|
||||
},
|
||||
error: (err: any) => {
|
||||
this.verifying.pan = false;
|
||||
this.verificationStatus.pan = 'FAILED';
|
||||
this.verificationError.pan =
|
||||
err?.error?.developerMessage ||
|
||||
err?.error?.defaultUserMessage ||
|
||||
err?.message ||
|
||||
'PAN verification failed. Please try again.';
|
||||
}
|
||||
});
|
||||
});
|
||||
}, 'pan');
|
||||
}
|
||||
|
||||
/** Show Aadhaar input in summary view for re-verification */
|
||||
@@ -305,31 +369,33 @@ export class KycTabComponent implements OnInit, OnDestroy {
|
||||
this.aadhaarOtpSent = false;
|
||||
this.aadhaarOtp = '';
|
||||
|
||||
this.clientsService
|
||||
.sendAadhaarOtp(this.clientId, this.kycId, aadhaar)
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe({
|
||||
next: (response: any) => {
|
||||
this.verifying.aadhaar = false;
|
||||
const refNumber =
|
||||
response?.changes?.aadhaarRefNumber ||
|
||||
response?.aadhaarRefNumber ||
|
||||
response?.changes?.referenceNumber ||
|
||||
response?.resourceId;
|
||||
this.aadhaarOtpSent = true;
|
||||
this.aadhaarOtpReferenceId = refNumber || null;
|
||||
this.verificationStatus.aadhaar = 'PENDING';
|
||||
},
|
||||
error: (err: any) => {
|
||||
this.verifying.aadhaar = false;
|
||||
this.verificationStatus.aadhaar = 'FAILED';
|
||||
this.verificationError.aadhaar =
|
||||
err?.error?.developerMessage ||
|
||||
err?.error?.defaultUserMessage ||
|
||||
err?.message ||
|
||||
'Failed to send OTP. Please try again.';
|
||||
}
|
||||
});
|
||||
this.saveKycBeforeVerify(() => {
|
||||
this.clientsService
|
||||
.sendAadhaarOtp(this.clientId, this.kycId, aadhaar)
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe({
|
||||
next: (response: any) => {
|
||||
this.verifying.aadhaar = false;
|
||||
const refNumber =
|
||||
response?.changes?.aadhaarRefNumber ||
|
||||
response?.aadhaarRefNumber ||
|
||||
response?.changes?.referenceNumber ||
|
||||
response?.resourceId;
|
||||
this.aadhaarOtpSent = true;
|
||||
this.aadhaarOtpReferenceId = refNumber || null;
|
||||
this.verificationStatus.aadhaar = 'PENDING';
|
||||
},
|
||||
error: (err: any) => {
|
||||
this.verifying.aadhaar = false;
|
||||
this.verificationStatus.aadhaar = 'FAILED';
|
||||
this.verificationError.aadhaar =
|
||||
err?.error?.developerMessage ||
|
||||
err?.error?.defaultUserMessage ||
|
||||
err?.message ||
|
||||
'Failed to send OTP. Please try again.';
|
||||
}
|
||||
});
|
||||
}, 'aadhaar');
|
||||
}
|
||||
|
||||
/** Step 2: Verify OTP entered by user */
|
||||
@@ -380,31 +446,33 @@ export class KycTabComponent implements OnInit, OnDestroy {
|
||||
this.verificationError.gstin = null;
|
||||
this.verificationDetails.gstin = null;
|
||||
|
||||
this.clientsService
|
||||
.verifyGSTIN(this.clientId, this.kycId)
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe({
|
||||
next: (response: any) => {
|
||||
this.verifying.gstin = false;
|
||||
if (response?.changes?.gstinVerified) {
|
||||
this.verificationStatus.gstin = 'VERIFIED';
|
||||
this.verificationDetails.gstin = response.changes;
|
||||
this.loadKycData();
|
||||
} else {
|
||||
this.saveKycBeforeVerify(() => {
|
||||
this.clientsService
|
||||
.verifyGSTIN(this.clientId, this.kycId)
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe({
|
||||
next: (response: any) => {
|
||||
this.verifying.gstin = false;
|
||||
if (response?.changes?.gstinVerified) {
|
||||
this.verificationStatus.gstin = 'VERIFIED';
|
||||
this.verificationDetails.gstin = response.changes;
|
||||
this.loadKycData();
|
||||
} else {
|
||||
this.verificationStatus.gstin = 'FAILED';
|
||||
this.verificationError.gstin = 'GSTIN verification failed.';
|
||||
}
|
||||
},
|
||||
error: (err: any) => {
|
||||
this.verifying.gstin = false;
|
||||
this.verificationStatus.gstin = 'FAILED';
|
||||
this.verificationError.gstin = 'GSTIN verification failed.';
|
||||
this.verificationError.gstin =
|
||||
err?.error?.developerMessage ||
|
||||
err?.error?.defaultUserMessage ||
|
||||
err?.message ||
|
||||
'GSTIN verification failed. Please try again.';
|
||||
}
|
||||
},
|
||||
error: (err: any) => {
|
||||
this.verifying.gstin = false;
|
||||
this.verificationStatus.gstin = 'FAILED';
|
||||
this.verificationError.gstin =
|
||||
err?.error?.developerMessage ||
|
||||
err?.error?.defaultUserMessage ||
|
||||
err?.message ||
|
||||
'GSTIN verification failed. Please try again.';
|
||||
}
|
||||
});
|
||||
});
|
||||
}, 'gstin');
|
||||
}
|
||||
|
||||
formatDate(date: any): string {
|
||||
|
||||
Reference in New Issue
Block a user