- Certificate PDFs, the preview dialog, and both share-certificate list views (demo + live) now pull bank name/address/reg no/seal text from the Institution Profile instead of a hardcoded "Nexora" identity. - Certificate preview dialog print CSS was clipped to the dialog's on-screen scroll viewport (maxHeight config); switched to position:fixed + unclipped overlay ancestors so the full certificate prints, not just a border sliver. - Global print stylesheet now also hides the app shell's real 2-row nav menu (.main-header/.kpi-ticker, not routed through <mifosx-toolbar>) and frees the CDK sidenav/tab-body scroll clipping, so printing any page no longer captures the nav chrome or gets cut off to one screen's height.
291 lines
8.8 KiB
TypeScript
291 lines
8.8 KiB
TypeScript
/**
|
||
* 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, OnInit } from '@angular/core';
|
||
import { CommonModule } from '@angular/common';
|
||
import { FormsModule } from '@angular/forms';
|
||
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
|
||
import { MatDialog } from '@angular/material/dialog';
|
||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||
import { MatTooltip } from '@angular/material/tooltip';
|
||
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||
|
||
import {
|
||
CertificatePreviewDialogComponent,
|
||
CertificatePreviewDialogData
|
||
} from '../certificate-preview-dialog/certificate-preview-dialog.component';
|
||
import { downloadShareCertificatePdf, setBankIdentity } from '../certificate-pdf';
|
||
import { DscSignService } from '../../dsc-sign-dialog/dsc-sign.service';
|
||
import { OrganizationService } from '../../../organization/organization.service';
|
||
import { RealShareAccountsViewComponent } from './real-share-accounts-view/real-share-accounts-view.component';
|
||
|
||
export type ShareClass = 'ORDINARY' | 'PREFERENCE';
|
||
|
||
export interface ShareCertificateRecord {
|
||
certificateNo: string;
|
||
folioNo: string;
|
||
memberId: string;
|
||
memberName: string;
|
||
memberPan: string;
|
||
memberAddress: string;
|
||
branch: string;
|
||
joiningDate: string;
|
||
shareClass: ShareClass;
|
||
shareCount: number;
|
||
faceValue: number;
|
||
issueDate: string;
|
||
/** Distinct numeric range of share numbers held (e.g. 1001–1100). */
|
||
shareNoFrom: number;
|
||
shareNoTo: number;
|
||
/** Total dividend received since joining. */
|
||
dividendYtd: number;
|
||
}
|
||
|
||
@Component({
|
||
selector: 'mifosx-share-certificate',
|
||
templateUrl: './share-certificate.component.html',
|
||
styleUrls: ['../certificates.shared.scss'],
|
||
imports: [
|
||
...STANDALONE_SHARED_IMPORTS,
|
||
CommonModule,
|
||
FormsModule,
|
||
FaIconComponent,
|
||
MatTooltip,
|
||
RealShareAccountsViewComponent
|
||
]
|
||
})
|
||
export class ShareCertificateComponent implements OnInit {
|
||
private dialog = inject(MatDialog);
|
||
private snack = inject(MatSnackBar);
|
||
private dscSign = inject(DscSignService);
|
||
private organizationService = inject(OrganizationService);
|
||
|
||
/** Toggles between the static sample table and the live m_share_account view. */
|
||
viewMode: 'demo' | 'real' = 'demo';
|
||
|
||
// ── Filters ──
|
||
search = '';
|
||
classFilter: '' | ShareClass = '';
|
||
branchFilter = '';
|
||
|
||
records: ShareCertificateRecord[] = [];
|
||
|
||
readonly classOptions: { value: ShareClass; label: string }[] = [
|
||
{ value: 'ORDINARY', label: 'Ordinary' },
|
||
{ value: 'PREFERENCE', label: 'Preference' }
|
||
];
|
||
|
||
ngOnInit(): void {
|
||
this.records = seedShareCertificates();
|
||
|
||
// Download here builds the PDF directly, without necessarily opening the preview dialog first,
|
||
// so this list must set the shared bank identity itself.
|
||
this.organizationService.getInstitutionProfile().subscribe({
|
||
next: (profile: any) => setBankIdentity(profile || {}),
|
||
error: () => {}
|
||
});
|
||
}
|
||
|
||
// ── Derived list ──
|
||
get filteredRecords(): ShareCertificateRecord[] {
|
||
const q = this.search.trim().toLowerCase();
|
||
const branch = this.branchFilter.trim().toLowerCase();
|
||
return this.records.filter((r) => {
|
||
if (this.classFilter && r.shareClass !== this.classFilter) return false;
|
||
if (branch && !r.branch.toLowerCase().includes(branch)) return false;
|
||
if (!q) return true;
|
||
return (
|
||
r.certificateNo.toLowerCase().includes(q) ||
|
||
r.folioNo.toLowerCase().includes(q) ||
|
||
r.memberId.toLowerCase().includes(q) ||
|
||
r.memberName.toLowerCase().includes(q) ||
|
||
r.memberPan.toLowerCase().includes(q)
|
||
);
|
||
});
|
||
}
|
||
|
||
get branchOptions(): string[] {
|
||
return Array.from(new Set(this.records.map((r) => r.branch))).sort();
|
||
}
|
||
|
||
classLabel(c: ShareClass): string {
|
||
return this.classOptions.find((o) => o.value === c)?.label || c;
|
||
}
|
||
|
||
totalShares(): number {
|
||
return this.filteredRecords.reduce((s, r) => s + r.shareCount, 0);
|
||
}
|
||
|
||
totalShareValue(): number {
|
||
return this.filteredRecords.reduce((s, r) => s + r.shareCount * r.faceValue, 0);
|
||
}
|
||
|
||
// ── Actions ──
|
||
clearFilters(): void {
|
||
this.search = '';
|
||
this.classFilter = '';
|
||
this.branchFilter = '';
|
||
}
|
||
|
||
viewCertificate(r: ShareCertificateRecord): void {
|
||
const data: CertificatePreviewDialogData = {
|
||
kind: 'share',
|
||
shareCertificate: r
|
||
};
|
||
this.dialog.open(CertificatePreviewDialogComponent, {
|
||
width: '880px',
|
||
maxWidth: '96vw',
|
||
maxHeight: '92vh',
|
||
autoFocus: false,
|
||
panelClass: 'cert-preview-dialog',
|
||
data
|
||
});
|
||
}
|
||
|
||
downloadCertificate(r: ShareCertificateRecord): void {
|
||
this.dscSign.promptThenDownload(
|
||
{
|
||
title: 'Share Certificate',
|
||
reference: `${r.certificateNo} · Folio ${r.folioNo} · ${r.memberName}`,
|
||
filename: `Share-Certificate-${r.certificateNo}.pdf`
|
||
},
|
||
(dsc) => downloadShareCertificatePdf(r, dsc)
|
||
);
|
||
}
|
||
|
||
/** Switches between the static sample table and the live m_share_account view. */
|
||
toggleViewMode(): void {
|
||
this.viewMode = this.viewMode === 'demo' ? 'real' : 'demo';
|
||
}
|
||
}
|
||
|
||
// ───────────────────── Mock seed (top-level export) ─────────────────────
|
||
export function seedShareCertificates(): ShareCertificateRecord[] {
|
||
return [
|
||
{
|
||
certificateNo: 'SC-2024-000123',
|
||
folioNo: 'F-00482',
|
||
memberId: 'MBR000482',
|
||
memberName: 'Rohan S. Mehta',
|
||
memberPan: 'ABCPM1234E',
|
||
memberAddress: 'Flat 902, Skyline Apt, Andheri (E), Mumbai 400069',
|
||
branch: 'Mumbai — Andheri (E)',
|
||
joiningDate: '2018-04-22',
|
||
shareClass: 'ORDINARY',
|
||
shareCount: 100,
|
||
faceValue: 100,
|
||
issueDate: '2018-04-22',
|
||
shareNoFrom: 48201,
|
||
shareNoTo: 48300,
|
||
dividendYtd: 7200
|
||
},
|
||
{
|
||
certificateNo: 'SC-2024-000124',
|
||
folioNo: 'F-00713',
|
||
memberId: 'MBR000713',
|
||
memberName: 'Anita Verma',
|
||
memberPan: 'EFGHV5678A',
|
||
memberAddress: 'B-12, Connaught Pl, New Delhi 110001',
|
||
branch: 'New Delhi — Connaught Place',
|
||
joiningDate: '2019-08-11',
|
||
shareClass: 'ORDINARY',
|
||
shareCount: 50,
|
||
faceValue: 100,
|
||
issueDate: '2019-08-11',
|
||
shareNoFrom: 71301,
|
||
shareNoTo: 71350,
|
||
dividendYtd: 3000
|
||
},
|
||
{
|
||
certificateNo: 'SC-2024-000125',
|
||
folioNo: 'F-01102',
|
||
memberId: 'MBR001102',
|
||
memberName: 'Karthik Rao',
|
||
memberPan: 'PQRSR2233Z',
|
||
memberAddress: '24, MG Road, Bengaluru 560001',
|
||
branch: 'Bengaluru — MG Road',
|
||
joiningDate: '2020-02-04',
|
||
shareClass: 'ORDINARY',
|
||
shareCount: 200,
|
||
faceValue: 100,
|
||
issueDate: '2020-02-04',
|
||
shareNoFrom: 110201,
|
||
shareNoTo: 110400,
|
||
dividendYtd: 14400
|
||
},
|
||
{
|
||
certificateNo: 'SC-2024-000126',
|
||
folioNo: 'F-01277',
|
||
memberId: 'MBR001277',
|
||
memberName: 'Madhavi Singh',
|
||
memberPan: 'TUVWS3344K',
|
||
memberAddress: 'D-5, Greater Kailash, New Delhi 110048',
|
||
branch: 'New Delhi — Connaught Place',
|
||
joiningDate: '2017-11-19',
|
||
shareClass: 'PREFERENCE',
|
||
shareCount: 75,
|
||
faceValue: 1000,
|
||
issueDate: '2017-11-19',
|
||
shareNoFrom: 12721,
|
||
shareNoTo: 12795,
|
||
dividendYtd: 67500
|
||
},
|
||
{
|
||
certificateNo: 'SC-2024-000127',
|
||
folioNo: 'F-01498',
|
||
memberId: 'MBR001498',
|
||
memberName: 'Vikram Joshi',
|
||
memberPan: 'LMNOJ9988X',
|
||
memberAddress: 'Office 3B, Koregaon Park Road, Pune 411001',
|
||
branch: 'Pune — Koregaon Park',
|
||
joiningDate: '2016-06-30',
|
||
shareClass: 'PREFERENCE',
|
||
shareCount: 250,
|
||
faceValue: 1000,
|
||
issueDate: '2016-06-30',
|
||
shareNoFrom: 14981,
|
||
shareNoTo: 15230,
|
||
dividendYtd: 225000
|
||
},
|
||
{
|
||
certificateNo: 'SC-2024-000128',
|
||
folioNo: 'F-01902',
|
||
memberId: 'MBR001902',
|
||
memberName: 'Lakshmi Naidu',
|
||
memberPan: 'XYZAN7788Q',
|
||
memberAddress: 'Plot 14, Road No. 3, Banjara Hills, Hyderabad 500034',
|
||
branch: 'Hyderabad — Banjara Hills',
|
||
joiningDate: '2021-03-15',
|
||
shareClass: 'ORDINARY',
|
||
shareCount: 30,
|
||
faceValue: 100,
|
||
issueDate: '2021-03-15',
|
||
shareNoFrom: 190201,
|
||
shareNoTo: 190230,
|
||
dividendYtd: 1800
|
||
},
|
||
{
|
||
certificateNo: 'SC-2024-000129',
|
||
folioNo: 'F-02011',
|
||
memberId: 'MBR002011',
|
||
memberName: 'Arjun Banerjee',
|
||
memberPan: 'TUVWB4455F',
|
||
memberAddress: '42, Park Street, Kolkata 700016',
|
||
branch: 'Kolkata — Park Street',
|
||
joiningDate: '2021-09-08',
|
||
shareClass: 'ORDINARY',
|
||
shareCount: 40,
|
||
faceValue: 100,
|
||
issueDate: '2021-09-08',
|
||
shareNoFrom: 201101,
|
||
shareNoTo: 201140,
|
||
dividendYtd: 2400
|
||
}
|
||
];
|
||
}
|