fix(letter-mgmt): make share certificate bank identity dynamic and fix broken printing
- 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.
This commit is contained in:
@@ -25,10 +25,68 @@ import { Form15Kind, Form15ghRecord } from './form-15gh/form-15gh.component';
|
||||
import { HypothecationRecord } from './hypothecation/hypothecation.component';
|
||||
import { NocRecord } from './noc/noc.component';
|
||||
|
||||
const BANK_NAME = 'Nexora Co-operative Bank Ltd.';
|
||||
const BANK_ADDRESS = 'Head Office, 4th Floor, Nexora Tower, Mumbai 400051';
|
||||
const BANK_REG = 'RBI Lic. No. NX-2018/MH/482';
|
||||
const BANK_CONTACT = 'info@nexorabank.in · 022 6789 0000';
|
||||
/**
|
||||
* The issuing bank's own identity, as set on the Institution Profile (Admin > Organization) — this
|
||||
* file is shared by every certificate type (loan interest, share, balance, Form 60/15G/15H,
|
||||
* hypothecation, NOC) and every tenant this app runs for, so nothing here can be a fixed name.
|
||||
* These defaults only cover the moment before whichever screen opened this module has fetched the
|
||||
* real profile and called {@link setBankIdentity}; they are never meant to reach a printed PDF.
|
||||
*/
|
||||
const bankIdentity = {
|
||||
name: 'Bank',
|
||||
address: '',
|
||||
regNo: '',
|
||||
contact: '',
|
||||
/** City/state/country line used by the Share Certificate's own letterhead style. */
|
||||
location: '',
|
||||
/** Short label for the circular seal graphic — two lines, e.g. bank's short name + type. */
|
||||
sealPrimary: 'BANK',
|
||||
sealSecondary: ''
|
||||
};
|
||||
|
||||
/** Called once the caller has fetched the real Institution Profile, so every certificate built
|
||||
* after this point — of any type — carries the actual bank's own details. */
|
||||
export function setBankIdentity(profile: {
|
||||
bankName?: string;
|
||||
statementHeaderName?: string;
|
||||
shortName?: string;
|
||||
bankType?: string;
|
||||
addressLine1?: string;
|
||||
addressLine2?: string;
|
||||
city?: string;
|
||||
state?: string;
|
||||
country?: string;
|
||||
licenseNumber?: string;
|
||||
contactEmail?: string;
|
||||
contactPhone?: string;
|
||||
}): void {
|
||||
bankIdentity.name = profile.statementHeaderName || profile.bankName || bankIdentity.name;
|
||||
bankIdentity.address = [
|
||||
profile.addressLine1,
|
||||
profile.addressLine2,
|
||||
profile.city
|
||||
]
|
||||
.filter((p) => !!p && String(p).trim())
|
||||
.join(', ');
|
||||
bankIdentity.regNo = profile.licenseNumber ? `RBI Lic. No. ${profile.licenseNumber}` : '';
|
||||
bankIdentity.contact = [
|
||||
profile.contactEmail,
|
||||
profile.contactPhone
|
||||
]
|
||||
.filter((p) => !!p && String(p).trim())
|
||||
.join(' · ');
|
||||
bankIdentity.location = [
|
||||
profile.city,
|
||||
profile.state,
|
||||
profile.country
|
||||
]
|
||||
.filter((p) => !!p && String(p).trim())
|
||||
.join(', ');
|
||||
bankIdentity.sealPrimary = (profile.shortName || profile.bankName || bankIdentity.name).toUpperCase();
|
||||
bankIdentity.sealSecondary = profile.bankType
|
||||
? profile.bankType.replace(/_/g, ' ').toUpperCase() + (/BANK$/i.test(profile.bankType) ? '' : ' BANK')
|
||||
: '';
|
||||
}
|
||||
|
||||
const C_TEXT: [number, number, number] = [
|
||||
15,
|
||||
@@ -141,14 +199,24 @@ function paintLetterhead(
|
||||
c.doc.setFont('times', 'bold');
|
||||
c.doc.setFontSize(19);
|
||||
setText(c, c.accent);
|
||||
c.doc.text(BANK_NAME, c.pageW / 2, y, { align: 'center' });
|
||||
c.doc.text(bankIdentity.name, c.pageW / 2, y, { align: 'center' });
|
||||
y += 5.5;
|
||||
c.doc.setFont('helvetica', 'normal');
|
||||
c.doc.setFontSize(9);
|
||||
setText(c, C_MUTED);
|
||||
c.doc.text(BANK_ADDRESS, c.pageW / 2, y, { align: 'center' });
|
||||
y += 4;
|
||||
c.doc.text(`${BANK_REG} · ${BANK_CONTACT}`, c.pageW / 2, y, { align: 'center' });
|
||||
if (bankIdentity.address) {
|
||||
c.doc.text(bankIdentity.address, c.pageW / 2, y, { align: 'center' });
|
||||
y += 4;
|
||||
}
|
||||
const regContactLine = [
|
||||
bankIdentity.regNo,
|
||||
bankIdentity.contact
|
||||
]
|
||||
.filter((p) => !!p)
|
||||
.join(' · ');
|
||||
if (regContactLine) {
|
||||
c.doc.text(regContactLine, c.pageW / 2, y, { align: 'center' });
|
||||
}
|
||||
y += 5;
|
||||
setDraw(c, C_BORDER);
|
||||
c.doc.setLineWidth(0.3);
|
||||
@@ -350,11 +418,10 @@ function paintSignoff(c: PdfCtx, y: number, branch: string): number {
|
||||
c.doc.setFont('helvetica', 'bold');
|
||||
c.doc.setFontSize(7);
|
||||
setText(c, c.accent);
|
||||
c.doc.text('NEXORA', cx, cy - 1, { align: 'center' });
|
||||
c.doc.text(bankIdentity.sealPrimary, cx, cy - 1, { align: 'center' });
|
||||
c.doc.setFontSize(5);
|
||||
setText(c, C_MUTED);
|
||||
c.doc.text('CO-OPERATIVE', cx, cy + 3, { align: 'center' });
|
||||
c.doc.text('BANK', cx, cy + 5.5, { align: 'center' });
|
||||
c.doc.text(bankIdentity.sealSecondary, cx, cy + 4, { align: 'center' });
|
||||
|
||||
return y + 28;
|
||||
}
|
||||
@@ -376,7 +443,7 @@ function paintFooter(c: PdfCtx, y: number): void {
|
||||
c.doc.setFontSize(8);
|
||||
setText(c, C_MUTED);
|
||||
c.doc.text(
|
||||
`Issued by ${BANK_NAME} on ${formatLongDate(today())}. Computer generated — does not require physical signature for record purposes.`,
|
||||
`Issued by ${bankIdentity.name} on ${formatLongDate(today())}. Computer generated — does not require physical signature for record purposes.`,
|
||||
c.pageW / 2,
|
||||
y,
|
||||
{ align: 'center' }
|
||||
@@ -609,13 +676,15 @@ export function buildShareCertificatePdf(r: ShareCertificateRecord): jsPDF {
|
||||
doc.setFont('times', 'bold');
|
||||
doc.setFontSize(22);
|
||||
doc.setTextColor(darkBlue[0], darkBlue[1], darkBlue[2]);
|
||||
doc.text('NEXORA CO-OPERATIVE BANK LTD.', pageW / 2, y, { align: 'center' });
|
||||
doc.text(bankIdentity.name.toUpperCase(), pageW / 2, y, { align: 'center' });
|
||||
|
||||
y += 5;
|
||||
doc.setFont('times', 'italic');
|
||||
doc.setFontSize(10.5);
|
||||
doc.setTextColor(textMuted[0], textMuted[1], textMuted[2]);
|
||||
doc.text('Mumbai, Maharashtra, India', pageW / 2, y, { align: 'center' });
|
||||
if (bankIdentity.location) {
|
||||
y += 5;
|
||||
doc.setFont('times', 'italic');
|
||||
doc.setFontSize(10.5);
|
||||
doc.setTextColor(textMuted[0], textMuted[1], textMuted[2]);
|
||||
doc.text(bankIdentity.location, pageW / 2, y, { align: 'center' });
|
||||
}
|
||||
|
||||
y += 4;
|
||||
doc.setDrawColor(242, 237, 213); // light gold separator
|
||||
@@ -685,7 +754,7 @@ export function buildShareCertificatePdf(r: ShareCertificateRecord): jsPDF {
|
||||
doc.setFontSize(11);
|
||||
doc.setTextColor(textDark[0], textDark[1], textDark[2]);
|
||||
|
||||
const bodyText = `This is to certify that ${r.memberName} is the registered holder of ${r.shareCount.toLocaleString('en-IN')} (${classLabel}) shares of Rs. ${r.faceValue.toLocaleString('en-IN')} each, fully paid up, in Nexora Co-operative Bank Ltd., subject to the memorandum, articles of association, and bye-laws of the bank.`;
|
||||
const bodyText = `This is to certify that ${r.memberName} is the registered holder of ${r.shareCount.toLocaleString('en-IN')} (${classLabel}) shares of Rs. ${r.faceValue.toLocaleString('en-IN')} each, fully paid up, in ${bankIdentity.name}, subject to the memorandum, articles of association, and bye-laws of the bank.`;
|
||||
const bodyLines = doc.splitTextToSize(bodyText, pageW - 50);
|
||||
for (const line of bodyLines) {
|
||||
doc.text(line, pageW / 2, y, { align: 'center' });
|
||||
@@ -763,7 +832,7 @@ export function buildShareCertificatePdf(r: ShareCertificateRecord): jsPDF {
|
||||
|
||||
// Row 1
|
||||
drawTableCell(25, y, tableColW, tableRowH, 'Branch', true);
|
||||
drawTableCell(25 + tableColW, y, tableColW, tableRowH, r.branch || 'Mumbai Main Branch', false);
|
||||
drawTableCell(25 + tableColW, y, tableColW, tableRowH, r.branch || 'Head Office', false);
|
||||
drawTableCell(25 + tableColW * 2, y, tableColW, tableRowH, 'Member Since', true);
|
||||
drawTableCell(25 + tableColW * 3, y, tableColW, tableRowH, formatLongDate(r.joiningDate), false);
|
||||
y += tableRowH;
|
||||
@@ -1168,7 +1237,7 @@ export function buildHypothecationPdf(r: HypothecationRecord): jsPDF {
|
||||
y = paintPara(
|
||||
c,
|
||||
y,
|
||||
`This is to certify that the asset described below stands hypothecated to ${BANK_NAME} as security for the captioned loan facility extended to ${r.customerName}, and the bank holds the first and exclusive charge over the said asset until the loan is fully discharged.`
|
||||
`This is to certify that the asset described below stands hypothecated to ${bankIdentity.name} as security for the captioned loan facility extended to ${r.customerName}, and the bank holds the first and exclusive charge over the said asset until the loan is fully discharged.`
|
||||
);
|
||||
|
||||
const rows: [string, string, string, string][] = [
|
||||
|
||||
Reference in New Issue
Block a user