// import * as pdfMake from 'pdfmake/build/pdfmake'; import { getAvailablePageWidth } from '../../../shared/table-section/pdf-table.section'; import { toStr } from '../../../shared/header-footer-section/pdf-shared.utils'; import { buildFooter, buildDocumentHeaderSection, buildDocumentHeadingSection, buildLogoWatermarkBackground, buildWatermark, deriveHeaderDataFromInvoice, normalizeHeaderStyle, resolvePageMargins, resolvePageOrientation } from '../../../shared/header-footer-section/pdf-header-footer.section'; const PAGE_SIZE = 'A4'; const PAGE_MARGINS: [number, number, number, number] = [20, 20, 20, 20]; export function CreateReceiptPDFService(DocumentData: any = {}, PrintConfigData: any = {}) { const dd = buildPdfDocDefinition(DocumentData, PrintConfigData); return dd; } export function DownloadReceiptPDFService(filename: string = 'receipt.pdf', DocumentData: any = {}, PrintConfigData: any = {}) { const dd = buildPdfDocDefinition(DocumentData, PrintConfigData); // pdfMake.createPdf(dd).download(filename); return dd; } export function GetReceiptPdfDataUrl(DocumentData: any = {}, PrintConfigData: any = {}) { const dd = buildPdfDocDefinition(DocumentData, PrintConfigData); // const pdfDoc: any = pdfMake.createPdf(dd); return dd; // return new Promise((resolve, reject) => { // let settled = false; // const done = (value: string) => { // if (!settled) { // settled = true; // resolve(value); // } // }; // const fail = (error: any) => { // if (!settled) { // settled = true; // reject(error); // } // }; // try { // if (typeof pdfDoc.getDataUrl === 'function') { // const result = pdfDoc.getDataUrl((dataUrl: string) => done(dataUrl)); // if (result && typeof result.then === 'function') { // result.then((dataUrl: string) => done(dataUrl)).catch(fail); // } // return; // } // if (typeof pdfDoc.getBlob === 'function') { // const result = pdfDoc.getBlob((blob: Blob) => done(URL.createObjectURL(blob))); // if (result && typeof result.then === 'function') { // result.then((blob: Blob) => done(URL.createObjectURL(blob))).catch(fail); // } // return; // } // fail(new Error('No supported preview API found on pdf document instance.')); // } catch (error) { // fail(error); // } // }); } export function buildPdfDocDefinition(DocumentData: any = {}, PrintConfigData: any = {}) { const PrintConfig = normalizePrintConfig(DocumentData, PrintConfigData); const pageOrientation = resolvePageOrientation(PrintConfig?.pageOrientation); const pageMargins = resolvePageMargins(PrintConfig?.Margin); const availableWidth = getAvailablePageWidth(PAGE_SIZE, pageOrientation, pageMargins); const watermark = buildWatermark(PrintConfig); const background = buildLogoWatermarkBackground(PrintConfig, DocumentData); const footer = buildFooter(PrintConfig); const invoiceHeaderContent = buildDocumentHeaderSection(PrintConfig, DocumentData); const invoiceHeadingContent = buildDocumentHeadingSection(DocumentData, PrintConfig, availableWidth); const receiptMetaContent = buildReceiptMetaSection(DocumentData); return { pageSize: PAGE_SIZE, pageOrientation, pageMargins, content: [ ...invoiceHeaderContent, ...invoiceHeadingContent, { margin: [20, 0, 20, 0], stack: receiptMetaContent } ], info: { title: 'receipt', subject: toStr(PrintConfig?.subject) || 'receipt header and heading' }, ...(background ? { background } : {}), ...(watermark ? { watermark } : {}), ...(footer ? { footer } : {}) }; } function buildReceiptMetaSection(DocumentData: any) { const receiptNo = toStr(DocumentData?.PaymentId).trim() || '-'; const paymentDate = formatDate(DocumentData?.PaidDate); const fullName = toStr(DocumentData?.FullName).trim() || '-'; const paymentMode = toStr(DocumentData?.PaymentType).trim() || '-'; const amountInWords = amountToWords(DocumentData?.TotalAmount); const totalAmount = formatAmount(DocumentData?.TotalAmount); return [ { columns: [ { width: '*', text: [ { text: 'Receipt No: ', color: '#6b7280' }, { text: receiptNo, bold: true, color: '#111827' } ], fontSize: 10, margin: [0, 0, 0, 12] }, { width: '*', text: [ { text: 'Payment Date: ', color: '#6b7280' }, { text: paymentDate, bold: true, color: '#111827' } ], fontSize: 10, alignment: 'right', margin: [0, 0, 0, 12] } ] }, { columns: [ { width: 86, text: 'Amount', color: '#6b7280', fontSize: 10, alignment: 'left', margin: [0, 9, 4, 0] }, { width: 10, text: ':', color: '#6b7280', fontSize: 10, alignment: 'center', margin: [0, 9, 8, 0] }, { width: 'auto', table: { body: [[{ text: totalAmount, bold: true, fontSize: 18, color: '#111827', fillColor: '#f9fafb', margin: [6, 3, 6, 3] }]] }, layout: { hLineColor: () => '#d1d5db', vLineColor: () => '#d1d5db', hLineWidth: () => 1, vLineWidth: () => 1, paddingLeft: () => 6, paddingRight: () => 6, paddingTop: () => 3, paddingBottom: () => 3 } } ], margin: [0, 0, 0, 16] }, createDottedValueRow('Received From', fullName), createDottedValueRow('In Words', amountInWords), createDottedValueRow('Payment Mode', paymentMode), ...buildPaymentForSection(DocumentData), // ...buildRefundForSection(DocumentData), ...buildAuthorizedSignatureSection(DocumentData) ]; } function createDottedValueRow(label: string, value: string) { const displayValue = toStr(value).trim() || '-'; return { columns: [ { width: 86, text: label, color: '#6b7280', fontSize: 10, alignment: 'left', margin: [0, 0, 4, 0] }, { width: 10, text: ':', color: '#6b7280', fontSize: 10, alignment: 'center', margin: [0, 0, 8, 0] }, { width: '*', stack: [ { canvas: [ { type: 'line', x1: 0, y1: 10, x2: 420, y2: 10, lineWidth: 0.8, lineColor: '#6b7280', dash: { length: 2, space: 2 } } ] }, { text: displayValue, bold: true, color: '#111827', fontSize: 10, margin: [4, -12, 0, 0] } ], margin: [0, 0, 0, 16] } ] }; } function buildPaymentForSection(DocumentData: any) { const allocRefs = Array.isArray(DocumentData?.AllocRefs) ? DocumentData.AllocRefs : []; const invoiceRefs = allocRefs.filter((entry: any) => String(entry?.Type || '').toUpperCase() === 'INV'); if (invoiceRefs.length === 0) { return []; } const tableBody: any[] = [ [ { text: 'S.No', bold: true, fillColor: '#f3f4f6', fontSize: 9 }, { text: 'Invoice#', bold: true, fillColor: '#f3f4f6', fontSize: 9 }, { text: 'Amount', bold: true, fillColor: '#f3f4f6', fontSize: 9, alignment: 'right' } ] ]; invoiceRefs.forEach((entry: any, index: number) => { const invoiceNo = toStr(entry?.Code || '-').trim() || '-'; const amount = formatTableAmount(entry?.Amt); tableBody.push([ { text: `${index + 1}`, fontSize: 9 }, { text: invoiceNo, fontSize: 9 }, { text: amount, fontSize: 9, alignment: 'right' } ]); }); return [ { text: 'Payment For', bold: true, fontSize: 11, color: '#374151', alignment: 'left', margin: [0, 6, 0, 8] }, { table: { headerRows: 1, widths: [36, 124, 80], body: tableBody }, layout: { hLineColor: () => '#e5e7eb', vLineColor: () => '#e5e7eb', hLineWidth: () => 0.5, vLineWidth: () => 0.5, paddingLeft: () => 5, paddingRight: () => 5, paddingTop: () => 4, paddingBottom: () => 4 }, margin: [0, 0, 0, 8] } ]; } // function buildRefundForSection(DocumentData: any) { // const allocRefs = Array.isArray(DocumentData?.AllocRefs) ? DocumentData.AllocRefs : []; // const refundRefs = allocRefs.filter((entry: any) => String(entry?.Type || '').toUpperCase() === 'REF'); // if (refundRefs.length === 0) { // return []; // } // const tableBody: any[] = [ // [ // { text: 'S.No', bold: true, fillColor: '#f3f4f6', fontSize: 10 }, // { text: 'Refund#', bold: true, fillColor: '#f3f4f6', fontSize: 10 }, // { text: 'Amount', bold: true, fillColor: '#f3f4f6', fontSize: 10, alignment: 'right' } // ] // ]; // refundRefs.forEach((entry: any, index: number) => { // const refundNo = toStr(entry?.RefundNo || entry?.RefNo || entry?.No || entry?.Code || entry?.Id || '-').trim() || '-'; // const amount = formatTableAmount(entry?.Amount ?? entry?.AllocAmt ?? entry?.Amt ?? entry?.Value); // tableBody.push([ // { text: `${index + 1}`, fontSize: 10 }, // { text: refundNo, fontSize: 10 }, // { text: amount, fontSize: 10, alignment: 'right' } // ]); // }); // return [ // { // text: 'Refund For', // bold: true, // fontSize: 11, // color: '#374151', // margin: [0, 6, 0, 8] // }, // { // table: { // headerRows: 1, // widths: [42, '*', 100], // body: tableBody // }, // layout: { // hLineColor: () => '#e5e7eb', // vLineColor: () => '#e5e7eb', // hLineWidth: () => 0.5, // vLineWidth: () => 0.5, // paddingLeft: () => 6, // paddingRight: () => 6, // paddingTop: () => 5, // paddingBottom: () => 5 // }, // margin: [0, 0, 0, 8] // } // ]; // } function buildAuthorizedSignatureSection(DocumentData: any) { const companyName = toStr(DocumentData?.Entity?.CName).trim(); return [ { width: '*', stack: [ { text: [ { text: 'For ', color: '#6b7280' }, { text: companyName || '-', bold: true, color: '#111827' } ], alignment: 'right', fontSize: 10, margin: [0, 8, 0, 32] }, { text: 'Authorized Signature', alignment: 'right', bold: true, color: '#111827', fontSize: 10 } ] } ]; } function formatDate(value: any) { const raw = toStr(value).trim(); if (!raw) { return '-'; } const dt = new Date(raw); if (Number.isNaN(dt.getTime())) { return raw; } const day = String(dt.getDate()).padStart(2, '0'); const month = dt.toLocaleString('en-US', { month: 'short' }); const year = dt.getFullYear(); return `${day}-${month}-${year}`; } function formatAmount(value: any) { const amount = Number(value); if (!Number.isFinite(amount)) { return '-'; } if (Number.isInteger(amount)) { return `Rs. ${amount}/-`; } return `Rs. ${amount.toFixed(2)}/-`; } function formatTableAmount(value: any) { const amount = Number(value); if (!Number.isFinite(amount)) { return '-'; } return Number.isInteger(amount) ? `${amount}` : `${amount.toFixed(2)}`; } function amountToWords(value: any) { const amount = Number(value); if (!Number.isFinite(amount) || amount < 0) { return '-'; } const integerPart = Math.floor(amount); const decimalPart = Math.round((amount - integerPart) * 100); const integerWords = numberToWords(integerPart); if (!decimalPart) { return `${integerWords} Rupee(s) Only`; } return `${integerWords} Rupee(s) and ${numberToWords(decimalPart)} Paise Only`; } function numberToWords(n: number): string { if (n === 0) { return 'Zero'; } const belowTwenty = ['', 'One', 'Two', 'Three', 'Four', 'Five', 'Six', 'Seven', 'Eight', 'Nine', 'Ten', 'Eleven', 'Twelve', 'Thirteen', 'Fourteen', 'Fifteen', 'Sixteen', 'Seventeen', 'Eighteen', 'Nineteen']; const tens = ['', '', 'Twenty', 'Thirty', 'Forty', 'Fifty', 'Sixty', 'Seventy', 'Eighty', 'Ninety']; const units = [ { value: 1000000000, label: 'Billion' }, { value: 1000000, label: 'Million' }, { value: 1000, label: 'Thousand' }, { value: 100, label: 'Hundred' } ]; const toWords = (num: number): string => { if (num < 20) { return belowTwenty[num]; } if (num < 100) { return `${tens[Math.floor(num / 10)]}${num % 10 ? ' ' + belowTwenty[num % 10] : ''}`; } for (const unit of units) { if (num >= unit.value) { const quotient = Math.floor(num / unit.value); const remainder = num % unit.value; const left = `${toWords(quotient)} ${unit.label}`; return remainder ? `${left} ${toWords(remainder)}` : left; } } return ''; }; return toWords(n).trim(); } function normalizePrintConfig(DocumentData: any, PrintConfigData: any) { const config = PrintConfigData || {}; const headerData = config?.headerData ? config.headerData : deriveHeaderDataFromInvoice(DocumentData); const pageMargins = resolvePageMargins(config?.pageMargins ?? PAGE_MARGINS); const watermarkText = toStr(config?.watermarkText); const watermark = !!config?.watermark; const watermarkEnabled = !!config?.watermarkEnabled; const footerText = toStr(config?.footerText); const headerStyles = normalizeHeaderStyle(config?.headerStyles ?? { OrgNameFsize: config?.OrgNameFsize, OrgNameClr: config?.OrgNameClr, AdrsFsize: config?.AdrsFsize, AdrsClr: config?.AdrsClr }); return { ...config, headerData, pageMargins, watermarkText, watermark, watermarkEnabled, footerText, headerStyles }; }