Files

292 lines
11 KiB
JSON
Raw Permalink 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": "Lead Qualified → Mietvertrag PDF",
"nodes": [
{
"parameters": {
"triggerOnNotify": true,
"channel": "lead_qualified",
"additionalFields": {}
},
"id": "pg-trigger-mv",
"name": "Postgres Trigger",
"type": "n8n-nodes-base.postgresTrigger",
"typeVersion": 1,
"position": [250, 300],
"credentials": {
"postgres": {
"id": "1",
"name": "MC Cars Postgres"
}
}
},
{
"parameters": {
"operation": "executeQuery",
"query": "SELECT value FROM public.site_settings WHERE key = 'mietvertrag_template_path'",
"additionalFields": {}
},
"id": "check-template",
"name": "Check Template Exists",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.5,
"position": [470, 300],
"credentials": {
"postgres": {
"id": "1",
"name": "MC Cars Postgres"
}
}
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict"
},
"conditions": [
{
"id": "cond1",
"leftValue": "={{ $json.value }}",
"rightValue": "",
"operator": {
"type": "string",
"operation": "notEmpty"
}
}
],
"combinator": "and"
},
"options": {}
},
"id": "if-template-exists",
"name": "Template Exists?",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [670, 300]
},
{
"parameters": {
"operation": "executeQuery",
"query": "SELECT 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,\n to_char(so.date_from, 'DD.MM.YYYY') as date_from_de,\n to_char(so.date_to, 'DD.MM.YYYY') as date_to_de,\n to_char(now(), 'DD.MM.YYYY') as today_de\nFROM public.customers c\nJOIN public.sales_orders so ON so.customer_id = c.id\nWHERE so.id = '{{ $('Postgres Trigger').item.json.sales_order_id }}'::uuid",
"additionalFields": {}
},
"id": "fetch-full-data",
"name": "Fetch Full Order+Customer",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.5,
"position": [890, 200],
"credentials": {
"postgres": {
"id": "1",
"name": "MC Cars Postgres"
}
}
},
{
"parameters": {
"url": "=http://kong:8000/storage/v1/object/document-templates/{{ $('Check Template Exists').item.json.value }}",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "apikey",
"value": "={{ $env.SERVICE_ROLE_KEY || 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImV4cCI6MTk4MzgxMjk5Nn0.EGIM96RAZx35lJzdJsyH-qQwv8Hdp7fsn3W0YpN81IU' }}"
},
{
"name": "Authorization",
"value": "=Bearer {{ $env.SERVICE_ROLE_KEY || 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImV4cCI6MTk4MzgxMjk5Nn0.EGIM96RAZx35lJzdJsyH-qQwv8Hdp7fsn3W0YpN81IU' }}"
}
]
},
"options": {
"response": {
"response": {
"responseFormat": "file"
}
}
}
},
"id": "download-template",
"name": "Download DOCX Template",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [1110, 200]
},
{
"parameters": {
"jsCode": "// Fill DOCX template placeholders using simple text replacement.\n// The DOCX is a ZIP containing XML. We replace {{placeholder}} markers\n// in the document.xml with actual values from the order data.\n\nconst JSZip = require('jszip');\n\nconst binaryData = await this.helpers.getBinaryDataBuffer(0, 'data');\nconst orderData = $('Fetch Full Order+Customer').first().json;\n\n// Placeholders map\nconst placeholders = {\n '{{KUNDE_NAME}}': orderData.name || '',\n '{{KUNDE_EMAIL}}': orderData.email || '',\n '{{KUNDE_TELEFON}}': orderData.phone || '',\n '{{BESTELLNUMMER}}': orderData.order_number || '',\n '{{FAHRZEUG}}': orderData.vehicle_label || '',\n '{{DATUM_VON}}': orderData.date_from_de || '',\n '{{DATUM_BIS}}': orderData.date_to_de || '',\n '{{TAGE_GESAMT}}': String(orderData.total_days || 0),\n '{{WOCHENTAGE}}': String(orderData.weekday_count || 0),\n '{{WOCHENENDTAGE}}': String(orderData.weekend_day_count || 0),\n '{{NETTO}}': String(orderData.subtotal_eur || 0),\n '{{MWST}}': String(orderData.vat_eur || 0),\n '{{GESAMT}}': String(orderData.total_eur || 0),\n '{{KAUTION}}': String(orderData.deposit_eur || 0),\n '{{TAGESSATZ}}': String(orderData.daily_subtotal || 0),\n '{{WOCHENENDZUSCHLAG}}': String(orderData.weekend_subtotal || 0),\n '{{DATUM_HEUTE}}': orderData.today_de || '',\n};\n\nconst zip = await JSZip.loadAsync(binaryData);\n\n// Process all XML files in the docx\nconst xmlFiles = Object.keys(zip.files).filter(f => f.endsWith('.xml'));\n\nfor (const xmlFile of xmlFiles) {\n let content = await zip.file(xmlFile).async('string');\n for (const [placeholder, value] of Object.entries(placeholders)) {\n // Handle split placeholders in XML (Word splits text into runs)\n // Simple approach: replace in the raw XML\n const escaped = placeholder.replace(/[{}]/g, c => `\\\\${c}`);\n content = content.split(placeholder).join(value);\n }\n zip.file(xmlFile, content);\n}\n\nconst filledDocx = await zip.generateAsync({ type: 'nodebuffer' });\n\nreturn [{\n json: { filename: `Mietvertrag_${orderData.order_number}.docx` },\n binary: {\n data: await this.helpers.prepareBinaryData(filledDocx, `Mietvertrag_${orderData.order_number}.docx`, 'application/vnd.openxmlformats-officedocument.wordprocessingml.document')\n }\n}];"
},
"id": "fill-template",
"name": "Fill DOCX Template",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [1330, 200]
},
{
"parameters": {
"url": "http://gotenberg:3000/forms/libreoffice/convert",
"method": "POST",
"sendBody": true,
"contentType": "multipart-form-data",
"bodyParameters": {
"parameters": [
{
"parameterType": "formBinaryData",
"name": "files",
"inputDataFieldName": "data"
}
]
},
"options": {
"response": {
"response": {
"responseFormat": "file"
}
}
}
},
"id": "convert-to-pdf",
"name": "Convert to PDF (Gotenberg)",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [1550, 200]
},
{
"parameters": {
"jsCode": "// Rename the binary output to have the correct PDF filename\nconst orderData = $('Fetch Full Order+Customer').first().json;\nconst binaryData = await this.helpers.getBinaryDataBuffer(0, 'data');\n\nreturn [{\n json: { filename: `Mietvertrag_${orderData.order_number}.pdf`, email: orderData.email, name: orderData.name, order_number: orderData.order_number },\n binary: {\n data: await this.helpers.prepareBinaryData(binaryData, `Mietvertrag_${orderData.order_number}.pdf`, 'application/pdf')\n }\n}];"
},
"id": "prepare-pdf",
"name": "Prepare PDF Attachment",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [1770, 200]
},
{
"parameters": {
"fromEmail": "info@mc-cars.at",
"toEmail": "={{ $json.email }}",
"subject": "MC Cars Ihr Mietvertrag {{ $json.order_number }}",
"emailType": "html",
"html": "<div style=\"font-family:Arial,sans-serif;max-width:600px;margin:0 auto;\">\n <div style=\"background:#1a1a1a;padding:20px;text-align:center;\">\n <h1 style=\"color:#c87941;margin:0;\">MC Cars</h1>\n </div>\n <div style=\"padding:30px;background:#f9f9f9;\">\n <p>Sehr geehrte/r <strong>{{ $json.name }}</strong>,</p>\n <p>anbei finden Sie Ihren Mietvertrag für die Bestellung <strong>{{ $json.order_number }}</strong>.</p>\n <p>Bitte prüfen Sie die Angaben und bringen Sie den unterschriebenen Vertrag zur Fahrzeugübergabe mit.</p>\n <hr style=\"border:none;border-top:1px solid #ddd;margin:25px 0;\" />\n <p>Bei Fragen stehen wir Ihnen jederzeit zur Verfügung.</p>\n <p>Mit freundlichen Grüßen,<br/><strong>MC Cars GmbH</strong><br/>info@mc-cars.at<br/>mc-cars.at</p>\n </div>\n</div>",
"options": {
"attachments": "data"
}
},
"id": "send-mietvertrag",
"name": "Send Mietvertrag Email",
"type": "n8n-nodes-base.emailSend",
"typeVersion": 2.1,
"position": [1990, 200],
"credentials": {
"smtp": {
"id": "2",
"name": "MC Cars SMTP"
}
}
}
],
"connections": {
"Postgres Trigger": {
"main": [
[
{
"node": "Check Template Exists",
"type": "main",
"index": 0
}
]
]
},
"Check Template Exists": {
"main": [
[
{
"node": "Template Exists?",
"type": "main",
"index": 0
}
]
]
},
"Template Exists?": {
"main": [
[
{
"node": "Fetch Full Order+Customer",
"type": "main",
"index": 0
}
],
[]
]
},
"Fetch Full Order+Customer": {
"main": [
[
{
"node": "Download DOCX Template",
"type": "main",
"index": 0
}
]
]
},
"Download DOCX Template": {
"main": [
[
{
"node": "Fill DOCX Template",
"type": "main",
"index": 0
}
]
]
},
"Fill DOCX Template": {
"main": [
[
{
"node": "Convert to PDF (Gotenberg)",
"type": "main",
"index": 0
}
]
]
},
"Convert to PDF (Gotenberg)": {
"main": [
[
{
"node": "Prepare PDF Attachment",
"type": "main",
"index": 0
}
]
]
},
"Prepare PDF Attachment": {
"main": [
[
{
"node": "Send Mietvertrag Email",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1"
},
"staticData": null,
"tags": [
{
"name": "mc-cars"
}
],
"triggerCount": 1
}