diff --git a/src/app/clients/client-stepper/client-india-address-step/client-india-address-step.component.ts b/src/app/clients/client-stepper/client-india-address-step/client-india-address-step.component.ts
index 4328be591..e02b48b3f 100644
--- a/src/app/clients/client-stepper/client-india-address-step/client-india-address-step.component.ts
+++ b/src/app/clients/client-stepper/client-india-address-step/client-india-address-step.component.ts
@@ -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 {
this.loadingProofs = true;
this.clientsService.getKycProofTypes().subscribe({
diff --git a/src/app/clients/client-stepper/client-kyc-step/client-kyc-step.component.html b/src/app/clients/client-stepper/client-kyc-step/client-kyc-step.component.html
index 60c70538c..efce2ddb7 100644
--- a/src/app/clients/client-stepper/client-kyc-step/client-kyc-step.component.html
+++ b/src/app/clients/client-stepper/client-kyc-step/client-kyc-step.component.html
@@ -161,6 +161,17 @@
}
}
+ @if (aadhaarOtpSent && aadhaarVerifyStatus !== 'VERIFIED') {
+
+ }
@if (aadhaarVerifyStatus === 'VERIFIED') {
Verified
}
diff --git a/src/app/clients/client-stepper/client-kyc-step/client-kyc-step.component.scss b/src/app/clients/client-stepper/client-kyc-step/client-kyc-step.component.scss
index 2b53e5ecc..b4f30d859 100644
--- a/src/app/clients/client-stepper/client-kyc-step/client-kyc-step.component.scss
+++ b/src/app/clients/client-stepper/client-kyc-step/client-kyc-step.component.scss
@@ -266,6 +266,23 @@
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 {
display: inline-flex;
align-items: center;
diff --git a/src/app/clients/client-stepper/client-kyc-step/client-kyc-step.component.ts b/src/app/clients/client-stepper/client-kyc-step/client-kyc-step.component.ts
index c3cf4edf8..78ad94746 100644
--- a/src/app/clients/client-stepper/client-kyc-step/client-kyc-step.component.ts
+++ b/src/app/clients/client-stepper/client-kyc-step/client-kyc-step.component.ts
@@ -462,15 +462,16 @@ export class ClientKycStepComponent implements OnInit, OnChanges, OnDestroy {
form15FY: ['']
});
- /** RBI OVDs a minor cannot hold: Voter ID and Driving Licence require adult age,
- * PAN and NREGA job cards are issued to adults. Aadhaar, Passport and NPR letters
- * are unaffected by age and stay available. */
- private static readonly MINOR_INELIGIBLE_DOC_KEYWORDS = [
- 'pan',
- 'driving',
- 'voter',
- 'nrega'
- ];
+ /** RBI-accepted OVDs for a minor client — mirrors the backend's minor branch in
+ * ClientKycApiResource.getRequiredDocuments(). Voter ID, Driving Licence, PAN and NREGA
+ * all require adult eligibility; National Population Register Letter is deliberately
+ * excluded too (not offered as a minor OVD in this system). */
+ private static readonly MINOR_ELIGIBLE_DOC_CODES = new Set([
+ 'AADHAAR',
+ 'PASSPORT',
+ 'BIRTH_CERTIFICATE',
+ 'SCHOOL_ID_CARD'
+ ]);
/** Birth Certificate / School ID Card are minor-specific OVDs — not relevant once the
* client is an adult, so they're hidden the other direction. */
@@ -481,27 +482,13 @@ export class ClientKycStepComponent implements OnInit, OnChanges, OnDestroy {
private filterDocTypesForMinor(docs: T[]): T[] {
if (this.isMinor) {
- return docs.filter((d) => {
- const text = `${d.name || ''} ${d.code || ''}`.toLowerCase();
- return !ClientKycStepComponent.MINOR_INELIGIBLE_DOC_KEYWORDS.some((k) => text.includes(k));
- });
+ return docs.filter((d) => ClientKycStepComponent.MINOR_ELIGIBLE_DOC_CODES.has((d.code || '').toUpperCase()));
}
return docs.filter((d) => !ClientKycStepComponent.MINOR_ONLY_DOC_CODES.has((d.code || '').toUpperCase()));
}
ngOnInit(): void {
- // Seed defaults immediately so the picker has options before clientId is set
- // (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.seedDefaultDocTypes();
this.loadExistingKycIfNeeded();
this.loadKycTemplate();
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 {
if (this.cinProgressTimer) clearInterval(this.cinProgressTimer);
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 */
verifyAadhaarOtp() {
if (!this.aadhaarOtp || !this.clientId || !this.kycId) return;
diff --git a/src/app/clients/create-client/create-client.component.ts b/src/app/clients/create-client/create-client.component.ts
index a71575059..52535f087 100644
--- a/src/app/clients/create-client/create-client.component.ts
+++ b/src/app/clients/create-client/create-client.component.ts
@@ -139,6 +139,8 @@ export class CreateClientComponent {
this.validationError = '';
this.prefillData = null;
this.clientGeneralStep?.resetForNewClient();
+ this.clientKycStep?.resetForNewClient();
+ this.clientIndiaAddressStep?.resetForNewClient();
}
/** Check if a tab is in read-only mode (completed tab navigated back to) */
diff --git a/src/environments/.env.ts b/src/environments/.env.ts
index 373b7c4a3..77c6490a2 100644
--- a/src/environments/.env.ts
+++ b/src/environments/.env.ts
@@ -10,7 +10,7 @@
export default {
'mifos_x': {
'version': '260728',
- 'hash': 'a9c60083'
+ 'hash': '2e4187c3'
},
'allow_switching_backend_instance': true
};