{
"name": "Manual Email Send",
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "manual-email-send",
"responseMode": "responseNode",
"options": {}
},
"id": "webhook-trigger",
"name": "Webhook",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2,
"position": [250, 300],
"webhookId": "manual-email-send"
},
{
"parameters": {
"operation": "executeQuery",
"query": "SELECT so.id, c.name, c.email, c.phone,\n so.order_number, so.total_eur, so.deposit_eur,\n so.date_from, so.date_to, so.vehicle_label,\n so.daily_subtotal, so.weekend_subtotal,\n so.subtotal_eur, so.vat_eur,\n so.total_days, so.weekday_count, so.weekend_day_count\nFROM public.customers c\nJOIN public.sales_orders so ON so.customer_id = c.id\nWHERE so.id = '{{ $json.body?.sales_order_id || $json.query?.sales_order_id || $json.sales_order_id }}'::uuid",
"options": {}
},
"id": "fetch-order-data",
"name": "Fetch Order Data",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.5,
"position": [470, 300],
"credentials": {
"postgres": {
"id": "__POSTGRES_CREDENTIAL_ID__",
"name": "Postgres account"
}
}
},
{
"parameters": {
"mode": "runOnceForEachItem",
"jsCode": "const item = $json;\n\nconst formatEur = (value) => {\n const n = Number(value || 0);\n return new Intl.NumberFormat(\"de-AT\", { style: \"currency\", currency: \"EUR\" }).format(n);\n};\n\nconst formatDate = (value) => {\n if (!value) return \"-\";\n const d = new Date(value);\n if (Number.isNaN(d.getTime())) return String(value);\n return new Intl.DateTimeFormat(\"de-AT\", { day: \"2-digit\", month: \"2-digit\", year: \"numeric\" }).format(d);\n};\n\nconst toNum = (value) => {\n const n = Number(value);\n return Number.isFinite(n) ? n : 0;\n};\n\nconst round2 = (value) => Math.round(value * 100) / 100;\n\nconst orderNumber = item.order_number || \"\";\nconst dateFrom = formatDate(item.date_from);\nconst dateTo = formatDate(item.date_to);\nconst rentalRange = `${dateFrom} bis ${dateTo}`;\n\nconst totalEurNum = toNum(item.total_eur);\nlet subtotalEurNum = toNum(item.subtotal_eur);\nlet vatEurNum = toNum(item.vat_eur);\n\nif (totalEurNum > 0 && subtotalEurNum === 0 && vatEurNum === 0) {\n subtotalEurNum = round2(totalEurNum / 1.2);\n vatEurNum = round2(totalEurNum - subtotalEurNum);\n}\n\nconst depositEur = formatEur(item.deposit_eur);\nconst rentalEur = formatEur(totalEurNum);\nconst subtotalEur = formatEur(subtotalEurNum);\nconst vatEur = formatEur(vatEurNum);\n\nconst safeName = item.name || \"Kundin/Kunde\";\nconst vehicle = item.vehicle_label || \"-\";\n\nconst subject = `MC Cars \u2013 Buchung best\u00e4tigt (${orderNumber}) \u2013 Zahlungsinformationen`;\n\nconst paypalButton = (url, alt) => `\n \n
\n \n`;\n\nconst html = `\n
| \n MC Cars \n Ihre Miete wurde freigegeben\n | \n ||||||||||||||
| \n Guten Tag ${safeName}, \n\n Ihre Buchung wurde auf Basis der von Ihnen bereitgestellten Informationen gepr\u00fcft und freigegeben.\n Nachfolgend finden Sie die Zahlungsanweisungen f\u00fcr Kaution und Mietbetrag.\n \n\n
1) Kaution bezahlen\nSie k\u00f6nnen die Kaution in H\u00f6he von ${depositEur} per PayPal bezahlen: \n ${paypalButton('__PAYPAL_KAUTION_LINK__', 'PayPal Kaution bezahlen')}\nAlternativ ist Barzahlung m\u00f6glich. In diesem Fall antworten Sie bitte so schnell wie m\u00f6glich auf diese E-Mail, damit wir die \u00dcbergabe best\u00e4tigen k\u00f6nnen. \n\n2) Mietbetrag bezahlen\nDen Mietbetrag von ${rentalEur} k\u00f6nnen Sie \u00fcber folgenden PayPal-Button bezahlen: \n ${paypalButton('__PAYPAL_MIETE_LINK__', 'PayPal Mietbetrag bezahlen')}\n\nFalls Sie Fragen haben, antworten Sie einfach auf diese E-Mail. \nFreundliche Gr\u00fc\u00dfe | \n