feat: letter-mgmt module + digital UPI/IMPS/ATM-POS reports + header redesign
letter-mgmt (new module): - Notice page: overdue loan list with filters, KPI strip, bulk actions, call disposition logging (Promise-to-Pay, Not Reachable, etc.), Speed Post dispatch dialog with consignment + post-office tracking, PDF preview + download, call-contact dialog with primary / alt / family / nominee numbers and per-contact disposition history. - Certificates: Loan Interest, Share, Balance, Form 60 (no-PAN flow), Form 15G/H (auto age-based), Hypothecation, NOC - each with shared preview dialog (six tone variants) and jsPDF generator using a common letterhead / summary-grid / signature-seal helper. digital: - IMPS module: report (P2A/P2P/Aadhaar tabs) + entry form with MMID/mobile lookup, NPCI switch resolve-to-A/C+IFSC BANL flow, sender autocomplete, hide sender field for P2P/Aadhaar, charges + 18% GST + waive checkbox, per-sender today-only history dialog. - UPI report with app-mix tab and full transaction filtering. - ATM/POS/ECOM hub with three ticket cards routing to today/status/cycle. - NEFT/RTGS entry: sender-account autocomplete, charges + GST + waive, field reorder (sender before amount), NEFT cap / RTGS floor validation, History button opening per-sender today's transactions. - NEFT/RTGS report: horizontal-bar trend leaderboard replacing tall bars. shell + theme: - Header redesigned with IBM Plex Sans 12/500 typography, 11-column grid per row, top-accent hover indicator, bordered cells via grid-gap. - Live KPI ticker below menu (CASH, TXN TODAY, CLEARING IN/OUT, NPA, CASA, CD RATIO, RBI CIRC, REPO) with marquee scroll, pause-on-hover, brand-blue gradient, amber bottom strip, pulsing red LIVE chip. - Sidebar 'KYC Management' -> 'KYC & ReKYC Management'. - Letter Mgmt / certificate menu items wired with green icon hints for items that have a working page. access-control: - MFA card layout compacted; method header inlines back button + title. icons: - Register faTruck/TruckFast, faEllipsisV/H, faCommentDots. - Add IBM Plex Sans Google Fonts import to index.html. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
4322f37c6d
commit
325228c514
+322
@@ -0,0 +1,322 @@
|
||||
/**
|
||||
* 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, 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 { 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
|
||||
} 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 {
|
||||
private dialogRef = inject(MatDialogRef<CertificatePreviewDialogComponent>);
|
||||
data: CertificatePreviewDialogData = inject(MAT_DIALOG_DATA);
|
||||
|
||||
readonly bankName = 'Nexora Co-operative Bank Ltd.';
|
||||
readonly bankAddress = 'Head Office, 4th Floor, Nexora Tower, Mumbai 400051';
|
||||
readonly bankRegNo = 'RBI Lic. No. NX-2018/MH/482';
|
||||
readonly bankContact = 'info@nexorabank.in · 022 6789 0000';
|
||||
|
||||
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 60 Declaration';
|
||||
case 'form15gh':
|
||||
return this.form15gh?.kind === '15H' ? 'Form 15H Declaration' : 'Form 15G 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 '';
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user