# workflow_history

versionId: 5c72a276-bbe1-4370-bdd2-792771bf7465
workflowId: 5hyLXhD4yRQ2k4XO
authors: Victor Colussi
createdAt: 2026-01-05 20:44:41.728
updatedAt: 2026-01-05 20:44:41.728
nodes:
  [{"parameters":{"httpMethod":"POST","path":"generar-presupuesto-pro","responseMode":"responseNode","options":{"allowedOrigins":"https://excelcertify.com"}},"id":"65f6315d-be37-493a-8239-579f0d0dbd5b","name":"Webhook Presupuesto","type":"n8n-nodes-base.webhook","typeVersion":1,"position":[496,64],"webhookId":"generar-presupuesto-pro"},{"parameters":{"jsCode":"// 1. Calculamos fechas\nconst now = $now;\nconst validityDate = $now.plus({ days: 30 });\nconst presupuestoID = Math.floor(Math.random() * 90000) + 10000;\n\n// 2. Formateamos el plan y precio\n// Aseguramos que plan_detalle exista para evitar error, si no, string vacío\nconst planDetalle = $json.body.plan_detalle || '';\nconst planParts = planDetalle.split('-');\nconst planNombre = planParts[0] ? planParts[0].trim() : 'Plan General';\nconst planPrecio = planParts[1] ? planParts[1].trim() : 'A consultar';\n\n// 3. Preparamos la lista de cursos\nconst cursosArray = $json.body.cursos ? $json.body.cursos.split(', ') : [];\nconst cursosHTML = cursosArray.map(c => `• ${c}`).join('<br>');\n\n// 4. HTML del Presupuesto (Diseño Final)\nconst htmlContent = `\n<!DOCTYPE html>\n<html lang=\"es\">\n<head>\n<meta charset=\"UTF-8\">\n<title>Presupuesto Formal</title>\n<style>\n@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;700&display=swap');\nbody {\n    font-family: 'Inter', Helvetica, Arial, sans-serif;\n    color: #374151;\n    line-height: 1.4;\n    margin: 0;\n    padding: 40px;\n    zoom: 0.8;\n}\n\n/* Header Compacto */\n.legal-top { font-size: 0.7rem; color: #9ca3af; text-transform: uppercase;\nletter-spacing: 0.5px; margin-bottom: 20px; border-bottom: 1px dashed #e5e7eb; padding-bottom: 5px; text-align: center; font-weight: 600; }\n.header { display: flex; justify-content: space-between;\nalign-items: center; border-bottom: 2px solid #10b981; padding-bottom: 20px; margin-bottom: 30px; }\n\n/* Logos */\n.logos-container { display: flex; flex-direction: column; gap: 10px; }\n.main-logo { height: 55px; object-fit: contain; display: block; }\n.partner-logos { display: flex; gap: 15px; align-items: center; }\n.partner-img { height: 22px; filter: grayscale(100%); opacity: 0.6; }\n\n.meta-info { text-align: right; font-size: 0.85rem; color: #6b7280; }\n.meta-info strong { color: #111827; }\n\nh1 { color: #111827; font-size: 24px; margin: 0 0 5px 0; font-weight: 800; }\nh2 { color: #111827; font-size: 15px;\nfont-weight: 700; border-bottom: 1px solid #e5e7eb; padding-bottom: 5px; margin-top: 25px; margin-bottom: 15px; text-transform: uppercase; letter-spacing: 0.5px; }\n\n.client-info { display: flex;\njustify-content: space-between; margin-bottom: 25px; background-color: #f9fafb; padding: 15px; border-radius: 8px; border: 1px solid #f3f4f6; }\n.client-col { width: 48%; }\n.client-col p { margin: 3px 0; font-size: 0.9rem; }\n.label { font-weight: 600; color: #4b5563; display: inline-block; width: 90px; }\n\ntable { width: 100%; border-collapse: collapse; margin-top: 10px; }\nth { background: #111827; color: #ffffff; padding: 8px 15px; text-align: left;\nfont-weight: 600; font-size: 0.8rem; }\ntd { padding: 12px 15px; border-bottom: 1px solid #e5e7eb; vertical-align: middle; }\n.plan-desc strong { font-size: 1rem; color: #111827; }\n.plan-desc span { font-size: 0.8rem; color: #6b7280; display: block; }\n.price-col { text-align: right; font-weight: 700; color: #111827;\nfont-size: 1rem; white-space: nowrap; background-color: #f0fdf4; }\n\n.courses-box { background: #fff; padding: 12px; border: 1px solid #e5e7eb; border-radius: 6px; font-size: 0.9rem;\ncolor: #374151; line-height: 1.6; }\n.change-warning { display: inline-block; font-size: 0.85rem; color: #16a34a; font-weight: 600; font-style: italic; margin-left: 5px; }\n\n.terms { margin-top: 25px; font-size: 0.75rem; color: #4b5563; }\n.terms ul { padding-left: 18px; margin-bottom: 0; }\n.terms li { margin-bottom: 4px; }\n\n.footer { margin-top: 40px; text-align: center; font-size: 0.7rem; color: #9ca3af; border-top: 1px solid #f3f4f6; padding-top: 15px; }\n.highlight { color: #10b981; font-weight: 600; }\n</style>\n</head>\n<body>\n\n<div class=\"legal-top\">Presupuesto válido para emitir Orden de Compra a favor de Excel Certify - Integralitas S.A.S según corresponda</div>\n\n<div class=\"header\">\n  <div class=\"logos-container\">\n    \n    <img src=\"data:image/png;base64,[encoded data, 14432 characters]\" alt=\"Excel Certify\" class=\"main-logo\">\n    \n    <div class=\"partner-logos\">\n        <img src=\"data:image/png;base64,[encoded data, 43856 characters]\" alt=\"Microsoft Partner\" class=\"partner-img\">\n        <img src=\"data:image/png;base64,[encoded data, 18680 characters]\" alt=\"Google Partner\" class=\"partner-img\">\n    </div>\n  </div>\n\n  <div class=\"meta-info\">\n    <p><strong>Fecha de Emisión:</strong> ${now.toFormat('dd/MM/yyyy')}</p>\n    <p><strong>Válido hasta:</strong> <span class=\"highlight\">${validityDate.toFormat('dd/MM/yyyy')}</span></p>\n    <p><strong>Presupuesto N°:</strong> PRE-26-${presupuestoID}</p>\n  </div>\n</div>\n\n<h1>Presupuesto de Capacitación</h1>\n<p style=\"color: #6b7280; margin-top: 0; font-size: 0.9rem;\">Propuesta profesional con tarifa congelada Enero 2025.</p>\n\n<div class=\"client-info\">\n  <div class=\"client-col\">\n    <p style=\"text-transform: uppercase; font-weight:bold; font-size: 0.75rem; color:#9ca3af; margin-bottom:5px;\">Cliente</p>\n    <p><span class=\"label\">Empresa:</span> <strong>${$json.body.empresa}</strong></p>\n    <p><span class=\"label\">CUIT / ID:</span> ${$json.body.cuit ? $json.body.cuit : 'No informado'}</p>\n  </div>\n  <div class=\"client-col\">\n    <p style=\"text-transform: uppercase; font-weight:bold; font-size: 0.75rem; color:#9ca3af; margin-bottom:5px;\">Contacto</p>\n    <p><span class=\"label\">Atención a:</span> ${$json.body.nombre_reserva}</p>\n    <p><span class=\"label\">Email:</span> ${$json.body.email_responsable}</p>\n  </div>\n</div>\n\n<h2>Detalle de la Inversión</h2>\n<table>\n  <thead><tr><th width=\"65%\">Descripción del Servicio</th><th width=\"35%\" style=\"text-align: right;\">Inversión Total</th></tr></thead>\n  <tbody>\n    <tr>\n      <td class=\"plan-desc\">\n        <strong>${planNombre}</strong>\n        <span>Modalidad Online en Vivo. Incluye certificación oficial.</span>\n      </td>\n      <td class=\"price-col\">\n        ${planPrecio} s / IVA\n      </td>\n    </tr>\n  </tbody>\n</table>\n\n<h2>Tecnologías Incluidas</h2>\n<p style=\"margin-bottom: 8px; font-size: 0.9rem;\">El presente presupuesto contempla la capacitación en las siguientes áreas seleccionadas:</p>\n\n<div class=\"courses-box\">\n  ${cursosHTML}\n  <span class=\"change-warning\">/ Los cursos pueden ser cambiados hasta 30 días antes de la capacitación efectiva.</span>\n</div>\n\n<div class=\"terms\">\n  <h3 style=\"margin-top: 0; font-size: 0.9rem; font-weight: 700; color: #111827; margin-bottom: 8px;\">Términos y Condiciones Comerciales</h3>\n  <ul>\n    <li><strong>Validez de la Oferta:</strong> Precios congelados (tarifa Enero 2025) válidos para ejecución hasta Junio 2026, confirmando reserva en Enero.</li>\n    <li><strong>Forma de Pago:</strong> Transferencia bancaria o eCheq a favor de Integralitas S.A.S.</li>\n    <li><strong>Facturación:</strong> Se emitirá Factura A o C tras la confirmación. Con Factura A, el precio promocional está sujeto a un recargo del 16% + IVA.</li>\n    <li><strong>Confidencialidad:</strong> Documento confidencial para uso exclusivo de la empresa destinataria.</li>\n  </ul>\n</div>\n\n<div class=\"footer\">\n  <p><strong>Excel Certify</strong> - Integralitas S.A.S</p>\n  <p>Microsoft Solutions Partner & Google Partner</p>\n  <p>www.excelcertify.com | info@excelcertify.com</p>\n</div>\n\n</body>\n</html>`;\n\nreturn {\n  html_final: htmlContent,\n  id_unico: presupuestoID,\n  fecha_validez: validityDate.toFormat('dd/MM/yyyy')\n};"},"id":"3f3ae538-0940-4494-aeda-e5d836306f8f","name":"Preparar HTML y Datos","type":"n8n-nodes-base.code","typeVersion":2,"position":[704,64]},{"parameters":{"method":"POST","url":"https://api.pdfshift.io/v3/convert/pdf","authentication":"genericCredentialType","genericAuthType":"httpBasicAuth","sendBody":true,"bodyParameters":{"parameters":[{"name":"source","value":"={{ $json.html_final }}"},{"name":"landscape","value":"false"},{"name":"use_print","value":"false"}]},"options":{"response":{"response":{"responseFormat":"file"}}}},"id":"e54e5c17-8b2e-4bdc-9dc6-61a5caac5478","name":"Generar PDF (PDFShift)","type":"n8n-nodes-base.httpRequest","typeVersion":4.1,"position":[928,64],"notesInFlow":true,"credentials":{"httpBasicAuth":{"id":"nUGJyhzEG2yOkIO7","name":"Unnamed credential"}}},{"parameters":{"fromEmail":"avisos@info.excelcertify.com","toEmail":"={{ $('Webhook Presupuesto').item.json.body.email_responsable}}","subject":"Presupuesto Formal (Válido 30 días) - ExcelCertify","html":"={{ '<p>Hola <strong>' + $('Webhook Presupuesto').item.json.body.nombre_reserva + '</strong>,</p><p>Adjunto encontrarás el presupuesto formal solicitado para <strong>' + $('Webhook Presupuesto').item.json.body.empresa + '</strong>.</p><ul><li><strong>Presupuesto N°:</strong> PRE-26-' + $('Preparar HTML y Datos').item.json.id_unico + '</li><li><strong>Válido hasta:</strong> ' + $('Preparar HTML y Datos').item.json.fecha_validez + '</li></ul><p>Quedamos a tu disposición para cualquier consulta.</p><p>Saludos,<br>El equipo de ExcelCertify.</p>' }}","options":{"appendAttribution":false,"attachments":"data","ccEmail":"info@excelcertify.com"}},"id":"ec0f84c2-8f21-4cd9-a2fe-650864ec8be1","name":"Enviar Email con PDF","type":"n8n-nodes-base.emailSend","typeVersion":2.1,"position":[1360,80],"webhookId":"e4c46f52-9f90-4110-8040-fe25c749258d","credentials":{"smtp":{"id":"OiV6sH0CDrHSeXXH","name":"SMTP account 2"}}},{"parameters":{"jsCode":"// 1. Obtener el nombre de la empresa y el ID desde el nodo anterior (o variables globales)\n// Asegúrate de que 'nombre_empresa' venga en tu JSON. Si no, cámbialo por la variable correcta.\nconst nombreEmpresa = $('Webhook Presupuesto').first().json.body.empresa || 'Cliente'; \nconst idUnico = $('Preparar HTML y Datos').first().json.id_unico;\n\n// 2. Definir el nuevo nombre\nconst nuevoNombre = `Presupuesto_${nombreEmpresa}_${idUnico}.pdf`;\n\n// 3. Modificar el nombre del archivo en los datos binarios\n// Nota: 'data' es la clave que se ve en tu captura de pantalla bajo OUTPUT\nif (items[0].binary && items[0].binary.data) {\n  items[0].binary.data.fileName = nuevoNombre;\n}\n\nreturn items;"},"type":"n8n-nodes-base.code","typeVersion":2,"position":[1104,64],"id":"9caf0bb3-c9a1-4a68-a666-809f330efdf8","name":"Code in JavaScript"},{"parameters":{"respondWith":"binary","responseDataSource":"set","options":{"responseHeaders":{"entries":[{"name":"Content-Type","value":"application/pdf"},{"name":"Content-Disposition","value":"=attachment; filename=\"{{ $('Code in JavaScript').first().binary.data.fileName }}\""},{"name":"Access-Control-Expose-Headers","value":"Content-Disposition"},{"name":"Access-Control-Allow-Origin","value":"https://excelcertify.com"}]}}},"id":"8e677bad-a037-43b4-a55a-cccd22d55126","name":"Entregar PDF","type":"n8n-nodes-base.respondToWebhook","typeVersion":1,"position":[1360,288],"alwaysOutputData":false}]

connections:
  {"Webhook Presupuesto":{"main":[[{"node":"Preparar HTML y Datos","type":"main","index":0}]]},"Preparar HTML y Datos":{"main":[[{"node":"Generar PDF (PDFShift)","type":"main","index":0}]]},"Generar PDF (PDFShift)":{"main":[[{"node":"Code in JavaScript","type":"main","index":0}]]},"Enviar Email con PDF":{"main":[[]]},"Code in JavaScript":{"main":[[{"node":"Entregar PDF","type":"main","index":0},{"node":"Enviar Email con PDF","type":"main","index":0}]]},"Entregar PDF":{"main":[[]]}}


versionId: 4f8b063f-b733-4dc8-9ed6-fd2628f8b5d4
workflowId: LR2Fl6iZzy7Oupgf
authors: Victor Colussi
createdAt: 2026-01-05 23:43:19.124
updatedAt: 2026-01-05 23:43:19.124
nodes:
  [{"parameters":{"httpMethod":"POST","path":"reserva-unificada-2026","options":{"allowedOrigins":"*"}},"id":"30efade6-cfbd-4856-b030-5df50eb8399e","name":"Webhook Formulario","type":"n8n-nodes-base.webhook","typeVersion":1,"position":[-3504,256],"webhookId":"reserva-unificada-2026"},{"parameters":{"operation":"append","documentId":{"__rl":true,"value":"https://docs.google.com/spreadsheets/d/1EoiocZTa9ELY8TQBXLEJSjxAZmohYClF1GH0N2qE4As/edit?gid=0#gid=0","mode":"url"},"sheetName":{"__rl":true,"value":324738822,"mode":"list","cachedResultName":"Hoja 2","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1EoiocZTa9ELY8TQBXLEJSjxAZmohYClF1GH0N2qE4As/edit#gid=324738822"},"columns":{"mappingMode":"defineBelow","value":{"Fecha":"={{ $now }}","Nombre":"={{ $json.body.nombre }}","Apellido":"={{ $json.body.apellido }}","Empresa":"={{ $json.body.empresa }}","CUIT":"={{ $json.body.cuit }}","Email":"={{ $json.body.email }}","Teléfono":"={{ $json.body.telefono }}","Plan":"={{ $json.body.plan_detalle }}","Cursos":"={{ $json.body.cursos }}","Respondio":""},"matchingColumns":[],"schema":[{"id":"Fecha","displayName":"Fecha","required":false,"defaultMatch":false,"display":true,"type":"string","canBeUsedToMatch":true},{"id":"Nombre","displayName":"Nombre","required":false,"defaultMatch":false,"display":true,"type":"string","canBeUsedToMatch":true},{"id":"Apellido","displayName":"Apellido","required":false,"defaultMatch":false,"display":true,"type":"string","canBeUsedToMatch":true},{"id":"Empresa","displayName":"Empresa","required":false,"defaultMatch":false,"display":true,"type":"string","canBeUsedToMatch":true},{"id":"CUIT","displayName":"CUIT","required":false,"defaultMatch":false,"display":true,"type":"string","canBeUsedToMatch":true},{"id":"Email","displayName":"Email","required":false,"defaultMatch":false,"display":true,"type":"string","canBeUsedToMatch":true},{"id":"Teléfono","displayName":"Teléfono","required":false,"defaultMatch":false,"display":true,"type":"string","canBeUsedToMatch":true},{"id":"Plan","displayName":"Plan","required":false,"defaultMatch":false,"display":true,"type":"string","canBeUsedToMatch":true},{"id":"Cursos","displayName":"Cursos","required":false,"defaultMatch":false,"display":true,"type":"string","canBeUsedToMatch":true},{"id":"Respondio","displayName":"Respondio","required":false,"defaultMatch":false,"display":true,"type":"string","canBeUsedToMatch":true}],"attemptToConvertTypes":false,"convertFieldsToString":false},"options":{}},"id":"035bf449-ff45-44c8-a62a-dc98a45aefbc","name":"1. Guardar Lead","type":"n8n-nodes-base.googleSheets","typeVersion":4.5,"position":[-3296,256],"credentials":{"googleSheetsOAuth2Api":{"id":"5TssK5sjUDI7k2MP","name":"Google Sheets account"}}},{"parameters":{"fromEmail":"avisos@info.excelcertify.com","toEmail":"={{ $('Webhook Formulario').item.json.body.email }}","subject":"Confirmado: Tu tarifa 2025 está congelada","html":"<div style=\"font-family: Arial, sans-serif; color: #333;\">\n  <h2 style=\"color: #10B981;\">¡Hola {{ $('Webhook Formulario').item.json.body.nombre }}!</h2>\n  <p>Te confirmo que hemos recibido tu reserva para <strong>{{ $('Webhook Formulario').item.json.body.empresa }}</strong>.</p>\n  <p>El precio promocional ha quedado congelado correctamente.</p>\n  <p><strong>¿Qué sigue ahora?</strong></p>\n  <p>En los próximos 30 minutos, uno de nuestros expertos armará tu <strong>Presupuesto Formal en PDF</strong> y te lo enviará por este medio para que puedas presentarlo. También te daremos más detalles del servicio.</p>\n  <hr style=\"border: 0; border-top: 1px solid #eee; margin: 20px 0;\">\n  <p style=\"font-size: 12px; color: #888;\">ExcelCertify - Microsoft & Google Partner</p>\n</div>","options":{"appendAttribution":false,"replyTo":"info@excelcertify.com"}},"id":"c0b3a4ee-f637-4dde-941e-2c27217c2501","name":"2. Email Confirmación","type":"n8n-nodes-base.emailSend","typeVersion":2.1,"position":[-3072,256],"webhookId":"90d710e3-d1ac-4d08-bfb8-ad3a55bf6987","credentials":{"smtp":{"id":"OiV6sH0CDrHSeXXH","name":"SMTP account 2"}}},{"parameters":{"amount":15,"unit":"minutes"},"id":"63f14a33-2684-424c-afc2-aa45a1c3a7df","name":"Esperar 15 Min","type":"n8n-nodes-base.wait","typeVersion":1,"position":[-2848,256],"webhookId":"cb315e96-6e27-463d-883a-48d56a29774e"},{"parameters":{"jsCode":"// LÓGICA DE PRESUPUESTO INTELIGENTE\nconst body = $('Webhook Formulario').item.json.body;\nconst now = $now;\nconst validityDate = $now.plus({ days: 30 });\nconst presupuestoID = Math.floor(Math.random() * 90000) + 10000;\n\n// 1. Detectar si es Pack o Individual\nlet planNombre = \"Curso Individual\";\nlet planPrecio = \"$980.000\";\nlet cursosArray = body.cursos ? body.cursos.split(', ') : [];\n\n// Si seleccionó \"Pack\" en el dropdown O eligió más de 1 curso\nif ((body.plan_detalle && body.plan_detalle.includes(\"Pack\")) || cursosArray.length > 1) {\n    planNombre = \"Pack Corporativo (Precio Congelado)\";\n    planPrecio = \"$750.000 c/u\";\n} else if (body.plan_detalle && body.plan_detalle.includes(\"Consultoria\")) {\n    planNombre = \"Servicio de Consultoría Anual\";\n    planPrecio = \"A Cotizar\";\n}\n\n// 2. Formatear lista de cursos para HTML\nconst cursosHTML = cursosArray.map(c => `• ${c}`).join('<br>');\n\n// 3. Generar HTML\nconst htmlContent = `\n<!DOCTYPE html>\n<html lang=\"es\">\n<head>\n<meta charset=\"UTF-8\">\n<style>\nbody { font-family: Helvetica, Arial, sans-serif; color: #333; padding: 40px; }\n.header { border-bottom: 2px solid #10b981; padding-bottom: 20px; margin-bottom: 30px; display: flex; justify-content: space-between; }\n.logo { height: 50px; }\nh1 { color: #111827; }\n.client-box { background: #f9fafb; padding: 20px; border-radius: 8px; margin-bottom: 30px; }\n.price-box { background: #f0fdf4; padding: 20px; border: 1px solid #10b981; border-radius: 8px; text-align: center; margin: 20px 0; }\n.price { font-size: 24px; font-weight: bold; color: #111827; }\n.footer { margin-top: 50px; font-size: 12px; color: #888; text-align: center; border-top: 1px solid #eee; padding-top: 20px; }\n</style>\n</head>\n<body>\n<div class=\"header\">\n  <img src=\"https://excelcertify.com/wp-content/uploads/2023/07/cropped-cropped-cropped-logoexcelcertify-bicubic-1-1-188x63.png\" class=\"logo\">\n  <div style=\"text-align:right;\">\n    <strong>Presupuesto N°:</strong> PRE-26-${presupuestoID}<br>\n    <strong>Fecha:</strong> ${now.toFormat('dd/MM/yyyy')}\n    <strong>Válido hasta:</strong> ${validityDate.toFormat('dd/MM/yyyy')}\n  </div>\n</div>\n\n<h1>Presupuesto de Capacitación 2026</h1>\n\n<div class=\"client-box\">\n  <p><strong>Empresa:</strong> ${body.empresa}</p>\n  <p><strong>CUIT:</strong> ${body.cuit || 'No informado'}</p>\n  <p><strong>Atención a:</strong> ${body.nombre} ${body.apellido}</p>\n  <p><strong>Email:</strong> ${body.email}</p>\n</div>\n\n<h3>Detalle del Servicio</h3>\n<p>Capacitación In-Company Online en Vivo (Instructor Experto).</p>\n<div style=\"margin-bottom: 20px; padding: 10px; border: 1px solid #eee;\">\n    <strong>Cursos Solicitados:</strong><br>\n    ${cursosHTML}\n</div>\n\n<div class=\"price-box\">\n  <p>Plan Seleccionado: <strong>${planNombre}</strong></p>\n  <p class=\"price\">Inversión: ${planPrecio} <span style=\"font-size:14px; font-weight:normal;\">(+ IVA si corresponde)</span></p>\n</div>\n\n<p><strong>Condiciones:</strong> Precio congelado válido confirmando reserva durante Enero 2025.</p>\n\n<div class=\"footer\">\n  ExcelCertify - Partner Oficial Microsoft & Google<br>\n  www.excelcertify.com\n</div>\n</body>\n</html>`;\n\n// Retornar array de objetos con clave json (CORRECCIÓN CRÍTICA)\nreturn [{\n  json: {\n    html_final: htmlContent,\n    filename: `Presupuesto_${(body.empresa || 'Cliente').replace(/[^a-zA-Z0-9]/g, '')}.pdf`\n  }\n}];"},"id":"f1b4a932-5223-4200-a86e-4fda06ead960","name":"Generar Lógica PDF","type":"n8n-nodes-base.code","typeVersion":2,"position":[-2624,256]},{"parameters":{"method":"POST","url":"https://api.pdfshift.io/v3/convert/pdf","authentication":"genericCredentialType","genericAuthType":"httpBasicAuth","sendBody":true,"bodyParameters":{"parameters":[{"name":"source","value":"={{ $json.html_final }}"},{"name":"landscape","value":"false"},{"name":"use_print","value":"false"}]},"options":{"response":{}}},"id":"c74874e0-65f3-4dc2-b9bf-decc6ead712c","name":"Crear PDF (API)","type":"n8n-nodes-base.httpRequest","typeVersion":4.1,"position":[-2416,256],"credentials":{"httpBasicAuth":{"id":"nUGJyhzEG2yOkIO7","name":"Unnamed credential"}}},{"parameters":{"fromEmail":"avisos@info.excelcertify.com","toEmail":"={{ $('Webhook Formulario').item.json.body.email }}","subject":"Tu Presupuesto Formal + Propuesta de Reunión","html":"<p>Hola <strong>{{ $('Webhook Formulario').item.json.body.nombre }}</strong>,</p>\n\n<p>Como prometimos, adjunto encontrarás el presupuesto formal para <strong>{{ $('Webhook Formulario').item.json.body.empresa }}</strong> con la tarifa congelada.</p>\n\n<p>Dado que tienes interés en capacitar a tu equipo en estas tecnologías, me gustaría tener una breve llamada de 15 minutos para conocer mejor el perfil de los alumnos y ajustar el temario.</p>\n\n<p>👉 <strong><a href=\"https://calendly.com/TU-USUARIO/reunion-15-min\">Haz clic aquí para elegir un horario en mi agenda</a></strong></p>\n\n<p>Quedo a la espera de tus comentarios.</p>\n<p>Saludos,<br>El equipo de ExcelCertify.</p>","options":{"appendAttribution":false,"attachments":"data","replyTo":"info@excelcertify.com"}},"id":"be4599f5-d317-4766-af62-765794077002","name":"3. Email con PDF","type":"n8n-nodes-base.emailSend","typeVersion":2.1,"position":[-2192,256],"webhookId":"c8a39101-04ea-4879-97da-c1a2f474707f","credentials":{"smtp":{"id":"OiV6sH0CDrHSeXXH","name":"SMTP account 2"}}},{"parameters":{"jsCode":"// CALCULAR FECHA DE SEGUIMIENTO (2 días hábiles a las 10 AM)\nconst now = new Date();\nlet target = new Date(now);\n\n// Sumar 2 días\ntarget.setDate(now.getDate() + 2);\n\n// Si cae Sábado (6), sumar 2 días más -> Lunes\n// Si cae Domingo (0), sumar 1 día más -> Lunes\nconst day = target.getDay();\nif (day === 6) {\n    target.setDate(target.getDate() + 2);\n} else if (day === 0) {\n    target.setDate(target.getDate() + 1);\n}\n\n// Fijar a las 10:00 AM\ntarget.setHours(10, 0, 0, 0);\n\n// Retornar array de objetos (CORRECCIÓN CRÍTICA)\nreturn [{\n  json: {\n    targetDate: target.toISOString()\n  }\n}];"},"id":"d3f055f0-cf22-401e-beef-a810b33b30c5","name":"Calcular Fecha (+2 días hábiles)","type":"n8n-nodes-base.code","typeVersion":2,"position":[-1968,256]},{"parameters":{"resume":"specificTime","dateTime":"={{ $json.targetDate }}"},"id":"7ff9a304-2729-43b2-b779-5a2d7f8d8a20","name":"Esperar 2 Días (10AM)","type":"n8n-nodes-base.wait","typeVersion":1,"position":[-1744,256],"webhookId":"97b372f8-d748-43d9-9523-74e2d4f82877"},{"parameters":{"documentId":{"__rl":true,"value":"https://docs.google.com/spreadsheets/d/1EoiocZTa9ELY8TQBXLEJSjxAZmohYClF1GH0N2qE4As/edit?gid=0#gid=0","mode":"url"},"sheetName":{"__rl":true,"value":324738822,"mode":"list","cachedResultName":"Hoja 2","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1EoiocZTa9ELY8TQBXLEJSjxAZmohYClF1GH0N2qE4As/edit#gid=324738822"},"filtersUI":{"values":[{"lookupColumn":"Email","lookupValue":"={{ $('Webhook Formulario').item.json.body.email }}"}]},"options":{}},"id":"9c602fda-c616-4197-8978-af6e7d5adc12","name":"Verificar Estado 1","type":"n8n-nodes-base.googleSheets","typeVersion":4.5,"position":[-1536,256],"credentials":{"googleSheetsOAuth2Api":{"id":"5TssK5sjUDI7k2MP","name":"Google Sheets account"}}},{"parameters":{"conditions":{"string":[{"value1":"={{ $json.Respondio }}","operation":"notEqual","value2":"SI"}]}},"id":"bda4a224-c2ff-4f89-aaa0-58a6eda6c2a3","name":"¿Respondió?","type":"n8n-nodes-base.if","typeVersion":1,"position":[-1312,256]},{"parameters":{"fromEmail":"avisos@info.excelcertify.com","toEmail":"={{ $('Webhook Formulario').item.json.body.email }}","subject":"¿Pudiste ver el presupuesto?","html":"<p>Hola {{ $('Webhook Formulario').item.json.body.nombre }},</p>\n<p>Te escribo para saber si pudiste revisar el presupuesto que te envié hace unos días.</p>\n<p>Recuerda que la tarifa promocional de 2025 solo la podemos mantener para reservas confirmadas en Enero.</p>\n<p>Si tienes alguna duda técnica o administrativa, respóndeme este correo y lo vemos.</p>\n<p>Saludos,</p>","options":{"appendAttribution":false,"replyTo":"info@excelcertify.com"}},"id":"853798fb-0294-4988-ba99-7927d43c3b5c","name":"4. Seguimiento (2 días)","type":"n8n-nodes-base.emailSend","typeVersion":2.1,"position":[-1088,240],"webhookId":"1dae335e-fdb5-43fc-b088-9aeab06ed1e2","credentials":{"smtp":{"id":"OiV6sH0CDrHSeXXH","name":"SMTP account 2"}}},{"parameters":{"amount":7,"unit":"days"},"id":"aec4c35f-e499-4246-84cc-2d1325e28281","name":"Esperar 7 Días","type":"n8n-nodes-base.wait","typeVersion":1,"position":[-864,240],"webhookId":"f7847b31-3312-4c28-9844-3c8745582c56"},{"parameters":{"documentId":{"__rl":true,"value":"https://docs.google.com/spreadsheets/d/1EoiocZTa9ELY8TQBXLEJSjxAZmohYClF1GH0N2qE4As/edit?gid=0#gid=0","mode":"url"},"sheetName":{"__rl":true,"value":324738822,"mode":"list","cachedResultName":"Hoja 2","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1EoiocZTa9ELY8TQBXLEJSjxAZmohYClF1GH0N2qE4As/edit#gid=324738822"},"filtersUI":{"values":[{"lookupColumn":"Email","lookupValue":"={{ $('Webhook Formulario').item.json.body.email }}"}]},"options":{}},"id":"0f9fd7e4-9807-4c78-8d16-55fd13a13922","name":"Verificar Estado 2","type":"n8n-nodes-base.googleSheets","typeVersion":4.5,"position":[-656,240],"credentials":{"googleSheetsOAuth2Api":{"id":"5TssK5sjUDI7k2MP","name":"Google Sheets account"}}},{"parameters":{"conditions":{"string":[{"value1":"={{ $json.Respondio }}","operation":"notEqual","value2":"SI"}]}},"id":"6c348413-5622-4c78-a1a5-c3017865ae68","name":"¿Respondió? (2)","type":"n8n-nodes-base.if","typeVersion":1,"position":[-432,240]},{"parameters":{"fromEmail":"avisos@info.excelcertify.com","toEmail":"={{ $('Webhook Formulario').item.json.body.email }}","subject":"Último aviso: Cupos 2026","html":"<p>Hola {{ $('Webhook Formulario').item.json.body.nombre }},</p>\n<p>No quisiera ser insistente, pero estamos cerrando los cupos con tarifa congelada esta semana y no recibimos tu confirmación.</p>\n<p>Si ya no estás interesado, por favor desestima este correo. Si aún te interesa, avísame hoy para guardarte el lugar.</p>\n<p>Saludos.</p>","options":{"appendAttribution":false,"replyTo":"info@excelcertify.com"}},"id":"1c2f1210-4e92-4e2b-a111-98d1c073194a","name":"5. Seguimiento (7 días)","type":"n8n-nodes-base.emailSend","typeVersion":2.1,"position":[-208,208],"webhookId":"f3f25634-1588-4b14-ae2c-d320a8a679cd","credentials":{"smtp":{"id":"OiV6sH0CDrHSeXXH","name":"SMTP account 2"}}},{"parameters":{"method":"POST","url":"https://api.whatsapp.com/send","options":{}},"id":"700d090d-ecf3-4fe2-ab1d-05e3fd89ea50","name":"WhatsApp (Desconectado)","type":"n8n-nodes-base.httpRequest","typeVersion":4.1,"position":[-1968,496],"notes":"Conectar aquí cuando tengas credenciales API"}]

connections:
  {"Webhook Formulario":{"main":[[{"node":"1. Guardar Lead","type":"main","index":0}]]},"1. Guardar Lead":{"main":[[{"node":"2. Email Confirmación","type":"main","index":0}]]},"2. Email Confirmación":{"main":[[{"node":"Esperar 15 Min","type":"main","index":0}]]},"Esperar 15 Min":{"main":[[{"node":"Generar Lógica PDF","type":"main","index":0}]]},"Generar Lógica PDF":{"main":[[{"node":"Crear PDF (API)","type":"main","index":0}]]},"Crear PDF (API)":{"main":[[{"node":"3. Email con PDF","type":"main","index":0}]]},"3. Email con PDF":{"main":[[{"node":"Calcular Fecha (+2 días hábiles)","type":"main","index":0}]]},"Calcular Fecha (+2 días hábiles)":{"main":[[{"node":"Esperar 2 Días (10AM)","type":"main","index":0}]]},"Esperar 2 Días (10AM)":{"main":[[{"node":"Verificar Estado 1","type":"main","index":0}]]},"Verificar Estado 1":{"main":[[{"node":"¿Respondió?","type":"main","index":0}]]},"¿Respondió?":{"main":[[{"node":"4. Seguimiento (2 días)","type":"main","index":0}]]},"4. Seguimiento (2 días)":{"main":[[{"node":"Esperar 7 Días","type":"main","index":0}]]},"Esperar 7 Días":{"main":[[{"node":"Verificar Estado 2","type":"main","index":0}]]},"Verificar Estado 2":{"main":[[{"node":"¿Respondió? (2)","type":"main","index":0}]]},"¿Respondió? (2)":{"main":[[{"node":"5. Seguimiento (7 días)","type":"main","index":0}]]}}


# credentials_entity

id: rU1lFD8D2vfG91MG
name: SMTP account
type: smtp
createdAt: 2025-12-08 20:02:25.347
updatedAt: 2025-12-08 20:02:25.334
data:
  U2FsdGVkX1+4rLaumUa685kDu5fimkQPvhIPPklI7eUpLucr4oXgnHlUoSiJpk48H+p2govRs0zdGdAFFOhEnOdIGKcxl9v3F5qXleSsq6IQbVzfsAF5nPwKPKORw+u/z2jexbPhS7pRRYx7CMUMuA==


id: Llk7W8MyvKeJ1ET0
name: Telegram account
type: telegramApi
createdAt: 2025-12-08 20:03:22.276
updatedAt: 2025-12-08 20:03:22.264
data:
  U2FsdGVkX18hR09W0cFMPgLN6cjlYvF7495i7Av/N8iEi+DfKWdCtbmccaiek5JS8S2PLGIJIWzcsZXYCTy/vMEzfC99Iu8LiW7NTgc1UloEsPwL1Ps2BXYB9JQkTW1J


id: 5TssK5sjUDI7k2MP
name: Google Sheets account
type: googleSheetsOAuth2Api
createdAt: 2026-01-05 13:23:41.054
updatedAt: 2026-01-05 23:46:52.175
data:
  U2FsdGVkX19RU8i3sCUubVxabNrTipK8HXzMlgA49nYVt6y+/P7eg7iBp9baz0kGHLncsCWdtMmkhenQiM5qXRQT1WOfsTSwNIkduorw6uAIJ/Gh4rDPGmd2L1GIWD0FGJfwb9YhbHPYbyXqBsi4Hb9ye+v7YjVADFXpUqiWHo6ApJvbczQ/90Glpfg851JNnretKLBPD529Gx6Rd0+gxw10NrPi9XCv4iP5KjFu3iUaqWQsO5PlFNcjGbLaoFXEb7OATEPtqsGK3DLmjqEquECV3P/2QdfAhyLWOMAnl5KFhQF8ckTM5EGgVQhX3+Zd4C5BPrjCLM/6Z6UwCTrYly5Q/+Fm9IQ66lMhoVwx5McEwVCVjZh8F6PMiu8Mrx2EFN24UYzkWQscS1cEujLrgr3NPzhlMObQ8laDvJATL/pkZ8kSsL7cKxrmJE2z3a/UJrxFtnvNWnuQ/sDXOqV//PFbHJ8XZ7CoX33Klsv51hZuYa3wxtWvA7iyH6HBCqmFI1KojFtGIANslzGynetNViD6J+1PqGW3opVR65AE/UCRfrLRB8GOHVgFELfSfwfipei59JwHlDEWro8BPB9nJAA+2rQRVkPYJQSgqkFV512owB+7Dbh1W97CUfQ4+1zLV0LlHlFJw5G5XX4kcgJYsa/wEzfA9J2LjDgAYAVWSwJumW9qvjWuPLgz7n1l4c9m+0soOeOjNftkhmi13f5h/iR47ZaxhxvYxH+rauUaEn6JbBwX0YHh5zMjetTEMCiz8tv8jHbid1pFwr1wKEwSAQISY7uHHqPbWTFxFtKzqKUjJ9orWO/1RCsSGAucGXAVYm8Y92gttZ9nHL16ipGRALtAwWy/00tlprw0TDK9La4+cCG0pgpE/qPdNSLyP4+hgoytmluBVaI4lailZev3qMHAeYBFbcVuzodKfbCLsM4PrYkBREptqbBzdwZj0oXDnsFDI6XXa3a3EKmfOfc/jGyXyiFYm60q/q4+CybmxT8BvL7T7Y5Kk+eNaKe9MOCnEIdllesLdYk8T65eeqVgOiNBx0kVpL1ScMEq9owPWEblTo1yfd7M3xuZXRxVEdYUfzgrVduL0kMwBciuVAjzDuCNr0su0ovSrcXE7gbjkoI7ChRfYkPoqbq32U/ccK7juYvIY1d06LcNa+umcmocfdQh2aEVj+8zVy/cSFjuP/S3wnymqwZlzkMft92jrmdr0kV+SSrt9wk4W+/9m/MRRg==


id: OiV6sH0CDrHSeXXH
name: SMTP account 2
type: smtp
createdAt: 2026-01-05 14:08:49.786
updatedAt: 2026-01-05 14:16:21.382
data:
  U2FsdGVkX1+zI0o8layrYs0SVLkjmIIpPlRsTCHk+WpVzTZOvpIVhH/dQinYqav0ivv4RmSXN5d6YkwK5Pva3G0WAp7q/4AOutl8jxsMPuLLx6NYpeqtzsZP28EBj7NS9McCfh6VR7BTcrIpM5FTJA==


id: bqJJSOzEExFN3lu9
name: HTML to PDF account
type: htmlcsstopdfApi
createdAt: 2026-01-05 16:23:55.618
updatedAt: 2026-01-05 16:23:55.614
data:
  U2FsdGVkX1/QtXdK/BYn/m9N7YQfH7dvFfW3aCxOOsNqp49+ZIChHKreAokBa1sLDrZbWYixncmS5iIUGFT9OOqMFUX9FyxJaZs0rfF1API=


id: nUGJyhzEG2yOkIO7
name: Unnamed credential
type: httpBasicAuth
createdAt: 2026-01-05 17:10:39.669
updatedAt: 2026-01-05 17:12:17.382
data:
  U2FsdGVkX1/VVKc1FMC45YTrKMq2K8LxxS2T81ZTnWcAH8gTxTuFW9sOIJAMpAD/XB2ajyTdWDZZvRnTmlfpufPZBQMdTUnTg8SKH91edgXii1zGytcIq9HvAn/qOMG1I/F8V+VB3xD9pzsDbyOjep7iTOXG1xkrMo3l9sITl94=


# workflow_entity

id: hXEHisCzN5N4YbGp
name: Busqueda diaria Torre Natalini Zonaprop (ScrapingBee)
pinData: {}
versionId: 7d2a9ec7-09d6-43b9-af60-790b77c98b16
meta: {"templateCredsSetupCompleted":true}
createdAt: 2025-12-08 20:03:32.408
updatedAt: 2025-12-10 18:46:29
nodes:
  [{"parameters":{"triggerTimes":{"item":[{"hour":9}]}},"name":"Cron","type":"n8n-nodes-base.cron","typeVersion":1,"position":[-1248,144],"id":"86748d59-307e-4cb4-bd06-bbb60106feee"},{"parameters":{"functionCode":"return [\n  { json: { url: \"https://www.zonaprop.com.ar/departamentos-alquiler-resistencia.html\" } },\n  { json: { url: \"https://www.zonaprop.com.ar/departamentos-alquiler-resistencia-pagina-2.html\" } }\n];"},"name":"Build URL List","type":"n8n-nodes-base.function","typeVersion":1,"position":[-1040,144],"id":"640c2354-9193-41e7-9d5a-fb13008d5821"},{"parameters":{"url":"={{'https://app.scrapingbee.com/api/v1?api_key=UTW0ABDB3AGUS5BCSZ2D9RL69FUVHI3QS8453C7OGNI410U6X27WAYOEMWFZTSCRJ06U7754S3C84WR4&render_js=true&url=' + encodeURIComponent($json[\"url\"])}}","responseFormat":"string","options":{},"queryParametersUi":{"parameter":[{"name":"stealth_proxy","value":"True"}]}},"name":"HTTP Get via ScrapingBee","type":"n8n-nodes-base.httpRequest","typeVersion":1,"position":[-800,144],"id":"2ae0d242-ab6b-44af-aea4-adaeff336446"},{"parameters":{"functionCode":"const pages = [\n  \"https://www.zonaprop.com.ar/departamentos-alquiler-resistencia.html\",\n  \"https://www.zonaprop.com.ar/departamentos-alquiler-resistencia-pagina-2.html\"\n];\n\nconst results = [];\n\nitems.forEach((item, index) => {\n  // El HTML viene en \"data\" por ScrapingBee\n  const html = item.json.data || \"\";\n  const lowerHtml = html.toLowerCase();\n\n  // Buscar solo Formosa / Natalini (sin importar mayúsculas, comas, etc.)\n  const hasFormosa  = lowerHtml.includes(\"formosa\");\n  const hasNatalini = lowerHtml.includes(\"natalini\");\n  \n  // Excluir SOLO \"formosa 40\" exacto (no 400, 140, etc.)\n  const hasFormosa40 = /formosa\\s+40\\b/.test(lowerHtml);\n\n  if ((hasFormosa || hasNatalini) && !hasFormosa40) {\n    // 1) Título de la página\n    let title = \"\";\n    const titleMatch = html.match(/<title[^>]*>([\\s\\S]*?)<\\/title>/i);\n    if (titleMatch) {\n      title = titleMatch[1].replace(/\\s+/g, \" \").trim();\n    }\n\n    // 2) Snippet de contexto alrededor de la primera coincidencia\n    const indexFormosa  = lowerHtml.indexOf(\"formosa\");\n    const indexNatalini = lowerHtml.indexOf(\"natalini\");\n\n    let keywordIndex = -1;\n    let keywordText  = \"\";\n\n    if (indexFormosa !== -1 && (indexNatalini === -1 || indexFormosa < indexNatalini)) {\n      keywordIndex = indexFormosa;\n      keywordText  = \"formosa\";\n    } else if (indexNatalini !== -1) {\n      keywordIndex = indexNatalini;\n      keywordText  = \"natalini\";\n    }\n\n    let snippet = \"\";\n    if (keywordIndex !== -1) {\n      const start = Math.max(0, keywordIndex - 80);\n      const end   = Math.min(html.length, keywordIndex + 80);\n\n      snippet = html\n        .substring(start, end)\n        .replace(/<[^>]+>/g, \" \")  // saco tags HTML\n        .replace(/\\s+/g, \" \")      // normalizo espacios\n        .trim();\n    }\n\n    results.push({\n      page: index + 1,\n      url: pages[index],\n      title,\n      hasFormosa,\n      hasNatalini,\n      keyword: keywordText,\n      snippet\n    });\n  }\n});\n\nreturn [{\n  json: {\n    count: results.length,\n    matches: results\n  }\n}];\n"},"name":"Search Natalini/Formosa","type":"n8n-nodes-base.function","typeVersion":1,"position":[-560,144],"id":"8332a10d-6ee2-4c76-9abb-f27dbda2c870"},{"parameters":{"conditions":{"number":[{"value1":"={{$json[\"count\"]}}","operation":"larger"}]}},"name":"IF Any Match","type":"n8n-nodes-base.if","typeVersion":1,"position":[-320,144],"id":"0f846290-a2ad-4fb4-b74c-4c5732aab7ec"},{"parameters":{"fromEmail":"info@excedera.com","toEmail":"victorrcolussi@gmail.com","subject":"Busqueda Natalini","text":"=={{ \n  'Se encontraron ' + $json.count + ' coincidencias para \"Formosa\" o \"Natalini\".\\n\\n' +\n  $json.matches.map(m =>\n    'Página ' + m.page + '\\n' +\n    'URL: ' + m.url + '\\n' +\n    'Título: ' + m.title + '\\n' +\n    'Coincidencia: ' + m.keyword + '\\n' +\n    'Contexto: ' + m.snippet + '\\n\\n'\n  ).join('')\n}}\n","html":"=={{ \n  '<h2>Resultados encontrados en Zonaprop</h2>' +\n  '<p>Se encontraron <strong>' + $json.count + '</strong> coincidencias para <strong>Formosa</strong> o <strong>Natalini</strong>.</p>' +\n  $json.matches.map(m =>\n    '<div style=\"border:1px solid #ddd; padding:10px; margin-bottom:15px;\">' +\n      '<h3>Página ' + m.page + '</h3>' +\n      '<p><strong>URL:</strong> <a href=\"' + m.url + '\" target=\"_blank\">' + m.url + '</a></p>' +\n      '<p><strong>Título:</strong> ' + m.title + '</p>' +\n      '<p><strong>Coincidencia detectada:</strong> ' + m.keyword + '</p>' +\n      '<p><strong>Contexto:</strong><br>' + m.snippet + '</p>' +\n    '</div>'\n  ).join('')\n}}\n","options":{}},"name":"Send Email","type":"n8n-nodes-base.emailSend","typeVersion":1,"position":[0,0],"id":"dbc1448a-b2b3-4572-9346-7c274599b117","credentials":{"smtp":{"id":"rU1lFD8D2vfG91MG","name":"SMTP account"}}},{"parameters":{"chatId":"7347036817","text":"={{ \n  'Se encontraron ' + $json.count + ' coincidencias para \"Formosa\" o \"Natalini\".\\n\\n' +\n  $json.matches.map(m =>\n    'Página ' + m.page + '\\n' +\n    'URL: ' + m.url + '\\n' +\n    'Título: ' + m.title + '\\n' +\n    'Coincidencia: ' + m.keyword + '\\n' +\n    'Contexto: ' + m.snippet + '\\n\\n'\n  ).join('')\n}}\n","additionalFields":{}},"type":"n8n-nodes-base.telegram","typeVersion":1.2,"position":[0,144],"id":"a05dedbe-2ad8-406d-b18b-9e613297f0e6","name":"Send a text message","webhookId":"6e90df6a-3c46-4c5b-8039-01d584bf33c0","credentials":{"telegramApi":{"id":"Llk7W8MyvKeJ1ET0","name":"Telegram account"}}}]

connections:
  {"Cron":{"main":[[{"node":"Build URL List","type":"main","index":0}]]},"Build URL List":{"main":[[{"node":"HTTP Get via ScrapingBee","type":"main","index":0}]]},"HTTP Get via ScrapingBee":{"main":[[{"node":"Search Natalini/Formosa","type":"main","index":0}]]},"Search Natalini/Formosa":{"main":[[{"node":"IF Any Match","type":"main","index":0}]]},"IF Any Match":{"main":[[{"node":"Send Email","type":"main","index":0},{"node":"Send a text message","type":"main","index":0}]]}}

settings:
  {"executionOrder":"v1","timezone":"America/Argentina/Buenos_Aires","callerPolicy":"workflowsFromSameOwner","availableInMCP":false}


id: dcJ6cEQ8CggXgQ6p
name: Horoscopo con Groq - Compatible
settings: {"executionOrder":"v1"}
pinData: {}
versionId: 81b85ac3-97b8-46a6-adac-743cf6fcaea5
createdAt: 2025-12-08 20:05:15.499
updatedAt: 2025-12-09 15:04:51
nodes:
  [{"parameters":{"triggerTimes":{"item":[{"hour":23}]}},"id":"3ff639e5-6ebc-4830-b9ec-9cbf7fc39cae","name":"Cron","type":"n8n-nodes-base.cron","typeVersion":1,"position":[-784,208]},{"parameters":{"functionCode":"const now = new Date();\nnow.setDate(now.getDate() + 1);\n\nconst yyyy = now.getFullYear();\nconst mm = String(now.getMonth() + 1).padStart(2, '0');\nconst dd = String(now.getDate()).padStart(2, '0');\nreturn [{ json: { dateFor: `${yyyy}-${mm}-${dd}` } }];"},"id":"1e4966a1-c6cf-4319-94b8-41e1fc1f731f","name":"Fecha mañana","type":"n8n-nodes-base.function","typeVersion":1,"position":[-560,208]},{"parameters":{"functionCode":"// Parse Groq JSON - MEJORADO\nconst item = $input.first().json;\nconst content = item.choices[0].message.content;\n\nlet parsed;\ntry {\n  // Intentar parsear el JSON\n  parsed = JSON.parse(content);\n} catch (e) {\n  // Si falla, intentar extraer JSON del texto\n  const jsonMatch = content.match(/\\{[\\s\\S]*\\}/);\n  if (jsonMatch) {\n    parsed = JSON.parse(jsonMatch[0]);\n  } else {\n    throw new Error('No se pudo parsear JSON de Groq: ' + content.substring(0, 200));\n  }\n}\n\n// Asegurar que tenga generated_at\nif (!parsed.generated_at) {\n  parsed.generated_at = new Date().toISOString();\n}\n\nreturn [{ json: parsed }];\n"},"id":"ff1ab031-f78f-409e-8209-4763d21ab017","name":"Parse Groq JSON","type":"n8n-nodes-base.function","typeVersion":1,"position":[-112,208]},{"parameters":{"method":"POST","url":"https://api.groq.com/openai/v1/chat/completions","sendHeaders":true,"headerParameters":{"parameters":[{"name":"Authorization","value":"Bearer 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"},{"name":"Content-Type","value":"application/json"}]},"sendBody":true,"specifyBody":"json","jsonBody":"={\n  \"model\": \"llama-3.1-8b-instant\",\n  \"temperature\": 0.95,\n  \"max_tokens\": 4000,\n  \"top_p\": 0.92,\n  \"messages\": [\n    {\n      \"role\": \"system\",\n      \"content\": \"Eres un astrólogo creativo y versátil con 20 años de experiencia. Tu especialidad es crear horóscopos únicos y personalizados que conectan emocionalmente con cada signo. REGLAS CRÍTICAS:\\n\\n1. Cada signo DEBE tener contenido 100% ÚNICO - cero repetición\\n2. Varía tu estilo entre: afirmaciones poderosas, preguntas reflexivas, consejos prácticos, manifestaciones, advertencias sabias, predicciones inspiradoras\\n3. Usa lenguaje emocional y evocativo - conecta con el alma de cada signo\\n4. Mezcla tonos: optimista, misterioso, desafiante, reconfortante, motivador\\n5. Incluye detalles específicos: colores, números, momentos del día, elementos naturales\\n6. Devuelves EXCLUSIVAMENTE JSON válido UTF-8 sin texto adicional\"\n    },\n    {\n      \"role\": \"user\",\n      \"content\": \"Crea el horóscopo diario para {{ $json.dateFor }}. Hoy tu estilo debe ser VARIADO y CREATIVO.\\n\\n📋 INSTRUCCIONES POR SIGNO:\\n\\nARIES: Usa tono MOTIVADOR con una llamada a la acción\\nTAURO: Usa tono REFLEXIVO con enfoque en sensorialidad\\nGÉMINIS: Usa tono CURIOSO con preguntas que inviten a explorar\\nCÁNCER: Usa tono EMOCIONAL con énfasis en intuición\\nLEÓN: Usa tono EMPODERADOR con afirmaciones de confianza\\nVIRGO: Usa tono PRÁCTICO con consejos específicos\\nLIBRA: Usa tono ARMONIOSO con énfasis en relaciones\\nESCORPIO: Usa tono MÍSTICO con profundidad psicológica\\nSAGITARIO: Usa tono AVENTURERO con visión expansiva\\nCAPRICORNio: Usa tono ESTRATÉGICO con enfoque en logros\\nACUARIO: Usa tono INNOVADOR con perspectiva futurista\\nPISCIS: Usa tono POÉTICO con metáforas y simbolismo\\n\\n🎨 ELEMENTOS CREATIVOS A INCLUIR:\\n- Menciona un momento específico del día (amanecer, mediodía, atardecer, noche)\\n- Incluye un elemento natural (agua, fuego, tierra, aire, luna, estrellas)\\n- Usa vocabulario variado: \\\"energía\\\", \\\"vibración\\\", \\\"resonancia\\\", \\\"flujo\\\", \\\"transformación\\\", \\\"manifestación\\\", \\\"alineación\\\"\\n- Alterna entre segunda persona (tú) y tercera persona (Aries siente...)\\n\\n🎯 ESTRUCTURA DE PREDICCIONES DE UNA PALABRA:\\n- AMOR: Usa palabras como: Pasión, Ternura, Sorpresa, Paciencia, Magnetismo, Diálogo, Reconciliación, Aventura, Compromiso, Libertad, Intensidad, Calma\\n- SALUD: Usa palabras como: Vitalidad, Descanso, Renovación, Equilibrio, Fuerza, Precaución, Energía, Sanación, Movimiento, Quietud, Resiliencia, Detox\\n- DINERO: Usa palabras como: Abundancia, Ahorro, Inversión, Oportunidad, Cautela, Crecimiento, Estabilidad, Cambio, Ganancia, Paciencia, Audacia, Planificación\\n\\n⚡ REQUISITOS TÉCNICOS:\\n1. Cada predicción en español: 60-85 palabras (varía la longitud)\\n2. Cada predicción en inglés: 60-85 palabras\\n3. Número de suerte: aleatorio 1-99 (que tenga relación numerológica si es posible)\\n4. ZERO repetición de frases entre signos\\n5. Usa acentos correctos en español (á, é, í, ó, ú, ñ)\\n\\n📊 FORMATO JSON EXACTO:\\n{\\n  \\\"date_for\\\": \\\"{{ $json.dateFor }}\\\",\\n  \\\"generated_at\\\": \\\"{{ new Date().toISOString() }}\\\",\\n  \\\"signs\\\": [\\n    {\\n      \\\"sign\\\": \\\"Aries\\\",\\n      \\\"sign_es\\\": \\\"Aries\\\",\\n      \\\"sign_en\\\": \\\"Aries\\\",\\n      \\\"lucky_number\\\": 47,\\n      \\\"predictions\\\": {\\n        \\\"love\\\": \\\"Magnetismo\\\",\\n        \\\"health\\\": \\\"Vitalidad\\\",\\n        \\\"money\\\": \\\"Oportunidad\\\"\\n      },\\n      \\\"es\\\": \\\"[Tu predicción creativa y única aquí - tono MOTIVADOR]\\\",\\n      \\\"en\\\": \\\"[Your creative and unique prediction here - MOTIVATING tone]\\\"\\n    }\\n  ]\\n}\\n\\nLos 12 signos en orden: Aries, Tauro, Géminis, Cáncer, León, Virgo, Libra, Escorpio, Sagitario, Capricornio, Acuario, Piscis.\\n\\n⚠️ VALIDACIÓN FINAL:\\n- Verifica que NO haya frases repetidas entre signos\\n- Confirma que cada signo tenga su tono distintivo\\n- Asegura variedad en las predicciones de una palabra\\n- Devuelve SOLO el JSON sin explicaciones\"\n    }\n  ]\n}\n\n","options":{}},"type":"n8n-nodes-base.httpRequest","typeVersion":4.3,"position":[-336,208],"id":"d086fa18-2c3a-4def-ae64-29b890a88ddf","name":"HTTP Request"},{"parameters":{"operation":"toJson","options":{"encoding":"utf8","fileName":"horoscopo89.json"}},"type":"n8n-nodes-base.convertToFile","typeVersion":1.1,"position":[352,208],"id":"944ac0c0-461d-4419-8c4b-d0a58c02479a","name":"Convert to File"},{"parameters":{"operation":"write","fileName":"/data/api-shared/horoscopo89.json","options":{}},"type":"n8n-nodes-base.readWriteFile","typeVersion":1,"position":[624,208],"id":"0e822224-458b-4e48-a159-4344bec83f2a","name":"Read/Write Files from Disk"},{"parameters":{"jsCode":"// Code Node: Validar y Limpiar JSON\nconst inputData = $input.first().json;\n\n// Schema de validación\nconst REQUIRED_FIELDS = ['date_for', 'generated_at', 'signs'];\nconst SIGN_FIELDS = ['sign', 'sign_es', 'sign_en', 'lucky_number', 'predictions', 'es', 'en'];\nconst PREDICTION_FIELDS = ['love', 'health', 'money'];\nconst VALID_SIGNS = ['Aries', 'Tauro', 'Géminis', 'Cáncer', 'León', 'Virgo', \n                     'Libra', 'Escorpio', 'Sagitario', 'Capricornio', 'Acuario', 'Piscis'];\n\n// Función de validación\nfunction validateHoroscope(data) {\n  const errors = [];\n  \n  // Validar campos principales\n  REQUIRED_FIELDS.forEach(field => {\n    if (!data[field]) errors.push(`Falta campo: ${field}`);\n  });\n  \n  // Validar array de signos\n  if (!Array.isArray(data.signs)) {\n    errors.push('signs debe ser un array');\n  } else if (data.signs.length !== 12) {\n    errors.push(`Se esperan 12 signos, se encontraron ${data.signs.length}`);\n  } else {\n    // Validar cada signo\n    data.signs.forEach((sign, index) => {\n      // Validar campos del signo\n      SIGN_FIELDS.forEach(field => {\n        if (sign[field] === undefined || sign[field] === null) {\n          errors.push(`Signo ${index}: Falta campo ${field}`);\n        }\n      });\n      \n      // Validar nombre del signo\n      if (!VALID_SIGNS.includes(sign.sign)) {\n        errors.push(`Signo inválido en posición ${index}: ${sign.sign}`);\n      }\n      \n      // Validar lucky_number\n      if (typeof sign.lucky_number !== 'number' || sign.lucky_number < 1 || sign.lucky_number > 99) {\n        errors.push(`Signo ${sign.sign}: lucky_number inválido`);\n      }\n      \n      // Validar predictions\n      if (typeof sign.predictions !== 'object') {\n        errors.push(`Signo ${sign.sign}: predictions debe ser objeto`);\n      } else {\n        PREDICTION_FIELDS.forEach(pred => {\n          if (!sign.predictions[pred] || typeof sign.predictions[pred] !== 'string') {\n            errors.push(`Signo ${sign.sign}: Falta predicción ${pred}`);\n          }\n        });\n      }\n      \n      // Validar textos no vacíos\n      if (!sign.es || sign.es.trim().length < 10) {\n        errors.push(`Signo ${sign.sign}: Texto en español muy corto o vacío`);\n      }\n      if (!sign.en || sign.en.trim().length < 10) {\n        errors.push(`Signo ${sign.sign}: Texto en inglés muy corto o vacío`);\n      }\n    });\n    \n    // Validar signos únicos (no duplicados)\n    const signNames = data.signs.map(s => s.sign);\n    const duplicates = signNames.filter((item, index) => signNames.indexOf(item) !== index);\n    if (duplicates.length > 0) {\n      errors.push(`Signos duplicados: ${duplicates.join(', ')}`);\n    }\n  }\n  \n  return errors;\n}\n\n// Función para limpiar texto (quitar caracteres raros)\nfunction cleanText(text) {\n  if (typeof text !== 'string') return text;\n  \n  // Normalizar y limpiar caracteres raros\n  return text\n    .normalize('NFC') // Normalización Unicode\n    .replace(/�/g, '') // Quitar caracteres de reemplazo\n    .replace(/[\\u0000-\\u001F\\u007F-\\u009F]/g, '') // Quitar caracteres de control\n    .trim();\n}\n\n// Ejecutar validación\nconst errors = validateHoroscope(inputData);\n\nif (errors.length > 0) {\n  throw new Error(`Validación fallida:\\n${errors.join('\\n')}`);\n}\n\n// Limpiar todos los textos\nconst cleanedData = {\n  date_for: inputData.date_for,\n  generated_at: inputData.generated_at,\n  signs: inputData.signs.map(sign => ({\n    sign: cleanText(sign.sign),\n    sign_es: cleanText(sign.sign_es),\n    sign_en: cleanText(sign.sign_en),\n    lucky_number: sign.lucky_number,\n    predictions: {\n      love: cleanText(sign.predictions.love),\n      health: cleanText(sign.predictions.health),\n      money: cleanText(sign.predictions.money)\n    },\n    es: cleanText(sign.es),\n    en: cleanText(sign.en)\n  }))\n};\n\n// Retornar datos limpios y validados\nreturn [{ json: cleanedData }];\n"},"type":"n8n-nodes-base.code","typeVersion":2,"position":[112,208],"id":"c9f5df20-c1df-49f0-b425-09dee649f483","name":"Code in JavaScript"}]

connections:
  {"Cron":{"main":[[{"node":"Fecha mañana","type":"main","index":0}]]},"Fecha mañana":{"main":[[{"node":"HTTP Request","type":"main","index":0}]]},"Parse Groq JSON":{"main":[[{"node":"Code in JavaScript","type":"main","index":0}]]},"HTTP Request":{"main":[[{"node":"Parse Groq JSON","type":"main","index":0}]]},"Convert to File":{"main":[[{"node":"Read/Write Files from Disk","type":"main","index":0}]]},"Code in JavaScript":{"main":[[{"node":"Convert to File","type":"main","index":0}]]}}


# user

id: f90ab502-df87-4a8e-8b0f-68add8e13e5b
email: victorrcolussi@gmail.com
firstName: Victor
lastName: Colussi
password: $2a$10$eJWWsaBNoVTJFUJRCYfWvObeNX5VqsCTRLXxfGJLWHvTMwqbvHq/e
createdAt: 2025-12-08 19:57:24.775
updatedAt: 2026-01-05 23:01:30
lastActiveAt: 2026-01-06
roleSlug: global:owner
personalizationAnswers:
  {"version":"v4","personalization_survey_submitted_at":"2025-12-08T20:00:42.376Z","personalization_survey_n8n_version":"1.119.2"}

settings:
  {"userActivated":true,"firstSuccessfulWorkflowId":"hXEHisCzN5N4YbGp","userActivatedAt":1765267224087,"npsSurvey":{"waitingForResponse":true,"ignoredCount":1,"lastShownAt":1767619936421}}


