/** * 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, Input, OnInit, OnChanges, SimpleChanges, inject } from '@angular/core'; import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module'; import { FaIconComponent } from '@fortawesome/angular-fontawesome'; import { MatCheckbox } from '@angular/material/checkbox'; import { MatIcon } from '@angular/material/icon'; import { MatTooltip } from '@angular/material/tooltip'; import { MatProgressSpinner } from '@angular/material/progress-spinner'; import { MatSlideToggle } from '@angular/material/slide-toggle'; import { ClientsService } from '../../clients.service'; import { SettingsService } from 'app/settings/settings.service'; import { Dates } from 'app/core/utils/dates'; export interface CategoryMeta { id: string; label: string; tag: string; tagColor: string; tagBg: string; desc: string; icon: string; } @Component({ selector: 'mifosx-client-entity-kyc-step', templateUrl: './client-entity-kyc-step.component.html', styleUrls: ['./client-entity-kyc-step.component.scss'], imports: [ ...STANDALONE_SHARED_IMPORTS, FaIconComponent, MatCheckbox, MatIcon, MatTooltip, MatProgressSpinner, MatSlideToggle ] }) export class ClientEntityKycStepComponent implements OnInit, OnChanges { private fb = inject(UntypedFormBuilder); private clientService = inject(ClientsService); private settingsService = inject(SettingsService); private dateUtils = inject(Dates); @Input() clientId: string = ''; @Input() constitutionType: string = ''; /** Read-only mode — disables form editing until user clicks edit icon */ @Input() readOnly = false; today = new Date(); /** Category metadata */ categories: CategoryMeta[] = [ { id: 'msme', label: 'MSME', tag: 'Udyam / MSME', tagColor: '#0A5C6B', tagBg: '#E6F4F6', desc: 'Micro, Small & Medium Enterprise — Ministry of MSME / Udyam Registration', icon: 'cogs' }, { id: 'startup', label: 'Startup India Registered', tag: 'DPIIT', tagColor: '#1A5FAB', tagBg: '#EAF2FB', desc: 'DPIIT recognition under Startup India initiative', icon: 'rocket' }, { id: 'mudra', label: 'Mudra Borrower', tag: 'PMMY', tagColor: '#8A5A00', tagBg: '#FEF3DC', desc: 'Pradhan Mantri Mudra Yojana — SIDBI / Mudra scheme', icon: 'hand-holding-usd' }, { id: 'eou', label: 'Export Oriented Unit', tag: 'EOU', tagColor: '#1B7A4A', tagBg: '#E8F5EE', desc: 'Customs-registered EOU under DGFT / Ministry of Commerce', icon: 'ship' }, { id: 'importexport', label: 'Import Export Business', tag: 'DGFT / IEC', tagColor: '#5B3A8A', tagBg: '#F0EBF8', desc: 'Entity with valid DGFT Importer Exporter Code', icon: 'exchange-alt' }, { id: 'psl', label: 'Priority Sector Borrower', tag: 'RBI PSL', tagColor: '#7B1F1F', tagBg: '#FCEAEA', desc: 'Eligible under RBI Priority Sector Lending guidelines', icon: 'bullseye' }, { id: 'nps', label: 'Non-Priority Sector', tag: 'General', tagColor: '#444441', tagBg: '#F1EFE8', desc: 'Standard corporate — no special priority sector classification', icon: 'building' } ]; /** Toggle & expand state per category */ enabled: Record = {}; expanded: Record = {}; /** Forms per category */ msmeForm!: UntypedFormGroup; startupForm!: UntypedFormGroup; mudraForm!: UntypedFormGroup; eouForm!: UntypedFormGroup; importexportForm!: UntypedFormGroup; pslForm!: UntypedFormGroup; npsForm!: UntypedFormGroup; /** Saving state */ saving: Record = {}; saved: Record = {}; ngOnInit() { this.initForms(); if (this.clientId) { this.loadExisting(); } } ngOnChanges(changes: SimpleChanges): void { if (changes['readOnly']) { const forms = [ this.msmeForm, this.startupForm, this.mudraForm, this.eouForm, this.importexportForm, this.pslForm, this.npsForm ]; for (const form of forms) { if (!form) continue; if (this.readOnly) { form.disable({ emitEvent: false }); } else { form.enable({ emitEvent: false }); } } } } private initForms() { this.msmeForm = this.fb.group({ udyamRegistrationNumber: [''], registrationDate: [''], registrationStatus: [''], msmeClassification: [''], enterpriseType: [''], nicActivityCode: [''], annualTurnover: [''], investmentPlantMachinery: [''], financialYearAssessment: [''], socialCategoryOwner: [''], genderPrimaryOwner: [''], noOfEmployees: [''], womenLedEnterprise: [false], divyangPwdOwned: [false] }); this.startupForm = this.fb.group({ dpiitRecognitionNumber: [''], recognitionDate: [''], certificateExpiryDate: [''], entityStage: [''], sectorAsDpiit: [''], nicIndustryCode: [''], taxExemption80iac: [false], sidbiFund: [false], selfCertification: [false], fastTrackPatent: [false], govtTenderExemption: [false], creditGuaranteeCgss: [false], pslLoanLimit: [''], pslSubCategory: [''] }); this.mudraForm = this.fb.group({ mudraCategory: [''], mudraLoanAccountNo: [''], lendingInstitutionName: [''], sanctionedAmount: [''], disbursementDate: [''], loanPurpose: [''], mudraCardNumber: [''], currentOutstanding: [''], repaymentStatus: [''], npaFlag: [false] }); this.eouForm = this.fb.group({ eouRegistrationNumber: [''], registeredDcZone: [''], bondLutNumber: [''], validityFrom: [''], validityTo: [''], gstinEou: [''], annualExportObligation: [''], nfeTarget: [''], softexFilingStatus: [''], brcSubmissionStatus: [''], adCategoryBankCode: [''], femaDeclarationDate: [''] }); this.importexportForm = this.fb.group({ iecCode: [''], iecIssueDate: [''], iecStatus: [''], tradeType: [''], primaryHsCode: [''], keyTradingCountries: [''], adCategoryBankCode: [''], ecgcPolicyNumber: [''], ecgcPolicyExpiry: [''], eefcAccountRequired: [false], pcfcFacilityRequired: [false], femaDeclarationObtained: [false] }); this.pslForm = this.fb.group({ pslCategory: [''], pslSubCategory: [''], pslLoanPurposeCode: [''], pslEligibilityBasis: [''], fiddReportingCode: [''], pslSanctionedLimit: [''], msmeClassification: [''], udyamRegistrationNumber: [''], udyamRegistrationDate: [''], annualTurnover: [''], investmentPlantMachinery: [''], weakerSectionFlag: [false], scStBorrowerFlag: [false], womenEntrepreneurFlag: [false], minorityCommunityFlag: [false] }); this.npsForm = this.fb.group({ industrySector: [''], nicCode: [''], industryDescription: [''], annualRevenueBand: [''], riskCategory: [''], customerRiskScore: [''], amlRiskClassification: [''], pepFlag: [false], amlWatchlistMatch: [false], adverseMediaFlag: [false] }); } getForm(categoryId: string): UntypedFormGroup { switch (categoryId) { case 'msme': return this.msmeForm; case 'startup': return this.startupForm; case 'mudra': return this.mudraForm; case 'eou': return this.eouForm; case 'importexport': return this.importexportForm; case 'psl': return this.pslForm; case 'nps': return this.npsForm; default: return this.fb.group({}); } } toggleCategory(id: string) { this.enabled[id] = !this.enabled[id]; if (this.enabled[id]) { this.expanded[id] = true; } } toggleExpand(id: string) { this.expanded[id] = !this.expanded[id]; } get enabledCategories(): CategoryMeta[] { return this.categories.filter((c) => this.enabled[c.id]); } get enabledCount(): number { return this.enabledCategories.length; } removeCategory(id: string) { this.enabled[id] = false; this.expanded[id] = false; } /** Save a single category */ saveCategory(categoryId: string) { if (!this.clientId) return; this.saving[categoryId] = true; const form = this.getForm(categoryId); const payload: any = { ...form.value, enabled: true, locale: 'en', dateFormat: this.settingsService.dateFormat }; // Format date fields for (const key of Object.keys(payload)) { if (payload[key] instanceof Date) { payload[key] = this.dateUtils.formatDate(payload[key], this.settingsService.dateFormat); } } this.clientService.saveEntityClassification(this.clientId, categoryId, payload).subscribe({ next: () => { this.saving[categoryId] = false; this.saved[categoryId] = true; setTimeout(() => (this.saved[categoryId] = false), 3000); }, error: () => { this.saving[categoryId] = false; } }); } /** Load existing classifications */ private loadExisting() { this.clientService.getEntityClassifications(this.clientId).subscribe({ next: (data: any) => { if (!data) return; for (const cat of this.categories) { const catData = data[cat.id]; if (catData && catData.enabled) { this.enabled[cat.id] = true; this.getForm(cat.id).patchValue(catData); } } } }); } /** Get all classification data for parent */ get classificationData(): any { const result: any = {}; for (const cat of this.categories) { if (this.enabled[cat.id]) { result[cat.id] = { ...this.getForm(cat.id).value, enabled: true }; } } return result; } get hasClassificationData(): boolean { return this.enabledCount > 0; } // Keep old getter for backward compatibility get entityKycData(): any { return this.classificationData; } get hasEntityKycData(): boolean { return this.hasClassificationData; } }