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

748 lines
56 KiB
JSON

{
"updatedAt": "2026-07-25T17:28:43.601Z",
"createdAt": "2026-07-09T13:29:42.391Z",
"id": "KuJTvjNNx9XmoazA",
"name": "Portal de Verificación de Nómina GT - Envío de Reporte",
"description": "Gestiona la resolución de reportes del Portal de Verificación de Nómina de Guatemala: valida la solicitud recibida desde la aplicación, marca el reporte como resuelto en Supabase, registra los datos de la resolución, envía una notificación por correo a Yanelly 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-gt-marcar-resuelto",
"responseMode": "responseNode",
"options": {}
},
"type": "n8n-nodes-base.webhook",
"typeVersion": 2.1,
"position": [
-560,
32
],
"id": "681b06d3-4b12-441e-b5b2-61b283b8f418",
"name": "Webhook Marcar Resuelto",
"webhookId": "5b7d6bd6-caa6-47e6-b9b8-982f6e7e0a0f"
},
{
"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": [
-352,
32
],
"id": "7df13555-97eb-4c62-be7d-13b12a631cd9",
"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": [
-144,
32
],
"id": "fdaa242f-9e63-4c95-82cd-27f645805f66",
"name": "¿Solicitud válida?"
},
{
"parameters": {
"method": "PATCH",
"url": "={{ 'https://dbit.digitalcompass.agency/rest/v1/cruces_cuentas_gt_reportes?id=eq.' + $json.reportId }}",
"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": [
192,
-80
],
"id": "31b2de6a-89f6-4d69-9712-59e5ee3957e8",
"name": "Actualizar reporte Supabase"
},
{
"parameters": {
"jsCode": "const input = $input.first().json || {};\nconst report = Array.isArray(input) ? input[0] : input;\nconst original = $('Validar resolución').first().json || {};\n\nif (!report || !report.id) {\n throw new Error('No se encontró el reporte para preparar la notificación.');\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 bancoSinBamboo = numberValue(report.banco_sin_bamboo);\nconst nominaSinBamboo = numberValue(report.nomina_sin_bamboo);\nconst bambooSinNomina = numberValue(report.bamboo_sin_nomina);\n\nconst resolvedAt = original.resolvedAt || new Date().toISOString();\n\nconst resolvedDateLabel = new Date(resolvedAt).toLocaleString('es-GT', {\n timeZone: 'America/Guatemala',\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 Guatemala - ${periodo}`;\n\nconst textBody = `\nHola Yanelly,\n\nSe marcó como resuelto un reporte de Cruce de Cuentas Guatemala.\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 Bamboo: ${bancoSinBamboo}\n- Nómina sin Bamboo: ${nominaSinBamboo}\n- Bamboo sin Nómina: ${bambooSinNomina}\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 Guatemala\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 Yanelly,\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 ${nominaSinBamboo}\n </div>\n\n <div style=\"\n color:#6B8FA3;\n font-size:11px;\n margin-top:4px;\n \">\n Nómina 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 ${bambooSinNomina}\n </div>\n\n <div style=\"\n color:#6B8FA3;\n font-size:11px;\n margin-top:4px;\n \">\n Bamboo sin Nómina\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: 'ymadera@gomezleemarketing.com, jgomez@gomezleemarketing.com, mgomez@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": [
400,
-80
],
"id": "fb3f529f-164b-4987-a2af-e99e8544c9b1",
"name": "Preparar correo Yanelly"
},
{
"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": [
608,
-80
],
"id": "86252093-a337-4c18-a733-d7f80a954a1f",
"name": "Enviar correo Yanelly",
"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 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": [
816,
-80
],
"id": "43dd0a1d-3829-46a6-bcf2-349ad4f5754a",
"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": [
1024,
-80
],
"id": "4fcda86c-0bd9-4797-a85a-273ce6876ad8",
"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": [
64,
128
],
"id": "15a0d2a5-d5f7-4da0-ba2b-ea08dc77dc23",
"name": "Responder error resolución"
},
{
"parameters": {
"content": "# ✅ CIERRE DE REPORTE — GUATEMALA\n\nRecibe desde el Portal de Verificación de Nóminas la solicitud para marcar un reporte de Guatemala como resuelto.\n\n## Validación de la solicitud\n\nEl Webhook recibe la información enviada por la aplicación y verifica que existan los datos necesarios para procesar el cierre, como:\n\n- Identificador del reporte.\n- Usuario que realizó la resolución.\n- Nuevo estado solicitado.\n- Comentario o detalle de la resolución.\n- Información necesaria para localizar el registro en Supabase.\n\nLa solicitud solamente continúa cuando los datos son válidos y suficientes.\n\n## Actualización en Supabase\n\nCuando la solicitud es correcta:\n\n1. Localiza el reporte correspondiente.\n2. Actualiza su estado a RESUELTO.\n3. Registra el usuario responsable del cierre.\n4. Guarda la fecha y hora de resolución.\n5. Conserva el comentario o detalle proporcionado.\n\nSupabase es la fuente oficial del estado mostrado en el Portal de Verificación de Nóminas.\n\n## Notificación a Yanelly\n\nDespués de confirmar la actualización:\n\n1. Se prepara un correo con los datos principales del reporte.\n2. Se informa que el caso de Guatemala fue marcado como resuelto.\n3. Se identifica al usuario que realizó el cierre.\n4. Se incluye el comentario de resolución, cuando esté disponible.\n5. Se envía la notificación a Yanelly mediante Gmail.\n\nEl correo solamente debe enviarse después de comprobar que Supabase fue actualizado correctamente.\n\n## Respuesta a la aplicación\n\nCuando el proceso termina correctamente:\n\n- Se construye una respuesta de éxito.\n- Se confirma el nuevo estado del reporte.\n- Se devuelve el resultado a la aplicación.\n- El portal puede actualizar inmediatamente la interfaz.\n\n## Ruta de error\n\nCuando la solicitud no supera la validación:\n\n- No se modifica el reporte en Supabase.\n- No se envía ningún correo.\n- Se devuelve una respuesta de error a la aplicación.\n- Se informa que la solicitud contiene datos incompletos o inválidos.\n\n## Reglas\n\n- No marcar un reporte como resuelto sin un identificador válido.\n- No enviar el correo antes de confirmar la actualización.\n- No declarar éxito si Supabase devolvió un error.\n- Evitar cambios parciales entre la base de datos y la notificación.\n- Ambas rutas deben responder al Webhook para evitar solicitudes abiertas.\n- La ruta inválida debe finalizar sin modificar información.",
"height": 1248,
"width": 2624,
"color": "#832F2F"
},
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
-1376,
-624
],
"id": "b9408dc9-bbab-4585-bf2a-9f88f5fe8eaa",
"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 Yanelly",
"type": "main",
"index": 0
}
]
]
},
"Preparar correo Yanelly": {
"main": [
[
{
"node": "Enviar correo Yanelly",
"type": "main",
"index": 0
}
]
]
},
"Enviar correo Yanelly": {
"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": {
"templateCredsSetupCompleted": true
},
"versionId": "afe39c11-be81-4a06-8937-36adaf938182",
"activeVersionId": "afe39c11-be81-4a06-8937-36adaf938182",
"versionCounter": 159,
"triggerCount": 1,
"shared": [
{
"updatedAt": "2026-07-09T13:29:42.395Z",
"createdAt": "2026-07-09T13:29:42.395Z",
"role": "workflow:owner",
"workflowId": "KuJTvjNNx9XmoazA",
"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-21T21:09:53.000Z",
"createdAt": "2026-07-21T21:09:51.188Z",
"versionId": "afe39c11-be81-4a06-8937-36adaf938182",
"workflowId": "KuJTvjNNx9XmoazA",
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "cruce-cuentas-gt-marcar-resuelto",
"responseMode": "responseNode",
"options": {}
},
"type": "n8n-nodes-base.webhook",
"typeVersion": 2.1,
"position": [
-560,
32
],
"id": "681b06d3-4b12-441e-b5b2-61b283b8f418",
"name": "Webhook Marcar Resuelto",
"webhookId": "5b7d6bd6-caa6-47e6-b9b8-982f6e7e0a0f"
},
{
"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": [
-352,
32
],
"id": "7df13555-97eb-4c62-be7d-13b12a631cd9",
"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": [
-144,
32
],
"id": "fdaa242f-9e63-4c95-82cd-27f645805f66",
"name": "¿Solicitud válida?"
},
{
"parameters": {
"method": "PATCH",
"url": "={{ 'https://dbit.digitalcompass.agency/rest/v1/cruces_cuentas_gt_reportes?id=eq.' + $json.reportId }}",
"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": [
192,
-80
],
"id": "31b2de6a-89f6-4d69-9712-59e5ee3957e8",
"name": "Actualizar reporte Supabase"
},
{
"parameters": {
"jsCode": "const input = $input.first().json || {};\nconst report = Array.isArray(input) ? input[0] : input;\nconst original = $('Validar resolución').first().json || {};\n\nif (!report || !report.id) {\n throw new Error('No se encontró el reporte para preparar la notificación.');\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 bancoSinBamboo = numberValue(report.banco_sin_bamboo);\nconst nominaSinBamboo = numberValue(report.nomina_sin_bamboo);\nconst bambooSinNomina = numberValue(report.bamboo_sin_nomina);\n\nconst resolvedAt = original.resolvedAt || new Date().toISOString();\n\nconst resolvedDateLabel = new Date(resolvedAt).toLocaleString('es-GT', {\n timeZone: 'America/Guatemala',\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 Guatemala - ${periodo}`;\n\nconst textBody = `\nHola Yanelly,\n\nSe marcó como resuelto un reporte de Cruce de Cuentas Guatemala.\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 Bamboo: ${bancoSinBamboo}\n- Nómina sin Bamboo: ${nominaSinBamboo}\n- Bamboo sin Nómina: ${bambooSinNomina}\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 Guatemala\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 Yanelly,\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 ${nominaSinBamboo}\n </div>\n\n <div style=\"\n color:#6B8FA3;\n font-size:11px;\n margin-top:4px;\n \">\n Nómina 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 ${bambooSinNomina}\n </div>\n\n <div style=\"\n color:#6B8FA3;\n font-size:11px;\n margin-top:4px;\n \">\n Bamboo sin Nómina\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: 'ymadera@gomezleemarketing.com, jgomez@gomezleemarketing.com, mgomez@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": [
400,
-80
],
"id": "fb3f529f-164b-4987-a2af-e99e8544c9b1",
"name": "Preparar correo Yanelly"
},
{
"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": [
608,
-80
],
"id": "86252093-a337-4c18-a733-d7f80a954a1f",
"name": "Enviar correo Yanelly",
"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 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": [
816,
-80
],
"id": "43dd0a1d-3829-46a6-bcf2-349ad4f5754a",
"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": [
1024,
-80
],
"id": "4fcda86c-0bd9-4797-a85a-273ce6876ad8",
"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": [
64,
128
],
"id": "15a0d2a5-d5f7-4da0-ba2b-ea08dc77dc23",
"name": "Responder error resolución"
},
{
"parameters": {
"content": "# ✅ CIERRE DE REPORTE — GUATEMALA\n\nRecibe desde el Portal de Verificación de Nóminas la solicitud para marcar un reporte de Guatemala como resuelto.\n\n## Validación de la solicitud\n\nEl Webhook recibe la información enviada por la aplicación y verifica que existan los datos necesarios para procesar el cierre, como:\n\n- Identificador del reporte.\n- Usuario que realizó la resolución.\n- Nuevo estado solicitado.\n- Comentario o detalle de la resolución.\n- Información necesaria para localizar el registro en Supabase.\n\nLa solicitud solamente continúa cuando los datos son válidos y suficientes.\n\n## Actualización en Supabase\n\nCuando la solicitud es correcta:\n\n1. Localiza el reporte correspondiente.\n2. Actualiza su estado a RESUELTO.\n3. Registra el usuario responsable del cierre.\n4. Guarda la fecha y hora de resolución.\n5. Conserva el comentario o detalle proporcionado.\n\nSupabase es la fuente oficial del estado mostrado en el Portal de Verificación de Nóminas.\n\n## Notificación a Yanelly\n\nDespués de confirmar la actualización:\n\n1. Se prepara un correo con los datos principales del reporte.\n2. Se informa que el caso de Guatemala fue marcado como resuelto.\n3. Se identifica al usuario que realizó el cierre.\n4. Se incluye el comentario de resolución, cuando esté disponible.\n5. Se envía la notificación a Yanelly mediante Gmail.\n\nEl correo solamente debe enviarse después de comprobar que Supabase fue actualizado correctamente.\n\n## Respuesta a la aplicación\n\nCuando el proceso termina correctamente:\n\n- Se construye una respuesta de éxito.\n- Se confirma el nuevo estado del reporte.\n- Se devuelve el resultado a la aplicación.\n- El portal puede actualizar inmediatamente la interfaz.\n\n## Ruta de error\n\nCuando la solicitud no supera la validación:\n\n- No se modifica el reporte en Supabase.\n- No se envía ningún correo.\n- Se devuelve una respuesta de error a la aplicación.\n- Se informa que la solicitud contiene datos incompletos o inválidos.\n\n## Reglas\n\n- No marcar un reporte como resuelto sin un identificador válido.\n- No enviar el correo antes de confirmar la actualización.\n- No declarar éxito si Supabase devolvió un error.\n- Evitar cambios parciales entre la base de datos y la notificación.\n- Ambas rutas deben responder al Webhook para evitar solicitudes abiertas.\n- La ruta inválida debe finalizar sin modificar información.",
"height": 1248,
"width": 2624,
"color": "#832F2F"
},
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
-1376,
-624
],
"id": "b9408dc9-bbab-4585-bf2a-9f88f5fe8eaa",
"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 Yanelly",
"type": "main",
"index": 0
}
]
]
},
"Preparar correo Yanelly": {
"main": [
[
{
"node": "Enviar correo Yanelly",
"type": "main",
"index": 0
}
]
]
},
"Enviar correo Yanelly": {
"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 afe39c11",
"description": "",
"autosaved": true,
"workflowPublishHistory": [
{
"createdAt": "2026-07-21T21:09:53.675Z",
"id": 3318,
"workflowId": "KuJTvjNNx9XmoazA",
"versionId": "afe39c11-be81-4a06-8937-36adaf938182",
"event": "activated",
"userId": "0a88c0b1-928e-4412-896e-c5d1c99b2029"
},
{
"createdAt": "2026-07-25T17:28:43.729Z",
"id": 3462,
"workflowId": "KuJTvjNNx9XmoazA",
"versionId": "afe39c11-be81-4a06-8937-36adaf938182",
"event": "activated",
"userId": "0a88c0b1-928e-4412-896e-c5d1c99b2029"
},
{
"createdAt": "2026-07-25T17:28:43.681Z",
"id": 3461,
"workflowId": "KuJTvjNNx9XmoazA",
"versionId": "afe39c11-be81-4a06-8937-36adaf938182",
"event": "deactivated",
"userId": "0a88c0b1-928e-4412-896e-c5d1c99b2029"
}
]
}
}