/** * 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, OnInit, inject } from '@angular/core'; import { CommonModule } from '@angular/common'; import { FaIconComponent } from '@fortawesome/angular-fontawesome'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { MatTooltip } from '@angular/material/tooltip'; import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module'; import { OrganizationService } from 'app/organization/organization.service'; import { FyInterestBreakup, LoanInterestRecord } from '../loan-interest/loan-interest.component'; import { ShareCertificateRecord } from '../share-certificate/share-certificate.component'; import { BalanceCertificateRecord } from '../balance-certificate/balance-certificate.component'; import { Form60Record } from '../form-60/form-60.component'; import { Form15Kind, Form15ghRecord } from '../form-15gh/form-15gh.component'; import { HypothecationRecord } from '../hypothecation/hypothecation.component'; import { NocRecord } from '../noc/noc.component'; import { downloadBalanceCertificatePdf, downloadForm15ghPdf, downloadForm60Pdf, downloadHypothecationPdf, downloadLoanInterestPdf, downloadNocPdf, downloadShareCertificatePdf, setBankIdentity } from '../certificate-pdf'; export interface InterestPreviewPayload { record: LoanInterestRecord; fy: FyInterestBreakup; } export interface BalancePreviewPayload { record: BalanceCertificateRecord; asOnDate: string; } export interface Form15ghPreviewPayload { record: Form15ghRecord; kind: Form15Kind; age: number; } export type CertificateKind = 'interest' | 'share' | 'balance' | 'form60' | 'form15gh' | 'hypothecation' | 'noc'; export interface CertificatePreviewDialogData { kind: CertificateKind; loanInterest?: InterestPreviewPayload; shareCertificate?: ShareCertificateRecord; balance?: BalancePreviewPayload; form60?: Form60Record; form15gh?: Form15ghPreviewPayload; hypothecation?: HypothecationRecord; noc?: NocRecord; } @Component({ selector: 'mifosx-certificate-preview-dialog', templateUrl: './certificate-preview-dialog.component.html', styleUrls: ['./certificate-preview-dialog.component.scss'], imports: [ ...STANDALONE_SHARED_IMPORTS, CommonModule, FaIconComponent, MatTooltip ] }) export class CertificatePreviewDialogComponent implements OnInit { private dialogRef = inject(MatDialogRef); private organizationService = inject(OrganizationService); data: CertificatePreviewDialogData = inject(MAT_DIALOG_DATA); /** The issuing bank's own details, fetched from the Institution Profile — this dialog is shared * by every certificate type and every tenant, so nothing here is a fixed name. */ bankName = 'Bank'; bankAddress = ''; bankRegNo = ''; bankContact = ''; bankSealPrimary = 'BANK'; bankSealSecondary = ''; ngOnInit(): void { this.organizationService.getInstitutionProfile().subscribe({ next: (profile: any) => { this.bankName = profile?.statementHeaderName || profile?.bankName || this.bankName; this.bankAddress = [ profile?.addressLine1, profile?.addressLine2, profile?.city ] .filter((p: any) => !!p && String(p).trim()) .join(', '); this.bankRegNo = profile?.licenseNumber ? `RBI Lic. No. ${profile.licenseNumber}` : ''; this.bankContact = [ profile?.contactEmail, profile?.contactPhone ] .filter((p: any) => !!p && String(p).trim()) .join(' · '); this.bankSealPrimary = (profile?.shortName || this.bankName).toUpperCase(); this.bankSealSecondary = profile?.bankType ? profile.bankType.replace(/_/g, ' ').toUpperCase() + (/BANK$/i.test(profile.bankType) ? '' : ' BANK') : ''; // Every certificate PDF this dialog can build (Download button below, or the list page's // own download icon opened without previewing first) reads the same shared identity, so // set it here once the real profile is in — never leave a PDF carrying the placeholder. setBankIdentity(profile || {}); }, // A missing/incomplete profile must not stop the certificate from rendering. error: () => {} }); } get isInterest(): boolean { return this.data.kind === 'interest'; } get isShare(): boolean { return this.data.kind === 'share'; } get isBalance(): boolean { return this.data.kind === 'balance'; } get isForm60(): boolean { return this.data.kind === 'form60'; } get isForm15gh(): boolean { return this.data.kind === 'form15gh'; } get isHypothecation(): boolean { return this.data.kind === 'hypothecation'; } get isNoc(): boolean { return this.data.kind === 'noc'; } get interest(): InterestPreviewPayload | undefined { return this.data.loanInterest; } get share(): ShareCertificateRecord | undefined { return this.data.shareCertificate; } get balance(): BalancePreviewPayload | undefined { return this.data.balance; } get form60(): Form60Record | undefined { return this.data.form60; } get form15gh(): Form15ghPreviewPayload | undefined { return this.data.form15gh; } get hypothecation(): HypothecationRecord | undefined { return this.data.hypothecation; } get noc(): NocRecord | undefined { return this.data.noc; } /** Tone class on `.cpd-page` — drives the accent stripe + seal + pill colour. */ get pageToneClass(): string { switch (this.data.kind) { case 'share': case 'form60': return 'cpd-page--amber'; case 'form15gh': return 'cpd-page--teal'; case 'hypothecation': return 'cpd-page--red'; case 'noc': return 'cpd-page--green'; case 'balance': case 'interest': default: return ''; } } get title(): string { switch (this.data.kind) { case 'interest': return 'Interest-Paid Certificate'; case 'share': return 'Share Certificate'; case 'balance': return 'Balance Certificate'; case 'form60': return 'Form 97 Declaration'; case 'form15gh': return 'Form 121 Declaration'; case 'hypothecation': return 'Hypothecation Certificate'; case 'noc': return 'No-Objection Certificate'; } } get refLine(): string { if (this.isInterest && this.interest) { return `${this.interest.record.accountNo} · ${this.interest.fy.fy}`; } if (this.isShare && this.share) { return `${this.share.certificateNo} · Folio ${this.share.folioNo}`; } if (this.isBalance && this.balance) { return `${this.balance.record.accountNo} · as on ${this.balance.asOnDate}`; } if (this.isForm60 && this.form60) { return `${this.form60.customerId} · ${this.form60.transactionType}`; } if (this.isForm15gh && this.form15gh) { return `${this.form15gh.record.customerId} · ${this.form15gh.kind} · ${this.form15gh.record.fy}`; } if (this.isHypothecation && this.hypothecation) { return `${this.hypothecation.certificateNo} · ${this.hypothecation.accountNo}`; } if (this.isNoc && this.noc) { return `${this.noc.nocNo} · ${this.noc.accountNo}`; } return ''; } get issuedOn(): string { return new Date().toISOString().slice(0, 10); } close(): void { this.dialogRef.close(); } printCertificate(): void { window.print(); } downloadPdf(): void { if (this.isInterest && this.interest) { downloadLoanInterestPdf(this.interest.record, this.interest.fy); } else if (this.isShare && this.share) { downloadShareCertificatePdf(this.share); } else if (this.isBalance && this.balance) { downloadBalanceCertificatePdf(this.balance.record, this.balance.asOnDate); } else if (this.isForm60 && this.form60) { downloadForm60Pdf(this.form60); } else if (this.isForm15gh && this.form15gh) { downloadForm15ghPdf(this.form15gh.record, this.form15gh.kind); } else if (this.isHypothecation && this.hypothecation) { downloadHypothecationPdf(this.hypothecation); } else if (this.isNoc && this.noc) { downloadNocPdf(this.noc); } } nocLoanTypeLabel(): string { const t = this.noc?.loanType; switch (t) { case 'AUTO': return 'Auto Loan'; case 'HOUSING': return 'Housing Loan'; case 'PERSONAL': return 'Personal Loan'; case 'EDUCATION': return 'Education Loan'; case 'GOLD': return 'Gold Loan'; case 'BUSINESS': return 'Business Loan'; case 'CC': return 'Cash Credit'; case 'OD': return 'Overdraft'; default: return ''; } } nocAssetLabel(): string { const t = this.noc?.assetType; switch (t) { case 'VEHICLE': return 'Vehicle'; case 'PROPERTY': return 'Property'; case 'GOLD': return 'Gold / Bullion'; case 'EQUIPMENT': return 'Equipment'; case 'STOCK_DEBTORS': return 'Stock / Debtors'; case 'NONE': return 'Unsecured'; default: return ''; } } classLabelText(): string { return this.share?.shareClass === 'PREFERENCE' ? 'Preference' : 'Ordinary'; } accountTypeLabelText(): string { const t = this.balance?.record.accountType; switch (t) { case 'SAVINGS': return 'Savings'; case 'CURRENT': return 'Current'; case 'FIXED_DEPOSIT': return 'Fixed Deposit'; case 'RD': return 'Recurring Deposit'; case 'NRE': return 'NRE Savings'; case 'NRO': return 'NRO Savings'; default: return ''; } } idProofLabelText(): string { const t = this.form60?.idProofType; switch (t) { case 'AADHAAR': return 'Aadhaar Card'; case 'VOTER_ID': return 'Voter Identity Card'; case 'DRIVING_LICENSE': return 'Driving License'; case 'PASSPORT': return 'Passport'; case 'RATION': return 'Ration Card'; default: return ''; } } assetLabelText(): string { const t = this.hypothecation?.assetType; switch (t) { case 'VEHICLE': return 'Vehicle'; case 'PLANT_MACHINERY': return 'Plant & Machinery'; case 'STOCK_DEBTORS': return 'Stock / Debtors'; case 'GOLD': return 'Gold / Bullion'; case 'EQUIPMENT': return 'Equipment'; default: return ''; } } }