Files
mc_cars_gmbh_infraestructure/n8n/workflows/03-manual-email-send.json
T
Lago e34d56e36a feat: Add manual email sending workflow and related database changes
- Implemented a new n8n workflow for manual email sending, including webhook trigger, order data fetching, email building, and sending.
- Added logic to format email content with customer and order details.
- Introduced new columns in the sales_orders table to track email sending status.
- Updated database functions to handle new rental types and email status.
- Created new RPCs for updating email status and retrieving email details for sales orders.
2026-05-17 18:04:36 +02:00

207 lines
10 KiB
JSON
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{
"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 c.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.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 orderNumber = item.order_number || \"\";\nconst dateFrom = formatDate(item.date_from);\nconst dateTo = formatDate(item.date_to);\nconst rentalRange = `${dateFrom} bis ${dateTo}`;\n\nconst depositEur = formatEur(item.deposit_eur);\nconst rentalEur = formatEur(item.total_eur);\nconst subtotalEur = formatEur(item.subtotal_eur);\nconst vatEur = formatEur(item.vat_eur);\n\nconst safeName = item.name || \"Kundin/Kunde\";\nconst vehicle = item.vehicle_label || \"-\";\n\nconst subject = `MC Cars Buchung bestätigt (${orderNumber}) Zahlungsinformationen`;\n\nconst paypalButton = (url, alt) => `\n <a href=\"${url}\" style=\"display:inline-block;text-decoration:none;\" target=\"_blank\" rel=\"noopener noreferrer\">\n <img src=\"https://www.paypalobjects.com/webstatic/en_US/i/buttons/checkout-logo-large.png\" alt=\"${alt}\" style=\"display:block;border:0;max-width:290px;width:100%;height:auto;\">\n </a>\n`;\n\nconst html = `\n<div style=\"margin:0;padding:24px;background:#f3f1ed;font-family:Arial,sans-serif;color:#151515;\">\n <table role=\"presentation\" style=\"width:100%;max-width:680px;margin:0 auto;border-collapse:collapse;background:#ffffff;border-radius:14px;overflow:hidden;\">\n <tr>\n <td style=\"background:#101010;padding:24px 28px;\">\n <div style=\"font-size:13px;letter-spacing:0.18em;text-transform:uppercase;color:#caa06a;\">MC Cars</div>\n <h1 style=\"margin:10px 0 0 0;font-size:24px;line-height:1.2;color:#ffffff;\">Ihre Miete wurde freigegeben</h1>\n </td>\n </tr>\n <tr>\n <td style=\"padding:28px;\">\n <p style=\"margin:0 0 14px 0;font-size:16px;\">Guten Tag <strong>${safeName}</strong>,</p>\n <p style=\"margin:0 0 18px 0;font-size:15px;line-height:1.6;\">\n Ihre Buchung wurde auf Basis der von Ihnen bereitgestellten Informationen geprüft und freigegeben.\n Nachfolgend finden Sie die Zahlungsanweisungen für Kaution und Mietbetrag.\n </p>\n\n <table role=\"presentation\" style=\"width:100%;border-collapse:collapse;background:#f8f8f8;border:1px solid #e8e8e8;border-radius:10px;overflow:hidden;margin:0 0 22px 0;\">\n <tr>\n <td style=\"padding:12px 14px;border-bottom:1px solid #e8e8e8;width:44%;color:#666;\">Bestellnummer</td>\n <td style=\"padding:12px 14px;border-bottom:1px solid #e8e8e8;\"><strong>${orderNumber}</strong></td>\n </tr>\n <tr>\n <td style=\"padding:12px 14px;border-bottom:1px solid #e8e8e8;width:44%;color:#666;\">Fahrzeug</td>\n <td style=\"padding:12px 14px;border-bottom:1px solid #e8e8e8;\">${vehicle}</td>\n </tr>\n <tr>\n <td style=\"padding:12px 14px;border-bottom:1px solid #e8e8e8;width:44%;color:#666;\">Mietzeitraum</td>\n <td style=\"padding:12px 14px;border-bottom:1px solid #e8e8e8;\">${rentalRange}</td>\n </tr>\n <tr>\n <td style=\"padding:12px 14px;border-bottom:1px solid #e8e8e8;width:44%;color:#666;\">Zwischensumme</td>\n <td style=\"padding:12px 14px;border-bottom:1px solid #e8e8e8;\">${subtotalEur}</td>\n </tr>\n <tr>\n <td style=\"padding:12px 14px;border-bottom:1px solid #e8e8e8;width:44%;color:#666;\">MwSt.</td>\n <td style=\"padding:12px 14px;border-bottom:1px solid #e8e8e8;\">${vatEur}</td>\n </tr>\n <tr>\n <td style=\"padding:12px 14px;border-bottom:1px solid #e8e8e8;width:44%;color:#666;\">Mietbetrag</td>\n <td style=\"padding:12px 14px;border-bottom:1px solid #e8e8e8;\"><strong>${rentalEur}</strong></td>\n </tr>\n <tr>\n <td style=\"padding:12px 14px;width:44%;color:#666;\">Kaution</td>\n <td style=\"padding:12px 14px;\"><strong>${depositEur}</strong></td>\n </tr>\n </table>\n\n <h2 style=\"margin:0 0 10px 0;font-size:18px;color:#101010;\">1) Kaution bezahlen</h2>\n <p style=\"margin:0 0 12px 0;font-size:14px;line-height:1.6;\">Sie können die Kaution in Höhe von <strong>${depositEur}</strong> per PayPal bezahlen:</p>\n ${paypalButton('__PAYPAL_KAUTION_LINK__', 'PayPal Kaution bezahlen')}\n <p style=\"margin:12px 0 0 0;font-size:14px;line-height:1.6;\">Alternativ ist Barzahlung möglich. In diesem Fall antworten Sie bitte so schnell wie möglich auf diese E-Mail, damit wir die Übergabe bestätigen können.</p>\n\n <h2 style=\"margin:22px 0 10px 0;font-size:18px;color:#101010;\">2) Mietbetrag bezahlen</h2>\n <p style=\"margin:0 0 12px 0;font-size:14px;line-height:1.6;\">Den Mietbetrag von <strong>${rentalEur}</strong> können Sie über folgenden PayPal-Button bezahlen:</p>\n ${paypalButton('__PAYPAL_MIETE_LINK__', 'PayPal Mietbetrag bezahlen')}\n\n <p style=\"margin:20px 0 6px 0;font-size:14px;line-height:1.6;\">Falls Sie Fragen haben, antworten Sie einfach auf diese E-Mail.</p>\n <p style=\"margin:0;font-size:14px;line-height:1.6;\">Freundliche Grüße<br><strong>MC Cars Team</strong></p>\n </td>\n </tr>\n </table>\n</div>`;\n\nreturn {\n toEmail: item.email,\n subject,\n html,\n sales_order_id: item.id,\n};\n"
},
"id": "build-email",
"name": "Build Email",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [690, 300]
},
{
"parameters": {
"fromEmail": "office@mc-cars.at",
"toEmail": "={{ $json.toEmail }}",
"subject": "={{ $json.subject }}",
"html": "={{ $json.html }}",
"options": {
"appendAttribution": false
},
"continueOnFail": true
},
"id": "send-email",
"name": "Send Email",
"type": "n8n-nodes-base.emailSend",
"typeVersion": 2.1,
"position": [910, 300],
"credentials": {
"smtp": {
"id": "__SMTP_CREDENTIAL_ID__",
"name": "SMTP account"
}
}
},
{
"parameters": {
"operation": "executeQuery",
"query": "UPDATE public.sales_orders SET email_sent = 1, updated_at = now() WHERE id = '{{ $json.sales_order_id }}'::uuid",
"options": {}
},
"id": "update-email-1",
"name": "Update email_sent = 1",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.5,
"position": [1260, 200],
"credentials": {
"postgres": {
"id": "__POSTGRES_CREDENTIAL_ID__",
"name": "Postgres account"
}
}
},
{
"parameters": {
"operation": "executeQuery",
"query": "UPDATE public.sales_orders SET email_sent = 2, updated_at = now() WHERE id = '{{ $json.sales_order_id }}'::uuid",
"options": {}
},
"id": "update-email-2",
"name": "Update email_sent = 2",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.5,
"position": [1260, 400],
"credentials": {
"postgres": {
"id": "__POSTGRES_CREDENTIAL_ID__",
"name": "Postgres account"
}
}
},
{
"parameters": {
"conditions": {
"options": {
"testDirectly": true
},
"boolean": [
{
"leftValue": "={{ $json.error }}",
"condition": "isEmpty"
}
]
}
},
"id": "check-error",
"name": "IF",
"type": "n8n-nodes-base.if",
"typeVersion": 1,
"position": [1130, 300]
}
],
"pinData": {},
"connections": {
"Webhook": {
"main": [
[
{
"node": "Fetch Order Data",
"type": "main",
"index": 0
}
]
]
},
"Fetch Order Data": {
"main": [
[
{
"node": "Build Email",
"type": "main",
"index": 0
}
]
]
},
"Build Email": {
"main": [
[
{
"node": "Send Email",
"type": "main",
"index": 0
}
]
]
},
"Send Email": {
"main": [
[
{
"node": "IF",
"type": "main",
"index": 0
}
]
]
},
"IF": {
"main": [
[
{
"node": "Update email_sent = 1",
"type": "main",
"index": 0
}
],
[
{
"node": "Update email_sent = 2",
"type": "main",
"index": 0
}
]
]
}
},
"active": true,
"settings": {
"executionOrder": "v1"
},
"versionId": "d3c4e5f6-1234-5678-90ab-cdef12345678",
"meta": {
"templateCredsSetupCompleted": true
},
"id": "M3nU4lW0rkFl0w03",
"tags": [
{
"name": "mc-cars"
}
]
}