import { BadRequestException, InternalServerErrorException, Logger, } from '@nestjs/common'; import * as oracledb from 'oracledb'; const PDFDocument = require('pdfkit'); const fs = require('fs'); const path = require('path'); const PDFMerger = require('pdf-merger-js').default; import * as fsPromises from 'fs/promises'; import { BadRequestException as BR } from 'src/exceptions/badRequest.exception'; import { existsSync, readFileSync } from 'fs'; import { PDFDocument as pdfl, TextAlignment, PDFTextField, PDFCheckBox, PDFRadioGroup, PDFDropdown, PDFOptionList } from 'pdf-lib'; const logger = new Logger('Helper'); export const handleError = (error: any, context: string = 'UnknownService'): never => { if (error instanceof BadRequestException || error instanceof BR) { logger.warn(`[${context}] ${error.message}`); throw error; } if (error.message?.includes('NJS-107')) { logger.warn(`[${context}] Invalid cursor encountered: ${error.message}`); throw new BadRequestException('Invalid database response.'); } if (error.message?.includes('ORA-')) { logger.error(`[${context}] Oracle error occurred: ${error.message}`); throw new InternalServerErrorException(error.message); } logger.error(`[${context}] Unexpected error:`, error.stack || error); throw new InternalServerErrorException(error.message || 'Internal error'); }; export const closeOracleDbConnection = async (connection: any, context: string = 'UnknownService'): Promise => { if (connection) { try { await connection.close(); } catch (closeErr) { logger.error(`[${context}] Failed to close DB connection`, closeErr.stack || closeErr); } } }; export const fetchCursor = async (cursor: oracledb.ResultSet, context: string = 'UnknownService'): Promise => { try { const rows = await cursor.getRows(); await cursor.close(); return rows; } catch (err) { logger.error(`[${context}] Failed to fetch from cursor`, err.stack || err); throw new InternalServerErrorException('Error reading data from database.'); } }; export const setEmptyStringsToNull = (obj: any): void => { Object.keys(obj).forEach((key) => { if (typeof obj[key] === 'object' && obj[key] !== null) { setEmptyStringsToNull(obj[key]); } else if (obj[key] === '') { obj[key] = null; } }); } export interface pdfGLData { itemNo: number; description: string; noOfPieces: number; weight: string; itemValue: number; countryOfOrigin: string } export interface pdfCarnetData { carnetNo: string; ISSUEDBY: string; ISSUEDATE: string; EXPDATE: string; AUTHREP: string; NOOFUSSETS: number; NOOFFOREIGNSETS: number; NOOFTRANSITSETS: number; PRINTGOODSTOBEEXPORTED: string; HOLDERDATATOPRINT: string; CONTINUATIONSHEETS: number; NEXTUSCFNO: number; NEXTFOREIGNCFNO: number; NEXTTRANSITCFNO: number; contPageNo: number; // for GL table only } function formatNumber(num) { if (isNaN(num)) return 'N/A'; return num.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 }); } function toUSDateTime(isoString) { const date = new Date(isoString); const month = String(date.getMonth() + 1).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0'); const year = date.getFullYear(); let hours = date.getHours(); const minutes = String(date.getMinutes()).padStart(2, '0'); const seconds = String(date.getSeconds()).padStart(2, '0'); const ampm = hours >= 12 ? 'PM' : 'AM'; hours = hours % 12 || 12; // return `${month}-${day}-${year}, ${hours}:${minutes}:${seconds} ${ampm}`; return `${year}-${month}-${day}`; } export function replaceSlashWithDash(input) { return input.replace(/\//g, '-'); } export const generateGreenCoverPDF = (carnetData: pdfCarnetData) => { return new Promise(async (resolve, reject) => { try { const templatePath = path.join(__dirname, '../..', 'public/carnet-pdf', '1GreenCover.pdf'); const existingPdfBytes = fs.readFileSync(templatePath); const pdfDoc = await pdfl.load(existingPdfBytes); const form = pdfDoc.getForm(); const CURRENT_FONT = 11; const fields = form.getFields(); const fieldInfo = fields.map(f => { let type = 'unknown'; if (f instanceof PDFTextField) type = 'text'; else if (f instanceof PDFCheckBox) type = 'checkbox'; else if (f instanceof PDFRadioGroup) type = 'radio'; else if (f instanceof PDFDropdown) type = 'dropdown'; else if (f instanceof PDFOptionList) type = 'option-list'; return { name: f.getName(), type }; }); fieldInfo.forEach(x => { if (x.type === "text" && x.name === 'CarnetNo') { const nameField = form.getTextField(x.name); nameField.setFontSize(CURRENT_FONT); nameField.setText(carnetData.carnetNo); } else if (x.type === "text" && x.name === 'AuthBy') { const nameField = form.getTextField(x.name); nameField.setFontSize(CURRENT_FONT); nameField.setText(carnetData.AUTHREP); } else if (x.type === "text" && x.name === 'ContnSheetNo') { const nameField = form.getTextField(x.name); nameField.setFontSize(CURRENT_FONT); nameField.setText(carnetData.CONTINUATIONSHEETS + ""); } else if (x.type === "text" && x.name === 'GoodstobeExportedas') { const nameField = form.getTextField(x.name); nameField.setFontSize(CURRENT_FONT); nameField.setText(carnetData.PRINTGOODSTOBEEXPORTED); } else if (x.type === "text" && x.name === 'IssuedOn') { const nameField = form.getTextField(x.name); nameField.setFontSize(CURRENT_FONT); const formattedDate = toUSDateTime(carnetData.ISSUEDATE) nameField.setText(formattedDate); } else if (x.type === "text" && x.name === 'IssuedBy') { const nameField = form.getTextField(x.name); nameField.setFontSize(CURRENT_FONT); nameField.setText(carnetData.ISSUEDBY); } else if (x.type === "text" && x.name === 'ValidUntil') { const nameField = form.getTextField(x.name); nameField.setFontSize(CURRENT_FONT); const formattedDate = toUSDateTime(carnetData.EXPDATE) nameField.setText(formattedDate); } else if (x.type === "text" && x.name === 'HolderNameAddress') { const nameField = form.getTextField(x.name); nameField.enableMultiline(); nameField.setFontSize(CURRENT_FONT); const multilineAddress = carnetData.HOLDERDATATOPRINT.replace(/~/g, "\n"); nameField.setText(multilineAddress); } }); form.flatten(); const filledPdfBytes = await pdfDoc.save(); const outputPath = path.join(__dirname, '../..', 'public/carnet-pdf', `${replaceSlashWithDash(carnetData.carnetNo)}p1.pdf`); const writeStream = fs.createWriteStream(outputPath); writeStream.write(filledPdfBytes); writeStream.end(); writeStream.on('finish', () => { // console.log("PDF has been successfully created and saved."); resolve("p1 done"); // wait until file fully written }); writeStream.on('error', err => { console.error("Error writing PDF to file:", err); reject(err); }); } catch (err) { reject(err); } }); }; export const generateUSCounterFoilFront = (carnetData: pdfCarnetData, t1: string, t2: string, dn: number, pn: number): Promise => { return new Promise(async (resolve, reject) => { try { const templatePath = path.join(__dirname, '../..', 'public/carnet-pdf', '3USCounterFoilFront.pdf'); const existingPdfBytes = fs.readFileSync(templatePath); const pdfDoc = await pdfl.load(existingPdfBytes); const form = pdfDoc.getForm(); const CURRENT_FONT = 11; const fields = form.getFields(); const fieldInfo = fields.map(f => { let type = 'unknown'; if (f instanceof PDFTextField) type = 'text'; else if (f instanceof PDFCheckBox) type = 'checkbox'; else if (f instanceof PDFRadioGroup) type = 'radio'; else if (f instanceof PDFDropdown) type = 'dropdown'; else if (f instanceof PDFOptionList) type = 'option-list'; return { name: f.getName(), type }; }); // console.log(fieldInfo); fieldInfo.forEach(x => { if (x.type === "text" && x.name === 'Document No1') { const nameField = form.getTextField(x.name); nameField.setFontSize(CURRENT_FONT); if (t1 === "VALUE") { nameField.setText(dn + ""); dn++; } else { nameField.setText("VOID"); } } else if (x.type === "text" && x.name === 'CarnetNo') { const nameField = form.getTextField(x.name); nameField.setFontSize(CURRENT_FONT); nameField.setText(carnetData.carnetNo); } else if (x.type === "text" && x.name === 'Document No2') { const nameField = form.getTextField(x.name); nameField.setFontSize(CURRENT_FONT); if (t2 === "VALUE") { nameField.setText(dn + ""); dn++; } else { nameField.setText("VOID"); } } else if (x.type === "text" && x.name === 'PrintVoidText1') { const nameField = form.getTextField(x.name); nameField.setFontSize(CURRENT_FONT); if (t1 === "VOID") { nameField.setAlignment(TextAlignment.Center); nameField.setText(t1); } } else if (x.type === "text" && x.name === 'PrintVoidText2') { const nameField = form.getTextField(x.name); nameField.setFontSize(CURRENT_FONT); if (t2 === "VOID") { nameField.setAlignment(TextAlignment.Center); nameField.setText(t2); } } }); form.flatten(); const filledPdfBytes = await pdfDoc.save(); const outputPath = path.join(__dirname, '../..', 'public/carnet-pdf', `${replaceSlashWithDash(carnetData.carnetNo)}${pn}USFront.pdf`); const writeStream = fs.createWriteStream(outputPath); writeStream.write(filledPdfBytes); writeStream.end(); pn++; writeStream.on('finish', () => { // console.log(`${dn}USFront.pdf has been successfully created and saved.`); resolve(Number(dn)); // wait until file fully written }); writeStream.on('error', err => { console.error("Error writing PDF to file:", err); reject(err); }); } catch (err) { reject(err); } }); } export const generateUSCounterFoilBack = (carnetData: pdfCarnetData, t1: string, t2: string, dn: number, pn: number): Promise => { return new Promise(async (resolve, reject) => { try { const templatePath = path.join(__dirname, '../..', 'public/carnet-pdf', '4USCounterFoilBack.pdf'); const existingPdfBytes = fs.readFileSync(templatePath); const pdfDoc = await pdfl.load(existingPdfBytes); const form = pdfDoc.getForm(); const CURRENT_FONT = 11; const fields = form.getFields(); const fieldInfo = fields.map(f => { let type = 'unknown'; if (f instanceof PDFTextField) type = 'text'; else if (f instanceof PDFCheckBox) type = 'checkbox'; else if (f instanceof PDFRadioGroup) type = 'radio'; else if (f instanceof PDFDropdown) type = 'dropdown'; else if (f instanceof PDFOptionList) type = 'option-list'; return { name: f.getName(), type }; }); fieldInfo.forEach(x => { if (x.type === "text" && x.name === 'Document No1') { const nameField = form.getTextField(x.name); nameField.setFontSize(CURRENT_FONT); if (t1 === "VALUE") { nameField.setText(dn + ""); dn++; } else { nameField.setText("VOID"); } } else if (x.type === "text" && x.name === 'CarnetNo') { const nameField = form.getTextField(x.name); nameField.setFontSize(CURRENT_FONT); nameField.setText(carnetData.carnetNo); } else if (x.type === "text" && x.name === 'Document No2') { const nameField = form.getTextField(x.name); nameField.setFontSize(CURRENT_FONT); if (t2 === "VALUE") { nameField.setText(dn + ""); dn++; } else { nameField.setText("VOID"); } } else if (x.type === "text" && x.name === 'PrintVoidText1') { const nameField = form.getTextField(x.name); nameField.setFontSize(CURRENT_FONT); if (t1 === "VOID") { nameField.setAlignment(TextAlignment.Center); nameField.setText(t1); } } else if (x.type === "text" && x.name === 'PrintVoidText2') { const nameField = form.getTextField(x.name); nameField.setFontSize(CURRENT_FONT); if (t1 === "VOID") { nameField.setAlignment(TextAlignment.Center); nameField.setText(t1); } } }); form.flatten(); const filledPdfBytes = await pdfDoc.save(); const outputPath = path.join(__dirname, '../..', 'public/carnet-pdf', `${replaceSlashWithDash(carnetData.carnetNo)}${pn}USBack.pdf`); const writeStream = fs.createWriteStream(outputPath); writeStream.write(filledPdfBytes); writeStream.end(); pn++ writeStream.on('finish', () => { // console.log(`${pn}USBack.pdf` + " has been successfully created and saved."); resolve(Number(dn)); // wait until file fully written }); writeStream.on('error', err => { console.error("Error writing PDF to file:", err); reject(err); }); } catch (err) { reject(err); } }); } export const generateFNCounterFoilFront = (carnetData: pdfCarnetData, t1: string, t2: string, dn: number, pn: number): Promise => { return new Promise(async (resolve, reject) => { try { const templatePath = path.join(__dirname, '../..', 'public/carnet-pdf', '6ForeignCounterfoilFront.pdf'); const existingPdfBytes = fs.readFileSync(templatePath); const pdfDoc = await pdfl.load(existingPdfBytes); const form = pdfDoc.getForm(); const CURRENT_FONT = 11; const fields = form.getFields(); const fieldInfo = fields.map(f => { let type = 'unknown'; if (f instanceof PDFTextField) type = 'text'; else if (f instanceof PDFCheckBox) type = 'checkbox'; else if (f instanceof PDFRadioGroup) type = 'radio'; else if (f instanceof PDFDropdown) type = 'dropdown'; else if (f instanceof PDFOptionList) type = 'option-list'; return { name: f.getName(), type }; }); // console.log(fieldInfo); fieldInfo.forEach(x => { if (x.type === "text" && x.name === 'DocumentNo1') { const nameField = form.getTextField(x.name); nameField.setFontSize(CURRENT_FONT); if (t1 === "VALUE") { nameField.setText(dn + ""); dn++; } else { nameField.setText("VOID"); } } else if (x.type === "text" && x.name === 'CarnetNo') { const nameField = form.getTextField(x.name); nameField.setFontSize(CURRENT_FONT); nameField.setText(carnetData.carnetNo); } else if (x.type === "text" && x.name === 'DocumentNo2') { const nameField = form.getTextField(x.name); nameField.setFontSize(CURRENT_FONT); if (t2 === "VALUE") { nameField.setText(dn + ""); dn++; } else { nameField.setText("VOID"); } } else if (x.type === "text" && x.name === 'PrintVoidText1') { const nameField = form.getTextField(x.name); nameField.setFontSize(CURRENT_FONT); if (t1 === "VOID") { nameField.setAlignment(TextAlignment.Center); nameField.setText(t1); } } else if (x.type === "text" && x.name === 'PrintVoidText2') { const nameField = form.getTextField(x.name); nameField.setFontSize(CURRENT_FONT); if (t2 === "VOID") { nameField.setAlignment(TextAlignment.Center); nameField.setText(t2); } } }); form.flatten(); const filledPdfBytes = await pdfDoc.save(); const outputPath = path.join(__dirname, '../..', 'public/carnet-pdf', `${replaceSlashWithDash(carnetData.carnetNo)}${pn}FNFront.pdf`); const writeStream = fs.createWriteStream(outputPath); writeStream.write(filledPdfBytes); writeStream.end(); pn++; writeStream.on('finish', () => { // console.log(`${dn}FNFront.pdf has been successfully created and saved.`); resolve(Number(dn)); // wait until file fully written }); writeStream.on('error', err => { console.error("Error writing PDF to file:", err); reject(err); }); } catch (err) { reject(err); } }); } export const generateFNCounterFoilBack = (carnetData: pdfCarnetData, t1: string, t2: string, dn: number, pn: number): Promise => { return new Promise(async (resolve, reject) => { try { const templatePath = path.join(__dirname, '../..', 'public/carnet-pdf', '7ForeignCounterFoilBack.pdf'); const existingPdfBytes = fs.readFileSync(templatePath); const pdfDoc = await pdfl.load(existingPdfBytes); const form = pdfDoc.getForm(); const CURRENT_FONT = 11; const fields = form.getFields(); const fieldInfo = fields.map(f => { let type = 'unknown'; if (f instanceof PDFTextField) type = 'text'; else if (f instanceof PDFCheckBox) type = 'checkbox'; else if (f instanceof PDFRadioGroup) type = 'radio'; else if (f instanceof PDFDropdown) type = 'dropdown'; else if (f instanceof PDFOptionList) type = 'option-list'; return { name: f.getName(), type }; }); fieldInfo.forEach(x => { if (x.type === "text" && x.name === 'DocumentNo1') { const nameField = form.getTextField(x.name); nameField.setFontSize(CURRENT_FONT); if (t1 === "VALUE") { nameField.setText(dn + ""); dn++; } else { nameField.setText("VOID"); } } else if (x.type === "text" && x.name === 'CarnetNo') { const nameField = form.getTextField(x.name); nameField.setFontSize(CURRENT_FONT); nameField.setText(carnetData.carnetNo); } else if (x.type === "text" && x.name === 'DocumentNo2') { const nameField = form.getTextField(x.name); nameField.setFontSize(CURRENT_FONT); if (t2 === "VALUE") { nameField.setText(dn + ""); dn++; } else { nameField.setText("VOID"); } } else if (x.type === "text" && x.name === 'PrintVoidText1') { const nameField = form.getTextField(x.name); nameField.setFontSize(CURRENT_FONT); if (t1 === "VOID") { nameField.setAlignment(TextAlignment.Center); nameField.setText(t1); } } else if (x.type === "text" && x.name === 'PrintVoidText2') { const nameField = form.getTextField(x.name); nameField.setFontSize(CURRENT_FONT); if (t1 === "VOID") { nameField.setAlignment(TextAlignment.Center); nameField.setText(t1); } } }); form.flatten(); const filledPdfBytes = await pdfDoc.save(); const outputPath = path.join(__dirname, '../..', 'public/carnet-pdf', `${replaceSlashWithDash(carnetData.carnetNo)}${pn}FNBack.pdf`); const writeStream = fs.createWriteStream(outputPath); writeStream.write(filledPdfBytes); writeStream.end(); pn++ writeStream.on('finish', () => { // console.log(`${pn}FNBack.pdf` + " has been successfully created and saved."); resolve(Number(dn)); // wait until file fully written }); writeStream.on('error', err => { console.error("Error writing PDF to file:", err); reject(err); }); } catch (err) { reject(err); } }); } export const generateTSCounterFoilFront = (carnetData: pdfCarnetData, t1: string, t2: string, dn: number, pn: number): Promise => { return new Promise(async (resolve, reject) => { try { const templatePath = path.join(__dirname, '../..', 'public/carnet-pdf', '8TransitCounterFoilFront.pdf'); const existingPdfBytes = fs.readFileSync(templatePath); const pdfDoc = await pdfl.load(existingPdfBytes); const form = pdfDoc.getForm(); const CURRENT_FONT = 11; const fields = form.getFields(); const fieldInfo = fields.map(f => { let type = 'unknown'; if (f instanceof PDFTextField) type = 'text'; else if (f instanceof PDFCheckBox) type = 'checkbox'; else if (f instanceof PDFRadioGroup) type = 'radio'; else if (f instanceof PDFDropdown) type = 'dropdown'; else if (f instanceof PDFOptionList) type = 'option-list'; return { name: f.getName(), type }; }); // console.log(fieldInfo); fieldInfo.forEach(x => { if (x.type === "text" && x.name === 'DocumentNo1') { const nameField = form.getTextField(x.name); nameField.setFontSize(CURRENT_FONT); if (t1 === "VALUE") { nameField.setText(dn + ""); dn++; } else { nameField.setText("VOID"); } } else if (x.type === "text" && x.name === 'CarnetNo') { const nameField = form.getTextField(x.name); nameField.setFontSize(CURRENT_FONT); nameField.setText(carnetData.carnetNo); } else if (x.type === "text" && x.name === 'DocumentNo2') { const nameField = form.getTextField(x.name); nameField.setFontSize(CURRENT_FONT); if (t2 === "VALUE") { nameField.setText(dn + ""); dn++; } else { nameField.setText("VOID"); } } else if (x.type === "text" && x.name === 'PrintVoidText1') { const nameField = form.getTextField(x.name); nameField.setFontSize(CURRENT_FONT); if (t1 === "VOID") { nameField.setAlignment(TextAlignment.Center); nameField.setText(t1); } } else if (x.type === "text" && x.name === 'PrintVoidText2') { const nameField = form.getTextField(x.name); nameField.setFontSize(CURRENT_FONT); if (t2 === "VOID") { nameField.setAlignment(TextAlignment.Center); nameField.setText(t2); } } }); form.flatten(); const filledPdfBytes = await pdfDoc.save(); const outputPath = path.join(__dirname, '../..', 'public/carnet-pdf', `${replaceSlashWithDash(carnetData.carnetNo)}${pn}TSFront.pdf`); const writeStream = fs.createWriteStream(outputPath); writeStream.write(filledPdfBytes); writeStream.end(); pn++; writeStream.on('finish', () => { // console.log(`${dn}TSFront.pdf has been successfully created and saved.`); resolve(Number(dn)); // wait until file fully written }); writeStream.on('error', err => { console.error("Error writing PDF to file:", err); reject(err); }); } catch (err) { reject(err); } }); } export const generateTSCounterFoilBack = (carnetData: pdfCarnetData, t1: string, t2: string, dn: number, pn: number): Promise => { return new Promise(async (resolve, reject) => { try { const templatePath = path.join(__dirname, '../..', 'public/carnet-pdf', '9TransitCounterfoilBack.pdf'); const existingPdfBytes = fs.readFileSync(templatePath); const pdfDoc = await pdfl.load(existingPdfBytes); const form = pdfDoc.getForm(); const CURRENT_FONT = 11; const fields = form.getFields(); const fieldInfo = fields.map(f => { let type = 'unknown'; if (f instanceof PDFTextField) type = 'text'; else if (f instanceof PDFCheckBox) type = 'checkbox'; else if (f instanceof PDFRadioGroup) type = 'radio'; else if (f instanceof PDFDropdown) type = 'dropdown'; else if (f instanceof PDFOptionList) type = 'option-list'; return { name: f.getName(), type }; }); fieldInfo.forEach(x => { if (x.type === "text" && x.name === 'DocumentNo1') { const nameField = form.getTextField(x.name); nameField.setFontSize(CURRENT_FONT); if (t1 === "VALUE") { nameField.setText(dn + ""); dn++; } else { nameField.setText("VOID"); } } else if (x.type === "text" && x.name === 'CarnetNo') { const nameField = form.getTextField(x.name); nameField.setFontSize(CURRENT_FONT); nameField.setText(carnetData.carnetNo); } else if (x.type === "text" && x.name === 'DocumentNo2') { const nameField = form.getTextField(x.name); nameField.setFontSize(CURRENT_FONT); if (t2 === "VALUE") { nameField.setText(dn + ""); dn++; } else { nameField.setText("VOID"); } } else if (x.type === "text" && x.name === 'PrintVoidText1') { const nameField = form.getTextField(x.name); nameField.setFontSize(CURRENT_FONT); if (t1 === "VOID") { nameField.setAlignment(TextAlignment.Center); nameField.setText(t1); } } else if (x.type === "text" && x.name === 'PrintVoidText2') { const nameField = form.getTextField(x.name); nameField.setFontSize(CURRENT_FONT); if (t1 === "VOID") { nameField.setAlignment(TextAlignment.Center); nameField.setText(t1); } } }); form.flatten(); const filledPdfBytes = await pdfDoc.save(); const outputPath = path.join(__dirname, '../..', 'public/carnet-pdf', `${replaceSlashWithDash(carnetData.carnetNo)}${pn}TSBack.pdf`); const writeStream = fs.createWriteStream(outputPath); writeStream.write(filledPdfBytes); writeStream.end(); pn++ writeStream.on('finish', () => { // console.log(`${pn}TSBack.pdf` + " has been successfully created and saved."); resolve(Number(dn)); // wait until file fully written }); writeStream.on('error', err => { console.error("Error writing PDF to file:", err); reject(err); }); } catch (err) { reject(err); } }); } export const generateFNImportV = (carnetData: pdfCarnetData, dn: number, pn: number): Promise => { return new Promise(async (resolve, reject) => { try { const templatePath = path.join(__dirname, '../..', 'public/carnet-pdf', '10ImportVoucher.pdf'); const existingPdfBytes = fs.readFileSync(templatePath); const pdfDoc = await pdfl.load(existingPdfBytes); const form = pdfDoc.getForm(); const CURRENT_FONT = 11; const fields = form.getFields(); const fieldInfo = fields.map(f => { let type = 'unknown'; if (f instanceof PDFTextField) type = 'text'; else if (f instanceof PDFCheckBox) type = 'checkbox'; else if (f instanceof PDFRadioGroup) type = 'radio'; else if (f instanceof PDFDropdown) type = 'dropdown'; else if (f instanceof PDFOptionList) type = 'option-list'; return { name: f.getName(), type }; }); // console.log(fieldInfo); fieldInfo.forEach(x => { if (x.type === "text" && x.name === 'Valid Until') { const nameField = form.getTextField(x.name); nameField.setFontSize(CURRENT_FONT); const formattedDate = toUSDateTime(carnetData.EXPDATE) nameField.setText(formattedDate); } else if (x.type === "text" && x.name === 'CarnetNo') { const nameField = form.getTextField(x.name); nameField.setFontSize(CURRENT_FONT); nameField.setText(carnetData.carnetNo); } else if (x.type === "text" && x.name === 'VoucherNo') { const nameField = form.getTextField(x.name); nameField.setFontSize(CURRENT_FONT); nameField.setText(dn + ""); dn++; } else if (x.type === "text" && x.name === 'AuthorizedBy') { const nameField = form.getTextField(x.name); nameField.setFontSize(CURRENT_FONT); nameField.setText(carnetData.AUTHREP); } else if (x.type === "text" && x.name === 'GoodsDescription') { const nameField = form.getTextField(x.name); nameField.setFontSize(CURRENT_FONT); nameField.setText(carnetData.PRINTGOODSTOBEEXPORTED); } else if (x.type === "text" && x.name === 'IssuedBy') { const nameField = form.getTextField(x.name); nameField.setFontSize(CURRENT_FONT); nameField.setText(carnetData.ISSUEDBY); } else if (x.type === "text" && x.name === 'Issued') { const nameField = form.getTextField(x.name); nameField.setFontSize(CURRENT_FONT); const formattedDate = toUSDateTime(carnetData.ISSUEDATE) nameField.setText(formattedDate); } }); form.flatten(); const filledPdfBytes = await pdfDoc.save(); const outputPath = path.join(__dirname, '../..', 'public/carnet-pdf', `${replaceSlashWithDash(carnetData.carnetNo)}${pn}FNImportV.pdf`); const writeStream = fs.createWriteStream(outputPath); writeStream.write(filledPdfBytes); writeStream.end(); pn++; writeStream.on('finish', () => { // console.log(`${dn}FNImportV.pdf has been successfully created and saved.`); resolve(Number(dn)); // wait until file fully written }); writeStream.on('error', err => { console.error("Error writing PDF to file:", err); reject(err); }); } catch (err) { reject(err); } }); } export const generateFNExportV = (carnetData: pdfCarnetData, dn: number, pn: number): Promise => { return new Promise(async (resolve, reject) => { try { const templatePath = path.join(__dirname, '../..', 'public/carnet-pdf', '11ExportVoucher.pdf'); const existingPdfBytes = fs.readFileSync(templatePath); const pdfDoc = await pdfl.load(existingPdfBytes); const form = pdfDoc.getForm(); const CURRENT_FONT = 11; const fields = form.getFields(); const fieldInfo = fields.map(f => { let type = 'unknown'; if (f instanceof PDFTextField) type = 'text'; else if (f instanceof PDFCheckBox) type = 'checkbox'; else if (f instanceof PDFRadioGroup) type = 'radio'; else if (f instanceof PDFDropdown) type = 'dropdown'; else if (f instanceof PDFOptionList) type = 'option-list'; return { name: f.getName(), type }; }); // console.log(fieldInfo); fieldInfo.forEach(x => { if (x.type === "text" && x.name === 'Valid Until') { const nameField = form.getTextField(x.name); nameField.setFontSize(CURRENT_FONT); const formattedDate = toUSDateTime(carnetData.EXPDATE) nameField.setText(formattedDate); } else if (x.type === "text" && x.name === 'CarnetNo') { const nameField = form.getTextField(x.name); nameField.setFontSize(CURRENT_FONT); nameField.setText(carnetData.carnetNo); } else if (x.type === "text" && x.name === 'VoucherNo') { const nameField = form.getTextField(x.name); nameField.setFontSize(CURRENT_FONT); nameField.setText(dn + ""); dn++; } else if (x.type === "text" && x.name === 'AuthorizedBy') { const nameField = form.getTextField(x.name); nameField.setFontSize(CURRENT_FONT); nameField.setText(carnetData.AUTHREP); } else if (x.type === "text" && x.name === 'GoodsDescription') { const nameField = form.getTextField(x.name); nameField.setFontSize(CURRENT_FONT); nameField.setText(carnetData.PRINTGOODSTOBEEXPORTED); } else if (x.type === "text" && x.name === 'IssuedBy') { const nameField = form.getTextField(x.name); nameField.setFontSize(CURRENT_FONT); nameField.setText(carnetData.ISSUEDBY); } else if (x.type === "text" && x.name === 'Issued') { const nameField = form.getTextField(x.name); nameField.setFontSize(CURRENT_FONT); const formattedDate = toUSDateTime(carnetData.ISSUEDATE) nameField.setText(formattedDate); } }); form.flatten(); const filledPdfBytes = await pdfDoc.save(); const outputPath = path.join(__dirname, '../..', 'public/carnet-pdf', `${replaceSlashWithDash(carnetData.carnetNo)}${pn}FNExportV.pdf`); const writeStream = fs.createWriteStream(outputPath); writeStream.write(filledPdfBytes); writeStream.end(); pn++; writeStream.on('finish', () => { // console.log(`${dn}FNExportV.pdf has been successfully created and saved.`); resolve(Number(dn)); // wait until file fully written }); writeStream.on('error', err => { console.error("Error writing PDF to file:", err); reject(err); }); } catch (err) { reject(err); } }); } export const generateTNV = (carnetData: pdfCarnetData, dn: number, pn: number): Promise => { return new Promise(async (resolve, reject) => { try { const templatePath = path.join(__dirname, '../..', 'public/carnet-pdf', '12TransitVoucher.pdf'); const existingPdfBytes = fs.readFileSync(templatePath); const pdfDoc = await pdfl.load(existingPdfBytes); const form = pdfDoc.getForm(); const CURRENT_FONT = 11; const fields = form.getFields(); const fieldInfo = fields.map(f => { let type = 'unknown'; if (f instanceof PDFTextField) type = 'text'; else if (f instanceof PDFCheckBox) type = 'checkbox'; else if (f instanceof PDFRadioGroup) type = 'radio'; else if (f instanceof PDFDropdown) type = 'dropdown'; else if (f instanceof PDFOptionList) type = 'option-list'; return { name: f.getName(), type }; }); // console.log(fieldInfo); fieldInfo.forEach(x => { if (x.type === "text" && x.name === 'Valid Until') { const nameField = form.getTextField(x.name); nameField.setFontSize(CURRENT_FONT); const formattedDate = toUSDateTime(carnetData.EXPDATE) nameField.setText(formattedDate); } else if (x.type === "text" && x.name === 'CarnetNo') { const nameField = form.getTextField(x.name); nameField.setFontSize(CURRENT_FONT); nameField.setText(carnetData.carnetNo); } else if (x.type === "text" && x.name === 'VoucherNo') { const nameField = form.getTextField(x.name); nameField.setFontSize(CURRENT_FONT); nameField.setText(dn + ""); dn++; } else if (x.type === "text" && x.name === 'AuthorizedBy') { const nameField = form.getTextField(x.name); nameField.setFontSize(CURRENT_FONT); nameField.setText(carnetData.AUTHREP); } else if (x.type === "text" && x.name === 'GoodsDescription') { const nameField = form.getTextField(x.name); nameField.setFontSize(CURRENT_FONT); nameField.setText(carnetData.PRINTGOODSTOBEEXPORTED); } else if (x.type === "text" && x.name === 'IssuedBy') { const nameField = form.getTextField(x.name); nameField.setFontSize(CURRENT_FONT); nameField.setText(carnetData.ISSUEDBY); } else if (x.type === "text" && x.name === 'Issued') { const nameField = form.getTextField(x.name); nameField.setFontSize(CURRENT_FONT); const formattedDate = toUSDateTime(carnetData.ISSUEDATE) nameField.setText(formattedDate); } }); form.flatten(); const filledPdfBytes = await pdfDoc.save(); const outputPath = path.join(__dirname, '../..', 'public/carnet-pdf', `${replaceSlashWithDash(carnetData.carnetNo)}${pn}TNV.pdf`); const writeStream = fs.createWriteStream(outputPath); writeStream.write(filledPdfBytes); writeStream.end(); pn++; writeStream.on('finish', () => { // console.log(`${dn}TNV.pdf has been successfully created and saved.`); resolve(Number(dn)); // wait until file fully written }); writeStream.on('error', err => { console.error("Error writing PDF to file:", err); reject(err); }); } catch (err) { reject(err); } }); } function getPatternArray(n) { if (n < 1) { return []; } const numFours = Math.floor((n - 1) / 4); // Create an array with the leading 4s const result = Array(numFours).fill(4); // Calculate and add the final number const lastNumber = (n - 1) % 4 + 1; result.push(lastNumber); return result; } export async function usCounterFoil(carnetData: pdfCarnetData) { let documentNo = carnetData.NEXTUSCFNO; let fpdf = 1; const set = getPatternArray(carnetData.NOOFUSSETS) const generatedFiles: any = []; for (const s of set) { // console.log(" Current pattern value (s): ", s); // This is where you would use the 's' value to determine arguments // For now, let's keep the arguments constant as per your example const funFrontSecondArg = s > 1 ? "VALUE" : "VOID"; const funBackFirstArg = s > 2 ? "VALUE" : "VOID"; const funBackSecondArg = s > 3 ? "VALUE" : "VOID"; // Step 1: Await front PDF generation let inc1: number = await generateUSCounterFoilFront(carnetData, "VALUE", funFrontSecondArg, documentNo, fpdf); documentNo = inc1; generatedFiles.push(`${replaceSlashWithDash(carnetData.carnetNo)}${fpdf}USFront.pdf`); // Step 2: Await back PDF generation let inc2: number = await generateUSCounterFoilBack(carnetData, funBackFirstArg, funBackSecondArg, documentNo, fpdf); documentNo = inc2; generatedFiles.push(`${replaceSlashWithDash(carnetData.carnetNo)}${fpdf}USBack.pdf`); // Increment fpdf for the next loop fpdf++; } // console.log("All US Counter Foil PDFs have been completely generated."); // console.log(generatedFiles); // Return the list of generated filenames return generatedFiles; } export async function fnCounterFoil(carnetData: pdfCarnetData) { let documentNo = carnetData.NEXTFOREIGNCFNO; let fpdf = 1; const set = getPatternArray(carnetData.NOOFFOREIGNSETS) const generatedFiles: any = []; for (const s of set) { // This is where you would use the 's' value to determine arguments // For now, let's keep the arguments constant as per your example const funFrontSecondArg = s > 1 ? "VALUE" : "VOID"; const funBackFirstArg = s > 2 ? "VALUE" : "VOID"; const funBackSecondArg = s > 3 ? "VALUE" : "VOID"; // Step 1: Await front PDF generation let inc1: number = await generateFNCounterFoilFront(carnetData, "VALUE", funFrontSecondArg, documentNo, fpdf); documentNo = inc1; generatedFiles.push(`${replaceSlashWithDash(carnetData.carnetNo)}${fpdf}FNFront.pdf`); // Step 2: Await back PDF generation let inc2: number = await generateFNCounterFoilBack(carnetData, funBackFirstArg, funBackSecondArg, documentNo, fpdf); documentNo = inc2; generatedFiles.push(`${replaceSlashWithDash(carnetData.carnetNo)}${fpdf}FNBack.pdf`); // Increment fpdf for the next loop fpdf++; } // console.log("All US Counter Foil PDFs have been completely generated."); // console.log(generatedFiles); // Return the list of generated filenames return generatedFiles; } export async function tsCounterFoil(carnetData: pdfCarnetData) { let documentNo = carnetData.NEXTTRANSITCFNO; let fpdf = 1; const set = getPatternArray(carnetData.NOOFTRANSITSETS) const generatedFiles: any = []; for (const s of set) { // console.log(" Current pattern value (s): ", s); // This is where you would use the 's' value to determine arguments // For now, let's keep the arguments constant as per your example const funFrontSecondArg = s > 1 ? "VALUE" : "VOID"; const funBackFirstArg = s > 2 ? "VALUE" : "VOID"; const funBackSecondArg = s > 3 ? "VALUE" : "VOID"; // console.log("document no : ", s, " : ", documentNo); // Step 1: Await front PDF generation let inc1: number = await generateTSCounterFoilFront(carnetData, "VALUE", funFrontSecondArg, documentNo, fpdf); documentNo = inc1; generatedFiles.push(`${replaceSlashWithDash(carnetData.carnetNo)}${fpdf}TSFront.pdf`); // Step 2: Await back PDF generation let inc2: number = await generateTSCounterFoilBack(carnetData, funBackFirstArg, funBackSecondArg, documentNo, fpdf); documentNo = inc2; generatedFiles.push(`${replaceSlashWithDash(carnetData.carnetNo)}${fpdf}TSBack.pdf`); // Increment fpdf for the next loop fpdf++; } // console.log("All US Counter Foil PDFs have been completely generated."); // console.log(generatedFiles); // Return the list of generated filenames return generatedFiles; } export async function fnVochers(carnetData: pdfCarnetData) { let importNo = 1; let exportNo = 1; let fpdf = 1; const set = getPatternArray(carnetData.NOOFFOREIGNSETS) const generatedFiles: any = []; for (const s of set) { // Step 1: Await back PDF generation let inc1: number = await generateFNImportV(carnetData, importNo, fpdf); importNo = inc1; generatedFiles.push(`${replaceSlashWithDash(carnetData.carnetNo)}${fpdf}FNImportV.pdf`); generatedFiles.push(`2GeneralList.pdf`); // Step 2: Await back PDF generation let inc2: number = await generateFNExportV(carnetData, exportNo, fpdf); exportNo = inc2; generatedFiles.push(`${replaceSlashWithDash(carnetData.carnetNo)}${fpdf}FNExportV.pdf`); generatedFiles.push(`2GeneralList.pdf`); // Increment fpdf for the next loop fpdf++; } // console.log("All US Counter Foil PDFs have been completely generated."); // console.log(generatedFiles); // Return the list of generated filenames return generatedFiles; } export async function tnVochers(carnetData: pdfCarnetData) { let tnNo = 1; let fpdf = 1; const set = getPatternArray(carnetData.NOOFTRANSITSETS) const generatedFiles: any = []; for (const s of set) { // console.log(" Current pattern value (s): ", s); await generateTNV(carnetData, tnNo, fpdf); generatedFiles.push(`${replaceSlashWithDash(carnetData.carnetNo)}${fpdf}TNV.pdf`); generatedFiles.push(`2GeneralList.pdf`); fpdf++; } // console.log("All US Counter Foil PDFs have been completely generated."); // console.log(generatedFiles); return generatedFiles; } export const generateFinalPDF = async (inputFiles: string[], outputFile: string) => { const merger = new PDFMerger(); for (const fileName of inputFiles) { const filePath = path.join(__dirname, '../../public/carnet-pdf', fileName); // console.log(`Does the file exist? ${existsSync(filePath)}`); // console.log(`📄 Adding: ${filePath}`); try { const fileData = readFileSync(filePath); await merger.add(fileData); } catch (err) { console.error(`❌ Failed to add PDF: ${fileName}`, err); } } const outputPath = path.join(__dirname, '../../public/carnet-pdf', outputFile); try { await merger.save(outputPath); // console.log(`✅ Merged PDF saved to ${outputPath}`); } catch (err) { console.error(`❌ Failed to save merged PDF`, err); throw new Error("Failed to save merged PDF"); } }; export const deleteFilesAsync = async (relativeFilePaths: string[]): Promise => { for (const relativeFilePath of relativeFilePaths) { const filePath = path.join(__dirname, '../../public/carnet-pdf', relativeFilePath); if (fs.existsSync(filePath)) { try { await fsPromises.unlink(filePath); // console.log(`🗑️ Deleted: ${filePath}`); } catch (err) { console.error(`❌ Error deleting file: ${filePath}`, err); } } else { console.warn(`⚠️ File not found: ${filePath}`); } } };