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:
| Datum |
${returnDate} |
| Kunde |
${customerName} |
| Bestellung |
${orderNo} |
${externalOrderId ? `
| Externe Bestellnr. |
${externalOrderId} |
` : ''}
| Lieferschein |
${shipmentNo} |
| Rückgabegrund |
${reason} |
Retournierte Artikel:
| Artikelnr. |
Bezeichnung |
Menge |
${linesHtml}
|
|
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:
| Date |
${returnDate} |
| Customer |
${customerName} |
| Order |
${orderNo} |
${externalOrderId ? `
| External Order No. |
${externalOrderId} |
` : ''}
| Shipment |
${shipmentNo} |
| Return Reason |
${reason} |
Returned Articles:
| Article No. |
Description |
Qty |
${linesHtml}
|
|
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
})