import nodemailer from 'nodemailer' import refreshTokenHelper from "../../utils/refreshTokenHelper" import forceLogoutHelper from "../../utils/forceLogoutHelper" import errorHandlingHelper from "../../utils/errorHandlingHelper" import getTokenHelper from "../../utils/getTokenHelper" import fetchHelper from "../../utils/fetchHelper" interface ReturnLine { productName: string productValue: string qtyEntered: number } const formatDate = (dateStr: string, lang: string) => { if (!dateStr) return '' const date = new Date(dateStr) const isGerman = lang.startsWith('de') return date.toLocaleDateString(isGerman ? 'de-DE' : 'en-US', { day: '2-digit', month: '2-digit', year: 'numeric' }) } const generateHtmlNotificationDE = ( rmaName: string, returnDate: string, reason: string, customerName: string, shipmentNo: string, orderNo: string, externalOrderId: string, lines: ReturnLine[] ) => { const linesHtml = lines.map(line => ` ${line.productValue} ${line.productName} ${line.qtyEntered} `).join('') return ` Retoure-Benachrichtigung - ${rmaName}

Retoure eingegangen

${rmaName}

Eine neue Retoure wurde erfasst. Nachfolgend finden Sie die Details:

${externalOrderId ? `` : ''}
Datum ${returnDate}
Kunde ${customerName}
Bestellung ${orderNo}
Externe Bestellnr. ${externalOrderId}
Lieferschein ${shipmentNo}
Rückgabegrund ${reason}

Retournierte Artikel:

${linesHtml}
Artikelnr. Bezeichnung Menge

Diese E-Mail wurde automatisch versendet. Bitte antworten Sie nicht direkt auf diese E-Mail.

` } const generateHtmlNotificationEN = ( rmaName: string, returnDate: string, reason: string, customerName: string, shipmentNo: string, orderNo: string, externalOrderId: string, lines: ReturnLine[] ) => { const linesHtml = lines.map(line => ` ${line.productValue} ${line.productName} ${line.qtyEntered} `).join('') return ` Return Notification - ${rmaName}

Return Received

${rmaName}

A new return has been processed. Please find the details below:

${externalOrderId ? `` : ''}
Date ${returnDate}
Customer ${customerName}
Order ${orderNo}
External Order No. ${externalOrderId}
Shipment ${shipmentNo}
Return Reason ${reason}

Returned Articles:

${linesHtml}
Article No. Description Qty

This email was sent automatically. Please do not reply directly to this email.

` } const handleFunc = async (event: any, authToken: any = null) => { let data: any = { status: 200, message: 'Return notification sent successfully' } const token = authToken ?? await getTokenHelper(event) const body = await readBody(event) const { organizationId, rmaDocumentNo, returnDate, reason, customerName, shipmentNo, orderNo, externalOrderId, lines, testOnly, images } = body // Use the RMA DocumentNo from the API response (e.g., "10000123") const formattedRmaName = `RMA ${rmaDocumentNo}` if (!organizationId || !rmaDocumentNo || !lines || lines.length === 0) { return { status: 400, message: 'Missing required fields' } } let toEmail = 'info@logyou.de' let partnerLanguage = 'de_DE' // If not test only, get the organization's BPartner email if (!testOnly) { // Get the organization's BPartner to find the email const orgRes: any = await fetchHelper( event, `models/ad_org/${organizationId}?$select=C_BPartner_ID`, 'GET', token, null ) const orgBPartnerId = orgRes?.C_BPartner_ID?.id if (!orgBPartnerId) { return { status: 400, message: 'Organization has no associated BPartner' } } // Get the BPartner email and language const bpartnerRes: any = await fetchHelper( event, `models/c_bpartner/${orgBPartnerId}?$select=EMail,AD_Language`, 'GET', token, null ) toEmail = bpartnerRes?.EMail if (!toEmail) { return { status: 400, message: 'Organization BPartner has no email configured' } } partnerLanguage = bpartnerRes?.AD_Language?.id || 'de_DE' } const isGerman = partnerLanguage.startsWith('de') // Format the return date const formattedDate = formatDate(returnDate, partnerLanguage) // Generate HTML email based on language const htmlContent = isGerman ? generateHtmlNotificationDE(formattedRmaName, formattedDate, reason, customerName, shipmentNo, orderNo || '', externalOrderId || '', lines) : generateHtmlNotificationEN(formattedRmaName, formattedDate, reason, customerName, shipmentNo, orderNo || '', externalOrderId || '', lines) // Create email subject const subject = isGerman ? `Retoure-Benachrichtigung: ${formattedRmaName}` : `Return Notification: ${formattedRmaName}` // Plain text version const textContent = isGerman ? `Retoure ${formattedRmaName} wurde verarbeitet.\n\nKunde: ${customerName}\nBestellung: ${orderNo || '-'}${externalOrderId ? '\nExterne Bestellnr.: ' + externalOrderId : ''}\nLieferschein: ${shipmentNo}\nRückgabegrund: ${reason}\nDatum: ${formattedDate}\n\nArtikel:\n${lines.map((l: ReturnLine) => `- ${l.productValue}: ${l.productName} (${l.qtyEntered}x)`).join('\n')}` : `Return ${formattedRmaName} has been processed.\n\nCustomer: ${customerName}\nOrder: ${orderNo || '-'}${externalOrderId ? '\nExternal Order No.: ' + externalOrderId : ''}\nShipment: ${shipmentNo}\nReturn Reason: ${reason}\nDate: ${formattedDate}\n\nArticles:\n${lines.map((l: ReturnLine) => `- ${l.productValue}: ${l.productName} (${l.qtyEntered}x)`).join('\n')}` // Create transporter using localhost as smarthost on port 25 const transporter = nodemailer.createTransport({ host: 'localhost', port: 25, secure: false, tls: { rejectUnauthorized: false } }) // Build email options const emailOptions: any = { from: 'no-reply@logyou.de', to: toEmail, subject: subject, text: textContent, html: htmlContent } // Only add CC if not test mode if (!testOnly) { emailOptions.cc = 'info@logyou.de' } // Add image attachments if provided if (images && Array.isArray(images) && images.length > 0) { emailOptions.attachments = images.map((imageData: string, index: number) => { // Remove the data URL prefix (e.g., "data:image/jpeg;base64,") const base64Data = imageData.replace(/^data:image\/\w+;base64,/, '') const imageBuffer = Buffer.from(base64Data, 'base64') // Determine file extension from data URL const mimeMatch = imageData.match(/^data:image\/(\w+);base64,/) const extension = mimeMatch ? mimeMatch[1] : 'jpg' return { filename: `retoure-bild-${index + 1}.${extension}`, content: imageBuffer, contentType: `image/${extension}` } }) } // Send email try { await transporter.sendMail(emailOptions) } catch (err: any) { console.error('Email send error:', err) return { status: 500, message: `Failed to send return notification: ${err.message}` } } return data } export default defineEventHandler(async (event) => { let data: any = {} try { data = await handleFunc(event) } catch (err: any) { try { let authToken: any = await refreshTokenHelper(event) data = await handleFunc(event, authToken) } catch (error: any) { data = errorHandlingHelper(err?.data ?? err, error?.data ?? error) forceLogoutHelper(event, data) } } return data })