import nodemailer from 'nodemailer' import { PDFDocument, StandardFonts, rgb } from 'pdf-lib' import refreshTokenHelper from "../../utils/refreshTokenHelper" import forceLogoutHelper from "../../utils/forceLogoutHelper" import errorHandlingHelper from "../../utils/errorHandlingHelper" interface InOutLineRecord { organization: string shipment: string productName: string productValue: string productSku: string productMpn: string uom: string qtyEntered: number movementQty: number locator: string orderLine: string line: number } const formatDate = (date: Date, lang: string) => { const isGerman = lang.startsWith('de') return date.toLocaleDateString(isGerman ? 'de-DE' : 'en-US', { day: '2-digit', month: '2-digit', year: 'numeric', hour: '2-digit', minute: '2-digit' }) } const generatePdfReport = async (records: InOutLineRecord[], lang: string) => { const isGerman = lang.startsWith('de') const pdfDoc = await PDFDocument.create() const font = await pdfDoc.embedFont(StandardFonts.Helvetica) const fontBold = await pdfDoc.embedFont(StandardFonts.HelveticaBold) const pageWidth = 841.89 // A4 landscape const pageHeight = 595.28 const margin = 30 const lineHeight = 14 const headerHeight = 20 const colWidths = { org: 70, shipment: 90, prodName: 140, sku: 70, qty: 45, movQty: 50, locator: 70, orderLine: 80 } const addNewPage = () => pdfDoc.addPage([pageWidth, pageHeight]) const drawHeader = (page: any, yPos: number) => { const headers = isGerman ? ['Organisation', 'Lieferung', 'Produktname', 'SKU', 'Menge', 'Bew.Menge', 'Lagerplatz', 'Auftragspos.'] : ['Organization', 'Shipment', 'Product Name', 'SKU', 'Qty', 'Mov Qty', 'Locator', 'Order Line'] let xPos = margin page.drawRectangle({ x: margin - 5, y: yPos - 5, width: pageWidth - (margin * 2) + 10, height: headerHeight, color: rgb(0.9, 0.9, 0.9) }) const fontSize = 7 const widths = Object.values(colWidths) for (let i = 0; i < headers.length; i++) { page.drawText(headers[i], { x: xPos, y: yPos, size: fontSize, font: fontBold }) xPos += widths[i] } return yPos - headerHeight - 5 } const truncate = (str: string, max: number) => { if (!str) return '' return str.length > max ? str.substring(0, max - 3) + '...' : str } const drawRow = (page: any, record: InOutLineRecord, yPos: number) => { let xPos = margin const fontSize = 6 const widths = Object.values(colWidths) const values = [ truncate(record.organization, 16), truncate(record.shipment, 20), truncate(record.productName, 30), truncate(record.productSku, 14), String(record.qtyEntered || 0), String(record.movementQty || 0), truncate(record.locator, 14), truncate(record.orderLine, 16) ] for (let i = 0; i < values.length; i++) { page.drawText(values[i], { x: xPos, y: yPos, size: fontSize, font }) xPos += widths[i] } return yPos - lineHeight } let page = addNewPage() let yPos = pageHeight - margin const title = isGerman ? 'Warenausgangszeilen Bericht' : 'Shipment Line Report' page.drawText(title, { x: margin, y: yPos, size: 16, font: fontBold }) yPos -= 25 page.drawText((isGerman ? 'Erstellt am: ' : 'Generated on: ') + formatDate(new Date(), lang), { x: margin, y: yPos, size: 10, font }) yPos -= 15 page.drawText((isGerman ? 'Anzahl Eintraege: ' : 'Total Records: ') + records.length, { x: margin, y: yPos, size: 10, font }) yPos -= 15 const totalMovQty = records.reduce((sum, r) => sum + (r.movementQty || 0), 0) page.drawText((isGerman ? 'Gesamtbewegungsmenge: ' : 'Total Movement Qty: ') + totalMovQty, { x: margin, y: yPos, size: 10, font }) yPos -= 25 yPos = drawHeader(page, yPos) for (const record of records) { if (yPos < margin + 40) { page = addNewPage() yPos = pageHeight - margin yPos = drawHeader(page, yPos) } yPos = drawRow(page, record, yPos) } yPos -= 20 if (yPos < margin + 60) { page = addNewPage() yPos = pageHeight - margin } page.drawText((isGerman ? 'Gesamtbewegungsmenge: ' : 'Total Movement Qty: ') + totalMovQty, { x: margin, y: yPos, size: 12, font: fontBold }) const pdfBytes = await pdfDoc.save() return Buffer.from(pdfBytes) } const generateCsvReport = (records: InOutLineRecord[], lang: string) => { const isGerman = lang.startsWith('de') const headers = isGerman ? ['Nr.', 'Organisation', 'Lieferung', 'Produktname', 'Produktwert', 'SKU', 'MPN', 'ME', 'Menge Eingabe', 'Bewegungsmenge', 'Lagerplatz', 'Auftragsposition', 'Zeile'] : ['No.', 'Organization', 'Shipment', 'Product Name', 'Product Value', 'SKU', 'MPN', 'UOM', 'Qty Entered', 'Movement Qty', 'Locator', 'Order Line', 'Line'] const rows = records.map((r, i) => [ i + 1, r.organization || '', r.shipment || '', r.productName || '', r.productValue || '', r.productSku || '', r.productMpn || '', r.uom || '', r.qtyEntered || 0, r.movementQty || 0, r.locator || '', r.orderLine || '', r.line || 0 ]) const csvContent = [ headers.join(';'), ...rows.map(row => row.map(cell => `"${String(cell).replace(/"/g, '""')}"`).join(';')) ].join('\n') return Buffer.from('\uFEFF' + csvContent, 'utf-8') } const generateHtmlEmail = (lang: string, recordCount: number, totalMovQty: number) => { const isGerman = lang.startsWith('de') const title = isGerman ? 'Warenausgangszeilen Bericht' : 'Shipment Line Report' const greeting = isGerman ? 'Sehr geehrte Damen und Herren,' : 'Dear Sir or Madam,' const body = isGerman ? 'anbei finden Sie den Warenausgangszeilen-Bericht als Anhang.' : 'Please find attached the shipment line report.' const linesLabel = isGerman ? 'Anzahl Zeilen' : 'Total Lines' const totalLabel = isGerman ? 'Gesamtbewegungsmenge' : 'Total Movement Qty' const closing = isGerman ? 'Mit freundlichen Gruessen' : 'Best regards' const footer = isGerman ? 'Diese E-Mail wurde automatisch versendet.' : 'This email was sent automatically.' return `