Merge remote-tracking branch 'origin/uate' into uate
This commit is contained in:
+36
@@ -238,6 +238,42 @@ export class ClientIndiaAddressStepComponent implements OnInit, OnChanges {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets transient address-tab state for a brand-new client.
|
||||||
|
*
|
||||||
|
* This app's RouteReusableStrategy (core/route/route-reusable-strategy.ts) keeps this SAME
|
||||||
|
* component instance alive across repeat visits to /clients/create, so `ngOnInit` never
|
||||||
|
* re-runs for a second "create new client" session — the previous client's address forms,
|
||||||
|
* selected proof-of-address chip and uploaded files would otherwise leak into the new one.
|
||||||
|
* Called by CreateClientComponent.resetForNewClient() whenever a fresh create session begins.
|
||||||
|
*/
|
||||||
|
resetForNewClient(): void {
|
||||||
|
this.permanentForm.reset({ country: 'India' });
|
||||||
|
this.currentForm.reset({ country: 'India' });
|
||||||
|
this.officeForm.reset({ country: 'India' });
|
||||||
|
this.correspondenceForm.reset({ country: 'India' });
|
||||||
|
this.activeTab = 0;
|
||||||
|
this.sameAsPermanent = false;
|
||||||
|
this.pinStatus = {
|
||||||
|
permanent: { loading: false, found: false, error: false, message: '' },
|
||||||
|
current: { loading: false, found: false, error: false, message: '' },
|
||||||
|
office: { loading: false, found: false, error: false, message: '' },
|
||||||
|
correspondence: { loading: false, found: false, error: false, message: '' }
|
||||||
|
};
|
||||||
|
this.localityOptions = { permanent: [], current: [], office: [], correspondence: [] };
|
||||||
|
this.selectedAddrProof = null;
|
||||||
|
this.addrFiles = { front: null, back: null };
|
||||||
|
this.addrMergedFile = null;
|
||||||
|
this.addrMergedPreview = null;
|
||||||
|
this.existingAddressProofIdentifierId = null;
|
||||||
|
this.existingAddressProofDocuments = [];
|
||||||
|
this.addressLoaded = false;
|
||||||
|
// Re-fetch rather than re-filter `addressProofs` in place — if the previous session's
|
||||||
|
// isMinor filtering already reduced it (e.g. down to Aadhaar/Passport only), filtering
|
||||||
|
// that reduced list again can never recover the items it already removed.
|
||||||
|
this.loadProofTypes();
|
||||||
|
}
|
||||||
|
|
||||||
private loadProofTypes(): void {
|
private loadProofTypes(): void {
|
||||||
this.loadingProofs = true;
|
this.loadingProofs = true;
|
||||||
this.clientsService.getKycProofTypes().subscribe({
|
this.clientsService.getKycProofTypes().subscribe({
|
||||||
|
|||||||
@@ -161,6 +161,17 @@
|
|||||||
}
|
}
|
||||||
</button>
|
</button>
|
||||||
}
|
}
|
||||||
|
@if (aadhaarOtpSent && aadhaarVerifyStatus !== 'VERIFIED') {
|
||||||
|
<button
|
||||||
|
mat-stroked-button
|
||||||
|
type="button"
|
||||||
|
class="change-number-btn"
|
||||||
|
[disabled]="readOnly"
|
||||||
|
(click)="changeAadhaarNumber()"
|
||||||
|
>
|
||||||
|
<mat-icon>edit</mat-icon> Change Number
|
||||||
|
</button>
|
||||||
|
}
|
||||||
@if (aadhaarVerifyStatus === 'VERIFIED') {
|
@if (aadhaarVerifyStatus === 'VERIFIED') {
|
||||||
<span class="verify-chip verified"><fa-icon icon="check-circle"></fa-icon> Verified</span>
|
<span class="verify-chip verified"><fa-icon icon="check-circle"></fa-icon> Verified</span>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -266,6 +266,23 @@
|
|||||||
gap: 6px;
|
gap: 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.change-number-btn {
|
||||||
|
font-size: 12px !important;
|
||||||
|
font-weight: 600 !important;
|
||||||
|
padding: 0 14px !important;
|
||||||
|
height: 36px !important;
|
||||||
|
border-radius: 6px !important;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
|
||||||
|
mat-icon {
|
||||||
|
font-size: 16px;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.verify-chip {
|
.verify-chip {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|||||||
@@ -462,15 +462,16 @@ export class ClientKycStepComponent implements OnInit, OnChanges, OnDestroy {
|
|||||||
form15FY: ['']
|
form15FY: ['']
|
||||||
});
|
});
|
||||||
|
|
||||||
/** RBI OVDs a minor cannot hold: Voter ID and Driving Licence require adult age,
|
/** RBI-accepted OVDs for a minor client — mirrors the backend's minor branch in
|
||||||
* PAN and NREGA job cards are issued to adults. Aadhaar, Passport and NPR letters
|
* ClientKycApiResource.getRequiredDocuments(). Voter ID, Driving Licence, PAN and NREGA
|
||||||
* are unaffected by age and stay available. */
|
* all require adult eligibility; National Population Register Letter is deliberately
|
||||||
private static readonly MINOR_INELIGIBLE_DOC_KEYWORDS = [
|
* excluded too (not offered as a minor OVD in this system). */
|
||||||
'pan',
|
private static readonly MINOR_ELIGIBLE_DOC_CODES = new Set([
|
||||||
'driving',
|
'AADHAAR',
|
||||||
'voter',
|
'PASSPORT',
|
||||||
'nrega'
|
'BIRTH_CERTIFICATE',
|
||||||
];
|
'SCHOOL_ID_CARD'
|
||||||
|
]);
|
||||||
|
|
||||||
/** Birth Certificate / School ID Card are minor-specific OVDs — not relevant once the
|
/** Birth Certificate / School ID Card are minor-specific OVDs — not relevant once the
|
||||||
* client is an adult, so they're hidden the other direction. */
|
* client is an adult, so they're hidden the other direction. */
|
||||||
@@ -481,27 +482,13 @@ export class ClientKycStepComponent implements OnInit, OnChanges, OnDestroy {
|
|||||||
|
|
||||||
private filterDocTypesForMinor<T extends { name: string; code?: string }>(docs: T[]): T[] {
|
private filterDocTypesForMinor<T extends { name: string; code?: string }>(docs: T[]): T[] {
|
||||||
if (this.isMinor) {
|
if (this.isMinor) {
|
||||||
return docs.filter((d) => {
|
return docs.filter((d) => ClientKycStepComponent.MINOR_ELIGIBLE_DOC_CODES.has((d.code || '').toUpperCase()));
|
||||||
const text = `${d.name || ''} ${d.code || ''}`.toLowerCase();
|
|
||||||
return !ClientKycStepComponent.MINOR_INELIGIBLE_DOC_KEYWORDS.some((k) => text.includes(k));
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
return docs.filter((d) => !ClientKycStepComponent.MINOR_ONLY_DOC_CODES.has((d.code || '').toUpperCase()));
|
return docs.filter((d) => !ClientKycStepComponent.MINOR_ONLY_DOC_CODES.has((d.code || '').toUpperCase()));
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
// Seed defaults immediately so the picker has options before clientId is set
|
this.seedDefaultDocTypes();
|
||||||
// (template API requires clientId; user can still pick a type pre-save).
|
|
||||||
if (!this.kycDocumentTypes.length) {
|
|
||||||
this.kycDocumentTypes = this.filterDocTypesForMinor(
|
|
||||||
this.defaultDocumentTypes.map((d) => ({
|
|
||||||
name: d.name,
|
|
||||||
code: d.code,
|
|
||||||
mandatory: false
|
|
||||||
}))
|
|
||||||
);
|
|
||||||
this.rebuildKycDocPicker();
|
|
||||||
}
|
|
||||||
this.loadExistingKycIfNeeded();
|
this.loadExistingKycIfNeeded();
|
||||||
this.loadKycTemplate();
|
this.loadKycTemplate();
|
||||||
if (this.isNonIndividual && this.constitutionMeta) {
|
if (this.isNonIndividual && this.constitutionMeta) {
|
||||||
@@ -509,6 +496,92 @@ export class ClientKycStepComponent implements OnInit, OnChanges, OnDestroy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Seed the document-type picker from defaults, filtered by the current isMinor input.
|
||||||
|
* Only seeds when the list is empty — the template API (loadKycTemplate) takes over once
|
||||||
|
* a clientId is available. */
|
||||||
|
private seedDefaultDocTypes(): void {
|
||||||
|
if (this.kycDocumentTypes.length) return;
|
||||||
|
this.kycDocumentTypes = this.filterDocTypesForMinor(
|
||||||
|
this.defaultDocumentTypes.map((d) => ({
|
||||||
|
name: d.name,
|
||||||
|
code: d.code,
|
||||||
|
mandatory: false
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
this.rebuildKycDocPicker();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets transient KYC-tab state for a brand-new client.
|
||||||
|
*
|
||||||
|
* This app's RouteReusableStrategy (core/route/route-reusable-strategy.ts) keeps this SAME
|
||||||
|
* component instance alive across repeat visits to /clients/create, so `ngOnInit` never
|
||||||
|
* re-runs for a second "create new client" session. Without this, the document-type picker
|
||||||
|
* (and any PAN/Aadhaar verification state, uploaded photo/signature) would otherwise leak
|
||||||
|
* from whatever client was created in the previous session into the new one. Called by
|
||||||
|
* CreateClientComponent.resetForNewClient() whenever a fresh create session begins.
|
||||||
|
*/
|
||||||
|
resetForNewClient(): void {
|
||||||
|
this.kycForm.reset({
|
||||||
|
hasPan: true,
|
||||||
|
riskCategory: 1,
|
||||||
|
amlCheckStatus: 'CLEAR',
|
||||||
|
bannedEntityMatch: 'NO',
|
||||||
|
willfulDefaulter: 'NO',
|
||||||
|
ecgcSalFlag: 'NO',
|
||||||
|
dormantFlag: 'ACTIVE',
|
||||||
|
accountStatus: 'ACTIVE',
|
||||||
|
form60Type: 'FORM_60',
|
||||||
|
form15Type: '15G'
|
||||||
|
});
|
||||||
|
this.kycId = '';
|
||||||
|
this.kycLoaded = false;
|
||||||
|
this.kycStatus = 0;
|
||||||
|
this.kycTemplate = null;
|
||||||
|
this.kycTemplateLoaded = false;
|
||||||
|
this.kycDocumentTypes = [];
|
||||||
|
this.selectedKycDoc = null;
|
||||||
|
this.kycDocFiles = { front: null, back: null };
|
||||||
|
this.kycDocMergedFile = null;
|
||||||
|
this.kycDocMergedPreview = null;
|
||||||
|
this.existingKycIdentifierId = null;
|
||||||
|
this.existingKycDocuments = [];
|
||||||
|
this.photoSigTouched = false;
|
||||||
|
this.panVerifyStatus = 'NONE';
|
||||||
|
this.panVerifying = false;
|
||||||
|
this.panVerifyError = '';
|
||||||
|
this.panVerifyName = '';
|
||||||
|
this.panVerifiedOn = '';
|
||||||
|
this.aadhaarVerifyStatus = 'NONE';
|
||||||
|
this.aadhaarVerifying = false;
|
||||||
|
this.aadhaarVerifyError = '';
|
||||||
|
this.aadhaarVerifyName = '';
|
||||||
|
this.aadhaarVisible = false;
|
||||||
|
this.aadhaarOtpSent = false;
|
||||||
|
this.resetOtpDigits();
|
||||||
|
this.aadhaarOtpReferenceId = '';
|
||||||
|
this.panAadhaarSeedingStatus = '';
|
||||||
|
this.entPanVerifyStatus = 'NONE';
|
||||||
|
this.entPanVerifying = false;
|
||||||
|
this.entPanVerifyName = '';
|
||||||
|
this.entPanVerifiedOn = '';
|
||||||
|
this.gstinVerifyStatus = 'NONE';
|
||||||
|
this.gstinVerifying = false;
|
||||||
|
this.gstinVerifyName = '';
|
||||||
|
this.gstinVerifiedOn = '';
|
||||||
|
this.gstinVerifyState = '';
|
||||||
|
this.cinVerifyStatus = 'NONE';
|
||||||
|
this.cinVerifying = false;
|
||||||
|
this.cinVerifiedOn = '';
|
||||||
|
this.cinCompanyName = '';
|
||||||
|
this.photographFile = null;
|
||||||
|
this.photographPreview = null;
|
||||||
|
this.signatureFile = null;
|
||||||
|
this.signaturePreview = null;
|
||||||
|
this.existingSignatureDocId = '';
|
||||||
|
this.seedDefaultDocTypes();
|
||||||
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
if (this.cinProgressTimer) clearInterval(this.cinProgressTimer);
|
if (this.cinProgressTimer) clearInterval(this.cinProgressTimer);
|
||||||
if (this.resendTimer) clearInterval(this.resendTimer);
|
if (this.resendTimer) clearInterval(this.resendTimer);
|
||||||
@@ -1375,6 +1448,21 @@ export class ClientKycStepComponent implements OnInit, OnChanges, OnDestroy {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Lets the user go back and fix a wrong Aadhaar number after an OTP was already sent —
|
||||||
|
* unlocks the (readonly-while-OTP-pending) input and discards the in-flight OTP session,
|
||||||
|
* since it was requested for the now-being-corrected number. */
|
||||||
|
changeAadhaarNumber(): void {
|
||||||
|
this.aadhaarOtpSent = false;
|
||||||
|
this.aadhaarVerifyError = '';
|
||||||
|
this.aadhaarOtpReferenceId = '';
|
||||||
|
this.resetOtpDigits();
|
||||||
|
this.resendCountdown = 0;
|
||||||
|
if (this.resendTimer) {
|
||||||
|
clearInterval(this.resendTimer);
|
||||||
|
this.resendTimer = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Verify Aadhaar OTP */
|
/** Verify Aadhaar OTP */
|
||||||
verifyAadhaarOtp() {
|
verifyAadhaarOtp() {
|
||||||
if (!this.aadhaarOtp || !this.clientId || !this.kycId) return;
|
if (!this.aadhaarOtp || !this.clientId || !this.kycId) return;
|
||||||
|
|||||||
@@ -139,6 +139,8 @@ export class CreateClientComponent {
|
|||||||
this.validationError = '';
|
this.validationError = '';
|
||||||
this.prefillData = null;
|
this.prefillData = null;
|
||||||
this.clientGeneralStep?.resetForNewClient();
|
this.clientGeneralStep?.resetForNewClient();
|
||||||
|
this.clientKycStep?.resetForNewClient();
|
||||||
|
this.clientIndiaAddressStep?.resetForNewClient();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Check if a tab is in read-only mode (completed tab navigated back to) */
|
/** Check if a tab is in read-only mode (completed tab navigated back to) */
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
export default {
|
export default {
|
||||||
'mifos_x': {
|
'mifos_x': {
|
||||||
'version': '260728',
|
'version': '260728',
|
||||||
'hash': 'a9c60083'
|
'hash': '2e4187c3'
|
||||||
},
|
},
|
||||||
'allow_switching_backend_instance': true
|
'allow_switching_backend_instance': true
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user