Generar facturas PDF usando la API de CustomJS
Este es unFinanceflujo de automatización del dominio deautomatización que contiene 5 nodos.Utiliza principalmente nodos como Set, Code, Webhook, RespondToWebhook, Html2Pdf. Generar facturas PDF usando CustomJS API
- •Punto final de HTTP Webhook (n8n generará automáticamente)
Nodos utilizados (5)
Categoría
{
"meta": {
"instanceId": "fcf18fc485cc336a31bc65574fd28e124660f468281b7aad773616b17903afe6",
"templateCredsSetupCompleted": true
},
"nodes": [
{
"id": "de602925-4d9d-4045-9d9d-ed37dfb65490",
"name": "HTML a PDF",
"type": "@custom-js/n8n-nodes-pdf-toolkit.html2Pdf",
"position": [
460,
-20
],
"parameters": {
"htmlInput": "=<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>Invoice</title>\n <style>\n /* Global Reset */\n * {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n }\n\n /* Body and Container */\n body {\n font-family: 'Roboto', sans-serif;\n background: #f4f7fc;\n display: flex;\n justify-content: center;\n padding: 30px;\n }\n\n .invoice-wrapper {\n width: 100%;\n max-width: 900px;\n background: linear-gradient(145deg, #ffffff, #e6f7ff);\n border-radius: 10px;\n box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);\n padding: 40px;\n margin-top: 50px;\n }\n\n /* Header */\n .header {\n background: linear-gradient(145deg, #3f51b5, #2196f3);\n text-align: center;\n color: #fff;\n padding: 30px;\n border-radius: 8px;\n }\n\n .header h1 {\n font-size: 40px;\n margin-bottom: 10px;\n }\n\n .header p {\n font-size: 18px;\n font-weight: 400;\n }\n\n /* Invoice Details Section */\n .invoice-details {\n display: flex;\n justify-content: space-between;\n margin-top: 30px;\n border-top: 2px solid #eee;\n padding-top: 30px;\n }\n\n .invoice-details div {\n width: 48%;\n }\n\n .invoice-details h3 {\n color: #3f51b5;\n font-size: 20px;\n margin-bottom: 15px;\n }\n\n .invoice-details p {\n font-size: 15px;\n color: #555;\n line-height: 1.6;\n }\n\n /* Table Styling */\n .table {\n width: 100%;\n border-collapse: collapse;\n margin-top: 30px;\n }\n\n .table th,\n .table td {\n padding: 16px;\n text-align: left;\n font-size: 15px;\n color: #555;\n }\n\n .table th {\n background-color: #f1f5fc;\n color: #3f51b5;\n font-weight: 500;\n }\n\n .table td {\n background-color: #fff;\n border-bottom: 1px solid #e6e9f1;\n }\n\n .table tr:last-child td {\n border-bottom: none;\n }\n\n .table .total {\n font-weight: 600;\n font-size: 18px;\n color: #333;\n background-color: #f1f5fc;\n }\n\n .table .total td {\n text-align: right;\n }\n\n .table tr:nth-child(even) {\n background-color: #f9f9f9;\n }\n\n /* Footer */\n .footer {\n text-align: center;\n margin-top: 30px;\n font-size: 15px;\n color: #777;\n }\n\n .footer a {\n color: #2196f3;\n text-decoration: none;\n font-weight: 500;\n }\n\n .footer a:hover {\n text-decoration: underline;\n }\n\n /* Button */\n .btn {\n display: inline-block;\n background-color: #2196f3;\n color: white !important;\n font-size: 16px;\n font-weight: 600;\n padding: 12px 25px;\n margin-top: 25px;\n text-decoration: none;\n border-radius: 5px;\n transition: background-color 0.3s ease;\n box-shadow: 0 6px 15px rgba(33, 150, 243, 0.2);\n }\n\n .btn:hover {\n background-color: #1976d2;\n }\n\n .btn:active {\n background-color: #1565c0;\n }\n </style>\n</head>\n<body>\n\n<div class=\"invoice-wrapper\">\n <div class=\"header\">\n <h1>Invoice</h1>\n <p>Invoice #{{ $('Set data').item.json['Invoice No'] }}</p>\n </div>\n\n <div class=\"invoice-details\">\n <div>\n <h3>Billed To:</h3>\n {{ $json.bill_to }}\n </div>\n <div>\n <h3>From:</h3>\n {{ $json.from }}\n <p>Email: {{ $('Set data').item.json.Email }}</p>\n </div>\n </div>\n\n <table class=\"table\">\n <thead>\n <tr>\n <th>Description</th>\n <th>Unit Price</th>\n <th>Quantity</th>\n <th>Total</th>\n </tr>\n </thead>\n <tbody>\n {{ $json.details }}\n <tr class=\"total\">\n <td colspan=\"3\">Total Amount</td>\n <td>${{ $json.total }}</td>\n </tr>\n </tbody>\n </table>\n\n <div class=\"footer\">\n <p>Thank you for doing business with us!</p>\n <p>If you have any questions regarding this invoice, please contact us at <a href=\"mailto:contact@abccorp.com\">{{ $('Set data').item.json.Email }}</a>.</p>\n <a href=\"mailto:{{ $('Set data').item.json.Email }}\" class=\"btn\">Contact Us</a>\n </div>\n</div>\n\n</body>\n</html>"
},
"credentials": {
"customJsApi": {
"id": "SZkqeEHVYyWhaGem",
"name": "CustomJS account"
}
},
"typeVersion": 1
},
{
"id": "5a8efc8a-c60b-4616-a17a-6275cc326978",
"name": "Preprocesar",
"type": "n8n-nodes-base.code",
"position": [
240,
-20
],
"parameters": {
"mode": "runOnceForEachItem",
"jsCode": "const input = $input.item.json\nconst bill_to = input['Bill To'].split('\\n').map(item => '<p>' + item + '</p>')\nconst from = input['From'].split('\\n').map(item => '<p>' + item + '</p>')\nconst details = input['Details'].map(item => {\n const price = item.price*item.qty\n return `\n <tr>\n <td>${item.description}</td>\n <td>$${item.price}</td>\n <td>${item.qty}</td>\n <td>$${price}</td>\n </tr>\n `\n})\nconst total = input['Details'].reduce((val, next) => {\n\treturn val+next.price*next.qty\n}, 0)\nreturn {\n bill_to: bill_to.join('\\n'),\n from: from.join('\\n'),\n details: details.join('\\n'),\n total\n}"
},
"typeVersion": 2
},
{
"id": "7da4fb46-1f74-44d8-8392-16fc90f23928",
"name": "Establecer datos",
"type": "n8n-nodes-base.set",
"position": [
20,
-20
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "5342001f-a513-46c3-b31f-4590e8514411",
"name": "Invoice No",
"type": "string",
"value": "1"
},
{
"id": "ec357d39-c697-4bb8-8d9d-1bc303352dd0",
"name": "Bill To",
"type": "string",
"value": "John Doe\n1234 Elm St, Apt 567\nCity, Country, 12345"
},
{
"id": "88d6b470-4075-43ec-a684-a4adfd889278",
"name": "From",
"type": "string",
"value": "ABC Corporation\n789 Business Ave\nCity, Country, 67890"
},
{
"id": "061a8020-644a-4cec-bade-3bcd7e15adee",
"name": "Details",
"type": "array",
"value": "[ { \"description\": \"Web Hosting\", \"price\": 150, \"qty\": 2 }, { \"description\": \"Domain\", \"price\": 15, \"qty\": 5 } ]"
},
{
"id": "1c2c6c4b-6aa5-4656-8cae-43ffac71d478",
"name": "Email",
"type": "string",
"value": "support@mycompany.com"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "a6d39cc4-b9c2-4eed-b4a6-46d622a87c14",
"name": "Disparador Webhook",
"type": "n8n-nodes-base.webhook",
"position": [
-200,
-20
],
"webhookId": "526fd864-6f85-4cde-97aa-39b61a3e5b83",
"parameters": {
"path": "526fd864-6f85-4cde-97aa-39b61a3e5b83",
"options": {},
"responseMode": "responseNode"
},
"typeVersion": 2
},
{
"id": "c7d1cc1d-88e3-463a-886f-182a2ba72b11",
"name": "Responder a Disparador Webhook",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
660,
-20
],
"parameters": {
"options": {},
"respondWith": "binary"
},
"typeVersion": 1.1
}
],
"pinData": {},
"connections": {
"Webhook": {
"main": [
[
{
"node": "7da4fb46-1f74-44d8-8392-16fc90f23928",
"type": "main",
"index": 0
}
]
]
},
"7da4fb46-1f74-44d8-8392-16fc90f23928": {
"main": [
[
{
"node": "5a8efc8a-c60b-4616-a17a-6275cc326978",
"type": "main",
"index": 0
}
]
]
},
"5a8efc8a-c60b-4616-a17a-6275cc326978": {
"main": [
[
{
"node": "de602925-4d9d-4045-9d9d-ed37dfb65490",
"type": "main",
"index": 0
}
]
]
},
"de602925-4d9d-4045-9d9d-ed37dfb65490": {
"main": [
[
{
"node": "Responder a Webhook",
"type": "main",
"index": 0
}
]
]
}
}
}¿Cómo usar este flujo de trabajo?
Copie el código de configuración JSON de arriba, cree un nuevo flujo de trabajo en su instancia de n8n y seleccione "Importar desde JSON", pegue la configuración y luego modifique la configuración de credenciales según sea necesario.
¿En qué escenarios es adecuado este flujo de trabajo?
Principiante - Finanzas
¿Es de pago?
Este flujo de trabajo es completamente gratuito, puede importarlo y usarlo directamente. Sin embargo, tenga en cuenta que los servicios de terceros utilizados en el flujo de trabajo (como la API de OpenAI) pueden requerir un pago por su cuenta.
Flujos de trabajo relacionados recomendados
CustomJS
@customjsCompartir este flujo de trabajo