From bc6487bba4a75588a5428ff02a49c477bdc5d110 Mon Sep 17 00:00:00 2001 From: DanielS Date: Fri, 10 Jul 2026 08:57:52 +0200 Subject: [PATCH] feat(email): include order item configurations in confirmation email --- shop/lib/actions/email-templates.ts | 9 +++- shop/lib/actions/orders.ts | 75 ++++++++++++++++++++++++++++- 2 files changed, 80 insertions(+), 4 deletions(-) diff --git a/shop/lib/actions/email-templates.ts b/shop/lib/actions/email-templates.ts index b645421..209f167 100644 --- a/shop/lib/actions/email-templates.ts +++ b/shop/lib/actions/email-templates.ts @@ -4,6 +4,8 @@ interface EmailDetails { customerCompanyName: string totalDetailsText: string totalDetailsHtml: string + itemsDetailsText?: string + itemsDetailsHtml?: string } export function getOrderEmailTemplate( @@ -16,7 +18,7 @@ export function getOrderEmailTemplate( ? `Deine Anfrage ${details.orderNumber} wurde aktualisiert.` : `Deine Anfrage ${details.orderNumber} ist bei uns eingegangen und wird bearbeitet.` - const text = `Hallo,\n\n${isUpdate ? 'Deine Anfrage wurde aktualisiert.' : 'Deine Anfrage ist bei uns eingegangen.'}\n\nDetails:\n- Nummer: ${details.orderNumber}\n- Datum: ${details.formattedDate}\n- Kunde: ${details.customerCompanyName}\n${details.totalDetailsText}\n\nDeine Anfragebestätigung findest du im Anhang als PDF.\n\nPDF-Link: ${siteUrl}/api/orders/${details.orderNumber}/download\n\nViele Grüße,\nDein CASPOS Team` + const text = `Hallo,\n\n${isUpdate ? 'Deine Anfrage wurde aktualisiert.' : 'Deine Anfrage ist bei uns eingegangen.'}\n\nDetails:\n- Nummer: ${details.orderNumber}\n- Datum: ${details.formattedDate}\n- Kunde: ${details.customerCompanyName}\n${details.itemsDetailsText || ''}\n${details.totalDetailsText}\n\nDeine Anfragebestätigung findest du im Anhang als PDF.\n\nPDF-Link: ${siteUrl}/api/orders/${details.orderNumber}/download\n\nViele Grüße,\nDein CASPOS Team` const html = `
@@ -38,11 +40,14 @@ export function getOrderEmailTemplate( Kunde: ${details.customerCompanyName} + ${details.itemsDetailsHtml || ''} ${details.totalDetailsHtml}

Die Bestätigung liegt als PDF im Anhang.

- +

+ Anfragebestätigung PDF herunterladen +

Viele Grüße,
Dein CASPOS Team

` diff --git a/shop/lib/actions/orders.ts b/shop/lib/actions/orders.ts index 1a59793..92a51af 100644 --- a/shop/lib/actions/orders.ts +++ b/shop/lib/actions/orders.ts @@ -16,6 +16,69 @@ import { getOrderEmailTemplate, getStatusEmailTemplate } from '@/lib/actions/ema // ─── Hilfsfunktionen ───────────────────────────────────────────────────────── +function buildEmailItemsSection(items: any[]) { + const groupedItems: { [key: string]: any[] } = {} + items.forEach((item: any) => { + const devName = item.device_name || 'Kasse 1' + if (!groupedItems[devName]) { + groupedItems[devName] = [] + } + groupedItems[devName].push(item) + }) + + let itemsDetailsText = '\nKassen-Konfigurationen:' + let itemsDetailsHtml = ` + + Kassen-Konfigurationen: + + ` + + Object.entries(groupedItems).forEach(([deviceName, devItems]) => { + itemsDetailsText += `\n- Kasse: \${deviceName}` + itemsDetailsHtml += ` + + Kasse: \${deviceName} + + ` + + devItems.forEach((item: any) => { + itemsDetailsText += `\n * \${item.product_name} (\${item.category_name}): \${item.base_price.toLocaleString('de-DE', { style: 'currency', currency: 'EUR' })} \${item.billing_interval === 'one_time' ? 'einmalig' : 'mtl.'}` + itemsDetailsHtml += ` + + + \${item.product_name} (\${item.category_name}) + + + \${item.base_price.toLocaleString('de-DE', { style: 'currency', currency: 'EUR' })} \${item.billing_interval === 'one_time' ? 'einmalig' : 'mtl.'} + + + ` + + item.selected_modules?.forEach((mod: any) => { + const qty = mod.quantity || 1 + const price = mod.total_price ?? (mod.price * qty) + itemsDetailsText += `\n + \${mod.module_name} \${qty > 1 ? \`(x\${qty})\` : ''}: +\${price.toLocaleString('de-DE', { style: 'currency', currency: 'EUR' })} mtl.` + itemsDetailsHtml += ` + + + + \${mod.module_name} \${qty > 1 ? \`(x\${qty})\` : ''} + + + +\${price.toLocaleString('de-DE', { style: 'currency', currency: 'EUR' })} mtl. + + + ` + }) + }) + }) + + return { + text: itemsDetailsText + '\n', + html: itemsDetailsHtml + } +} + + /** * Erzeugt eine menschenlesbare, nicht-sequenzielle Bestellnummer. * Format: BE-YYYY-NNNNN (z.B. BE-2026-84731) @@ -256,12 +319,16 @@ export async function submitOrder(params: { ` } + const itemsSection = buildEmailItemsSection(items) + const emailTemplate = getOrderEmailTemplate({ orderNumber, formattedDate, customerCompanyName: customerSnapshot.company_name, totalDetailsText, - totalDetailsHtml + totalDetailsHtml, + itemsDetailsText: itemsSection.text, + itemsDetailsHtml: itemsSection.html }, `${process.env.NEXT_PUBLIC_SITE_URL || 'https://staging.hephex.de'}`, false) await sendMail({ @@ -577,12 +644,16 @@ export async function updateOrder( ` } + const itemsSection = buildEmailItemsSection(items) + const emailTemplate = getOrderEmailTemplate({ orderNumber: order.order_number, formattedDate, customerCompanyName: customerSnapshot.company_name, totalDetailsText, - totalDetailsHtml + totalDetailsHtml, + itemsDetailsText: itemsSection.text, + itemsDetailsHtml: itemsSection.html }, `${process.env.NEXT_PUBLIC_SITE_URL || 'https://staging.hephex.de'}`, true) await sendMail({