import { promisify } from 'node:util' import child_process from 'node:child_process' import { existsSync, mkdirSync } from 'node:fs' import { writeFile } from 'node:fs/promises' import { jsPDF } from 'jspdf' import fetchHelper from '../../utils/fetchHelper' import getTokenHelper from '../../utils/getTokenHelper' // let notoSansBase64: string | null = null // async function getNotoSansBase64() { // if (!notoSansBase64) { // const storage = useStorage('assets:server') // const fontBuffer = await storage.getItemRaw('fonts/NotoSans-Regular.ttf') // notoSansBase64 = Buffer.from(fontBuffer!).toString('base64') // } // return notoSansBase64 // } const labelByPrinter = (doc, no, entry, orgNames = {}, customSettings = null) => { const s = customSettings if(entry.labelPrinterId === 'b') { doc.addPage() doc.setPage(no) doc.setFontSize(s?.productFontSize ?? 18) doc.text(String(entry.product.replace("FOREVER ", "")), s?.productX ?? 0, s?.productY ?? 6) doc.setFontSize(s?.skuFontSize ?? 15) doc.text(String( 'SKU:'+ entry.productSKU+ ' - '+ entry.organizationId?.toString().slice(-2)), s?.skuX ?? 0, s?.skuY ?? 13) doc.addImage(entry.labelBarcode, 'image/png', s?.barcodeX ?? 1, s?.barcodeY ?? 16, s?.barcodeW ?? 74, s?.barcodeH ?? 32) } else if(entry.labelPrinterId === 'c') { doc.addPage() doc.setPage(no) doc.setFontSize(s?.productFontSize ?? 12) const productText = String(entry.product.replace("FOREVER ", "")) const splitProduct = doc.splitTextToSize(productText, s?.productW ?? 70) doc.text(splitProduct, s?.productX ?? 0, s?.productY ?? 5) const productLines = Math.min(splitProduct.length, 3) const tableStart = (s?.productY ?? 5) + (productLines * 5) doc.setFontSize(s?.tableFontSize ?? 9) doc.rect(1, tableStart, 71, 4) doc.text(String('SKU: ' + entry.productSKU), 2, tableStart + 3) doc.rect(1, tableStart + 4, 32, 4) doc.text(String('Artikelnr.:' + entry.productValue), 2, tableStart + 7) doc.rect(33, tableStart + 4, 39, 4) doc.text(String('EAN: ' + entry.productUPC), 35, tableStart + 7) doc.rect(1, tableStart + 8, 32, 4) doc.text(String((orgNames[entry.organizationId] || entry.organizationId?.toString().slice(-2))), 2, tableStart + 11) doc.rect(33, tableStart + 8, 39, 4) doc.text(String(new Date().toLocaleString('de-DE', { day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit', timeZone: 'Europe/Berlin' }).replace(',', '')), 35, tableStart + 11) doc.setFontSize(12) doc.addImage(entry.labelBarcode, 'image/png', s?.barcodeX ?? 2, tableStart + 13, s?.barcodeW ?? 70, s?.barcodeH ?? 20) } else if(entry.labelPrinterId === 'd') { doc.addPage() doc.setPage(no) doc.setFontSize(s?.productFontSize ?? 12) const productTextD = String(entry.product.replace("FOREVER ", "")) const splitProductD = doc.splitTextToSize(productTextD, s?.productW ?? 70) doc.text(splitProductD, s?.productX ?? 0, s?.productY ?? 5) doc.setFontSize(s?.tableFontSize ?? 9) const tableStartD = s?.tableStartY ?? 19 doc.rect(1, tableStartD, 71, 4) doc.text(String('SKU: ' + entry.productSKU), 2, tableStartD + 3) doc.rect(1, tableStartD + 4, 32, 4) doc.text(String('Artikelnr.:' + entry.productValue), 2, tableStartD + 7) doc.rect(33, tableStartD + 4, 39, 4) doc.text(String('EAN: ' + entry.productUPC), 35, tableStartD + 7) doc.rect(1, tableStartD + 8, 32, 4) doc.text(String((orgNames[entry.organizationId] || entry.organizationId?.toString().slice(-2))), 2, tableStartD + 11) doc.rect(33, tableStartD + 8, 39, 4) doc.text(String( new Date().toLocaleString('de-DE', { day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit', timeZone: 'Europe/Berlin' }).replace(',', '')), 35, tableStartD + 11) doc.setFontSize(12) doc.addImage(entry.labelBarcode, 'image/png', s?.barcodeX ?? 2, s?.barcodeY ?? 32, s?.barcodeW ?? 70, s?.barcodeH ?? 20) } else if(entry.labelPrinterId === 'e') { doc.addPage() doc.setPage(no) doc.setFontSize(s?.productFontSize ?? 12) const productTextE = String(entry.product.replace("FOREVER ", "")) const splitProductE = doc.splitTextToSize(productTextE, s?.productW ?? 70) doc.text(splitProductE, s?.productX ?? 0, s?.productY ?? 5) doc.setFontSize(s?.tableFontSize ?? 9) const tableStartE = s?.tableStartY ?? 19 doc.rect(1, tableStartE, 71, 4) doc.text(String('SKU: ' + entry.productSKU), 2, tableStartE + 3) doc.rect(1, tableStartE + 4, 32, 4) doc.text(String('Artikelnr.:' + entry.productValue), 2, tableStartE + 7) doc.rect(33, tableStartE + 4, 39, 4) doc.text(String('EAN: ' + entry.productUPC), 35, tableStartE + 7) doc.rect(1, tableStartE + 8, 32, 4) doc.text(String((orgNames[entry.organizationId] || entry.organizationId?.toString().slice(-2))), 2, tableStartE + 11) doc.rect(33, tableStartE + 8, 39, 4) doc.text(String('Erst.:' + new Date().toLocaleString('de-DE', { day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit', timeZone: 'Europe/Berlin' }).replace(',', '')), 35, tableStartE + 11) doc.setFontSize(12) doc.addImage(entry.labelBarcode, 'image/png', s?.barcodeX ?? 2, s?.barcodeY ?? 32, s?.barcodeW ?? 70, s?.barcodeH ?? 20) } else if(entry.labelPrinterId === 'f') { let fFormat = [54, 52] if (s?.format && /^\d+,\d+$/.test(s.format)) { const [w, h] = s.format.split(',').map(Number) fFormat = [w, h] } doc.addPage(fFormat) doc.setPage(no) doc.setFontSize(s?.productFontSize ?? 12) const productTextF = String(entry.product.replace("FOREVER ", "")) const splitProductF = doc.splitTextToSize(productTextF, s?.productW ?? 52) doc.text(splitProductF, s?.productX ?? 0, s?.productY ?? 6) const productLinesF = Math.min(splitProductF.length, 3) const tableStartF = (s?.productY ?? 6) + (productLinesF * 5) doc.setFontSize(s?.tableFontSize ?? 9) doc.rect(1, tableStartF, 51, 4) doc.text(String('SKU: ' + entry.productSKU), 2, tableStartF + 3) doc.rect(1, tableStartF + 4, 25, 4) doc.text(String('Art:' + entry.productValue), 2, tableStartF + 7) doc.rect(26, tableStartF + 4, 26, 4) doc.text(String('EAN: ' + entry.productUPC), 27, tableStartF + 7) doc.rect(1, tableStartF + 8, 25, 4) doc.text(String((orgNames[entry.organizationId] || entry.organizationId?.toString().slice(-2))), 2, tableStartF + 11) doc.rect(26, tableStartF + 8, 26, 4) doc.text(String('Erst:' + new Date().toLocaleString('de-DE', { day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit', timeZone: 'Europe/Berlin' }).replace(',', '')), 27, tableStartF + 11) doc.setFontSize(12) doc.addImage(entry.labelBarcode, 'image/png', s?.barcodeX ?? 2, tableStartF + 14, s?.barcodeW ?? 50, s?.barcodeH ?? 18) } else { doc.addPage() doc.setPage(no) doc.setFontSize(18) doc.text(String(entry.product.replace("FOREVER ", "")), 0, 8) doc.setFontSize(14) doc.text(String( 'SKU: '+ entry.productSKU + ' | VAL: ' + entry.productValue+ ' | ORG: '+ entry.organizationId?.toString().slice(-2)), 0, 17) doc.addImage(entry.labelBarcode, 'image/png', 9, 20, 60, 28) } } const serverPrinting = async (item) => { const exec = promisify(child_process.exec) const labelPrinters = { a: 'labelprinter-1', b: 'labelprinter-2', c: 'labelprinter-3', d: 'labelprinter-4', e: 'labelprinter-5', f: 'labelprinter-6', } let labelPrinter = 'labelprinter-2' if(labelPrinters[item.labelEntry]) { labelPrinter = labelPrinters[item.labelEntry] } let newResult = {} try { if(!existsSync(item.filePath)) { mkdirSync(item.filePath, { recursive: true }) } await writeFile(`${item.filePath}/${item.fileName}`, Buffer.from(item.fileContent, 'base64')) const { stdout, stderr } = await exec(`lp -d ${labelPrinter} -o fit-to-page ${item.filePath}/${item.fileName}`); newResult['stdout'] = stdout newResult['stderr'] = stderr } catch(err: any) { newResult['stdout'] = item.fileContent newResult['stderr'] = err?.message || err?.data?.message || 'Error when printing via server side' } return newResult } export default defineEventHandler(async (event) => { let data: any = {} const body = await readBody(event) const exec = promisify(child_process.exec) const pathName = body.pathName const filePath = `/root/storage/${pathName}` const fileName = body.fileName const labelEntries = body.labelEntries const customSettings = body.customSettings || null data['path'] = filePath data['name'] = fileName data['contents'] = [] // Fetch org company names once for the entire print session const orgNames: Record = {} try { const orgIds = [...new Set(labelEntries.flatMap(([, vals]) => vals.flat().map((e: any) => e.organizationId)).filter(Boolean))] if (orgIds.length > 0) { const token = await getTokenHelper(event) const orgFilter = orgIds.map(id => `AD_Org_ID eq ${id}`).join(' or ') const orgRes: any = await fetchHelper(event, `models/ad_org?$filter=${orgFilter}&$select=AD_Org_ID,companyname,Name`, 'GET', token, null) for (const org of orgRes?.records || []) { orgNames[org.id] = org.companyname || org.Name || '' } } } catch (e) { // fallback: orgNames stays empty, label will use organizationId } for(const [labelEntry, labelValues] of labelEntries) { let pageFormat: any = 'a8' if (customSettings?.format) { const formatStr = customSettings.format if (/^\d+,\d+$/.test(formatStr)) { const [w, h] = formatStr.split(',').map(Number) pageFormat = [w, h] } else { pageFormat = formatStr } } const doc = new jsPDF({ orientation: 'l', unit: 'mm', format: pageFormat, putOnlyUsedFonts: true, compress: true }) // doc.addFileToVFS('NotoSans-Regular.ttf', await getNotoSansBase64()) // doc.addFont('NotoSans-Regular.ttf', 'NotoSans', 'normal') // doc.setFont('NotoSans') doc.addPage() let no = 2; for(let entry of labelValues.flat()) { for(let i = 0; i < Number(entry.qtyEntered || 0); i++) { labelByPrinter(doc, no, entry, orgNames, customSettings) no++ } } doc.deletePage(1) doc.deletePage(Number(no) - 1) const fileContent = doc.output('dataurlstring')?.replace('data:application/pdf;filename=generated.pdf;base64,', '') data['contents'].push({ label: labelEntry, content: fileContent }) const resPrint = await serverPrinting({ filePath, fileName: fileName.replace('-LABELS-', `-LABELPRINTER-${labelEntry}-`), fileContent, labelEntry }) if(resPrint) { data['print_result'] = resPrint } } return data })