Files
portal-de-verificacion-de-n…/portal-de-verificacion-de-nomina-tt-envio-de-reporte.json

746 lines
57 KiB
JSON

{
"updatedAt": "2026-07-25T17:29:15.951Z",
"createdAt": "2026-07-14T15:32:29.194Z",
"id": "aihmNdYFskfvf3XF",
"name": "Portal de Verificación de Nómina TT - Envío de Reporte",
"description": "Gestiona la resolución de reportes del Portal de Verificación de Nómina de Trinidad y Tobago: valida la solicitud recibida desde la aplicación, marca el reporte como resuelto en Supabase, registra los datos de la resolución, notifica por correo al equipo responsable de TT y devuelve la confirmación final al portal, incluyendo manejo de solicitudes inválidas.",
"active": true,
"isArchived": false,
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "cruce-cuentas-tt-marcar-resuelto",
"responseMode": "responseNode",
"options": {}
},
"type": "n8n-nodes-base.webhook",
"typeVersion": 2.1,
"position": [
-752,
112
],
"id": "1affa570-6b53-43d0-afab-25aaf5b8da2d",
"name": "Webhook Marcar Resuelto",
"webhookId": "b0f8173c-c81a-4d32-9205-ab0102dec679"
},
{
"parameters": {
"jsCode": "const body = $input.first().json.body || $input.first().json || {};\n\nfunction clean(value) {\n return String(value ?? '').replace(/\\s+/g, ' ').trim();\n}\n\nconst reportId = clean(body.reportId || body.id);\nconst comentarioResolucion = clean(body.comentarioResolucion || body.comentario || '');\nconst resueltoPorNombre = clean(body.resueltoPorNombre || body.userName || 'Usuario GLM');\nconst resueltoPorEmail = clean(body.resueltoPorEmail || body.userEmail || '');\n\nconst errors = [];\n\nif (!reportId) {\n errors.push('No se recibió el ID del reporte.');\n}\n\nif (!comentarioResolucion) {\n errors.push('Debe indicar un comentario de resolución.');\n}\n\nif (comentarioResolucion.length < 10) {\n errors.push('El comentario de resolución debe ser más descriptivo.');\n}\n\nif (errors.length > 0) {\n return [\n {\n json: {\n ok: false,\n stage: 'validacion_resolucion',\n errors,\n reportId,\n },\n },\n ];\n}\n\nreturn [\n {\n json: {\n ok: true,\n stage: 'resolucion_validada',\n reportId,\n comentarioResolucion,\n resueltoPorNombre,\n resueltoPorEmail,\n resolvedAt: new Date().toISOString(),\n },\n },\n];"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
-544,
112
],
"id": "5e78d132-c731-4d6a-8926-8afa88e5df12",
"name": "Validar resolución"
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 3
},
"conditions": [
{
"id": "c89884c6-de96-4b08-bd20-54644bb95bc7",
"leftValue": "={{ $json.ok }}",
"rightValue": "",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
}
}
],
"combinator": "and"
},
"options": {}
},
"type": "n8n-nodes-base.if",
"typeVersion": 2.3,
"position": [
-336,
112
],
"id": "cc34f3e6-40f2-43e3-99f1-0aea4fb502c4",
"name": "¿Solicitud válida?"
},
{
"parameters": {
"method": "PATCH",
"url": "={{ 'https://dbit.digitalcompass.agency/rest/v1/cruces_cuentas_gt_reportes?id=eq.' + encodeURIComponent($json.reportId) + '&country=eq.TT' }}",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "apikey",
"value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJzZXJ2aWNlX3JvbGUiLAogICAgImlzcyI6ICJzdXBhYmFzZS1kZW1vIiwKICAgICJpYXQiOiAxNjQxNzY5MjAwLAogICAgImV4cCI6IDE3OTk1MzU2MDAKfQ.DaYlNEoUrrEn2Ig7tqibS-PHK5vgusbcbo7X36XVt4Q"
},
{
"name": "Authorization",
"value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJzZXJ2aWNlX3JvbGUiLAogICAgImlzcyI6ICJzdXBhYmFzZS1kZW1vIiwKICAgICJpYXQiOiAxNjQxNzY5MjAwLAogICAgImV4cCI6IDE3OTk1MzU2MDAKfQ.DaYlNEoUrrEn2Ig7tqibS-PHK5vgusbcbo7X36XVt4Q"
},
{
"name": "Content-Type",
"value": "application/json"
},
{
"name": "Prefer",
"value": "return=representation"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={{\n {\n estado: 'resuelto',\n resuelto_por_nombre: $json.resueltoPorNombre,\n resuelto_por_email: $json.resueltoPorEmail,\n resuelto_en: $json.resolvedAt,\n comentario_resolucion: $json.comentarioResolucion,\n updated_at: $json.resolvedAt\n }\n}}",
"options": {}
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.4,
"position": [
0,
0
],
"id": "52b2af1a-ac9f-4b47-9950-2f91e32084b0",
"name": "Actualizar reporte Supabase"
},
{
"parameters": {
"jsCode": "const input = $input.first().json || {};\nconst report = Array.isArray(input) ? input[0] : input;\n\nif (!report || !report.id) {\n throw new Error(\n 'No se encontró un reporte de Trinidad y Tobago con el ID recibido.'\n );\n}\n\nif (String(report.country || '').toUpperCase() !== 'TT') {\n throw new Error(\n 'El reporte localizado no pertenece a Trinidad y Tobago.'\n );\n}\nconst original = $('Validar resolución').first().json || {};\n\n\nfunction escapeHtml(value) {\n return String(value ?? '')\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&#039;');\n}\n\nfunction numberValue(value) {\n const parsed = Number(value);\n return Number.isFinite(parsed) ? parsed : 0;\n}\n\nconst periodo = report.period_label || 'Período no especificado';\nconst reportUrl = report.report_url || '';\n\nconst discrepancias = numberValue(report.discrepancias);\nconst bancoSinNomina = numberValue(report.banco_sin_nomina);\nconst bancoSinBamboo = numberValue(report.banco_sin_bamboo);\nconst nominaSinCuenta = numberValue(report.nomina_sin_cuenta);\n\nconst resolvedAt = original.resolvedAt || new Date().toISOString();\n\nconst resolvedDateLabel = new Date(resolvedAt).toLocaleString('es-DO', {\n timeZone: 'America/Port_of_Spain',\n dateStyle: 'long',\n timeStyle: 'short',\n});\n\nconst resolvedByName =\n original.resueltoPorNombre || 'Usuario GLM';\n\nconst resolvedByEmail =\n original.resueltoPorEmail || '';\n\nconst resolutionComment =\n original.comentarioResolucion || 'Sin comentario registrado.';\n\nconst logoUrl =\n 'https://dbit.digitalcompass.agency/storage/v1/object/public/public-assets/GLM_completo.png';\n\nconst subject =\n `Reporte resuelto - Cruce de Cuentas Trinidad y Tobago - ${periodo}`;\n\nconst textBody = `\nHola equipo,\n\nSe marcó como resuelto un reporte de Cruce de Cuentas Trinidad y Tobago.\n\nPeríodo:\n${periodo}\n\nResuelto por:\n${resolvedByName}${resolvedByEmail ? ` (${resolvedByEmail})` : ''}\n\nFecha/hora:\n${resolvedDateLabel}\n\nResumen:\n- Discrepancias: ${discrepancias}\n- Banco sin nómina: ${bancoSinNomina}\n- Banco sin Bamboo: ${bancoSinBamboo}\n- Nómina sin cuenta: ${nominaSinCuenta}\n\nComentario:\n${resolutionComment}\n\nGoogle Sheet:\n${reportUrl || 'No disponible'}\n\nSaludos,\nPortal Cruce de Cuentas GLM\n`.trim();\n\nconst htmlBody = `\n<!doctype html>\n<html lang=\"es\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width\">\n <title>${escapeHtml(subject)}</title>\n</head>\n\n<body style=\"\n margin:0;\n padding:0;\n background:#F5F5F5;\n font-family:Arial, Helvetica, sans-serif;\n color:#4A4A4A;\n\">\n\n <table\n role=\"presentation\"\n width=\"100%\"\n cellspacing=\"0\"\n cellpadding=\"0\"\n border=\"0\"\n style=\"background:#F5F5F5;padding:24px 12px;\"\n >\n <tr>\n <td align=\"center\">\n\n <table\n role=\"presentation\"\n width=\"640\"\n cellspacing=\"0\"\n cellpadding=\"0\"\n border=\"0\"\n style=\"\n width:100%;\n max-width:640px;\n background:#FFFFFF;\n border:1px solid #D0D0D0;\n border-collapse:separate;\n \"\n >\n\n <tr>\n <td style=\"padding:28px 32px 20px 32px;\">\n <img\n src=\"${escapeHtml(logoUrl)}\"\n width=\"230\"\n alt=\"GomezLee Marketing\"\n style=\"\n display:block;\n width:230px;\n max-width:100%;\n height:auto;\n border:0;\n \"\n >\n </td>\n </tr>\n\n <tr>\n <td style=\"\n height:4px;\n background:#6CC24A;\n font-size:0;\n line-height:0;\n \">&nbsp;</td>\n </tr>\n\n <tr>\n <td style=\"padding:28px 32px 8px 32px;\">\n <div style=\"\n color:#6CC24A;\n font-size:12px;\n font-weight:bold;\n letter-spacing:0.8px;\n text-transform:uppercase;\n margin-bottom:8px;\n \">\n Cruce de Cuentas Trinidad y Tobago\n </div>\n\n <h1 style=\"\n margin:0;\n color:#4F758B;\n font-size:25px;\n line-height:1.25;\n font-weight:700;\n \">\n Reporte marcado como resuelto\n </h1>\n </td>\n </tr>\n\n <tr>\n <td style=\"padding:12px 32px 8px 32px;\">\n <p style=\"\n margin:0 0 16px 0;\n font-size:15px;\n line-height:1.6;\n \">\n Hola equipo,\n </p>\n\n <p style=\"\n margin:0;\n font-size:15px;\n line-height:1.6;\n \">\n El siguiente reporte fue revisado y marcado como\n <strong style=\"color:#4F758B;\">resuelto</strong>.\n </p>\n </td>\n </tr>\n\n <tr>\n <td style=\"padding:20px 32px 8px 32px;\">\n <table\n role=\"presentation\"\n width=\"100%\"\n cellspacing=\"0\"\n cellpadding=\"0\"\n border=\"0\"\n style=\"\n border-collapse:collapse;\n border:1px solid #D0D0D0;\n \"\n >\n <tr>\n <td style=\"\n width:34%;\n padding:11px 14px;\n background:#EEF6E8;\n color:#4F758B;\n font-size:13px;\n font-weight:bold;\n border-bottom:1px solid #D0D0D0;\n \">\n Período\n </td>\n\n <td style=\"\n padding:11px 14px;\n background:#FFFFFF;\n font-size:13px;\n border-bottom:1px solid #D0D0D0;\n \">\n ${escapeHtml(periodo)}\n </td>\n </tr>\n\n <tr>\n <td style=\"\n padding:11px 14px;\n background:#EEF6E8;\n color:#4F758B;\n font-size:13px;\n font-weight:bold;\n border-bottom:1px solid #D0D0D0;\n \">\n Resuelto por\n </td>\n\n <td style=\"\n padding:11px 14px;\n background:#FFFFFF;\n font-size:13px;\n border-bottom:1px solid #D0D0D0;\n \">\n ${escapeHtml(resolvedByName)}\n ${\n resolvedByEmail\n ? `<br><span style=\"color:#6B8FA3;\">${escapeHtml(resolvedByEmail)}</span>`\n : ''\n }\n </td>\n </tr>\n\n <tr>\n <td style=\"\n padding:11px 14px;\n background:#EEF6E8;\n color:#4F758B;\n font-size:13px;\n font-weight:bold;\n \">\n Fecha y hora\n </td>\n\n <td style=\"\n padding:11px 14px;\n background:#FFFFFF;\n font-size:13px;\n \">\n ${escapeHtml(resolvedDateLabel)}\n </td>\n </tr>\n </table>\n </td>\n </tr>\n\n <tr>\n <td style=\"padding:22px 32px 8px 32px;\">\n <div style=\"\n color:#4F758B;\n font-size:15px;\n font-weight:bold;\n border-bottom:2px solid #6CC24A;\n padding-bottom:7px;\n \">\n Resumen del reporte\n </div>\n </td>\n </tr>\n\n <tr>\n <td style=\"padding:12px 32px 8px 32px;\">\n <table\n role=\"presentation\"\n width=\"100%\"\n cellspacing=\"0\"\n cellpadding=\"0\"\n border=\"0\"\n style=\"border-collapse:collapse;\"\n >\n <tr>\n <td style=\"\n width:25%;\n padding:12px 8px;\n text-align:center;\n border:1px solid #D0D0D0;\n background:#FFFFFF;\n \">\n <div style=\"\n color:#4F758B;\n font-size:22px;\n font-weight:bold;\n \">\n ${discrepancias}\n </div>\n\n <div style=\"\n color:#6B8FA3;\n font-size:11px;\n margin-top:4px;\n \">\n Discrepancias\n </div>\n </td>\n\n <td style=\"\n width:25%;\n padding:12px 8px;\n text-align:center;\n border:1px solid #D0D0D0;\n background:#FFFFFF;\n \">\n <div style=\"\n color:#4F758B;\n font-size:22px;\n font-weight:bold;\n \">\n ${bancoSinBamboo}\n </div>\n\n <div style=\"\n color:#6B8FA3;\n font-size:11px;\n margin-top:4px;\n \">\n Banco sin Bamboo\n </div>\n </td>\n\n <td style=\"\n width:25%;\n padding:12px 8px;\n text-align:center;\n border:1px solid #D0D0D0;\n background:#FFFFFF;\n \">\n <div style=\"\n color:#4F758B;\n font-size:22px;\n font-weight:bold;\n \">\n ${bancoSinNomina}\n </div>\n\n <div style=\"\n color:#6B8FA3;\n font-size:11px;\n margin-top:4px;\n \">\n Banco sin nómina\n </div>\n </td>\n\n <td style=\"\n width:25%;\n padding:12px 8px;\n text-align:center;\n border:1px solid #D0D0D0;\n background:#FFFFFF;\n \">\n <div style=\"\n color:#4F758B;\n font-size:22px;\n font-weight:bold;\n \">\n ${nominaSinCuenta}\n </div>\n\n <div style=\"\n color:#6B8FA3;\n font-size:11px;\n margin-top:4px;\n \">\n Nómina sin cuenta\n </div>\n </td>\n </tr>\n </table>\n </td>\n </tr>\n\n <tr>\n <td style=\"padding:22px 32px 8px 32px;\">\n <div style=\"\n color:#4F758B;\n font-size:15px;\n font-weight:bold;\n border-bottom:2px solid #6CC24A;\n padding-bottom:7px;\n \">\n Comentario de resolución\n </div>\n </td>\n </tr>\n\n <tr>\n <td style=\"padding:12px 32px 8px 32px;\">\n <div style=\"\n padding:16px 18px;\n background:#D6E8F4;\n border:1px solid #D0D0D0;\n color:#4A4A4A;\n font-size:14px;\n line-height:1.6;\n \">\n ${escapeHtml(resolutionComment).replace(/\\n/g, '<br>')}\n </div>\n </td>\n </tr>\n\n ${\n reportUrl\n ? `\n <tr>\n <td align=\"center\" style=\"padding:26px 32px 30px 32px;\">\n <a\n href=\"${escapeHtml(reportUrl)}\"\n target=\"_blank\"\n style=\"\n display:inline-block;\n padding:12px 22px;\n background:#4F758B;\n color:#FFFFFF;\n text-decoration:none;\n font-size:14px;\n font-weight:bold;\n border-bottom:4px solid #6CC24A;\n \"\n >\n Abrir Google Sheet\n </a>\n </td>\n </tr>\n `\n : ''\n }\n\n <tr>\n <td style=\"\n padding:18px 32px;\n border-top:1px solid #D0D0D0;\n color:#6B8FA3;\n font-size:11px;\n line-height:1.5;\n \">\n Mensaje automático del Portal Cruce de Cuentas GLM.\n </td>\n </tr>\n\n </table>\n </td>\n </tr>\n </table>\n\n</body>\n</html>\n`.trim();\n\nreturn [\n {\n json: {\n to: 'jgomez@gomezleemarketing.com, mgomez@gomezleemarketing.com, ymadera@gomezleemarketing.com',\n cc: 'iaracena@gomezleemarketing.com',\n subject,\n textBody,\n htmlBody,\n report,\n resolution: original,\n },\n },\n];"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
208,
0
],
"id": "966b80c6-0935-46fe-a700-d073bbc95b2f",
"name": "Preparar correo equipo TT"
},
{
"parameters": {
"sendTo": "={{$json.to}}",
"subject": "={{$json.subject}}",
"message": "={{ $json.htmlBody }}",
"options": {
"appendAttribution": false,
"ccList": "={{ $json.cc }}"
}
},
"type": "n8n-nodes-base.gmail",
"typeVersion": 2.2,
"position": [
416,
0
],
"id": "dc52381c-3e76-4991-bc09-a87472d51d64",
"name": "Enviar correo equipo TT",
"webhookId": "da3b90f2-2e52-4a99-beea-5bc580486f75",
"credentials": {
"gmailOAuth2": {
"id": "UDcO1FLJqA453V2D",
"name": "Gmail account 3"
}
}
},
{
"parameters": {
"jsCode": "const original = $('Validar resolución').first().json || {};\nconst updatedResponse = $('Actualizar reporte Supabase').first().json || {};\nconst updatedReport = Array.isArray(updatedResponse) ? updatedResponse[0] : updatedResponse;\n\nreturn [\n {\n json: {\n ok: true,\n stage: 'reporte_resuelto',\n message: 'Reporte marcado como resuelto correctamente.',\n report: {\n id: original.reportId,\n estado: 'resuelto',\n estadoLabel: 'RESUELTO',\n country: 'TT',\n countryName: 'Trinidad y Tobago',\n resueltoPorNombre: original.resueltoPorNombre,\n resueltoPorEmail: original.resueltoPorEmail,\n resueltoEn: original.resolvedAt,\n comentarioResolucion: original.comentarioResolucion,\n reportUrl: updatedReport.report_url || '',\n },\n },\n },\n];"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
624,
0
],
"id": "d0b12567-ae34-4d7a-8b8c-70e4e855bf35",
"name": "Preparar respuesta resuelto"
},
{
"parameters": {
"respondWith": "json",
"responseBody": "={{ $json }}",
"options": {
"responseCode": 200,
"responseHeaders": {
"entries": [
{
"name": "Content-Type",
"value": "application/json"
},
{
"name": "Access-Control-Allow-Origin",
"value": "*"
},
{
"name": "Access-Control-Allow-Methods",
"value": "GET,POST,OPTIONS"
},
{
"name": "Access-Control-Allow-Headers",
"value": "Content-Type, Authorization"
}
]
}
}
},
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.5,
"position": [
832,
0
],
"id": "f6ea0dba-e017-41f8-9cb4-2685a608a58d",
"name": "Responder resuelto app"
},
{
"parameters": {
"respondWith": "json",
"responseBody": "={{ $json }}",
"options": {
"responseCode": 400,
"responseHeaders": {
"entries": [
{
"name": "Content-Type",
"value": "application/json"
},
{
"name": "Access-Control-Allow-Origin",
"value": "*"
},
{
"name": "Access-Control-Allow-Methods",
"value": "GET,POST,OPTIONS"
},
{
"name": "Access-Control-Allow-Headers",
"value": "Content-Type, Authorization"
}
]
}
}
},
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.5,
"position": [
-128,
208
],
"id": "4fbe8e29-c6b3-4095-8474-4d82a1e8c639",
"name": "Responder error resolución"
},
{
"parameters": {
"content": "# ✅ CIERRE DE REPORTE — TRINIDAD Y TOBAGO\n\nRecibe desde el Portal de Verificación de Nóminas la solicitud para marcar un reporte de Trinidad y Tobago como resuelto.\n\n## Validación inicial\n\nEl Webhook recibe la información enviada por la aplicación y valida datos como:\n\n- Identificador del reporte.\n- Usuario que realizó el cierre.\n- Estado solicitado.\n- Comentario o detalle de resolución.\n- Datos necesarios para localizar el registro en Supabase.\n\nLa solicitud solamente continúa cuando contiene información válida y suficiente.\n\n## Actualización del reporte\n\nCuando la solicitud es correcta:\n\n1. Localiza el reporte correspondiente en Supabase.\n2. Cambia su estado a RESUELTO.\n3. Registra quién realizó la resolución.\n4. Guarda la fecha y hora del cierre.\n5. Conserva el comentario o información de seguimiento disponible.\n\nSupabase es la fuente oficial del estado del reporte dentro del portal.\n\n## Notificación al equipo TT\n\nDespués de actualizar el registro:\n\n1. Se prepara un correo para el equipo responsable de Trinidad y Tobago.\n2. Se incluyen los datos principales del reporte.\n3. Se informa que el caso fue marcado como resuelto.\n4. Se identifica al usuario que realizó el cierre.\n5. Se envía el correo mediante Gmail.\n\nLa notificación permite que el equipo conozca el cambio sin tener que revisar manualmente el portal.\n\n## Respuesta a la aplicación\n\nCuando el proceso termina correctamente:\n\n- Se construye una respuesta de éxito.\n- Se confirma que el reporte fue actualizado.\n- Se devuelve el nuevo estado a la aplicación.\n- El portal puede actualizar inmediatamente su interfaz.\n\n## Ruta de error\n\nCuando la solicitud es inválida:\n\n- No se modifica Supabase.\n- No se envía el correo al equipo TT.\n- Se devuelve una respuesta de error a la aplicación.\n- Se informa que faltan datos o que la solicitud no pudo procesarse.\n\n## Reglas\n\n- No marcar un reporte como resuelto sin un identificador válido.\n- No enviar la notificación antes de confirmar la actualización en Supabase.\n- No declarar éxito cuando la base de datos no fue actualizada.\n- Toda respuesta del Webhook debe cerrarse correctamente para evitar solicitudes abiertas.\n- La ruta de error debe terminar sin realizar cambios parciales.",
"height": 1264,
"width": 2624,
"color": "#28765F"
},
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
-1536,
-480
],
"id": "e58c6673-d3ac-40e1-9b10-ae20e09730af",
"name": "Sticky Note"
}
],
"connections": {
"Webhook Marcar Resuelto": {
"main": [
[
{
"node": "Validar resolución",
"type": "main",
"index": 0
}
]
]
},
"Validar resolución": {
"main": [
[
{
"node": "¿Solicitud válida?",
"type": "main",
"index": 0
}
]
]
},
"¿Solicitud válida?": {
"main": [
[
{
"node": "Actualizar reporte Supabase",
"type": "main",
"index": 0
}
],
[
{
"node": "Responder error resolución",
"type": "main",
"index": 0
}
]
]
},
"Actualizar reporte Supabase": {
"main": [
[
{
"node": "Preparar correo equipo TT",
"type": "main",
"index": 0
}
]
]
},
"Preparar correo equipo TT": {
"main": [
[
{
"node": "Enviar correo equipo TT",
"type": "main",
"index": 0
}
]
]
},
"Enviar correo equipo TT": {
"main": [
[
{
"node": "Preparar respuesta resuelto",
"type": "main",
"index": 0
}
]
]
},
"Preparar respuesta resuelto": {
"main": [
[
{
"node": "Responder resuelto app",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1",
"binaryMode": "separate",
"availableInMCP": true,
"timeSavedMode": "fixed",
"errorWorkflow": "puF4LUczoSz3hcek",
"timezone": "America/Santo_Domingo",
"callerPolicy": "workflowsFromSameOwner"
},
"staticData": null,
"meta": null,
"versionId": "59895fdc-0362-4c8f-88d1-3f5e866711e0",
"activeVersionId": "59895fdc-0362-4c8f-88d1-3f5e866711e0",
"versionCounter": 25,
"triggerCount": 1,
"shared": [
{
"updatedAt": "2026-07-14T15:32:29.214Z",
"createdAt": "2026-07-14T15:32:29.214Z",
"role": "workflow:owner",
"workflowId": "aihmNdYFskfvf3XF",
"projectId": "PJpTANzTXIFibWsW",
"project": {
"updatedAt": "2026-04-22T14:25:09.686Z",
"createdAt": "2026-04-22T14:22:54.790Z",
"id": "PJpTANzTXIFibWsW",
"name": "Isaac Aracena <iaracena@gomezleemarketing.com>",
"type": "personal",
"icon": null,
"description": null,
"creatorId": "0a88c0b1-928e-4412-896e-c5d1c99b2029"
}
}
],
"tags": [],
"activeVersion": {
"updatedAt": "2026-07-21T16:04:00.000Z",
"createdAt": "2026-07-21T16:03:55.958Z",
"versionId": "59895fdc-0362-4c8f-88d1-3f5e866711e0",
"workflowId": "aihmNdYFskfvf3XF",
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "cruce-cuentas-tt-marcar-resuelto",
"responseMode": "responseNode",
"options": {}
},
"type": "n8n-nodes-base.webhook",
"typeVersion": 2.1,
"position": [
-752,
112
],
"id": "1affa570-6b53-43d0-afab-25aaf5b8da2d",
"name": "Webhook Marcar Resuelto",
"webhookId": "b0f8173c-c81a-4d32-9205-ab0102dec679"
},
{
"parameters": {
"jsCode": "const body = $input.first().json.body || $input.first().json || {};\n\nfunction clean(value) {\n return String(value ?? '').replace(/\\s+/g, ' ').trim();\n}\n\nconst reportId = clean(body.reportId || body.id);\nconst comentarioResolucion = clean(body.comentarioResolucion || body.comentario || '');\nconst resueltoPorNombre = clean(body.resueltoPorNombre || body.userName || 'Usuario GLM');\nconst resueltoPorEmail = clean(body.resueltoPorEmail || body.userEmail || '');\n\nconst errors = [];\n\nif (!reportId) {\n errors.push('No se recibió el ID del reporte.');\n}\n\nif (!comentarioResolucion) {\n errors.push('Debe indicar un comentario de resolución.');\n}\n\nif (comentarioResolucion.length < 10) {\n errors.push('El comentario de resolución debe ser más descriptivo.');\n}\n\nif (errors.length > 0) {\n return [\n {\n json: {\n ok: false,\n stage: 'validacion_resolucion',\n errors,\n reportId,\n },\n },\n ];\n}\n\nreturn [\n {\n json: {\n ok: true,\n stage: 'resolucion_validada',\n reportId,\n comentarioResolucion,\n resueltoPorNombre,\n resueltoPorEmail,\n resolvedAt: new Date().toISOString(),\n },\n },\n];"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
-544,
112
],
"id": "5e78d132-c731-4d6a-8926-8afa88e5df12",
"name": "Validar resolución"
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict",
"version": 3
},
"conditions": [
{
"id": "c89884c6-de96-4b08-bd20-54644bb95bc7",
"leftValue": "={{ $json.ok }}",
"rightValue": "",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
}
}
],
"combinator": "and"
},
"options": {}
},
"type": "n8n-nodes-base.if",
"typeVersion": 2.3,
"position": [
-336,
112
],
"id": "cc34f3e6-40f2-43e3-99f1-0aea4fb502c4",
"name": "¿Solicitud válida?"
},
{
"parameters": {
"method": "PATCH",
"url": "={{ 'https://dbit.digitalcompass.agency/rest/v1/cruces_cuentas_gt_reportes?id=eq.' + encodeURIComponent($json.reportId) + '&country=eq.TT' }}",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "apikey",
"value": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJzZXJ2aWNlX3JvbGUiLAogICAgImlzcyI6ICJzdXBhYmFzZS1kZW1vIiwKICAgICJpYXQiOiAxNjQxNzY5MjAwLAogICAgImV4cCI6IDE3OTk1MzU2MDAKfQ.DaYlNEoUrrEn2Ig7tqibS-PHK5vgusbcbo7X36XVt4Q"
},
{
"name": "Authorization",
"value": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJzZXJ2aWNlX3JvbGUiLAogICAgImlzcyI6ICJzdXBhYmFzZS1kZW1vIiwKICAgICJpYXQiOiAxNjQxNzY5MjAwLAogICAgImV4cCI6IDE3OTk1MzU2MDAKfQ.DaYlNEoUrrEn2Ig7tqibS-PHK5vgusbcbo7X36XVt4Q"
},
{
"name": "Content-Type",
"value": "application/json"
},
{
"name": "Prefer",
"value": "return=representation"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={{\n {\n estado: 'resuelto',\n resuelto_por_nombre: $json.resueltoPorNombre,\n resuelto_por_email: $json.resueltoPorEmail,\n resuelto_en: $json.resolvedAt,\n comentario_resolucion: $json.comentarioResolucion,\n updated_at: $json.resolvedAt\n }\n}}",
"options": {}
},
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.4,
"position": [
0,
0
],
"id": "52b2af1a-ac9f-4b47-9950-2f91e32084b0",
"name": "Actualizar reporte Supabase"
},
{
"parameters": {
"jsCode": "const input = $input.first().json || {};\nconst report = Array.isArray(input) ? input[0] : input;\n\nif (!report || !report.id) {\n throw new Error(\n 'No se encontró un reporte de Trinidad y Tobago con el ID recibido.'\n );\n}\n\nif (String(report.country || '').toUpperCase() !== 'TT') {\n throw new Error(\n 'El reporte localizado no pertenece a Trinidad y Tobago.'\n );\n}\nconst original = $('Validar resolución').first().json || {};\n\n\nfunction escapeHtml(value) {\n return String(value ?? '')\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&#039;');\n}\n\nfunction numberValue(value) {\n const parsed = Number(value);\n return Number.isFinite(parsed) ? parsed : 0;\n}\n\nconst periodo = report.period_label || 'Período no especificado';\nconst reportUrl = report.report_url || '';\n\nconst discrepancias = numberValue(report.discrepancias);\nconst bancoSinNomina = numberValue(report.banco_sin_nomina);\nconst bancoSinBamboo = numberValue(report.banco_sin_bamboo);\nconst nominaSinCuenta = numberValue(report.nomina_sin_cuenta);\n\nconst resolvedAt = original.resolvedAt || new Date().toISOString();\n\nconst resolvedDateLabel = new Date(resolvedAt).toLocaleString('es-DO', {\n timeZone: 'America/Port_of_Spain',\n dateStyle: 'long',\n timeStyle: 'short',\n});\n\nconst resolvedByName =\n original.resueltoPorNombre || 'Usuario GLM';\n\nconst resolvedByEmail =\n original.resueltoPorEmail || '';\n\nconst resolutionComment =\n original.comentarioResolucion || 'Sin comentario registrado.';\n\nconst logoUrl =\n 'https://dbit.digitalcompass.agency/storage/v1/object/public/public-assets/GLM_completo.png';\n\nconst subject =\n `Reporte resuelto - Cruce de Cuentas Trinidad y Tobago - ${periodo}`;\n\nconst textBody = `\nHola equipo,\n\nSe marcó como resuelto un reporte de Cruce de Cuentas Trinidad y Tobago.\n\nPeríodo:\n${periodo}\n\nResuelto por:\n${resolvedByName}${resolvedByEmail ? ` (${resolvedByEmail})` : ''}\n\nFecha/hora:\n${resolvedDateLabel}\n\nResumen:\n- Discrepancias: ${discrepancias}\n- Banco sin nómina: ${bancoSinNomina}\n- Banco sin Bamboo: ${bancoSinBamboo}\n- Nómina sin cuenta: ${nominaSinCuenta}\n\nComentario:\n${resolutionComment}\n\nGoogle Sheet:\n${reportUrl || 'No disponible'}\n\nSaludos,\nPortal Cruce de Cuentas GLM\n`.trim();\n\nconst htmlBody = `\n<!doctype html>\n<html lang=\"es\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width\">\n <title>${escapeHtml(subject)}</title>\n</head>\n\n<body style=\"\n margin:0;\n padding:0;\n background:#F5F5F5;\n font-family:Arial, Helvetica, sans-serif;\n color:#4A4A4A;\n\">\n\n <table\n role=\"presentation\"\n width=\"100%\"\n cellspacing=\"0\"\n cellpadding=\"0\"\n border=\"0\"\n style=\"background:#F5F5F5;padding:24px 12px;\"\n >\n <tr>\n <td align=\"center\">\n\n <table\n role=\"presentation\"\n width=\"640\"\n cellspacing=\"0\"\n cellpadding=\"0\"\n border=\"0\"\n style=\"\n width:100%;\n max-width:640px;\n background:#FFFFFF;\n border:1px solid #D0D0D0;\n border-collapse:separate;\n \"\n >\n\n <tr>\n <td style=\"padding:28px 32px 20px 32px;\">\n <img\n src=\"${escapeHtml(logoUrl)}\"\n width=\"230\"\n alt=\"GomezLee Marketing\"\n style=\"\n display:block;\n width:230px;\n max-width:100%;\n height:auto;\n border:0;\n \"\n >\n </td>\n </tr>\n\n <tr>\n <td style=\"\n height:4px;\n background:#6CC24A;\n font-size:0;\n line-height:0;\n \">&nbsp;</td>\n </tr>\n\n <tr>\n <td style=\"padding:28px 32px 8px 32px;\">\n <div style=\"\n color:#6CC24A;\n font-size:12px;\n font-weight:bold;\n letter-spacing:0.8px;\n text-transform:uppercase;\n margin-bottom:8px;\n \">\n Cruce de Cuentas Trinidad y Tobago\n </div>\n\n <h1 style=\"\n margin:0;\n color:#4F758B;\n font-size:25px;\n line-height:1.25;\n font-weight:700;\n \">\n Reporte marcado como resuelto\n </h1>\n </td>\n </tr>\n\n <tr>\n <td style=\"padding:12px 32px 8px 32px;\">\n <p style=\"\n margin:0 0 16px 0;\n font-size:15px;\n line-height:1.6;\n \">\n Hola equipo,\n </p>\n\n <p style=\"\n margin:0;\n font-size:15px;\n line-height:1.6;\n \">\n El siguiente reporte fue revisado y marcado como\n <strong style=\"color:#4F758B;\">resuelto</strong>.\n </p>\n </td>\n </tr>\n\n <tr>\n <td style=\"padding:20px 32px 8px 32px;\">\n <table\n role=\"presentation\"\n width=\"100%\"\n cellspacing=\"0\"\n cellpadding=\"0\"\n border=\"0\"\n style=\"\n border-collapse:collapse;\n border:1px solid #D0D0D0;\n \"\n >\n <tr>\n <td style=\"\n width:34%;\n padding:11px 14px;\n background:#EEF6E8;\n color:#4F758B;\n font-size:13px;\n font-weight:bold;\n border-bottom:1px solid #D0D0D0;\n \">\n Período\n </td>\n\n <td style=\"\n padding:11px 14px;\n background:#FFFFFF;\n font-size:13px;\n border-bottom:1px solid #D0D0D0;\n \">\n ${escapeHtml(periodo)}\n </td>\n </tr>\n\n <tr>\n <td style=\"\n padding:11px 14px;\n background:#EEF6E8;\n color:#4F758B;\n font-size:13px;\n font-weight:bold;\n border-bottom:1px solid #D0D0D0;\n \">\n Resuelto por\n </td>\n\n <td style=\"\n padding:11px 14px;\n background:#FFFFFF;\n font-size:13px;\n border-bottom:1px solid #D0D0D0;\n \">\n ${escapeHtml(resolvedByName)}\n ${\n resolvedByEmail\n ? `<br><span style=\"color:#6B8FA3;\">${escapeHtml(resolvedByEmail)}</span>`\n : ''\n }\n </td>\n </tr>\n\n <tr>\n <td style=\"\n padding:11px 14px;\n background:#EEF6E8;\n color:#4F758B;\n font-size:13px;\n font-weight:bold;\n \">\n Fecha y hora\n </td>\n\n <td style=\"\n padding:11px 14px;\n background:#FFFFFF;\n font-size:13px;\n \">\n ${escapeHtml(resolvedDateLabel)}\n </td>\n </tr>\n </table>\n </td>\n </tr>\n\n <tr>\n <td style=\"padding:22px 32px 8px 32px;\">\n <div style=\"\n color:#4F758B;\n font-size:15px;\n font-weight:bold;\n border-bottom:2px solid #6CC24A;\n padding-bottom:7px;\n \">\n Resumen del reporte\n </div>\n </td>\n </tr>\n\n <tr>\n <td style=\"padding:12px 32px 8px 32px;\">\n <table\n role=\"presentation\"\n width=\"100%\"\n cellspacing=\"0\"\n cellpadding=\"0\"\n border=\"0\"\n style=\"border-collapse:collapse;\"\n >\n <tr>\n <td style=\"\n width:25%;\n padding:12px 8px;\n text-align:center;\n border:1px solid #D0D0D0;\n background:#FFFFFF;\n \">\n <div style=\"\n color:#4F758B;\n font-size:22px;\n font-weight:bold;\n \">\n ${discrepancias}\n </div>\n\n <div style=\"\n color:#6B8FA3;\n font-size:11px;\n margin-top:4px;\n \">\n Discrepancias\n </div>\n </td>\n\n <td style=\"\n width:25%;\n padding:12px 8px;\n text-align:center;\n border:1px solid #D0D0D0;\n background:#FFFFFF;\n \">\n <div style=\"\n color:#4F758B;\n font-size:22px;\n font-weight:bold;\n \">\n ${bancoSinBamboo}\n </div>\n\n <div style=\"\n color:#6B8FA3;\n font-size:11px;\n margin-top:4px;\n \">\n Banco sin Bamboo\n </div>\n </td>\n\n <td style=\"\n width:25%;\n padding:12px 8px;\n text-align:center;\n border:1px solid #D0D0D0;\n background:#FFFFFF;\n \">\n <div style=\"\n color:#4F758B;\n font-size:22px;\n font-weight:bold;\n \">\n ${bancoSinNomina}\n </div>\n\n <div style=\"\n color:#6B8FA3;\n font-size:11px;\n margin-top:4px;\n \">\n Banco sin nómina\n </div>\n </td>\n\n <td style=\"\n width:25%;\n padding:12px 8px;\n text-align:center;\n border:1px solid #D0D0D0;\n background:#FFFFFF;\n \">\n <div style=\"\n color:#4F758B;\n font-size:22px;\n font-weight:bold;\n \">\n ${nominaSinCuenta}\n </div>\n\n <div style=\"\n color:#6B8FA3;\n font-size:11px;\n margin-top:4px;\n \">\n Nómina sin cuenta\n </div>\n </td>\n </tr>\n </table>\n </td>\n </tr>\n\n <tr>\n <td style=\"padding:22px 32px 8px 32px;\">\n <div style=\"\n color:#4F758B;\n font-size:15px;\n font-weight:bold;\n border-bottom:2px solid #6CC24A;\n padding-bottom:7px;\n \">\n Comentario de resolución\n </div>\n </td>\n </tr>\n\n <tr>\n <td style=\"padding:12px 32px 8px 32px;\">\n <div style=\"\n padding:16px 18px;\n background:#D6E8F4;\n border:1px solid #D0D0D0;\n color:#4A4A4A;\n font-size:14px;\n line-height:1.6;\n \">\n ${escapeHtml(resolutionComment).replace(/\\n/g, '<br>')}\n </div>\n </td>\n </tr>\n\n ${\n reportUrl\n ? `\n <tr>\n <td align=\"center\" style=\"padding:26px 32px 30px 32px;\">\n <a\n href=\"${escapeHtml(reportUrl)}\"\n target=\"_blank\"\n style=\"\n display:inline-block;\n padding:12px 22px;\n background:#4F758B;\n color:#FFFFFF;\n text-decoration:none;\n font-size:14px;\n font-weight:bold;\n border-bottom:4px solid #6CC24A;\n \"\n >\n Abrir Google Sheet\n </a>\n </td>\n </tr>\n `\n : ''\n }\n\n <tr>\n <td style=\"\n padding:18px 32px;\n border-top:1px solid #D0D0D0;\n color:#6B8FA3;\n font-size:11px;\n line-height:1.5;\n \">\n Mensaje automático del Portal Cruce de Cuentas GLM.\n </td>\n </tr>\n\n </table>\n </td>\n </tr>\n </table>\n\n</body>\n</html>\n`.trim();\n\nreturn [\n {\n json: {\n to: 'jgomez@gomezleemarketing.com, mgomez@gomezleemarketing.com, ymadera@gomezleemarketing.com',\n cc: 'iaracena@gomezleemarketing.com',\n subject,\n textBody,\n htmlBody,\n report,\n resolution: original,\n },\n },\n];"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
208,
0
],
"id": "966b80c6-0935-46fe-a700-d073bbc95b2f",
"name": "Preparar correo equipo TT"
},
{
"parameters": {
"sendTo": "={{$json.to}}",
"subject": "={{$json.subject}}",
"message": "={{ $json.htmlBody }}",
"options": {
"appendAttribution": false,
"ccList": "={{ $json.cc }}"
}
},
"type": "n8n-nodes-base.gmail",
"typeVersion": 2.2,
"position": [
416,
0
],
"id": "dc52381c-3e76-4991-bc09-a87472d51d64",
"name": "Enviar correo equipo TT",
"webhookId": "da3b90f2-2e52-4a99-beea-5bc580486f75",
"credentials": {
"gmailOAuth2": {
"id": "UDcO1FLJqA453V2D",
"name": "Gmail account 3"
}
}
},
{
"parameters": {
"jsCode": "const original = $('Validar resolución').first().json || {};\nconst updatedResponse = $('Actualizar reporte Supabase').first().json || {};\nconst updatedReport = Array.isArray(updatedResponse) ? updatedResponse[0] : updatedResponse;\n\nreturn [\n {\n json: {\n ok: true,\n stage: 'reporte_resuelto',\n message: 'Reporte marcado como resuelto correctamente.',\n report: {\n id: original.reportId,\n estado: 'resuelto',\n estadoLabel: 'RESUELTO',\n country: 'TT',\n countryName: 'Trinidad y Tobago',\n resueltoPorNombre: original.resueltoPorNombre,\n resueltoPorEmail: original.resueltoPorEmail,\n resueltoEn: original.resolvedAt,\n comentarioResolucion: original.comentarioResolucion,\n reportUrl: updatedReport.report_url || '',\n },\n },\n },\n];"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
624,
0
],
"id": "d0b12567-ae34-4d7a-8b8c-70e4e855bf35",
"name": "Preparar respuesta resuelto"
},
{
"parameters": {
"respondWith": "json",
"responseBody": "={{ $json }}",
"options": {
"responseCode": 200,
"responseHeaders": {
"entries": [
{
"name": "Content-Type",
"value": "application/json"
},
{
"name": "Access-Control-Allow-Origin",
"value": "*"
},
{
"name": "Access-Control-Allow-Methods",
"value": "GET,POST,OPTIONS"
},
{
"name": "Access-Control-Allow-Headers",
"value": "Content-Type, Authorization"
}
]
}
}
},
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.5,
"position": [
832,
0
],
"id": "f6ea0dba-e017-41f8-9cb4-2685a608a58d",
"name": "Responder resuelto app"
},
{
"parameters": {
"respondWith": "json",
"responseBody": "={{ $json }}",
"options": {
"responseCode": 400,
"responseHeaders": {
"entries": [
{
"name": "Content-Type",
"value": "application/json"
},
{
"name": "Access-Control-Allow-Origin",
"value": "*"
},
{
"name": "Access-Control-Allow-Methods",
"value": "GET,POST,OPTIONS"
},
{
"name": "Access-Control-Allow-Headers",
"value": "Content-Type, Authorization"
}
]
}
}
},
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.5,
"position": [
-128,
208
],
"id": "4fbe8e29-c6b3-4095-8474-4d82a1e8c639",
"name": "Responder error resolución"
},
{
"parameters": {
"content": "# ✅ CIERRE DE REPORTE — TRINIDAD Y TOBAGO\n\nRecibe desde el Portal de Verificación de Nóminas la solicitud para marcar un reporte de Trinidad y Tobago como resuelto.\n\n## Validación inicial\n\nEl Webhook recibe la información enviada por la aplicación y valida datos como:\n\n- Identificador del reporte.\n- Usuario que realizó el cierre.\n- Estado solicitado.\n- Comentario o detalle de resolución.\n- Datos necesarios para localizar el registro en Supabase.\n\nLa solicitud solamente continúa cuando contiene información válida y suficiente.\n\n## Actualización del reporte\n\nCuando la solicitud es correcta:\n\n1. Localiza el reporte correspondiente en Supabase.\n2. Cambia su estado a RESUELTO.\n3. Registra quién realizó la resolución.\n4. Guarda la fecha y hora del cierre.\n5. Conserva el comentario o información de seguimiento disponible.\n\nSupabase es la fuente oficial del estado del reporte dentro del portal.\n\n## Notificación al equipo TT\n\nDespués de actualizar el registro:\n\n1. Se prepara un correo para el equipo responsable de Trinidad y Tobago.\n2. Se incluyen los datos principales del reporte.\n3. Se informa que el caso fue marcado como resuelto.\n4. Se identifica al usuario que realizó el cierre.\n5. Se envía el correo mediante Gmail.\n\nLa notificación permite que el equipo conozca el cambio sin tener que revisar manualmente el portal.\n\n## Respuesta a la aplicación\n\nCuando el proceso termina correctamente:\n\n- Se construye una respuesta de éxito.\n- Se confirma que el reporte fue actualizado.\n- Se devuelve el nuevo estado a la aplicación.\n- El portal puede actualizar inmediatamente su interfaz.\n\n## Ruta de error\n\nCuando la solicitud es inválida:\n\n- No se modifica Supabase.\n- No se envía el correo al equipo TT.\n- Se devuelve una respuesta de error a la aplicación.\n- Se informa que faltan datos o que la solicitud no pudo procesarse.\n\n## Reglas\n\n- No marcar un reporte como resuelto sin un identificador válido.\n- No enviar la notificación antes de confirmar la actualización en Supabase.\n- No declarar éxito cuando la base de datos no fue actualizada.\n- Toda respuesta del Webhook debe cerrarse correctamente para evitar solicitudes abiertas.\n- La ruta de error debe terminar sin realizar cambios parciales.",
"height": 1264,
"width": 2624,
"color": "#28765F"
},
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
-1536,
-480
],
"id": "e58c6673-d3ac-40e1-9b10-ae20e09730af",
"name": "Sticky Note"
}
],
"connections": {
"Webhook Marcar Resuelto": {
"main": [
[
{
"node": "Validar resolución",
"type": "main",
"index": 0
}
]
]
},
"Validar resolución": {
"main": [
[
{
"node": "¿Solicitud válida?",
"type": "main",
"index": 0
}
]
]
},
"¿Solicitud válida?": {
"main": [
[
{
"node": "Actualizar reporte Supabase",
"type": "main",
"index": 0
}
],
[
{
"node": "Responder error resolución",
"type": "main",
"index": 0
}
]
]
},
"Actualizar reporte Supabase": {
"main": [
[
{
"node": "Preparar correo equipo TT",
"type": "main",
"index": 0
}
]
]
},
"Preparar correo equipo TT": {
"main": [
[
{
"node": "Enviar correo equipo TT",
"type": "main",
"index": 0
}
]
]
},
"Enviar correo equipo TT": {
"main": [
[
{
"node": "Preparar respuesta resuelto",
"type": "main",
"index": 0
}
]
]
},
"Preparar respuesta resuelto": {
"main": [
[
{
"node": "Responder resuelto app",
"type": "main",
"index": 0
}
]
]
}
},
"authors": "Isaac Aracena",
"name": "Version 59895fdc",
"description": "",
"autosaved": true,
"workflowPublishHistory": [
{
"createdAt": "2026-07-21T16:04:00.665Z",
"id": 3294,
"workflowId": "aihmNdYFskfvf3XF",
"versionId": "59895fdc-0362-4c8f-88d1-3f5e866711e0",
"event": "activated",
"userId": "0a88c0b1-928e-4412-896e-c5d1c99b2029"
},
{
"createdAt": "2026-07-25T17:29:16.109Z",
"id": 3468,
"workflowId": "aihmNdYFskfvf3XF",
"versionId": "59895fdc-0362-4c8f-88d1-3f5e866711e0",
"event": "activated",
"userId": "0a88c0b1-928e-4412-896e-c5d1c99b2029"
},
{
"createdAt": "2026-07-25T17:29:16.054Z",
"id": 3467,
"workflowId": "aihmNdYFskfvf3XF",
"versionId": "59895fdc-0362-4c8f-88d1-3f5e866711e0",
"event": "deactivated",
"userId": "0a88c0b1-928e-4412-896e-c5d1c99b2029"
}
]
}
}