diff --git a/glmway-workflow.json b/glmway-workflow.json index 700c590..4451e5c 100644 --- a/glmway-workflow.json +++ b/glmway-workflow.json @@ -1,6 +1,6 @@ { "$json": { - "updatedAt": "2026-07-06T20:58:21.467Z", + "updatedAt": "2026-07-21T15:16:43.905Z", "createdAt": "2026-06-08T13:50:12.174Z", "id": "F1iPg8hktNAebZua", "name": "GLMWay", @@ -290,8 +290,8 @@ "type": "n8n-nodes-base.googleSheets", "typeVersion": 4.7, "position": [ - 2752, - 1328 + 2672, + 1840 ], "id": "b7a1afb4-5e9c-4fc0-8a64-99b2b71c918e", "name": "Get row(s) in sheet1", @@ -630,8 +630,8 @@ "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ - 2544, - 1328 + 2464, + 1840 ], "id": "a088f9b0-7ec6-40d0-9a90-fa2047ab0461", "name": "Cambiar formato de fecha" @@ -920,10 +920,6 @@ "fieldId": "departamento", "fieldValue": "={{ $('Get an employee').item.json.department }}" }, - { - "fieldId": "supervisor_id", - "fieldValue": "={{ $('Informacion extra del empleado').item.json.supervisorEId }}" - }, { "fieldId": "fecha_ingreso", "fieldValue": "={{ $('Informacion extra del empleado').item.json.hireDate }}" @@ -1178,7 +1174,7 @@ "parameters": { "content": "## Recordatorio a coordinador RRHH 48 y 24 horas antes de la sesion\n", "height": 496, - "width": 2640, + "width": 3152, "color": 6 }, "type": "n8n-nodes-base.stickyNote", @@ -1267,14 +1263,14 @@ "mode": "list", "cachedResultName": "ethen@gomezleemarketing.com" }, - "triggerOn": "eventStarted", + "triggerOn": "eventEnded", "options": {} }, "type": "n8n-nodes-base.googleCalendarTrigger", "typeVersion": 1, "position": [ - -544, - 3552 + -736, + 3616 ], "id": "35ec709a-30fd-4e3b-8492-cf6d8928e372", "name": "Prueba", @@ -1673,7 +1669,7 @@ "parameters": { "content": "## Notificacion a facilitador\n\n- Manda un listado de las personas inscritas en la sesion del miercoles al facilitador.\n- Si no hay personas inscritas envia un alerta al facilitador.", "height": 768, - "width": 1392, + "width": 2112, "color": 3 }, "type": "n8n-nodes-base.stickyNote", @@ -1687,7 +1683,7 @@ }, { "parameters": { - "sendTo": "=eidan.then14@gmail.com", + "sendTo": "={{ $('Loop Over Items1').item.json.email }}", "subject": "Entrenamiento #TheGLMWay", "emailType": "text", "message": "=¡Hola, GLMer!\n\nEste es un recordatorio de tu entrenamiento, donde te transmitiremos nuestra cultura, nuestro ADN y por qué somos diferentes al resto.\n\n¡Te esperamos puntual y con toda la energía para aprender!\n\nÚnete aquí:\n\n{{ $('Obtener sesion').item.json.enlace_reunion }}", @@ -1713,7 +1709,7 @@ }, { "parameters": { - "sendTo": "=eidan.then14@gmail.com", + "sendTo": "={{ $('Loop Over Items1').item.json.email }}", "subject": "#TheGLMWay Training", "emailType": "text", "message": "=Hello, GLMer!\n\nThis is a reminder about your training session, where we'll share our culture, our DNA, and what makes us different from the rest.\n\nWe're looking forward to seeing you on time and ready to learn!\n\nJoin here:\n\n{{ $('Obtener sesion').item.json.enlace_reunion }}", @@ -1865,6 +1861,7 @@ "id": "3a6f198b-e136-49fb-a171-78164e10b600", "name": "Obtener coordinador1", "alwaysOutputData": true, + "retryOnFail": true, "credentials": { "googleSheetsOAuth2Api": { "id": "8Pp0ek3NPsEkyXfY", @@ -1951,8 +1948,8 @@ "type": "n8n-nodes-base.googleCalendar", "typeVersion": 1.3, "position": [ - 1520, - 2080 + 1664, + 3040 ], "id": "7dd9a706-4d80-45c6-942a-c703eb074a20", "name": "Entrenamiento español2", @@ -1981,8 +1978,8 @@ "type": "n8n-nodes-base.googleCalendar", "typeVersion": 1.3, "position": [ - 1520, - 1904 + 1664, + 2864 ], "id": "d8253a7a-4e37-4c14-b4da-e0029571cd21", "name": "Entrenamiento ingles5", @@ -2520,8 +2517,8 @@ "type": "n8n-nodes-base.supabase", "typeVersion": 1, "position": [ - 1360, - 864 + 1376, + 880 ], "id": "ddf0a273-d3bc-44cc-888b-d789ce72ff77", "name": "Actualizar estado a recordado", @@ -2545,8 +2542,8 @@ "type": "n8n-nodes-base.gmail", "typeVersion": 2.2, "position": [ - 1744, - 1584 + 2240, + 2064 ], "id": "39331d88-6f2b-4df1-ac76-dda9ff47dfec", "name": "Send a message espanol3", @@ -2556,8 +2553,7 @@ "id": "QWNicjw1khRm5BVI", "name": "Eidan - Gmail account" } - }, - "disabled": true + } }, { "parameters": { @@ -2572,8 +2568,8 @@ "type": "n8n-nodes-base.gmail", "typeVersion": 2.2, "position": [ - 1744, - 1408 + 2240, + 1888 ], "id": "9d4f57a4-ac2f-49bd-b5fa-50658a8d928e", "name": "Send a message ingles3", @@ -2583,15 +2579,18 @@ "id": "QWNicjw1khRm5BVI", "name": "Eidan - Gmail account" } - }, - "disabled": true + } }, { "parameters": { "rule": { "interval": [ { - "triggerAtHour": 9 + "field": "weeks", + "triggerAtDay": [ + 2 + ], + "triggerAtHour": 16 } ] } @@ -2612,8 +2611,8 @@ "type": "n8n-nodes-base.splitInBatches", "typeVersion": 3, "position": [ - -16, - 1568 + 416, + 1296 ], "id": "7545364a-df0a-4420-a1af-5bcd4f8c9602", "name": "Loop Over Items2" @@ -2625,8 +2624,8 @@ "type": "n8n-nodes-base.wait", "typeVersion": 1.1, "position": [ - 1536, - 1296 + 1856, + 1136 ], "id": "617ab85d-23a6-4546-9331-eff343d9b1c5", "name": "Wait3", @@ -2644,7 +2643,7 @@ "conditions": [ { "id": "9674fd7e-dd62-42d4-8931-6c67e59e3dd7", - "leftValue": "={{ Object.keys($json)[0] }}", + "leftValue": "={{ $json.pais }}", "rightValue": "Jamaica", "operator": { "type": "string", @@ -2653,7 +2652,7 @@ }, { "id": "32931394-f4ea-4055-b866-906a81988173", - "leftValue": "={{ Object.keys($json)[0] }}", + "leftValue": "={{ $json.pais }}", "rightValue": "Trinidad and Tobago", "operator": { "type": "string", @@ -2662,7 +2661,7 @@ }, { "id": "ea2a8466-96c6-460f-b08f-d23c06b2d18c", - "leftValue": "={{ Object.keys($json)[0] }}", + "leftValue": "={{ $json.pais }}", "rightValue": "Barbados", "operator": { "type": "string", @@ -2671,7 +2670,7 @@ }, { "id": "28e49217-0c1a-4462-9642-676e54926d3e", - "leftValue": "={{ Object.keys($json)[0] }}", + "leftValue": "={{ $json.pais }}", "rightValue": "Saint Thomas", "operator": { "type": "string", @@ -2680,7 +2679,7 @@ }, { "id": "c6a6aea5-48f4-44dc-92ca-a9f9de9cacf9", - "leftValue": "={{ Object.keys($json)[0] }}", + "leftValue": "={{ $json.pais }}", "rightValue": "St. Croix", "operator": { "type": "string", @@ -2689,7 +2688,7 @@ }, { "id": "e6f52339-ea7c-462f-bdc2-8b7353160e4c", - "leftValue": "={{ Object.keys($json)[0] }}", + "leftValue": "={{ $json.pais }}", "rightValue": "Tobago", "operator": { "type": "string", @@ -2698,7 +2697,7 @@ }, { "id": "b308c2b6-53b4-4d49-b540-cdc03e36528b", - "leftValue": "={{ Object.keys($json)[0] }}", + "leftValue": "={{ $json.pais }}", "rightValue": "Guyana", "operator": { "type": "string", @@ -2707,7 +2706,7 @@ }, { "id": "35a50a33-a2b5-4116-9336-11300357569e", - "leftValue": "={{ Object.keys($json)[0] }}", + "leftValue": "={{ $json.pais }}", "rightValue": "Aruba", "operator": { "type": "string", @@ -2722,7 +2721,7 @@ "type": "n8n-nodes-base.if", "typeVersion": 2.2, "position": [ - 1424, + 1824, 1440 ], "id": "13ee807a-f1cd-48ef-921b-7b5c260ba116", @@ -2756,8 +2755,8 @@ "type": "n8n-nodes-base.if", "typeVersion": 2.2, "position": [ - 416, - 1568 + -32, + 1376 ], "id": "0fea4950-f873-4375-8964-45cfc3fead02", "name": "Falta 48h para el evento?1" @@ -3004,7 +3003,7 @@ { "parameters": { "operation": "get", - "employeeId": "=50764", + "employeeId": "=50821", "options": {} }, "type": "n8n-nodes-base.bambooHr", @@ -3157,20 +3156,6 @@ } } }, - { - "parameters": { - "url": "=https://www.googleapis.com/calendar/v3/calendars/primary/events/{{ $json.id }}", - "options": {} - }, - "type": "n8n-nodes-base.httpRequest", - "typeVersion": 4.4, - "position": [ - 112, - 3488 - ], - "id": "602289b9-3c7d-4ced-b507-b27401ed9910", - "name": "HTTP Request1" - }, { "parameters": { "url": "=https://www.googleapis.com/calendar/v3/calendars/primary/events/{{ $json.id }}", @@ -3248,13 +3233,9 @@ }, { "parameters": { - "url": "=https://meet.googleapis.com/v2/conferenceRecords/6nSLUwAKD6mX-LzgI_J7DxIXOAIIigIgABgBCA/participants", + "url": "=https://meet.googleapis.com/v2/{{ $json.conferenceRecords[4].name }}/participants", "authentication": "predefinedCredentialType", "nodeCredentialType": "googleOAuth2Api", - "sendQuery": true, - "queryParameters": { - "parameters": [] - }, "options": {} }, "type": "n8n-nodes-base.httpRequest", @@ -3671,139 +3652,19 @@ "id": "0db9e6a4-2e5e-4513-97fd-71d22aa90822", "name": "Calcular sesion mas cercana4" }, - { - "parameters": { - "sendTo": "=eidan.then14@gmail.com", - "subject": "Entrenamiento #TheGLMWay", - "emailType": "text", - "message": "=Hello,\n\nI am writing to inform you that there are no registered participants for today's scheduled activity.\n\nBest regards", - "options": { - "appendAttribution": false - } - }, - "type": "n8n-nodes-base.gmail", - "typeVersion": 2.2, - "position": [ - 624, - 2432 - ], - "id": "0cf2219c-db12-4231-bac6-8e5f2816530f", - "name": "Send a message espanol5", - "webhookId": "a6043707-89d1-4c99-8de2-e60d9aaf7ed2", - "credentials": { - "gmailOAuth2": { - "id": "QWNicjw1khRm5BVI", - "name": "Eidan - Gmail account" - } - } - }, - { - "parameters": { - "sendTo": "=eidan.then14@gmail.com", - "subject": "#TheGLMWay Training", - "emailType": "text", - "message": "=Hello,\n\nThis is to inform you that, as of now, there are no people enrolled for today's activity.\n\nBest regards.\n\nThis is an automated message generated by the enrollment management system.", - "options": { - "appendAttribution": false - } - }, - "type": "n8n-nodes-base.gmail", - "typeVersion": 2.2, - "position": [ - 624, - 2256 - ], - "id": "96bac1b9-d921-418d-947d-f07980bb76aa", - "name": "Send a message ingles5", - "webhookId": "a6043707-89d1-4c99-8de2-e60d9aaf7ed2", - "credentials": { - "gmailOAuth2": { - "id": "QWNicjw1khRm5BVI", - "name": "Eidan - Gmail account" - } - } - }, - { - "parameters": { - "conditions": { - "options": { - "caseSensitive": true, - "leftValue": "", - "typeValidation": "strict", - "version": 3 - }, - "conditions": [ - { - "id": "df25aa3e-d48f-4e52-ae1f-47678e954d52", - "leftValue": "={{ $('Obtener sesion1').item.json.idioma }}", - "rightValue": "EN", - "operator": { - "type": "string", - "operation": "equals", - "name": "filter.operator.equals" - } - } - ], - "combinator": "and" - }, - "options": {} - }, - "type": "n8n-nodes-base.if", - "typeVersion": 2.3, - "position": [ - 416, - 2352 - ], - "id": "748f3ae7-7e6d-41f5-be1d-861a9566ec00", - "name": "Es espanol o ingles" - }, { "parameters": { "content": "## Falta añadir mensaje de aviso" }, "type": "n8n-nodes-base.stickyNote", "position": [ - 912, - 1904 + 1872, + 2944 ], "typeVersion": 1, "id": "2d9a27b5-9ca6-4518-bd06-3a91389c4736", "name": "Sticky Note9" }, - { - "parameters": { - "conditions": { - "options": { - "caseSensitive": true, - "leftValue": "", - "typeValidation": "strict", - "version": 3 - }, - "conditions": [ - { - "id": "df25aa3e-d48f-4e52-ae1f-47678e954d52", - "leftValue": "={{ $json.foundSession }}", - "rightValue": "EN", - "operator": { - "type": "boolean", - "operation": "true", - "singleValue": true - } - } - ], - "combinator": "and" - }, - "options": {} - }, - "type": "n8n-nodes-base.if", - "typeVersion": 2.3, - "position": [ - 2000, - 1136 - ], - "id": "03832c44-864b-4277-a9fb-f94d56dc0f1c", - "name": "Hay sesion?" - }, { "parameters": { "content": "## Al final añadir flujo para resetear los estados de los coordinadores e instructores", @@ -3883,8 +3744,8 @@ "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ - 208, - 1568 + -224, + 1376 ], "id": "e8d383b8-9081-4829-8516-a03f6f5a1b63", "name": "Calcular falta 48h o 24h" @@ -3952,7 +3813,7 @@ "type": "n8n-nodes-base.if", "typeVersion": 2.3, "position": [ - 592, + 208, 1568 ], "id": "334a5703-db8a-4a88-b528-8468ee61ddbc", @@ -3960,7 +3821,7 @@ }, { "parameters": { - "jsCode": "// Sesión válida (salida del nodo \"Calcular falta 48h o 24h\")\nconst sesion = $(\"Calcular falta 48h o 24h\").first().json.sesion;\n\n// Coordinadores\nconst coordinadores = $(\"Obtener coordinadores1\").all().map(i => i.json);\n\nconst resultado = [];\n\n// Participantes viene como:\n// {\n// \"Colombia\": [...],\n// \"Mexico\": [...]\n// }\nconst participantesPorPais = sesion.participantes || {};\n\nfor (const [pais, participantes] of Object.entries(participantesPorPais)) {\n\n // Buscar coordinador del país\n const coordinador = coordinadores.find(c => c.pais === pais);\n\n resultado.push({\n json: {\n [pais]: {\n coordinador: coordinador\n ? {\n nombre: coordinador.nombre,\n correo: coordinador.correo\n }\n : null,\n\n participantes\n }\n }\n });\n\n}\n\nreturn resultado;" + "jsCode": "// 1. Obtener la sesión del nodo anterior\nconst datosNodoAnterior = $(\"Calcular falta 48h o 24h1\").first().json;\nconst sesion = datosNodoAnterior.sesion;\nconst participantesPorPais = sesion?.participantes || {};\n\n// 2. Obtener todos los coordinadores\nconst coordinadores = $(\"Obtener coordinadores1\").all().map(i => i.json);\n\nconst resultado = [];\n\n// Función para quitar acentos y dejar en minúsculas (evita fallos de coincidencia)\nconst limpiarTexto = (texto) => \n texto ? texto.toLowerCase().normalize(\"NFD\").replace(/[\\u0300-\\u036f]/g, \"\").trim() : \"\";\n\n// 3. Recorrer los países que tienen participantes en la sesión\nfor (const [paisParticipante] of Object.entries(participantesPorPais)) {\n\n // Buscar el coordinador cuyo país coincida limpiando acentos\n const coordinadorMatch = coordinadores.find(c => \n limpiarTexto(c.pais) === limpiarTexto(paisParticipante)\n );\n\n resultado.push({\n json: {\n pais: paisParticipante,\n coordinador: coordinadorMatch \n ? {\n nombre: coordinadorMatch.nombre,\n correo: coordinadorMatch.correo,\n pais_coordinador: coordinadorMatch.pais\n } \n : null,\n }\n });\n}\n\nreturn resultado;" }, "type": "n8n-nodes-base.code", "typeVersion": 2, @@ -3971,19 +3832,6 @@ "id": "3073d739-a2c7-4ba1-81bc-aeae266ad3ff", "name": "Matchear coordinador y pais inscrito" }, - { - "parameters": { - "options": {} - }, - "type": "n8n-nodes-base.splitInBatches", - "typeVersion": 3, - "position": [ - 1152, - 1440 - ], - "id": "15c6bc9c-047f-4f56-ac8e-9a1d40b816a7", - "name": "Loop Over Items3" - }, { "parameters": { "amount": 2 @@ -3991,8 +3839,8 @@ "type": "n8n-nodes-base.wait", "typeVersion": 1.1, "position": [ - 2128, - 1504 + 2640, + 1488 ], "id": "8fef83c7-d197-484c-b40f-817a198bf5fc", "name": "Wait6", @@ -4023,8 +3871,8 @@ "type": "n8n-nodes-base.supabase", "typeVersion": 1, "position": [ - 1952, - 1504 + 2464, + 1488 ], "id": "0881ba84-bd04-4e91-9c09-0ba18e28ed28", "name": "Actualizar estado a notificado", @@ -4047,7 +3895,7 @@ "conditions": [ { "id": "df25aa3e-d48f-4e52-ae1f-47678e954d52", - "leftValue": "={{ $json.session.participantes }}", + "leftValue": "={{ $('Calcular sesion mas cercana4').item.json.session.participantes }}", "rightValue": "EN", "operator": { "type": "object", @@ -4063,7 +3911,7 @@ "type": "n8n-nodes-base.if", "typeVersion": 2.3, "position": [ - 192, + 864, 2144 ], "id": "d1472787-4c2f-4e1d-8673-5c2368d469ab", @@ -4150,7 +3998,7 @@ }, "sendBody": true, "specifyBody": "json", - "jsonBody": "={\n \"p_sesion_id\": \"{{ $('Calcular sesion mas cercana2').item.json.session.id }}\",\n \"p_pais\": \"{{ $json.pais }}\",\n \"p_empleados\": [\n {\n \"nombre\": \"{{ $json.nombre }}\",\n \"correo\": \"{{ $json.email }}\",\n \"departamento\": \"{{ $json.departamento }}\",\n \"division\": \"{{ $json.division }}\"\n }\n ]\n}", + "jsonBody": "={\n \"p_sesion_id\": \"{{ $('Calcular sesion mas cercana2').item.json.session.id }}\",\n \"p_pais\": \"{{ $('Get an employee1').item.json.location }}\",\n \"p_empleados\": [\n {\n \"nombre\": \"{{ $('Get an employee1').item.json.displayName }}\",\n \"correo\": \"{{ $('Get an employee1').item.json.workEmail }}\",\n \"departamento\": \"{{ $('Get an employee1').item.json.department }}\",\n \"division\": \"{{ $('Get an employee1').item.json.division }}\"\n }\n ]\n}", "options": {} }, "type": "n8n-nodes-base.httpRequest", @@ -4181,7 +4029,7 @@ }, "sendBody": true, "specifyBody": "json", - "jsonBody": "={\n \"p_sesion_id\": \"{{ $('Calcular sesion mas cercana3').item.json.session.id }}\",\n \"p_pais\": \"{{ $json.pais }}\",\n \"p_empleados\": [\n {\n \"nombre\": \"{{ $json.nombre }}\",\n \"correo\": \"{{ $json.email }}\",\n \"departamento\": \"{{ $json.departamento }}\",\n \"division\": \"{{ $json.division }}\"\n }\n ]\n}", + "jsonBody": "={\n \"p_sesion_id\": \"{{ $('Calcular sesion mas cercana3').item.json.session.id }}\",\n \"p_pais\": \"{{ $('Get an employee1').item.json.location }}\",\n \"p_empleados\": [\n {\n \"nombre\": \"{{ $('Get an employee1').item.json.displayName }}\",\n \"correo\": \"{{ $('Get an employee1').item.json.workEmail }}\",\n \"departamento\": \"{{ $('Get an employee1').item.json.department }}\",\n \"division\": \"{{ $('Get an employee1').item.json.division }}\"\n }\n ]\n}", "options": {} }, "type": "n8n-nodes-base.httpRequest", @@ -4258,8 +4106,8 @@ "type": "n8n-nodes-base.gmail", "typeVersion": 2.2, "position": [ - 624, - 2032 + 1872, + 2784 ], "id": "3167fd45-4eae-4db4-92fb-9c80223cb4fa", "name": "Send a message espanol6", @@ -4272,67 +4120,6 @@ }, "disabled": true }, - { - "parameters": { - "sendTo": "={{ $json.session.correo_instructor }}", - "subject": "#TheGLMWay Training", - "emailType": "text", - "message": "=Hello,\n\nThis is to inform you that, as of now, there are no people enrolled for today's activity.\n\nBest regards.\n\nThis is an automated message generated by the enrollment management system.", - "options": { - "appendAttribution": false - } - }, - "type": "n8n-nodes-base.gmail", - "typeVersion": 2.2, - "position": [ - 624, - 1856 - ], - "id": "0cd1d4fb-062f-42ca-bf9c-1424e17d50f0", - "name": "Send a message ingles6", - "webhookId": "a6043707-89d1-4c99-8de2-e60d9aaf7ed2", - "credentials": { - "gmailOAuth2": { - "id": "QWNicjw1khRm5BVI", - "name": "Eidan - Gmail account" - } - }, - "disabled": true - }, - { - "parameters": { - "conditions": { - "options": { - "caseSensitive": true, - "leftValue": "", - "typeValidation": "strict", - "version": 3 - }, - "conditions": [ - { - "id": "df25aa3e-d48f-4e52-ae1f-47678e954d52", - "leftValue": "={{ $json.session.idioma }}", - "rightValue": "EN", - "operator": { - "type": "string", - "operation": "equals", - "name": "filter.operator.equals" - } - } - ], - "combinator": "and" - }, - "options": {} - }, - "type": "n8n-nodes-base.if", - "typeVersion": 2.3, - "position": [ - 416, - 1936 - ], - "id": "dd5cce8e-ef5a-4bd4-967c-aec464f30fc4", - "name": "Es espanol o ingles1" - }, { "parameters": { "jsCode": "const TIMEZONES = {\n \"Argentina\": \"America/Argentina/Buenos_Aires\",\n \"Bolivia\": \"America/La_Paz\",\n \"Brasil\": \"America/Sao_Paulo\",\n \"Chile\": \"America/Santiago\",\n \"Colombia\": \"America/Bogota\",\n \"Costa Rica\": \"America/Costa_Rica\",\n \"Cuba\": \"America/Havana\",\n \"Ecuador\": \"America/Guayaquil\",\n \"El Salvador\": \"America/El_Salvador\",\n \"Guatemala\": \"America/Guatemala\",\n \"Honduras\": \"America/Tegucigalpa\",\n \"Mexico\": \"America/Mexico_City\",\n \"Nicaragua\": \"America/Managua\",\n \"Panama\": \"America/Panama\",\n \"Paraguay\": \"America/Asuncion\",\n \"Peru\": \"America/Lima\",\n \"Puerto Rico\": \"America/Puerto_Rico\",\n \"Republica Dominicana\": \"America/Santo_Domingo\",\n \"Uruguay\": \"America/Montevideo\",\n \"Venezuela\": \"America/Caracas\",\n \"Jamaica\": \"America/Jamaica\",\n \"Trinidad and Tobago\": \"America/Port_of_Spain\",\n \"Guyana\": \"America/Guyana\",\n \"Surinam\": \"America/Paramaribo\",\n \"Belice\": \"America/Belize\"\n};\n\n// ==============================\n// FUNCIONES\n// ==============================\n\nfunction normalizarPais(texto) {\n return texto\n .normalize(\"NFD\")\n .replace(/[\\u0300-\\u036f]/g, \"\")\n .trim()\n .toLowerCase();\n}\n\nfunction obtenerOffsetMinutos(fecha, timeZone) {\n const dtf = new Intl.DateTimeFormat(\"en-US\", {\n timeZone,\n hour12: false,\n year: \"numeric\",\n month: \"2-digit\",\n day: \"2-digit\",\n hour: \"2-digit\",\n minute: \"2-digit\",\n second: \"2-digit\"\n });\n\n const partes = dtf.formatToParts(fecha).reduce((acc, p) => {\n acc[p.type] = p.value;\n return acc;\n }, {});\n\n const utcEquivalente = Date.UTC(\n Number(partes.year),\n Number(partes.month) - 1,\n Number(partes.day),\n Number(partes.hour),\n Number(partes.minute),\n Number(partes.second)\n );\n\n return (utcEquivalente - fecha.getTime()) / 60000;\n}\n\nfunction obtenerUTCDesdeHoraLocal(horaTexto, timeZone) {\n const [hora, minuto] = horaTexto.split(\":\").map(Number);\n\n const ahora = new Date();\n\n const y = ahora.getUTCFullYear();\n const m = ahora.getUTCMonth();\n const d = ahora.getUTCDate();\n\n let fechaUTC = new Date(Date.UTC(y, m, d, hora, minuto, 0));\n\n const offset = obtenerOffsetMinutos(fechaUTC, timeZone);\n\n fechaUTC = new Date(fechaUTC.getTime() - offset * 60000);\n\n return fechaUTC;\n}\n\nfunction formatearHora(fechaUTC, timeZone) {\n return new Intl.DateTimeFormat(\"es-DO\", {\n timeZone,\n hour: \"2-digit\",\n minute: \"2-digit\",\n hour12: false\n }).format(fechaUTC);\n}\n\nfunction convertirHoraDesdeSantoDomingo(horaTexto) {\n\n const fechaUTC = obtenerUTCDesdeHoraLocal(\n horaTexto,\n TIMEZONES[\"Republica Dominicana\"]\n );\n\n const resultado = {};\n\n for (const [pais, tz] of Object.entries(TIMEZONES)) {\n resultado[pais] = formatearHora(fechaUTC, tz);\n }\n\n return resultado;\n}\n\n// ==============================\n// EJECUCIÓN\n// ==============================\n\nconst horaEntrada = $('Calcular sesion mas cercana')\n .first()\n .json\n .session\n .hora_inicio;\n\nif (!horaEntrada || !/^\\d{1,2}:\\d{2}$/.test(horaEntrada)) {\n throw new Error(\n `Formato de hora inválido: \"${horaEntrada}\". Usa HH:mm, por ejemplo 19:00`\n );\n}\n\nconst conversiones = convertirHoraDesdeSantoDomingo(horaEntrada);\n\nreturn items.map(item => {\n\n const paisEntrada = $('Guardar datos del empleado y sesion asignada').first().json.pais;\n\n if (!paisEntrada) {\n throw new Error('Cada item debe contener el campo \"pais\".');\n }\n\n // Buscar el país ignorando mayúsculas y acentos\n const paisEncontrado = Object.keys(TIMEZONES).find(\n pais => normalizarPais(pais) === normalizarPais(paisEntrada)\n );\n\n if (!paisEncontrado) {\n throw new Error(\n `País no reconocido: \"${paisEntrada}\". Países válidos: ${Object.keys(TIMEZONES).join(\", \")}`\n );\n }\n\n return {\n json: {\n hora_base: horaEntrada,\n pais_base: \"Republica Dominicana\",\n hora_convertida: conversiones[paisEncontrado],\n conversiones\n }\n };\n});" @@ -4705,26 +4492,6 @@ } } }, - { - "parameters": { - "resource": "audio", - "additionalFields": {} - }, - "type": "@firefliesai/n8n-nodes-fireflies.fireflies", - "typeVersion": 1, - "position": [ - -256, - 3616 - ], - "id": "14fa274e-6c75-4db5-bfdd-6fb4499f74bb", - "name": "Upload audio", - "credentials": { - "firefliesApi": { - "id": "3KMwcovPfZBeQOlm", - "name": "Eidan (Maximo) - Fireflies account" - } - } - }, { "parameters": { "resource": "meeting", @@ -4745,6 +4512,665 @@ "name": "Eidan (Maximo) - Fireflies account" } } + }, + { + "parameters": { + "url": "=https://meet.googleapis.com/v2/conferenceRecords", + "authentication": "predefinedCredentialType", + "nodeCredentialType": "googleOAuth2Api", + "sendQuery": true, + "queryParameters": { + "parameters": [ + { + "name": "filter", + "value": "start_time>=\"2026-07-08T19:00:50.545Z\"" + } + ] + }, + "options": {} + }, + "type": "n8n-nodes-base.httpRequest", + "typeVersion": 4.4, + "position": [ + -32, + 3360 + ], + "id": "26bbeb6d-3c51-4d8a-b487-801fa9bf3637", + "name": "HTTP Request4", + "credentials": { + "googleOAuth2Api": { + "id": "0HsSRUm82KPsWdiJ", + "name": "Eidan - Google account" + } + } + }, + { + "parameters": { + "pollTimes": { + "item": [ + { + "mode": "everyMinute" + } + ] + }, + "calendarId": { + "__rl": true, + "value": "ethen@gomezleemarketing.com", + "mode": "list", + "cachedResultName": "ethen@gomezleemarketing.com" + }, + "triggerOn": "eventStarted", + "options": {} + }, + "type": "n8n-nodes-base.googleCalendarTrigger", + "typeVersion": 1, + "position": [ + -416, + 3808 + ], + "id": "eb3ace4c-1285-4495-9239-09d18d993874", + "name": "Prueba1", + "credentials": { + "googleCalendarOAuth2Api": { + "id": "yEmGG4av5RxOK7wu", + "name": "Eidan - Google Calendar account" + } + } + }, + { + "parameters": { + "resource": "meeting" + }, + "type": "@firefliesai/n8n-nodes-fireflies.fireflies", + "typeVersion": 1, + "position": [ + 288, + 3824 + ], + "id": "14fa274e-6c75-4db5-bfdd-6fb4499f74bb", + "name": "Get active meetings", + "credentials": { + "firefliesApi": { + "id": "ILtybc8HxTqTGEX3", + "name": "Eidan Prueba - Fireflies account" + } + } + }, + { + "parameters": { + "url": "=https://meet.googleapis.com/v2/conferenceRecords", + "authentication": "predefinedCredentialType", + "nodeCredentialType": "googleOAuth2Api", + "options": {} + }, + "type": "n8n-nodes-base.httpRequest", + "typeVersion": 4.4, + "position": [ + -544, + 3616 + ], + "id": "602289b9-3c7d-4ced-b507-b27401ed9910", + "name": "Obtener conferenceRecord", + "credentials": { + "googleOAuth2Api": { + "id": "0HsSRUm82KPsWdiJ", + "name": "Eidan - Google account" + } + } + }, + { + "parameters": { + "url": "=https://meet.googleapis.com/v2/conferenceRecords/SWfRlwz4RqZSEwnrm7fcDxIWOBABMgUIigIgABgBCA/participants", + "authentication": "predefinedCredentialType", + "nodeCredentialType": "googleOAuth2Api", + "options": {} + }, + "type": "n8n-nodes-base.httpRequest", + "typeVersion": 4.4, + "position": [ + 112, + 3616 + ], + "id": "30910677-628e-4376-b15c-788d352d9ca0", + "name": "HTTP Request5", + "credentials": { + "googleOAuth2Api": { + "id": "0HsSRUm82KPsWdiJ", + "name": "Eidan - Google account" + } + } + }, + { + "parameters": { + "jsCode": "// 1. Obtener la lista completa de conferencias desde el JSON de entrada\nconst records = $input.first().json.conferenceRecords || [];\n\n\nlet ultimoItemMatch = null;\n\n// 2. Iterar por todos los registros para encontrar el que aplica\nfor (const record of records) {\n // Convertir el string UTC nativo a objeto de fecha\n const fechaStartUTC = new Date(record.startTime);\n \n // Extraer la hora específicamente en la zona horaria de RD\n const horaRD = parseInt(fechaStartUTC.toLocaleTimeString(\"en-US\", { \n timeZone: \"America/Santo_Domingo\", \n hour12: false, \n hour: \"2-digit\" \n }), 10);\n\n // 3. Evaluar si la hora de inicio es igual a las 19:00 (7 PM)\n if (horaRD === 19) {\n // Al ir asignándolo secuencialmente, el último que haga match sobreescribirá al anterior\n ultimoItemMatch = {\n json: {\n id: record.name.split('/').pop(),\n name: record.name,\n space: record.space,\n startTimeRaw: record.startTime,\n endTimeRaw: record.endTime,\n startTimeLocalRD: fechaStartUTC.toLocaleString(\"es-DO\", { timeZone: \"America/Santo_Domingo\" }),\n endTimeLocalRD: new Date(record.endTime).toLocaleString(\"es-DO\", { timeZone: \"America/Santo_Domingo\" })\n }\n };\n }\n}\n\n// 4. Si se encontró un elemento que haga match, se devuelve. Si no, devuelve un arreglo vacío.\nreturn ultimoItemMatch ? [ultimoItemMatch] : [];\n" + }, + "type": "n8n-nodes-base.code", + "typeVersion": 2, + "position": [ + -352, + 3616 + ], + "id": "0c4e04b2-06ec-4d33-97ee-926325533116", + "name": "Code in JavaScript" + }, + { + "parameters": { + "content": "# Añadir la hora en el mensaje" + }, + "type": "n8n-nodes-base.stickyNote", + "position": [ + 1616, + 800 + ], + "typeVersion": 1, + "id": "e8d3205f-4278-4cad-9f49-9be1839d1434", + "name": "Sticky Note11" + }, + { + "parameters": { + "method": "POST", + "url": "=https://chat.googleapis.com/v1/spaces/AAQAR2K6i8Y/messages?key=AIzaSyDdI0hCZtE6vySjMm-WEfRq3CPzqKqqsHI&token=yOTYTZ6rayK3NlOworCkaKMPCqssxjbokfKY3wFjeXg", + "sendHeaders": true, + "headerParameters": { + "parameters": [ + {} + ] + }, + "sendBody": true, + "specifyBody": "json", + "jsonBody": "={{ $json }}", + "options": {} + }, + "type": "n8n-nodes-base.httpRequest", + "typeVersion": 4.2, + "position": [ + 1536, + 1936 + ], + "id": "11458855-2bd1-4778-81f6-efe07ee1ee8b", + "name": "Enviar al espacio de prueba", + "retryOnFail": true + }, + { + "parameters": { + "operation": "get", + "contactId": "={{ $json.idLimpio }}", + "fields": [ + "emailAddresses", + "names" + ] + }, + "type": "n8n-nodes-base.googleContacts", + "typeVersion": 1, + "position": [ + 528, + 2144 + ], + "id": "1382bd89-9dd0-4fd5-a78d-853ac02840fb", + "name": "Get a contact", + "credentials": { + "googleContactsOAuth2Api": { + "id": "Qmeljx6s3HU998tB", + "name": "Eidan - Google Contacts account" + } + } + }, + { + "parameters": { + "jsCode": "// 1. Obtenemos la lista de miembros del nodo anterior\n// Nota: Ajusta 'memberships' si tu JSON viene estructurado de otra forma\nconst memberships = $input.first().json.memberships || [];\n\n// 2. Mapeamos y limpiamos cada usuario\nconst usuariosLimpios = memberships.map(item => {\n const fullUserPath = item.member.name; // Ej: \"users/117120277440258194844\"\n \n // Reemplazamos \"users/\" por nada para dejar solo el número\n const idLimpio = fullUserPath.replace('users/', ''); \n \n return {\n json: {\n idOriginal: fullUserPath,\n idLimpio: idLimpio,\n role: item.role,\n type: item.member.type\n }\n };\n});\n\n// 3. Devolvemos la lista para que n8n los procese en lote\nreturn usuariosLimpios;" + }, + "type": "n8n-nodes-base.code", + "typeVersion": 2, + "position": [ + 352, + 2144 + ], + "id": "41e5b9fd-598f-4dfb-b7f6-53d473ec1d71", + "name": "Limpiar id" + }, + { + "parameters": { + "jsCode": "// 1. Obtenemos el nombre del instructor del nodo \"Calcular sesion mas cercana4\"\nconst sessionItem = $('Calcular sesion mas cercana4').first();\nconst instructor = sessionItem?.json?.session?.instructor;\n\nif (!instructor) {\n return []; // Si no hay instructor, devolvemos una lista vacía para evitar errores\n}\n\nconst instructorClean = instructor.toLowerCase().trim();\n\n// 2. Obtenemos todos los contactos de \"Get a contact\"\nconst contacts = $('Get a contact').all();\n\n// 3. Filtramos los contactos donde haya coincidencia con el instructor\nconst matchingContacts = contacts.filter(item => {\n const displayName = item.json.names?.displayName;\n if (!displayName) return false; // Ignora contactos sin nombre (como el último de tu lista)\n\n const displayNameClean = displayName.toLowerCase().trim();\n\n return displayNameClean.includes(instructorClean) || instructorClean.includes(displayNameClean);\n});\n\nreturn matchingContacts;" + }, + "type": "n8n-nodes-base.code", + "typeVersion": 2, + "position": [ + 688, + 2144 + ], + "id": "aa48e478-2800-4462-b8a5-fb4651701b2d", + "name": "Unir datos2" + }, + { + "parameters": { + "url": "=https://chat.googleapis.com/v1/spaces/AAQAgX1mjaY/members", + "authentication": "predefinedCredentialType", + "nodeCredentialType": "googleChatOAuth2Api", + "options": {} + }, + "type": "n8n-nodes-base.httpRequest", + "typeVersion": 4.2, + "position": [ + 192, + 2144 + ], + "id": "7e8c9e23-1bfb-4111-983d-898eb43f4981", + "name": "Obtener miembros", + "retryOnFail": true, + "credentials": { + "googleChatOAuth2Api": { + "id": "Tg9EZ8oKp4hqoWvX", + "name": "Eidan - Chat account" + } + } + }, + { + "parameters": { + "jsCode": "// 1. Obtener datos de la sesión del nodo \"Calcular sesion mas cercana4\"\nconst sessionNode = $('Calcular sesion mas cercana4').first();\nconst session = sessionNode?.json?.session || {};\nconst titulo = session.titulo || \"Sin título\";\nconst horaInicio = session.hora_inicio || \"--:--\";\nconst horaFin = session.hora_fin || \"--:--\";\nconst enlace = session.enlace_reunion || \"\";\n\n// 2. Contar participantes sumando los de todos los países de forma dinámica\nlet totalParticipantes = 0;\nif (session.participantes) {\n Object.keys(session.participantes).forEach(pais => {\n const listaPais = session.participantes[pais];\n if (Array.isArray(listaPais)) {\n totalParticipantes += listaPais.length;\n }\n });\n}\n\n// 3. Obtener los contactId del nodo anterior para generar las menciones\nlet menciones = \"\";\ntry {\n const itemsUnirDatos = $('Unir datos2').all();\n const idsUnicos = [...new Set(\n itemsUnirDatos\n .map(item => item.json.contactId)\n .filter(id => id !== undefined && id !== null && id !== \"\")\n )];\n menciones = idsUnicos.map(id => ``).join(\" \");\n} catch (error) {\n menciones = \"\";\n}\n\n// 4. Construir cuerpo del mensaje con los datos de la sesión\nconst body = {\n text: `🔔 *Recordatorio de #TheGLMWay para hoy* \\n\\nInstructor: ${menciones}`,\n cardsV2: [\n {\n cardId: \"session-reminder\",\n card: {\n header: {\n title: \"🎓 Sesión de Capacitación\"\n },\n sections: [\n {\n widgets: [\n {\n textParagraph: {\n text: `Tema: ${titulo}
` +\n `Participantes inscritos: ${totalParticipantes} personas`\n }\n },\n {\n textParagraph: {\n text: `👉 Entrar a la reunión aquí`\n }\n }\n ]\n }\n ]\n }\n }\n ]\n};\n\nreturn [{ json: body }];" + }, + "type": "n8n-nodes-base.code", + "typeVersion": 2, + "position": [ + 1296, + 2032 + ], + "id": "18d7cd2e-ba38-4c1b-b2e1-f3db9fe301d5", + "name": "Formatear datos espanol" + }, + { + "parameters": { + "jsCode": "// 1. Obtener datos de la sesión del nodo \"Calcular sesion mas cercana4\"\nconst sessionNode = $('Calcular sesion mas cercana4').first();\nconst session = sessionNode?.json?.session || {};\nconst titulo = session.titulo || \"Untitled\";\nconst horaInicio = session.hora_inicio || \"--:--\";\nconst horaFin = session.hora_fin || \"--:--\";\nconst enlace = session.enlace_reunion || \"\";\n\n// 2. Contar participantes sumando los de todos los países de forma dinámica\nlet totalParticipantes = 0;\nif (session.participantes) {\n Object.keys(session.participantes).forEach(pais => {\n const listaPais = session.participantes[pais];\n if (Array.isArray(listaPais)) {\n totalParticipantes += listaPais.length;\n }\n });\n}\n\n// 3. Obtener los contactId del nodo anterior para generar las menciones\nlet menciones = \"\";\ntry {\n const itemsUnirDatos = $('Unir datos2').all();\n const idsUnicos = [...new Set(\n itemsUnirDatos\n .map(item => item.json.contactId)\n .filter(id => id !== undefined && id !== null && id !== \"\")\n )];\n menciones = idsUnicos.map(id => ``).join(\" \");\n} catch (error) {\n menciones = \"\";\n}\n\n// 4. Construir cuerpo del mensaje con los datos de la sesión\nconst body = {\n text: `🔔 *#TheGLMWay Reminder for today* \\n\\nInstructor: ${menciones}`,\n cardsV2: [\n {\n cardId: \"session-reminder\",\n card: {\n header: {\n title: \"🎓 Training Session\"\n },\n sections: [\n {\n widgets: [\n {\n textParagraph: {\n text: `Topic: ${titulo}
` +\n `Registered participants: ${totalParticipantes} people`\n }\n },\n {\n textParagraph: {\n text: `👉 Join the meeting here`\n }\n }\n ]\n }\n ]\n }\n }\n ]\n};\n\nreturn [{ json: body }];" + }, + "type": "n8n-nodes-base.code", + "typeVersion": 2, + "position": [ + 1296, + 1872 + ], + "id": "36ad61bf-4d83-42f8-987e-8b8216115a67", + "name": "Formatear datos ingles" + }, + { + "parameters": { + "rules": { + "values": [ + { + "conditions": { + "options": { + "caseSensitive": true, + "leftValue": "", + "typeValidation": "strict", + "version": 3 + }, + "conditions": [ + { + "leftValue": "={{ $('Calcular sesion mas cercana4').item.json.session.idioma }}", + "rightValue": "EN", + "operator": { + "type": "string", + "operation": "equals" + }, + "id": "a6a13143-17cd-4020-b789-726c8faae456" + } + ], + "combinator": "and" + } + }, + { + "conditions": { + "options": { + "caseSensitive": true, + "leftValue": "", + "typeValidation": "strict", + "version": 3 + }, + "conditions": [ + { + "id": "5ffc2081-5b80-4d72-96fc-121dc727683a", + "leftValue": "={{ $('Calcular sesion mas cercana4').item.json.session.idioma }}", + "rightValue": "ES", + "operator": { + "type": "string", + "operation": "equals", + "name": "filter.operator.equals" + } + } + ], + "combinator": "and" + } + } + ] + }, + "options": {} + }, + "type": "n8n-nodes-base.switch", + "typeVersion": 3.4, + "position": [ + 1088, + 1952 + ], + "id": "afe4c647-cec2-4cb4-84c5-4b52914ced09", + "name": "Es espanol o ingles1" + }, + { + "parameters": { + "rules": { + "values": [ + { + "conditions": { + "options": { + "caseSensitive": true, + "leftValue": "", + "typeValidation": "strict", + "version": 3 + }, + "conditions": [ + { + "leftValue": "={{ $('Calcular sesion mas cercana4').item.json.session.idioma }}", + "rightValue": "EN", + "operator": { + "type": "string", + "operation": "equals" + }, + "id": "a6a13143-17cd-4020-b789-726c8faae456" + } + ], + "combinator": "and" + } + }, + { + "conditions": { + "options": { + "caseSensitive": true, + "leftValue": "", + "typeValidation": "strict", + "version": 3 + }, + "conditions": [ + { + "id": "5ffc2081-5b80-4d72-96fc-121dc727683a", + "leftValue": "={{ $('Calcular sesion mas cercana4').item.json.session.idioma }}", + "rightValue": "ES", + "operator": { + "type": "string", + "operation": "equals", + "name": "filter.operator.equals" + } + } + ], + "combinator": "and" + } + } + ] + }, + "options": {} + }, + "type": "n8n-nodes-base.switch", + "typeVersion": 3.4, + "position": [ + 1104, + 2288 + ], + "id": "17143de2-2245-45a8-b5db-06d73aa2104f", + "name": "Es espanol o ingles" + }, + { + "parameters": { + "jsCode": "// 1. Obtener datos de la sesión del nodo \"Calcular sesion mas cercana4\"\nconst sessionNode = $('Calcular sesion mas cercana4').first();\nconst session = sessionNode?.json?.session || {};\nconst titulo = session.titulo || \"Sin título\";\nconst horaInicio = session.hora_inicio || \"--:--\";\nconst horaFin = session.hora_fin || \"--:--\";\nconst enlace = session.enlace_reunion || \"\";\n\n// 2. Contar participantes sumando los de todos los países de forma dinámica\nlet totalParticipantes = 0;\nif (session.participantes) {\n Object.keys(session.participantes).forEach(pais => {\n const listaPais = session.participantes[pais];\n if (Array.isArray(listaPais)) {\n totalParticipantes += listaPais.length;\n }\n });\n}\n\n// 3. Obtener los contactId del nodo anterior para generar las menciones\nlet menciones = \"\";\ntry {\n const itemsUnirDatos = $('Unir datos2').all();\n const idsUnicos = [...new Set(\n itemsUnirDatos\n .map(item => item.json.contactId)\n .filter(id => id !== undefined && id !== null && id !== \"\")\n )];\n menciones = idsUnicos.map(id => ``).join(\" \");\n} catch (error) {\n menciones = \"\";\n}\n\n// 4. Construir cuerpo del mensaje con el aviso de que no hay participantes\nconst body = {\n text: `🔔 *Aviso de sesión sin participantes* \\n\\nInstructor: ${menciones}`,\n cardsV2: [\n {\n cardId: \"session-reminder\",\n card: {\n header: {\n title: \"⚠️ Sesión de Capacitación\"\n },\n sections: [\n {\n widgets: [\n {\n textParagraph: {\n text: `Tema: ${titulo}
\\n` +\n `No se han registrado participantes para la sesión de hoy, por lo que no es necesario que te conectes.`\n }\n }\n ]\n }\n ]\n }\n }\n ]\n};\n\nreturn [{ json: body }];" + }, + "type": "n8n-nodes-base.code", + "typeVersion": 2, + "position": [ + 1296, + 2368 + ], + "id": "953f5fb0-8eea-40f7-8910-a1da77516176", + "name": "Formatear datos espanol1" + }, + { + "parameters": { + "jsCode": "// 1. Get session data from the \"Calcular sesion mas cercana4\" node\nconst sessionNode = $('Calcular sesion mas cercana4').first();\nconst session = sessionNode?.json?.session || {};\nconst titulo = session.titulo || \"Untitled\";\nconst horaInicio = session.hora_inicio || \"--:--\";\nconst horaFin = session.hora_fin || \"--:--\";\nconst enlace = session.enlace_reunion || \"\";\n\n// 2. Count participants by dynamically summing all countries\nlet totalParticipantes = 0;\nif (session.participantes) {\n Object.keys(session.participantes).forEach(pais => {\n const listaPais = session.participantes[pais];\n if (Array.isArray(listaPais)) {\n totalParticipantes += listaPais.length;\n }\n });\n}\n\n// 3. Get contactId from the previous node to generate mentions\nlet menciones = \"\";\ntry {\n const itemsUnirDatos = $('Unir datos2').all();\n const idsUnicos = [...new Set(\n itemsUnirDatos\n .map(item => item.json.contactId)\n .filter(id => id !== undefined && id !== null && id !== \"\")\n )];\n menciones = idsUnicos.map(id => ``).join(\" \");\n} catch (error) {\n menciones = \"\";\n}\n\n// 4. Build the message body with the notice of no participants\nconst body = {\n text: `🔔 *No participants for today's session* \\n\\nInstructor: ${menciones}`,\n cardsV2: [\n {\n cardId: \"session-reminder\",\n card: {\n header: {\n title: \"⚠️ Training Session\"\n },\n sections: [\n {\n widgets: [\n {\n textParagraph: {\n text: `Topic: ${titulo}
\\n` +\n `No participants have registered for today's session, so you do not need to connect.`\n }\n }\n ]\n }\n ]\n }\n }\n ]\n};\n\nreturn [{ json: body }];" + }, + "type": "n8n-nodes-base.code", + "typeVersion": 2, + "position": [ + 1296, + 2208 + ], + "id": "adb8c1b5-1696-49b1-aa2d-8b329846c007", + "name": "Formatear datos ingles1" + }, + { + "parameters": { + "method": "POST", + "url": "=https://chat.googleapis.com/v1/spaces/AAQAgX1mjaY/messages?key=AIzaSyDdI0hCZtE6vySjMm-WEfRq3CPzqKqqsHI&token=drBaE6ZeBbHhPKCmJd_odP3UcYcq4Ie64JXmbI29Vp8", + "sendBody": true, + "specifyBody": "json", + "jsonBody": "={{ $json }}", + "options": {} + }, + "type": "n8n-nodes-base.httpRequest", + "typeVersion": 4.2, + "position": [ + 1520, + 2128 + ], + "id": "db80a48f-bf0b-4b4e-a1d6-06c9da6c188c", + "name": "Enviar notifacion a glmway notificaciones", + "retryOnFail": true + }, + { + "parameters": { + "pollTimes": { + "item": [ + { + "mode": "everyMinute" + } + ] + }, + "calendarId": { + "__rl": true, + "value": "ethen@gomezleemarketing.com", + "mode": "list", + "cachedResultName": "ethen@gomezleemarketing.com" + }, + "triggerOn": "eventEnded", + "options": { + "matchTerm": "Entrenamiento #TheGLMWay" + } + }, + "type": "n8n-nodes-base.googleCalendarTrigger", + "typeVersion": 1, + "position": [ + -32, + 3040 + ], + "id": "5a3cf15f-3237-4520-86e0-cd4fcfb2e997", + "name": "Inicio evento español1", + "credentials": { + "googleCalendarOAuth2Api": { + "id": "yEmGG4av5RxOK7wu", + "name": "Eidan - Google Calendar account" + } + } + }, + { + "parameters": { + "operation": "get", + "tableId": "empleados_glm", + "filters": { + "conditions": [ + { + "keyName": "work_email", + "keyValue": "=jtrujillo@gomezleemarketing.com" + } + ] + } + }, + "type": "n8n-nodes-base.supabase", + "typeVersion": 1, + "position": [ + 240, + 3344 + ], + "id": "e4115807-580d-4075-8d62-de14c174c43a", + "name": "Actualizar estado a recordado3", + "credentials": { + "supabaseApi": { + "id": "2PlsR6rpK7rQTIEn", + "name": "Sofia test - Supabase account" + } + } + }, + { + "parameters": { + "method": "POST", + "url": "=https://chat.googleapis.com/v1/spaces/AAQAR2K6i8Y/messages?key=AIzaSyDdI0hCZtE6vySjMm-WEfRq3CPzqKqqsHI&token=yOTYTZ6rayK3NlOworCkaKMPCqssxjbokfKY3wFjeXg", + "sendBody": true, + "specifyBody": "json", + "jsonBody": "={{ $json }}", + "options": {} + }, + "type": "n8n-nodes-base.httpRequest", + "typeVersion": 4.2, + "position": [ + 2224, + 1360 + ], + "id": "5d50cef9-0ebb-4f28-8deb-69c7feb6f62e", + "name": "Enviar al espacio de prueba1", + "retryOnFail": true + }, + { + "parameters": { + "method": "POST", + "url": "=https://chat.googleapis.com/v1/spaces/AAQAR2K6i8Y/messages?key=AIzaSyDdI0hCZtE6vySjMm-WEfRq3CPzqKqqsHI&token=yOTYTZ6rayK3NlOworCkaKMPCqssxjbokfKY3wFjeXg", + "sendBody": true, + "specifyBody": "json", + "jsonBody": "={{ $json }}", + "options": {} + }, + "type": "n8n-nodes-base.httpRequest", + "typeVersion": 4.2, + "position": [ + 2224, + 1536 + ], + "id": "c83590cd-6e98-4e2d-81f6-6e2f204a948d", + "name": "Enviar al espacio de prueba2", + "retryOnFail": true + }, + { + "parameters": { + "jsCode": "// 1. Obtener datos de la sesión del nodo \"Calcular falta 48h o 24h1\"\nconst sessionNode = $('Calcular falta 48h o 24h1').first();\nconst sesion = sessionNode?.json?.sesion || {}; // Leído desde la raíz del JSON\n\n// 2. Contar participantes y construir de forma dinámica la lista por país\nlet totalParticipantes = 0;\nlet listaParticipantesTexto = \"\";\n\nif (sesion.participantes) {\n Object.keys(sesion.participantes).forEach(pais => {\n const listaPais = sesion.participantes[pais];\n if (Array.isArray(listaPais) && listaPais.length > 0) {\n totalParticipantes += listaPais.length;\n \n // Añadir el encabezado del país\n listaParticipantesTexto += `
📍 ${pais} (${listaPais.length}):
`;\n \n // Listar cada participante de ese país\n listaPais.forEach(p => {\n listaParticipantesTexto += `• ${p.nombre} (${p.departamento || 'Sin Depto'} | ${p.division || 'Sin Division'})
`;\n });\n }\n });\n}\n\n// 3. Obtener los contactId del nodo anterior para generar las menciones de los coordinadores\nlet menciones = \"\";\ntry {\n const itemsUnirDatos = $('Unir datos3').all(); // Asegúrate de verificar si tu nodo se llama Unir datos3 o similar\n const idsUnicos = [...new Set(\n itemsUnirDatos\n .map(item => item.json.contactId)\n .filter(id => id !== undefined && id !== null && id !== \"\")\n )];\n menciones = idsUnicos.map(id => ``).join(\" \");\n} catch (error) {\n menciones = \"\";\n}\n\n// 4. Construir cuerpo del mensaje con formato Google Chat Card\nconst body = {\n text: `🔔 *Aviso para Coordinadores RRHH* \\nEstimados ${menciones}, aquí está el listado de personas inscritas para la sesión de mañana.`,\n cardsV2: [\n {\n cardId: \"session-reminder-hr\",\n card: {\n header: {\n title: `🎓 Capacitación #TheGLMWay de mañana`,\n },\n sections: [\n {\n header: \"📈 Resumen de Asistencia\",\n widgets: [\n {\n textParagraph: {\n text: `Total inscritos: ${totalParticipantes} personas
` + \n listaParticipantesTexto\n }\n }\n ]\n }\n ]\n }\n }\n ]\n};\n\nreturn [{ json: body }];" + }, + "type": "n8n-nodes-base.code", + "typeVersion": 2, + "position": [ + 2048, + 1536 + ], + "id": "87ace248-4ea5-406f-89da-88d450ad413e", + "name": "Formatear datos espanol2" + }, + { + "parameters": { + "jsCode": "// 1. Obtener datos de la sesión del nodo \"Calcular sesion mas cercana4\"\nconst sessionNode = $('Calcular sesion mas cercana4').first();\nconst session = sessionNode?.json?.session || {};\nconst titulo = session.titulo || \"Untitled\";\nconst horaInicio = session.hora_inicio || \"--:--\";\nconst horaFin = session.hora_fin || \"--:--\";\nconst enlace = session.enlace_reunion || \"\";\n\n// 2. Contar participantes sumando los de todos los países de forma dinámica\nlet totalParticipantes = 0;\nif (session.participantes) {\n Object.keys(session.participantes).forEach(pais => {\n const listaPais = session.participantes[pais];\n if (Array.isArray(listaPais)) {\n totalParticipantes += listaPais.length;\n }\n });\n}\n\n// 3. Obtener los contactId del nodo anterior para generar las menciones\nlet menciones = \"\";\ntry {\n const itemsUnirDatos = $('Unir datos2').all();\n const idsUnicos = [...new Set(\n itemsUnirDatos\n .map(item => item.json.contactId)\n .filter(id => id !== undefined && id !== null && id !== \"\")\n )];\n menciones = idsUnicos.map(id => ``).join(\" \");\n} catch (error) {\n menciones = \"\";\n}\n\n// 4. Construir cuerpo del mensaje con los datos de la sesión\nconst body = {\n text: `🔔 *#TheGLMWay Reminder for today* \\n\\nInstructor: ${menciones}`,\n cardsV2: [\n {\n cardId: \"session-reminder\",\n card: {\n header: {\n title: \"🎓 Training Session\"\n },\n sections: [\n {\n widgets: [\n {\n textParagraph: {\n text: `Topic: ${titulo}
` +\n `Registered participants: ${totalParticipantes} people`\n }\n },\n {\n textParagraph: {\n text: `👉 Join the meeting here`\n }\n }\n ]\n }\n ]\n }\n }\n ]\n};\n\nreturn [{ json: body }];" + }, + "type": "n8n-nodes-base.code", + "typeVersion": 2, + "position": [ + 2048, + 1360 + ], + "id": "bb4cbe19-9364-4c83-a309-5594d9c5a26b", + "name": "Formatear datos ingles2" + }, + { + "parameters": { + "jsCode": "// Obtener todos los elementos que entran al nodo\nconst items = $input.all();\n\nconst hoy = new Date();\nhoy.setHours(0, 0, 0, 0);\n\nlet mejorItem = null;\nlet menorDiferencia = Infinity;\nlet mejorFechaHoyStr = '';\n\n// Recorrer cada sesión para calcular cuál es la más cercana\nfor (const item of items) {\n const fecha_sesion = item.json.fecha_sesion;\n if (!fecha_sesion) continue;\n\n // Crear la fecha de la sesión usando el año actual\n let sesion = new Date(`${fecha_sesion} ${hoy.getFullYear()}`);\n sesion.setHours(0, 0, 0, 0);\n\n // Si la fecha ya pasó este año, se toma la del año que viene\n if (sesion < hoy) {\n sesion = new Date(`${fecha_sesion} ${hoy.getFullYear() + 1}`);\n sesion.setHours(0, 0, 0, 0);\n }\n\n // Calcular diferencia en días\n const diferenciaDias = Math.floor((sesion - hoy) / (1000 * 60 * 60 * 24));\n\n // Si esta sesión es más cercana que las anteriores analizadas, la guardamos\n if (diferenciaDias < menorDiferencia) {\n menorDiferencia = diferenciaDias;\n mejorItem = item.json;\n mejorFechaHoyStr = hoy.toLocaleDateString('en-GB', {\n day: 'numeric',\n month: 'long'\n });\n }\n}\n\n// Si no se encontró ninguna sesión válida, no devuelve nada\nif (!mejorItem) return [];\n\n// Retorna únicamente la sesión más cercana encontrada\nreturn [\n {\n json: {\n sesion: mejorItem,\n fecha_hoy: mejorFechaHoyStr,\n diferenciaDias: menorDiferencia\n }\n }\n];" + }, + "type": "n8n-nodes-base.code", + "typeVersion": 2, + "position": [ + 0, + 1568 + ], + "id": "47542a5b-ebe1-4e85-8229-bb9aa7e1b744", + "name": "Calcular falta 48h o 24h1" + }, + { + "parameters": { + "operation": "get", + "contactId": "={{ $json.idLimpio }}", + "fields": [ + "emailAddresses", + "names" + ] + }, + "type": "n8n-nodes-base.googleContacts", + "typeVersion": 1, + "position": [ + 1504, + 1440 + ], + "id": "f49640d2-f7a0-43da-b9e1-1da5dbe93a22", + "name": "Get a contact1", + "credentials": { + "googleContactsOAuth2Api": { + "id": "Qmeljx6s3HU998tB", + "name": "Eidan - Google Contacts account" + } + } + }, + { + "parameters": { + "jsCode": "// 1. Obtenemos la lista de miembros del nodo anterior\n// Nota: Ajusta 'memberships' si tu JSON viene estructurado de otra forma\nconst memberships = $input.first().json.memberships || [];\n\n// 2. Mapeamos y limpiamos cada usuario\nconst usuariosLimpios = memberships.map(item => {\n const fullUserPath = item.member.name; // Ej: \"users/117120277440258194844\"\n \n // Reemplazamos \"users/\" por nada para dejar solo el número\n const idLimpio = fullUserPath.replace('users/', ''); \n \n return {\n json: {\n idOriginal: fullUserPath,\n idLimpio: idLimpio,\n role: item.role,\n type: item.member.type\n }\n };\n});\n\n// 3. Devolvemos la lista para que n8n los procese en lote\nreturn usuariosLimpios;" + }, + "type": "n8n-nodes-base.code", + "typeVersion": 2, + "position": [ + 1328, + 1440 + ], + "id": "c17d8ecc-45f9-4c03-a4d4-88d90ae8a3ec", + "name": "Limpiar id1" + }, + { + "parameters": { + "jsCode": "// 1. Forzar la lectura del nodo de coordinadores\nconst itemsCoordinadores = $('Matchear coordinador y pais inscrito').all();\n\n// 2. Obtener todos los contactos cargados de \"Get a contact1\"\nconst contacts = $('Get a contact1').all();\n\nconst resultado = [];\n\n// Función para limpiar tildes, espacios y pasarlo a minúsculas\nconst limpiarTexto = (texto) => \n texto ? texto.toLowerCase().normalize(\"NFD\").replace(/[\\u0300-\\u036f]/g, \"\").trim() : \"\";\n\n// 3. Procesar la lista de coordinadores\nfor (const item of itemsCoordinadores) {\n const coordinadorNombre = item.json.coordinador?.nombre;\n const paisCoordinador = item.json.pais; // Extraemos el país\n if (!coordinadorNombre) continue;\n\n const coordinadorClean = limpiarTexto(coordinadorNombre);\n\n // 4. Buscar coincidencias en los contactos de Google\n const matchingContacts = contacts.filter(c => {\n const displayName = c.json.names?.displayName;\n if (!displayName) return false;\n\n const displayNameClean = limpiarTexto(displayName);\n return displayNameClean === coordinadorClean || displayNameClean.includes(coordinadorClean) || coordinadorClean.includes(displayNameClean);\n });\n\n // 5. Guardar los resultados encontrados incluyendo el país\n for (const contactItem of matchingContacts) {\n resultado.push({\n json: {\n pais: paisCoordinador,\n nombre_detectado: contactItem.json.names.displayName,\n contactId: contactItem.json.contactId\n }\n });\n }\n}\n\nreturn resultado;" + }, + "type": "n8n-nodes-base.code", + "typeVersion": 2, + "position": [ + 1664, + 1440 + ], + "id": "73de340f-189b-4963-bdf6-9b1bfd603cd6", + "name": "Unir datos3" + }, + { + "parameters": { + "url": "=https://chat.googleapis.com/v1/spaces/AAQAQj1t9AA/members", + "authentication": "predefinedCredentialType", + "nodeCredentialType": "googleChatOAuth2Api", + "options": {} + }, + "type": "n8n-nodes-base.httpRequest", + "typeVersion": 4.2, + "position": [ + 1168, + 1440 + ], + "id": "949eb6ae-2aba-43d2-a262-f91313336d2f", + "name": "Obtener miembros RRHH Notificaciones", + "retryOnFail": true, + "credentials": { + "googleChatOAuth2Api": { + "id": "Tg9EZ8oKp4hqoWvX", + "name": "Eidan - Chat account" + } + } } ], "connections": { @@ -5444,24 +5870,12 @@ }, "Send a message espanol3": { "main": [ - [ - { - "node": "Actualizar estado a notificado", - "type": "main", - "index": 0 - } - ] + [] ] }, "Send a message ingles3": { "main": [ - [ - { - "node": "Actualizar estado a notificado", - "type": "main", - "index": 0 - } - ] + [] ] }, "Schedule Trigger3": { @@ -5478,38 +5892,26 @@ "Loop Over Items2": { "main": [ [], - [ - { - "node": "Calcular falta 48h o 24h", - "type": "main", - "index": 0 - } - ] + [] ] }, "Wait3": { "main": [ - [ - { - "node": "Loop Over Items2", - "type": "main", - "index": 0 - } - ] + [] ] }, "Pais?3": { "main": [ [ { - "node": "Send a message ingles3", + "node": "Formatear datos ingles2", "type": "main", "index": 0 } ], [ { - "node": "Send a message espanol3", + "node": "Formatear datos espanol2", "type": "main", "index": 0 } @@ -5518,13 +5920,7 @@ }, "Falta 48h para el evento?1": { "main": [ - [ - { - "node": "Hay inscritos en la sesion?", - "type": "main", - "index": 0 - } - ], + [], [] ] }, @@ -5778,41 +6174,18 @@ "main": [ [ { - "node": "Hay inscritos?", + "node": "Obtener miembros", "type": "main", "index": 0 } ] ] }, - "Es espanol o ingles": { - "main": [ - [ - { - "node": "Send a message ingles5", - "type": "main", - "index": 0 - } - ], - [ - { - "node": "Send a message espanol5", - "type": "main", - "index": 0 - } - ] - ] - }, - "Hay sesion?": { - "main": [ - [] - ] - }, "Obtener sesiones": { "main": [ [ { - "node": "Loop Over Items2", + "node": "Calcular falta 48h o 24h1", "type": "main", "index": 0 } @@ -5850,38 +6223,14 @@ "index": 0 } ], - [ - { - "node": "Wait3", - "type": "main", - "index": 0 - } - ] + [] ] }, "Matchear coordinador y pais inscrito": { "main": [ [ { - "node": "Loop Over Items3", - "type": "main", - "index": 0 - } - ] - ] - }, - "Loop Over Items3": { - "main": [ - [ - { - "node": "Wait3", - "type": "main", - "index": 0 - } - ], - [ - { - "node": "Pais?3", + "node": "Obtener miembros RRHH Notificaciones", "type": "main", "index": 0 } @@ -5890,13 +6239,7 @@ }, "Wait6": { "main": [ - [ - { - "node": "Loop Over Items3", - "type": "main", - "index": 0 - } - ] + [] ] }, "Actualizar estado a notificado": { @@ -6004,24 +6347,6 @@ ] ] }, - "Es espanol o ingles1": { - "main": [ - [ - { - "node": "Send a message ingles6", - "type": "main", - "index": 0 - } - ], - [ - { - "node": "Send a message espanol6", - "type": "main", - "index": 0 - } - ] - ] - }, "Cambiar zona horaria": { "main": [ [ @@ -6200,6 +6525,261 @@ } ] ] + }, + "Prueba1": { + "main": [ + [] + ] + }, + "Prueba": { + "main": [ + [ + { + "node": "Obtener conferenceRecord", + "type": "main", + "index": 0 + } + ] + ] + }, + "Obtener conferenceRecord": { + "main": [ + [ + { + "node": "Code in JavaScript", + "type": "main", + "index": 0 + } + ] + ] + }, + "HTTP Request5": { + "main": [ + [] + ] + }, + "Limpiar id": { + "main": [ + [ + { + "node": "Get a contact", + "type": "main", + "index": 0 + } + ] + ] + }, + "Get a contact": { + "main": [ + [ + { + "node": "Unir datos2", + "type": "main", + "index": 0 + } + ] + ] + }, + "Unir datos2": { + "main": [ + [ + { + "node": "Hay inscritos?", + "type": "main", + "index": 0 + } + ] + ] + }, + "Obtener miembros": { + "main": [ + [ + { + "node": "Limpiar id", + "type": "main", + "index": 0 + } + ] + ] + }, + "Formatear datos espanol": { + "main": [ + [ + { + "node": "Enviar notifacion a glmway notificaciones", + "type": "main", + "index": 0 + } + ] + ] + }, + "Formatear datos ingles": { + "main": [ + [ + { + "node": "Enviar notifacion a glmway notificaciones", + "type": "main", + "index": 0 + } + ] + ] + }, + "Es espanol o ingles1": { + "main": [ + [ + { + "node": "Formatear datos ingles", + "type": "main", + "index": 0 + } + ], + [ + { + "node": "Formatear datos espanol", + "type": "main", + "index": 0 + } + ] + ] + }, + "Es espanol o ingles": { + "main": [ + [ + { + "node": "Formatear datos ingles1", + "type": "main", + "index": 0 + } + ], + [ + { + "node": "Formatear datos espanol1", + "type": "main", + "index": 0 + } + ] + ] + }, + "Formatear datos ingles1": { + "main": [ + [ + { + "node": "Enviar notifacion a glmway notificaciones", + "type": "main", + "index": 0 + } + ] + ] + }, + "Formatear datos espanol1": { + "main": [ + [ + { + "node": "Enviar notifacion a glmway notificaciones", + "type": "main", + "index": 0 + } + ] + ] + }, + "Enviar al espacio de prueba2": { + "main": [ + [ + { + "node": "Actualizar estado a notificado", + "type": "main", + "index": 0 + } + ] + ] + }, + "Enviar al espacio de prueba1": { + "main": [ + [ + { + "node": "Actualizar estado a notificado", + "type": "main", + "index": 0 + } + ] + ] + }, + "Formatear datos ingles2": { + "main": [ + [ + { + "node": "Enviar al espacio de prueba1", + "type": "main", + "index": 0 + } + ] + ] + }, + "Formatear datos espanol2": { + "main": [ + [ + { + "node": "Enviar al espacio de prueba2", + "type": "main", + "index": 0 + } + ] + ] + }, + "Calcular falta 48h o 24h1": { + "main": [ + [ + { + "node": "Hay inscritos en la sesion?", + "type": "main", + "index": 0 + } + ] + ] + }, + "Get a contact1": { + "main": [ + [ + { + "node": "Unir datos3", + "type": "main", + "index": 0 + } + ] + ] + }, + "Limpiar id1": { + "main": [ + [ + { + "node": "Get a contact1", + "type": "main", + "index": 0 + } + ] + ] + }, + "Unir datos3": { + "main": [ + [ + { + "node": "Pais?3", + "type": "main", + "index": 0 + } + ] + ] + }, + "Obtener miembros RRHH Notificaciones": { + "main": [ + [ + { + "node": "Limpiar id1", + "type": "main", + "index": 0 + } + ] + ] } }, "settings": { @@ -6224,19 +6804,19 @@ "recurrenceRules": [] }, "node:Comenzo evento ingles": { - "lastTimeChecked": "2026-07-06T20:58:22Z" + "lastTimeChecked": "2026-07-21T15:16:49Z" }, "node:Comenzo evento español": { - "lastTimeChecked": "2026-07-06T20:58:23Z" + "lastTimeChecked": "2026-07-21T15:16:49Z" }, "node:Termino evento español": { - "lastTimeChecked": "2026-07-06T20:58:23Z" + "lastTimeChecked": "2026-07-21T15:16:50Z" }, "node:Termino evento ingles": { - "lastTimeChecked": "2026-07-06T20:58:23Z" + "lastTimeChecked": "2026-07-21T15:16:50Z" }, "node:Prueba": { - "lastTimeChecked": "2026-07-06T20:58:23Z" + "lastTimeChecked": "2026-07-21T15:16:50Z" }, "node:Schedule Trigger2": { "recurrenceRules": [] @@ -6252,6 +6832,12 @@ }, "node:Schedule Trigger6": { "recurrenceRules": [] + }, + "node:Prueba1": { + "lastTimeChecked": "2026-07-21T15:16:50Z" + }, + "node:Inicio evento español1": { + "lastTimeChecked": "2026-07-21T15:16:50Z" } }, "meta": { @@ -6271,17 +6857,181 @@ } } ], + "Prueba1": [ + { + "json": { + "kind": "calendar#event", + "etag": "\"3568107432244542\"", + "id": "7irbet5fsuc3qmj2s2dc18mfse", + "status": "confirmed", + "htmlLink": "https://www.google.com/calendar/event?eid=N2lyYmV0NWZzdWMzcW1qMnMyZGMxOG1mc2UgZXRoZW5AZ29tZXpsZWVtYXJrZXRpbmcuY29t", + "created": "2026-07-14T18:28:33.000Z", + "updated": "2026-07-14T18:28:36.122Z", + "summary": "Prueba prueba", + "creator": { + "email": "ethen@gomezleemarketing.com", + "self": true + }, + "organizer": { + "email": "ethen@gomezleemarketing.com", + "self": true + }, + "start": { + "dateTime": "2026-07-14T14:30:00-04:00", + "timeZone": "America/Santo_Domingo" + }, + "end": { + "dateTime": "2026-07-14T14:35:00-04:00", + "timeZone": "America/Santo_Domingo" + }, + "iCalUID": "7irbet5fsuc3qmj2s2dc18mfse@google.com", + "sequence": 0, + "attendees": [ + { + "email": "ethen@gomezleemarketing.com", + "organizer": true, + "self": true, + "responseStatus": "accepted" + }, + { + "email": "fred@fireflies.ai", + "responseStatus": "needsAction" + } + ], + "hangoutLink": "https://meet.google.com/hqp-ptby-xmb", + "conferenceData": { + "entryPoints": [ + { + "entryPointType": "video", + "uri": "https://meet.google.com/hqp-ptby-xmb", + "label": "meet.google.com/hqp-ptby-xmb" + }, + { + "entryPointType": "more", + "uri": "https://tel.meet/hqp-ptby-xmb?pin=3459300644906", + "pin": "3459300644906" + }, + { + "regionCode": "DO", + "entryPointType": "phone", + "uri": "tel:+1-829-953-4930", + "label": "+1 829-953-4930", + "pin": "3459300644906" + } + ], + "conferenceSolution": { + "key": { + "type": "hangoutsMeet" + }, + "name": "Google Meet", + "iconUri": "https://fonts.gstatic.com/s/i/productlogos/meet_2020q4/v6/web-512dp/logo_meet_2020q4_color_2x_web_512dp.png" + }, + "conferenceId": "hqp-ptby-xmb" + }, + "guestsCanModify": true, + "reminders": { + "useDefault": true + }, + "eventType": "default" + }, + "pairedItem": { + "item": 0 + } + } + ], + "Prueba": [ + { + "json": { + "kind": "calendar#event", + "etag": "\"3568107432244542\"", + "id": "7irbet5fsuc3qmj2s2dc18mfse", + "status": "confirmed", + "htmlLink": "https://www.google.com/calendar/event?eid=N2lyYmV0NWZzdWMzcW1qMnMyZGMxOG1mc2UgZXRoZW5AZ29tZXpsZWVtYXJrZXRpbmcuY29t", + "created": "2026-07-14T18:28:33.000Z", + "updated": "2026-07-14T18:28:36.122Z", + "summary": "Prueba prueba", + "creator": { + "email": "ethen@gomezleemarketing.com", + "self": true + }, + "organizer": { + "email": "ethen@gomezleemarketing.com", + "self": true + }, + "start": { + "dateTime": "2026-07-14T14:30:00-04:00", + "timeZone": "America/Santo_Domingo" + }, + "end": { + "dateTime": "2026-07-14T14:35:00-04:00", + "timeZone": "America/Santo_Domingo" + }, + "iCalUID": "7irbet5fsuc3qmj2s2dc18mfse@google.com", + "sequence": 0, + "attendees": [ + { + "email": "ethen@gomezleemarketing.com", + "organizer": true, + "self": true, + "responseStatus": "accepted" + }, + { + "email": "fred@fireflies.ai", + "responseStatus": "needsAction" + } + ], + "hangoutLink": "https://meet.google.com/hqp-ptby-xmb", + "conferenceData": { + "entryPoints": [ + { + "entryPointType": "video", + "uri": "https://meet.google.com/hqp-ptby-xmb", + "label": "meet.google.com/hqp-ptby-xmb" + }, + { + "entryPointType": "more", + "uri": "https://tel.meet/hqp-ptby-xmb?pin=3459300644906", + "pin": "3459300644906" + }, + { + "regionCode": "DO", + "entryPointType": "phone", + "uri": "tel:+1-829-953-4930", + "label": "+1 829-953-4930", + "pin": "3459300644906" + } + ], + "conferenceSolution": { + "key": { + "type": "hangoutsMeet" + }, + "name": "Google Meet", + "iconUri": "https://fonts.gstatic.com/s/i/productlogos/meet_2020q4/v6/web-512dp/logo_meet_2020q4_color_2x_web_512dp.png" + }, + "conferenceId": "hqp-ptby-xmb" + }, + "guestsCanModify": true, + "reminders": { + "useDefault": true + }, + "eventType": "default" + }, + "pairedItem": { + "item": 0 + } + } + ], "Schedule Trigger1": [ { "json": { - "timestamp": "2026-07-03T19:00:24.013-04:00", - "Readable date": "July 3rd 2026, 7:00:24 pm", - "Readable time": "7:00:24 pm", - "Day of week": "Friday", + "timestamp": "2026-07-18T02:00:24.005-04:00", + "Readable date": "July 18th 2026, 2:00:24 am", + "Readable time": "2:00:24 am", + "Day of week": "Saturday", "Year": "2026", "Month": "July", - "Day of month": "03", - "Hour": "19", + "Day of month": "18", + "Hour": "02", "Minute": "00", "Second": "24", "Timezone": "America/Santo_Domingo (UTC-04:00)" @@ -6290,12 +7040,114 @@ "item": 0 } } + ], + "Calcular falta 48h o 24h1": [ + { + "json": { + "sesion": { + "titulo": "#TheGLMWay Training", + "descripcion": null, + "fecha_sesion": "22 July", + "hora_inicio": "19:00", + "hora_fin": "20:00", + "instructor": "Francis", + "enlace_reunion": "https://meet.google.com/mmc-iupp-sao", + "idioma": "EN", + "created_at": "2026-06-25T21:44:29.483246+00:00", + "id": "eb17c8a3-618f-470c-9bc1-eb6b0c45c869", + "correo_instructor": "null", + "meet_id": "c82i08rqs6mt3gg9j4it0mulmc_20260722T230000Z", + "participantes": { + "Colombia": [ + { + "correo": "ccendales@gomezleemarketing.com", + "nombre": "Camilo Andres Cendales Sanchez", + "division": "GLM Colombia", + "departamento": "GLM Analytics" + }, + { + "correo": "aperez09@gomezleemarketing.com", + "nombre": "Alejandro Perez Paez", + "division": "GLM Colombia", + "departamento": "GLM Analytics" + }, + { + "correo": "lmarquinez@gomezlee.marketing", + "nombre": "Leydy Jhoanna Marquinez Erazo", + "division": "Whirlpool", + "departamento": "Field Force" + }, + { + "correo": "ngarcia02@gomezlee.marketing", + "nombre": "Nicol Garcia Romero", + "division": "Whirlpool", + "departamento": "Field Force" + }, + { + "correo": "mmendoza06@gomezlee.marketing", + "nombre": "Melany Giselle Mendoza Garcia", + "division": "Whirlpool", + "departamento": "Field Force" + }, + { + "correo": "wcampos02@gomezlee.marketing", + "nombre": "Wilson Guillermo Campos Cardona", + "division": "", + "departamento": "Field Force" + } + ], + "Guatemala": [ + { + "correo": "yrodas@gomezlee.marketing", + "nombre": "Yamileth Del Carmen Rodas García", + "division": "Motorola", + "departamento": "Field Force" + }, + { + "correo": "jvillatoro02@gomezlee.marketing", + "nombre": "Jennifer Anali Villatoro Méndez", + "division": "Motorola", + "departamento": "Field Force" + }, + { + "correo": "hcortez@gomezlee.marketing", + "nombre": "Helen Cortez", + "division": "Motorola", + "departamento": "Field Force" + } + ], + "Jamaica": [ + { + "correo": "yrodas@gomezlee.marketing", + "nombre": "Yamileth Del Carmen Rodas García", + "division": "Motorola", + "departamento": "Field Force" + }, + { + "correo": "jvillatoro02@gomezlee.marketing", + "nombre": "Jennifer Anali Villatoro Méndez", + "division": "Motorola", + "departamento": "Field Force" + }, + { + "correo": "hcortez@gomezlee.marketing", + "nombre": "Helen Cortez", + "division": "Motorola", + "departamento": "Field Force" + } + ] + } + }, + "fecha_hoy": "18 July", + "diferenciaDias": 4 + } + } ] }, - "versionId": "e6f9b5db-0927-4fb3-8518-2c4a10541c76", - "activeVersionId": "e6f9b5db-0927-4fb3-8518-2c4a10541c76", - "versionCounter": 4357, - "triggerCount": 13, + "versionId": "69f1dcec-ccc3-4ec2-9e89-7e8b63f7197a", + "activeVersionId": "69f1dcec-ccc3-4ec2-9e89-7e8b63f7197a", + "versionCounter": 5448, + "triggerCount": 15, "shared": [ { "updatedAt": "2026-06-08T13:50:12.177Z", @@ -6317,9 +7169,9 @@ ], "tags": [], "activeVersion": { - "updatedAt": "2026-07-06T20:58:23.000Z", - "createdAt": "2026-07-06T20:58:21.471Z", - "versionId": "e6f9b5db-0927-4fb3-8518-2c4a10541c76", + "updatedAt": "2026-07-21T15:16:51.000Z", + "createdAt": "2026-07-21T15:16:43.913Z", + "versionId": "69f1dcec-ccc3-4ec2-9e89-7e8b63f7197a", "workflowId": "F1iPg8hktNAebZua", "nodes": [ { @@ -6604,8 +7456,8 @@ "type": "n8n-nodes-base.googleSheets", "typeVersion": 4.7, "position": [ - 2752, - 1328 + 2672, + 1840 ], "id": "b7a1afb4-5e9c-4fc0-8a64-99b2b71c918e", "name": "Get row(s) in sheet1", @@ -6944,8 +7796,8 @@ "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ - 2544, - 1328 + 2464, + 1840 ], "id": "a088f9b0-7ec6-40d0-9a90-fa2047ab0461", "name": "Cambiar formato de fecha" @@ -7234,10 +8086,6 @@ "fieldId": "departamento", "fieldValue": "={{ $('Get an employee').item.json.department }}" }, - { - "fieldId": "supervisor_id", - "fieldValue": "={{ $('Informacion extra del empleado').item.json.supervisorEId }}" - }, { "fieldId": "fecha_ingreso", "fieldValue": "={{ $('Informacion extra del empleado').item.json.hireDate }}" @@ -7492,7 +8340,7 @@ "parameters": { "content": "## Recordatorio a coordinador RRHH 48 y 24 horas antes de la sesion\n", "height": 496, - "width": 2640, + "width": 3152, "color": 6 }, "type": "n8n-nodes-base.stickyNote", @@ -7581,14 +8429,14 @@ "mode": "list", "cachedResultName": "ethen@gomezleemarketing.com" }, - "triggerOn": "eventStarted", + "triggerOn": "eventEnded", "options": {} }, "type": "n8n-nodes-base.googleCalendarTrigger", "typeVersion": 1, "position": [ - -544, - 3552 + -736, + 3616 ], "id": "35ec709a-30fd-4e3b-8492-cf6d8928e372", "name": "Prueba", @@ -7987,7 +8835,7 @@ "parameters": { "content": "## Notificacion a facilitador\n\n- Manda un listado de las personas inscritas en la sesion del miercoles al facilitador.\n- Si no hay personas inscritas envia un alerta al facilitador.", "height": 768, - "width": 1392, + "width": 2112, "color": 3 }, "type": "n8n-nodes-base.stickyNote", @@ -8001,7 +8849,7 @@ }, { "parameters": { - "sendTo": "=eidan.then14@gmail.com", + "sendTo": "={{ $('Loop Over Items1').item.json.email }}", "subject": "Entrenamiento #TheGLMWay", "emailType": "text", "message": "=¡Hola, GLMer!\n\nEste es un recordatorio de tu entrenamiento, donde te transmitiremos nuestra cultura, nuestro ADN y por qué somos diferentes al resto.\n\n¡Te esperamos puntual y con toda la energía para aprender!\n\nÚnete aquí:\n\n{{ $('Obtener sesion').item.json.enlace_reunion }}", @@ -8027,7 +8875,7 @@ }, { "parameters": { - "sendTo": "=eidan.then14@gmail.com", + "sendTo": "={{ $('Loop Over Items1').item.json.email }}", "subject": "#TheGLMWay Training", "emailType": "text", "message": "=Hello, GLMer!\n\nThis is a reminder about your training session, where we'll share our culture, our DNA, and what makes us different from the rest.\n\nWe're looking forward to seeing you on time and ready to learn!\n\nJoin here:\n\n{{ $('Obtener sesion').item.json.enlace_reunion }}", @@ -8179,6 +9027,7 @@ "id": "3a6f198b-e136-49fb-a171-78164e10b600", "name": "Obtener coordinador1", "alwaysOutputData": true, + "retryOnFail": true, "credentials": { "googleSheetsOAuth2Api": { "id": "8Pp0ek3NPsEkyXfY", @@ -8265,8 +9114,8 @@ "type": "n8n-nodes-base.googleCalendar", "typeVersion": 1.3, "position": [ - 1520, - 2080 + 1664, + 3040 ], "id": "7dd9a706-4d80-45c6-942a-c703eb074a20", "name": "Entrenamiento español2", @@ -8295,8 +9144,8 @@ "type": "n8n-nodes-base.googleCalendar", "typeVersion": 1.3, "position": [ - 1520, - 1904 + 1664, + 2864 ], "id": "d8253a7a-4e37-4c14-b4da-e0029571cd21", "name": "Entrenamiento ingles5", @@ -8834,8 +9683,8 @@ "type": "n8n-nodes-base.supabase", "typeVersion": 1, "position": [ - 1360, - 864 + 1376, + 880 ], "id": "ddf0a273-d3bc-44cc-888b-d789ce72ff77", "name": "Actualizar estado a recordado", @@ -8859,8 +9708,8 @@ "type": "n8n-nodes-base.gmail", "typeVersion": 2.2, "position": [ - 1744, - 1584 + 2240, + 2064 ], "id": "39331d88-6f2b-4df1-ac76-dda9ff47dfec", "name": "Send a message espanol3", @@ -8870,8 +9719,7 @@ "id": "QWNicjw1khRm5BVI", "name": "Eidan - Gmail account" } - }, - "disabled": true + } }, { "parameters": { @@ -8886,8 +9734,8 @@ "type": "n8n-nodes-base.gmail", "typeVersion": 2.2, "position": [ - 1744, - 1408 + 2240, + 1888 ], "id": "9d4f57a4-ac2f-49bd-b5fa-50658a8d928e", "name": "Send a message ingles3", @@ -8897,15 +9745,18 @@ "id": "QWNicjw1khRm5BVI", "name": "Eidan - Gmail account" } - }, - "disabled": true + } }, { "parameters": { "rule": { "interval": [ { - "triggerAtHour": 9 + "field": "weeks", + "triggerAtDay": [ + 2 + ], + "triggerAtHour": 16 } ] } @@ -8926,8 +9777,8 @@ "type": "n8n-nodes-base.splitInBatches", "typeVersion": 3, "position": [ - -16, - 1568 + 416, + 1296 ], "id": "7545364a-df0a-4420-a1af-5bcd4f8c9602", "name": "Loop Over Items2" @@ -8939,8 +9790,8 @@ "type": "n8n-nodes-base.wait", "typeVersion": 1.1, "position": [ - 1536, - 1296 + 1856, + 1136 ], "id": "617ab85d-23a6-4546-9331-eff343d9b1c5", "name": "Wait3", @@ -8958,7 +9809,7 @@ "conditions": [ { "id": "9674fd7e-dd62-42d4-8931-6c67e59e3dd7", - "leftValue": "={{ Object.keys($json)[0] }}", + "leftValue": "={{ $json.pais }}", "rightValue": "Jamaica", "operator": { "type": "string", @@ -8967,7 +9818,7 @@ }, { "id": "32931394-f4ea-4055-b866-906a81988173", - "leftValue": "={{ Object.keys($json)[0] }}", + "leftValue": "={{ $json.pais }}", "rightValue": "Trinidad and Tobago", "operator": { "type": "string", @@ -8976,7 +9827,7 @@ }, { "id": "ea2a8466-96c6-460f-b08f-d23c06b2d18c", - "leftValue": "={{ Object.keys($json)[0] }}", + "leftValue": "={{ $json.pais }}", "rightValue": "Barbados", "operator": { "type": "string", @@ -8985,7 +9836,7 @@ }, { "id": "28e49217-0c1a-4462-9642-676e54926d3e", - "leftValue": "={{ Object.keys($json)[0] }}", + "leftValue": "={{ $json.pais }}", "rightValue": "Saint Thomas", "operator": { "type": "string", @@ -8994,7 +9845,7 @@ }, { "id": "c6a6aea5-48f4-44dc-92ca-a9f9de9cacf9", - "leftValue": "={{ Object.keys($json)[0] }}", + "leftValue": "={{ $json.pais }}", "rightValue": "St. Croix", "operator": { "type": "string", @@ -9003,7 +9854,7 @@ }, { "id": "e6f52339-ea7c-462f-bdc2-8b7353160e4c", - "leftValue": "={{ Object.keys($json)[0] }}", + "leftValue": "={{ $json.pais }}", "rightValue": "Tobago", "operator": { "type": "string", @@ -9012,7 +9863,7 @@ }, { "id": "b308c2b6-53b4-4d49-b540-cdc03e36528b", - "leftValue": "={{ Object.keys($json)[0] }}", + "leftValue": "={{ $json.pais }}", "rightValue": "Guyana", "operator": { "type": "string", @@ -9021,7 +9872,7 @@ }, { "id": "35a50a33-a2b5-4116-9336-11300357569e", - "leftValue": "={{ Object.keys($json)[0] }}", + "leftValue": "={{ $json.pais }}", "rightValue": "Aruba", "operator": { "type": "string", @@ -9036,7 +9887,7 @@ "type": "n8n-nodes-base.if", "typeVersion": 2.2, "position": [ - 1424, + 1824, 1440 ], "id": "13ee807a-f1cd-48ef-921b-7b5c260ba116", @@ -9070,8 +9921,8 @@ "type": "n8n-nodes-base.if", "typeVersion": 2.2, "position": [ - 416, - 1568 + -32, + 1376 ], "id": "0fea4950-f873-4375-8964-45cfc3fead02", "name": "Falta 48h para el evento?1" @@ -9318,7 +10169,7 @@ { "parameters": { "operation": "get", - "employeeId": "=50764", + "employeeId": "=50821", "options": {} }, "type": "n8n-nodes-base.bambooHr", @@ -9471,20 +10322,6 @@ } } }, - { - "parameters": { - "url": "=https://www.googleapis.com/calendar/v3/calendars/primary/events/{{ $json.id }}", - "options": {} - }, - "type": "n8n-nodes-base.httpRequest", - "typeVersion": 4.4, - "position": [ - 112, - 3488 - ], - "id": "602289b9-3c7d-4ced-b507-b27401ed9910", - "name": "HTTP Request1" - }, { "parameters": { "url": "=https://www.googleapis.com/calendar/v3/calendars/primary/events/{{ $json.id }}", @@ -9562,13 +10399,9 @@ }, { "parameters": { - "url": "=https://meet.googleapis.com/v2/conferenceRecords/6nSLUwAKD6mX-LzgI_J7DxIXOAIIigIgABgBCA/participants", + "url": "=https://meet.googleapis.com/v2/{{ $json.conferenceRecords[4].name }}/participants", "authentication": "predefinedCredentialType", "nodeCredentialType": "googleOAuth2Api", - "sendQuery": true, - "queryParameters": { - "parameters": [] - }, "options": {} }, "type": "n8n-nodes-base.httpRequest", @@ -9985,139 +10818,19 @@ "id": "0db9e6a4-2e5e-4513-97fd-71d22aa90822", "name": "Calcular sesion mas cercana4" }, - { - "parameters": { - "sendTo": "=eidan.then14@gmail.com", - "subject": "Entrenamiento #TheGLMWay", - "emailType": "text", - "message": "=Hello,\n\nI am writing to inform you that there are no registered participants for today's scheduled activity.\n\nBest regards", - "options": { - "appendAttribution": false - } - }, - "type": "n8n-nodes-base.gmail", - "typeVersion": 2.2, - "position": [ - 624, - 2432 - ], - "id": "0cf2219c-db12-4231-bac6-8e5f2816530f", - "name": "Send a message espanol5", - "webhookId": "a6043707-89d1-4c99-8de2-e60d9aaf7ed2", - "credentials": { - "gmailOAuth2": { - "id": "QWNicjw1khRm5BVI", - "name": "Eidan - Gmail account" - } - } - }, - { - "parameters": { - "sendTo": "=eidan.then14@gmail.com", - "subject": "#TheGLMWay Training", - "emailType": "text", - "message": "=Hello,\n\nThis is to inform you that, as of now, there are no people enrolled for today's activity.\n\nBest regards.\n\nThis is an automated message generated by the enrollment management system.", - "options": { - "appendAttribution": false - } - }, - "type": "n8n-nodes-base.gmail", - "typeVersion": 2.2, - "position": [ - 624, - 2256 - ], - "id": "96bac1b9-d921-418d-947d-f07980bb76aa", - "name": "Send a message ingles5", - "webhookId": "a6043707-89d1-4c99-8de2-e60d9aaf7ed2", - "credentials": { - "gmailOAuth2": { - "id": "QWNicjw1khRm5BVI", - "name": "Eidan - Gmail account" - } - } - }, - { - "parameters": { - "conditions": { - "options": { - "caseSensitive": true, - "leftValue": "", - "typeValidation": "strict", - "version": 3 - }, - "conditions": [ - { - "id": "df25aa3e-d48f-4e52-ae1f-47678e954d52", - "leftValue": "={{ $('Obtener sesion1').item.json.idioma }}", - "rightValue": "EN", - "operator": { - "type": "string", - "operation": "equals", - "name": "filter.operator.equals" - } - } - ], - "combinator": "and" - }, - "options": {} - }, - "type": "n8n-nodes-base.if", - "typeVersion": 2.3, - "position": [ - 416, - 2352 - ], - "id": "748f3ae7-7e6d-41f5-be1d-861a9566ec00", - "name": "Es espanol o ingles" - }, { "parameters": { "content": "## Falta añadir mensaje de aviso" }, "type": "n8n-nodes-base.stickyNote", "position": [ - 912, - 1904 + 1872, + 2944 ], "typeVersion": 1, "id": "2d9a27b5-9ca6-4518-bd06-3a91389c4736", "name": "Sticky Note9" }, - { - "parameters": { - "conditions": { - "options": { - "caseSensitive": true, - "leftValue": "", - "typeValidation": "strict", - "version": 3 - }, - "conditions": [ - { - "id": "df25aa3e-d48f-4e52-ae1f-47678e954d52", - "leftValue": "={{ $json.foundSession }}", - "rightValue": "EN", - "operator": { - "type": "boolean", - "operation": "true", - "singleValue": true - } - } - ], - "combinator": "and" - }, - "options": {} - }, - "type": "n8n-nodes-base.if", - "typeVersion": 2.3, - "position": [ - 2000, - 1136 - ], - "id": "03832c44-864b-4277-a9fb-f94d56dc0f1c", - "name": "Hay sesion?" - }, { "parameters": { "content": "## Al final añadir flujo para resetear los estados de los coordinadores e instructores", @@ -10197,8 +10910,8 @@ "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ - 208, - 1568 + -224, + 1376 ], "id": "e8d383b8-9081-4829-8516-a03f6f5a1b63", "name": "Calcular falta 48h o 24h" @@ -10266,7 +10979,7 @@ "type": "n8n-nodes-base.if", "typeVersion": 2.3, "position": [ - 592, + 208, 1568 ], "id": "334a5703-db8a-4a88-b528-8468ee61ddbc", @@ -10274,7 +10987,7 @@ }, { "parameters": { - "jsCode": "// Sesión válida (salida del nodo \"Calcular falta 48h o 24h\")\nconst sesion = $(\"Calcular falta 48h o 24h\").first().json.sesion;\n\n// Coordinadores\nconst coordinadores = $(\"Obtener coordinadores1\").all().map(i => i.json);\n\nconst resultado = [];\n\n// Participantes viene como:\n// {\n// \"Colombia\": [...],\n// \"Mexico\": [...]\n// }\nconst participantesPorPais = sesion.participantes || {};\n\nfor (const [pais, participantes] of Object.entries(participantesPorPais)) {\n\n // Buscar coordinador del país\n const coordinador = coordinadores.find(c => c.pais === pais);\n\n resultado.push({\n json: {\n [pais]: {\n coordinador: coordinador\n ? {\n nombre: coordinador.nombre,\n correo: coordinador.correo\n }\n : null,\n\n participantes\n }\n }\n });\n\n}\n\nreturn resultado;" + "jsCode": "// 1. Obtener la sesión del nodo anterior\nconst datosNodoAnterior = $(\"Calcular falta 48h o 24h1\").first().json;\nconst sesion = datosNodoAnterior.sesion;\nconst participantesPorPais = sesion?.participantes || {};\n\n// 2. Obtener todos los coordinadores\nconst coordinadores = $(\"Obtener coordinadores1\").all().map(i => i.json);\n\nconst resultado = [];\n\n// Función para quitar acentos y dejar en minúsculas (evita fallos de coincidencia)\nconst limpiarTexto = (texto) => \n texto ? texto.toLowerCase().normalize(\"NFD\").replace(/[\\u0300-\\u036f]/g, \"\").trim() : \"\";\n\n// 3. Recorrer los países que tienen participantes en la sesión\nfor (const [paisParticipante] of Object.entries(participantesPorPais)) {\n\n // Buscar el coordinador cuyo país coincida limpiando acentos\n const coordinadorMatch = coordinadores.find(c => \n limpiarTexto(c.pais) === limpiarTexto(paisParticipante)\n );\n\n resultado.push({\n json: {\n pais: paisParticipante,\n coordinador: coordinadorMatch \n ? {\n nombre: coordinadorMatch.nombre,\n correo: coordinadorMatch.correo,\n pais_coordinador: coordinadorMatch.pais\n } \n : null,\n }\n });\n}\n\nreturn resultado;" }, "type": "n8n-nodes-base.code", "typeVersion": 2, @@ -10285,19 +10998,6 @@ "id": "3073d739-a2c7-4ba1-81bc-aeae266ad3ff", "name": "Matchear coordinador y pais inscrito" }, - { - "parameters": { - "options": {} - }, - "type": "n8n-nodes-base.splitInBatches", - "typeVersion": 3, - "position": [ - 1152, - 1440 - ], - "id": "15c6bc9c-047f-4f56-ac8e-9a1d40b816a7", - "name": "Loop Over Items3" - }, { "parameters": { "amount": 2 @@ -10305,8 +11005,8 @@ "type": "n8n-nodes-base.wait", "typeVersion": 1.1, "position": [ - 2128, - 1504 + 2640, + 1488 ], "id": "8fef83c7-d197-484c-b40f-817a198bf5fc", "name": "Wait6", @@ -10337,8 +11037,8 @@ "type": "n8n-nodes-base.supabase", "typeVersion": 1, "position": [ - 1952, - 1504 + 2464, + 1488 ], "id": "0881ba84-bd04-4e91-9c09-0ba18e28ed28", "name": "Actualizar estado a notificado", @@ -10361,7 +11061,7 @@ "conditions": [ { "id": "df25aa3e-d48f-4e52-ae1f-47678e954d52", - "leftValue": "={{ $json.session.participantes }}", + "leftValue": "={{ $('Calcular sesion mas cercana4').item.json.session.participantes }}", "rightValue": "EN", "operator": { "type": "object", @@ -10377,7 +11077,7 @@ "type": "n8n-nodes-base.if", "typeVersion": 2.3, "position": [ - 192, + 864, 2144 ], "id": "d1472787-4c2f-4e1d-8673-5c2368d469ab", @@ -10464,7 +11164,7 @@ }, "sendBody": true, "specifyBody": "json", - "jsonBody": "={\n \"p_sesion_id\": \"{{ $('Calcular sesion mas cercana2').item.json.session.id }}\",\n \"p_pais\": \"{{ $json.pais }}\",\n \"p_empleados\": [\n {\n \"nombre\": \"{{ $json.nombre }}\",\n \"correo\": \"{{ $json.email }}\",\n \"departamento\": \"{{ $json.departamento }}\",\n \"division\": \"{{ $json.division }}\"\n }\n ]\n}", + "jsonBody": "={\n \"p_sesion_id\": \"{{ $('Calcular sesion mas cercana2').item.json.session.id }}\",\n \"p_pais\": \"{{ $('Get an employee1').item.json.location }}\",\n \"p_empleados\": [\n {\n \"nombre\": \"{{ $('Get an employee1').item.json.displayName }}\",\n \"correo\": \"{{ $('Get an employee1').item.json.workEmail }}\",\n \"departamento\": \"{{ $('Get an employee1').item.json.department }}\",\n \"division\": \"{{ $('Get an employee1').item.json.division }}\"\n }\n ]\n}", "options": {} }, "type": "n8n-nodes-base.httpRequest", @@ -10495,7 +11195,7 @@ }, "sendBody": true, "specifyBody": "json", - "jsonBody": "={\n \"p_sesion_id\": \"{{ $('Calcular sesion mas cercana3').item.json.session.id }}\",\n \"p_pais\": \"{{ $json.pais }}\",\n \"p_empleados\": [\n {\n \"nombre\": \"{{ $json.nombre }}\",\n \"correo\": \"{{ $json.email }}\",\n \"departamento\": \"{{ $json.departamento }}\",\n \"division\": \"{{ $json.division }}\"\n }\n ]\n}", + "jsonBody": "={\n \"p_sesion_id\": \"{{ $('Calcular sesion mas cercana3').item.json.session.id }}\",\n \"p_pais\": \"{{ $('Get an employee1').item.json.location }}\",\n \"p_empleados\": [\n {\n \"nombre\": \"{{ $('Get an employee1').item.json.displayName }}\",\n \"correo\": \"{{ $('Get an employee1').item.json.workEmail }}\",\n \"departamento\": \"{{ $('Get an employee1').item.json.department }}\",\n \"division\": \"{{ $('Get an employee1').item.json.division }}\"\n }\n ]\n}", "options": {} }, "type": "n8n-nodes-base.httpRequest", @@ -10572,8 +11272,8 @@ "type": "n8n-nodes-base.gmail", "typeVersion": 2.2, "position": [ - 624, - 2032 + 1872, + 2784 ], "id": "3167fd45-4eae-4db4-92fb-9c80223cb4fa", "name": "Send a message espanol6", @@ -10586,67 +11286,6 @@ }, "disabled": true }, - { - "parameters": { - "sendTo": "={{ $json.session.correo_instructor }}", - "subject": "#TheGLMWay Training", - "emailType": "text", - "message": "=Hello,\n\nThis is to inform you that, as of now, there are no people enrolled for today's activity.\n\nBest regards.\n\nThis is an automated message generated by the enrollment management system.", - "options": { - "appendAttribution": false - } - }, - "type": "n8n-nodes-base.gmail", - "typeVersion": 2.2, - "position": [ - 624, - 1856 - ], - "id": "0cd1d4fb-062f-42ca-bf9c-1424e17d50f0", - "name": "Send a message ingles6", - "webhookId": "a6043707-89d1-4c99-8de2-e60d9aaf7ed2", - "credentials": { - "gmailOAuth2": { - "id": "QWNicjw1khRm5BVI", - "name": "Eidan - Gmail account" - } - }, - "disabled": true - }, - { - "parameters": { - "conditions": { - "options": { - "caseSensitive": true, - "leftValue": "", - "typeValidation": "strict", - "version": 3 - }, - "conditions": [ - { - "id": "df25aa3e-d48f-4e52-ae1f-47678e954d52", - "leftValue": "={{ $json.session.idioma }}", - "rightValue": "EN", - "operator": { - "type": "string", - "operation": "equals", - "name": "filter.operator.equals" - } - } - ], - "combinator": "and" - }, - "options": {} - }, - "type": "n8n-nodes-base.if", - "typeVersion": 2.3, - "position": [ - 416, - 1936 - ], - "id": "dd5cce8e-ef5a-4bd4-967c-aec464f30fc4", - "name": "Es espanol o ingles1" - }, { "parameters": { "jsCode": "const TIMEZONES = {\n \"Argentina\": \"America/Argentina/Buenos_Aires\",\n \"Bolivia\": \"America/La_Paz\",\n \"Brasil\": \"America/Sao_Paulo\",\n \"Chile\": \"America/Santiago\",\n \"Colombia\": \"America/Bogota\",\n \"Costa Rica\": \"America/Costa_Rica\",\n \"Cuba\": \"America/Havana\",\n \"Ecuador\": \"America/Guayaquil\",\n \"El Salvador\": \"America/El_Salvador\",\n \"Guatemala\": \"America/Guatemala\",\n \"Honduras\": \"America/Tegucigalpa\",\n \"Mexico\": \"America/Mexico_City\",\n \"Nicaragua\": \"America/Managua\",\n \"Panama\": \"America/Panama\",\n \"Paraguay\": \"America/Asuncion\",\n \"Peru\": \"America/Lima\",\n \"Puerto Rico\": \"America/Puerto_Rico\",\n \"Republica Dominicana\": \"America/Santo_Domingo\",\n \"Uruguay\": \"America/Montevideo\",\n \"Venezuela\": \"America/Caracas\",\n \"Jamaica\": \"America/Jamaica\",\n \"Trinidad and Tobago\": \"America/Port_of_Spain\",\n \"Guyana\": \"America/Guyana\",\n \"Surinam\": \"America/Paramaribo\",\n \"Belice\": \"America/Belize\"\n};\n\n// ==============================\n// FUNCIONES\n// ==============================\n\nfunction normalizarPais(texto) {\n return texto\n .normalize(\"NFD\")\n .replace(/[\\u0300-\\u036f]/g, \"\")\n .trim()\n .toLowerCase();\n}\n\nfunction obtenerOffsetMinutos(fecha, timeZone) {\n const dtf = new Intl.DateTimeFormat(\"en-US\", {\n timeZone,\n hour12: false,\n year: \"numeric\",\n month: \"2-digit\",\n day: \"2-digit\",\n hour: \"2-digit\",\n minute: \"2-digit\",\n second: \"2-digit\"\n });\n\n const partes = dtf.formatToParts(fecha).reduce((acc, p) => {\n acc[p.type] = p.value;\n return acc;\n }, {});\n\n const utcEquivalente = Date.UTC(\n Number(partes.year),\n Number(partes.month) - 1,\n Number(partes.day),\n Number(partes.hour),\n Number(partes.minute),\n Number(partes.second)\n );\n\n return (utcEquivalente - fecha.getTime()) / 60000;\n}\n\nfunction obtenerUTCDesdeHoraLocal(horaTexto, timeZone) {\n const [hora, minuto] = horaTexto.split(\":\").map(Number);\n\n const ahora = new Date();\n\n const y = ahora.getUTCFullYear();\n const m = ahora.getUTCMonth();\n const d = ahora.getUTCDate();\n\n let fechaUTC = new Date(Date.UTC(y, m, d, hora, minuto, 0));\n\n const offset = obtenerOffsetMinutos(fechaUTC, timeZone);\n\n fechaUTC = new Date(fechaUTC.getTime() - offset * 60000);\n\n return fechaUTC;\n}\n\nfunction formatearHora(fechaUTC, timeZone) {\n return new Intl.DateTimeFormat(\"es-DO\", {\n timeZone,\n hour: \"2-digit\",\n minute: \"2-digit\",\n hour12: false\n }).format(fechaUTC);\n}\n\nfunction convertirHoraDesdeSantoDomingo(horaTexto) {\n\n const fechaUTC = obtenerUTCDesdeHoraLocal(\n horaTexto,\n TIMEZONES[\"Republica Dominicana\"]\n );\n\n const resultado = {};\n\n for (const [pais, tz] of Object.entries(TIMEZONES)) {\n resultado[pais] = formatearHora(fechaUTC, tz);\n }\n\n return resultado;\n}\n\n// ==============================\n// EJECUCIÓN\n// ==============================\n\nconst horaEntrada = $('Calcular sesion mas cercana')\n .first()\n .json\n .session\n .hora_inicio;\n\nif (!horaEntrada || !/^\\d{1,2}:\\d{2}$/.test(horaEntrada)) {\n throw new Error(\n `Formato de hora inválido: \"${horaEntrada}\". Usa HH:mm, por ejemplo 19:00`\n );\n}\n\nconst conversiones = convertirHoraDesdeSantoDomingo(horaEntrada);\n\nreturn items.map(item => {\n\n const paisEntrada = $('Guardar datos del empleado y sesion asignada').first().json.pais;\n\n if (!paisEntrada) {\n throw new Error('Cada item debe contener el campo \"pais\".');\n }\n\n // Buscar el país ignorando mayúsculas y acentos\n const paisEncontrado = Object.keys(TIMEZONES).find(\n pais => normalizarPais(pais) === normalizarPais(paisEntrada)\n );\n\n if (!paisEncontrado) {\n throw new Error(\n `País no reconocido: \"${paisEntrada}\". Países válidos: ${Object.keys(TIMEZONES).join(\", \")}`\n );\n }\n\n return {\n json: {\n hora_base: horaEntrada,\n pais_base: \"Republica Dominicana\",\n hora_convertida: conversiones[paisEncontrado],\n conversiones\n }\n };\n});" @@ -11019,26 +11658,6 @@ } } }, - { - "parameters": { - "resource": "audio", - "additionalFields": {} - }, - "type": "@firefliesai/n8n-nodes-fireflies.fireflies", - "typeVersion": 1, - "position": [ - -256, - 3616 - ], - "id": "14fa274e-6c75-4db5-bfdd-6fb4499f74bb", - "name": "Upload audio", - "credentials": { - "firefliesApi": { - "id": "3KMwcovPfZBeQOlm", - "name": "Eidan (Maximo) - Fireflies account" - } - } - }, { "parameters": { "resource": "meeting", @@ -11059,6 +11678,665 @@ "name": "Eidan (Maximo) - Fireflies account" } } + }, + { + "parameters": { + "url": "=https://meet.googleapis.com/v2/conferenceRecords", + "authentication": "predefinedCredentialType", + "nodeCredentialType": "googleOAuth2Api", + "sendQuery": true, + "queryParameters": { + "parameters": [ + { + "name": "filter", + "value": "start_time>=\"2026-07-08T19:00:50.545Z\"" + } + ] + }, + "options": {} + }, + "type": "n8n-nodes-base.httpRequest", + "typeVersion": 4.4, + "position": [ + -32, + 3360 + ], + "id": "26bbeb6d-3c51-4d8a-b487-801fa9bf3637", + "name": "HTTP Request4", + "credentials": { + "googleOAuth2Api": { + "id": "0HsSRUm82KPsWdiJ", + "name": "Eidan - Google account" + } + } + }, + { + "parameters": { + "pollTimes": { + "item": [ + { + "mode": "everyMinute" + } + ] + }, + "calendarId": { + "__rl": true, + "value": "ethen@gomezleemarketing.com", + "mode": "list", + "cachedResultName": "ethen@gomezleemarketing.com" + }, + "triggerOn": "eventStarted", + "options": {} + }, + "type": "n8n-nodes-base.googleCalendarTrigger", + "typeVersion": 1, + "position": [ + -416, + 3808 + ], + "id": "eb3ace4c-1285-4495-9239-09d18d993874", + "name": "Prueba1", + "credentials": { + "googleCalendarOAuth2Api": { + "id": "yEmGG4av5RxOK7wu", + "name": "Eidan - Google Calendar account" + } + } + }, + { + "parameters": { + "resource": "meeting" + }, + "type": "@firefliesai/n8n-nodes-fireflies.fireflies", + "typeVersion": 1, + "position": [ + 288, + 3824 + ], + "id": "14fa274e-6c75-4db5-bfdd-6fb4499f74bb", + "name": "Get active meetings", + "credentials": { + "firefliesApi": { + "id": "ILtybc8HxTqTGEX3", + "name": "Eidan Prueba - Fireflies account" + } + } + }, + { + "parameters": { + "url": "=https://meet.googleapis.com/v2/conferenceRecords", + "authentication": "predefinedCredentialType", + "nodeCredentialType": "googleOAuth2Api", + "options": {} + }, + "type": "n8n-nodes-base.httpRequest", + "typeVersion": 4.4, + "position": [ + -544, + 3616 + ], + "id": "602289b9-3c7d-4ced-b507-b27401ed9910", + "name": "Obtener conferenceRecord", + "credentials": { + "googleOAuth2Api": { + "id": "0HsSRUm82KPsWdiJ", + "name": "Eidan - Google account" + } + } + }, + { + "parameters": { + "url": "=https://meet.googleapis.com/v2/conferenceRecords/SWfRlwz4RqZSEwnrm7fcDxIWOBABMgUIigIgABgBCA/participants", + "authentication": "predefinedCredentialType", + "nodeCredentialType": "googleOAuth2Api", + "options": {} + }, + "type": "n8n-nodes-base.httpRequest", + "typeVersion": 4.4, + "position": [ + 112, + 3616 + ], + "id": "30910677-628e-4376-b15c-788d352d9ca0", + "name": "HTTP Request5", + "credentials": { + "googleOAuth2Api": { + "id": "0HsSRUm82KPsWdiJ", + "name": "Eidan - Google account" + } + } + }, + { + "parameters": { + "jsCode": "// 1. Obtener la lista completa de conferencias desde el JSON de entrada\nconst records = $input.first().json.conferenceRecords || [];\n\n\nlet ultimoItemMatch = null;\n\n// 2. Iterar por todos los registros para encontrar el que aplica\nfor (const record of records) {\n // Convertir el string UTC nativo a objeto de fecha\n const fechaStartUTC = new Date(record.startTime);\n \n // Extraer la hora específicamente en la zona horaria de RD\n const horaRD = parseInt(fechaStartUTC.toLocaleTimeString(\"en-US\", { \n timeZone: \"America/Santo_Domingo\", \n hour12: false, \n hour: \"2-digit\" \n }), 10);\n\n // 3. Evaluar si la hora de inicio es igual a las 19:00 (7 PM)\n if (horaRD === 19) {\n // Al ir asignándolo secuencialmente, el último que haga match sobreescribirá al anterior\n ultimoItemMatch = {\n json: {\n id: record.name.split('/').pop(),\n name: record.name,\n space: record.space,\n startTimeRaw: record.startTime,\n endTimeRaw: record.endTime,\n startTimeLocalRD: fechaStartUTC.toLocaleString(\"es-DO\", { timeZone: \"America/Santo_Domingo\" }),\n endTimeLocalRD: new Date(record.endTime).toLocaleString(\"es-DO\", { timeZone: \"America/Santo_Domingo\" })\n }\n };\n }\n}\n\n// 4. Si se encontró un elemento que haga match, se devuelve. Si no, devuelve un arreglo vacío.\nreturn ultimoItemMatch ? [ultimoItemMatch] : [];\n" + }, + "type": "n8n-nodes-base.code", + "typeVersion": 2, + "position": [ + -352, + 3616 + ], + "id": "0c4e04b2-06ec-4d33-97ee-926325533116", + "name": "Code in JavaScript" + }, + { + "parameters": { + "content": "# Añadir la hora en el mensaje" + }, + "type": "n8n-nodes-base.stickyNote", + "position": [ + 1616, + 800 + ], + "typeVersion": 1, + "id": "e8d3205f-4278-4cad-9f49-9be1839d1434", + "name": "Sticky Note11" + }, + { + "parameters": { + "method": "POST", + "url": "=https://chat.googleapis.com/v1/spaces/AAQAR2K6i8Y/messages?key=AIzaSyDdI0hCZtE6vySjMm-WEfRq3CPzqKqqsHI&token=yOTYTZ6rayK3NlOworCkaKMPCqssxjbokfKY3wFjeXg", + "sendHeaders": true, + "headerParameters": { + "parameters": [ + {} + ] + }, + "sendBody": true, + "specifyBody": "json", + "jsonBody": "={{ $json }}", + "options": {} + }, + "type": "n8n-nodes-base.httpRequest", + "typeVersion": 4.2, + "position": [ + 1536, + 1936 + ], + "id": "11458855-2bd1-4778-81f6-efe07ee1ee8b", + "name": "Enviar al espacio de prueba", + "retryOnFail": true + }, + { + "parameters": { + "operation": "get", + "contactId": "={{ $json.idLimpio }}", + "fields": [ + "emailAddresses", + "names" + ] + }, + "type": "n8n-nodes-base.googleContacts", + "typeVersion": 1, + "position": [ + 528, + 2144 + ], + "id": "1382bd89-9dd0-4fd5-a78d-853ac02840fb", + "name": "Get a contact", + "credentials": { + "googleContactsOAuth2Api": { + "id": "Qmeljx6s3HU998tB", + "name": "Eidan - Google Contacts account" + } + } + }, + { + "parameters": { + "jsCode": "// 1. Obtenemos la lista de miembros del nodo anterior\n// Nota: Ajusta 'memberships' si tu JSON viene estructurado de otra forma\nconst memberships = $input.first().json.memberships || [];\n\n// 2. Mapeamos y limpiamos cada usuario\nconst usuariosLimpios = memberships.map(item => {\n const fullUserPath = item.member.name; // Ej: \"users/117120277440258194844\"\n \n // Reemplazamos \"users/\" por nada para dejar solo el número\n const idLimpio = fullUserPath.replace('users/', ''); \n \n return {\n json: {\n idOriginal: fullUserPath,\n idLimpio: idLimpio,\n role: item.role,\n type: item.member.type\n }\n };\n});\n\n// 3. Devolvemos la lista para que n8n los procese en lote\nreturn usuariosLimpios;" + }, + "type": "n8n-nodes-base.code", + "typeVersion": 2, + "position": [ + 352, + 2144 + ], + "id": "41e5b9fd-598f-4dfb-b7f6-53d473ec1d71", + "name": "Limpiar id" + }, + { + "parameters": { + "jsCode": "// 1. Obtenemos el nombre del instructor del nodo \"Calcular sesion mas cercana4\"\nconst sessionItem = $('Calcular sesion mas cercana4').first();\nconst instructor = sessionItem?.json?.session?.instructor;\n\nif (!instructor) {\n return []; // Si no hay instructor, devolvemos una lista vacía para evitar errores\n}\n\nconst instructorClean = instructor.toLowerCase().trim();\n\n// 2. Obtenemos todos los contactos de \"Get a contact\"\nconst contacts = $('Get a contact').all();\n\n// 3. Filtramos los contactos donde haya coincidencia con el instructor\nconst matchingContacts = contacts.filter(item => {\n const displayName = item.json.names?.displayName;\n if (!displayName) return false; // Ignora contactos sin nombre (como el último de tu lista)\n\n const displayNameClean = displayName.toLowerCase().trim();\n\n return displayNameClean.includes(instructorClean) || instructorClean.includes(displayNameClean);\n});\n\nreturn matchingContacts;" + }, + "type": "n8n-nodes-base.code", + "typeVersion": 2, + "position": [ + 688, + 2144 + ], + "id": "aa48e478-2800-4462-b8a5-fb4651701b2d", + "name": "Unir datos2" + }, + { + "parameters": { + "url": "=https://chat.googleapis.com/v1/spaces/AAQAgX1mjaY/members", + "authentication": "predefinedCredentialType", + "nodeCredentialType": "googleChatOAuth2Api", + "options": {} + }, + "type": "n8n-nodes-base.httpRequest", + "typeVersion": 4.2, + "position": [ + 192, + 2144 + ], + "id": "7e8c9e23-1bfb-4111-983d-898eb43f4981", + "name": "Obtener miembros", + "retryOnFail": true, + "credentials": { + "googleChatOAuth2Api": { + "id": "Tg9EZ8oKp4hqoWvX", + "name": "Eidan - Chat account" + } + } + }, + { + "parameters": { + "jsCode": "// 1. Obtener datos de la sesión del nodo \"Calcular sesion mas cercana4\"\nconst sessionNode = $('Calcular sesion mas cercana4').first();\nconst session = sessionNode?.json?.session || {};\nconst titulo = session.titulo || \"Sin título\";\nconst horaInicio = session.hora_inicio || \"--:--\";\nconst horaFin = session.hora_fin || \"--:--\";\nconst enlace = session.enlace_reunion || \"\";\n\n// 2. Contar participantes sumando los de todos los países de forma dinámica\nlet totalParticipantes = 0;\nif (session.participantes) {\n Object.keys(session.participantes).forEach(pais => {\n const listaPais = session.participantes[pais];\n if (Array.isArray(listaPais)) {\n totalParticipantes += listaPais.length;\n }\n });\n}\n\n// 3. Obtener los contactId del nodo anterior para generar las menciones\nlet menciones = \"\";\ntry {\n const itemsUnirDatos = $('Unir datos2').all();\n const idsUnicos = [...new Set(\n itemsUnirDatos\n .map(item => item.json.contactId)\n .filter(id => id !== undefined && id !== null && id !== \"\")\n )];\n menciones = idsUnicos.map(id => ``).join(\" \");\n} catch (error) {\n menciones = \"\";\n}\n\n// 4. Construir cuerpo del mensaje con los datos de la sesión\nconst body = {\n text: `🔔 *Recordatorio de #TheGLMWay para hoy* \\n\\nInstructor: ${menciones}`,\n cardsV2: [\n {\n cardId: \"session-reminder\",\n card: {\n header: {\n title: \"🎓 Sesión de Capacitación\"\n },\n sections: [\n {\n widgets: [\n {\n textParagraph: {\n text: `Tema: ${titulo}
` +\n `Participantes inscritos: ${totalParticipantes} personas`\n }\n },\n {\n textParagraph: {\n text: `👉 Entrar a la reunión aquí`\n }\n }\n ]\n }\n ]\n }\n }\n ]\n};\n\nreturn [{ json: body }];" + }, + "type": "n8n-nodes-base.code", + "typeVersion": 2, + "position": [ + 1296, + 2032 + ], + "id": "18d7cd2e-ba38-4c1b-b2e1-f3db9fe301d5", + "name": "Formatear datos espanol" + }, + { + "parameters": { + "jsCode": "// 1. Obtener datos de la sesión del nodo \"Calcular sesion mas cercana4\"\nconst sessionNode = $('Calcular sesion mas cercana4').first();\nconst session = sessionNode?.json?.session || {};\nconst titulo = session.titulo || \"Untitled\";\nconst horaInicio = session.hora_inicio || \"--:--\";\nconst horaFin = session.hora_fin || \"--:--\";\nconst enlace = session.enlace_reunion || \"\";\n\n// 2. Contar participantes sumando los de todos los países de forma dinámica\nlet totalParticipantes = 0;\nif (session.participantes) {\n Object.keys(session.participantes).forEach(pais => {\n const listaPais = session.participantes[pais];\n if (Array.isArray(listaPais)) {\n totalParticipantes += listaPais.length;\n }\n });\n}\n\n// 3. Obtener los contactId del nodo anterior para generar las menciones\nlet menciones = \"\";\ntry {\n const itemsUnirDatos = $('Unir datos2').all();\n const idsUnicos = [...new Set(\n itemsUnirDatos\n .map(item => item.json.contactId)\n .filter(id => id !== undefined && id !== null && id !== \"\")\n )];\n menciones = idsUnicos.map(id => ``).join(\" \");\n} catch (error) {\n menciones = \"\";\n}\n\n// 4. Construir cuerpo del mensaje con los datos de la sesión\nconst body = {\n text: `🔔 *#TheGLMWay Reminder for today* \\n\\nInstructor: ${menciones}`,\n cardsV2: [\n {\n cardId: \"session-reminder\",\n card: {\n header: {\n title: \"🎓 Training Session\"\n },\n sections: [\n {\n widgets: [\n {\n textParagraph: {\n text: `Topic: ${titulo}
` +\n `Registered participants: ${totalParticipantes} people`\n }\n },\n {\n textParagraph: {\n text: `👉 Join the meeting here`\n }\n }\n ]\n }\n ]\n }\n }\n ]\n};\n\nreturn [{ json: body }];" + }, + "type": "n8n-nodes-base.code", + "typeVersion": 2, + "position": [ + 1296, + 1872 + ], + "id": "36ad61bf-4d83-42f8-987e-8b8216115a67", + "name": "Formatear datos ingles" + }, + { + "parameters": { + "rules": { + "values": [ + { + "conditions": { + "options": { + "caseSensitive": true, + "leftValue": "", + "typeValidation": "strict", + "version": 3 + }, + "conditions": [ + { + "leftValue": "={{ $('Calcular sesion mas cercana4').item.json.session.idioma }}", + "rightValue": "EN", + "operator": { + "type": "string", + "operation": "equals" + }, + "id": "a6a13143-17cd-4020-b789-726c8faae456" + } + ], + "combinator": "and" + } + }, + { + "conditions": { + "options": { + "caseSensitive": true, + "leftValue": "", + "typeValidation": "strict", + "version": 3 + }, + "conditions": [ + { + "id": "5ffc2081-5b80-4d72-96fc-121dc727683a", + "leftValue": "={{ $('Calcular sesion mas cercana4').item.json.session.idioma }}", + "rightValue": "ES", + "operator": { + "type": "string", + "operation": "equals", + "name": "filter.operator.equals" + } + } + ], + "combinator": "and" + } + } + ] + }, + "options": {} + }, + "type": "n8n-nodes-base.switch", + "typeVersion": 3.4, + "position": [ + 1088, + 1952 + ], + "id": "afe4c647-cec2-4cb4-84c5-4b52914ced09", + "name": "Es espanol o ingles1" + }, + { + "parameters": { + "rules": { + "values": [ + { + "conditions": { + "options": { + "caseSensitive": true, + "leftValue": "", + "typeValidation": "strict", + "version": 3 + }, + "conditions": [ + { + "leftValue": "={{ $('Calcular sesion mas cercana4').item.json.session.idioma }}", + "rightValue": "EN", + "operator": { + "type": "string", + "operation": "equals" + }, + "id": "a6a13143-17cd-4020-b789-726c8faae456" + } + ], + "combinator": "and" + } + }, + { + "conditions": { + "options": { + "caseSensitive": true, + "leftValue": "", + "typeValidation": "strict", + "version": 3 + }, + "conditions": [ + { + "id": "5ffc2081-5b80-4d72-96fc-121dc727683a", + "leftValue": "={{ $('Calcular sesion mas cercana4').item.json.session.idioma }}", + "rightValue": "ES", + "operator": { + "type": "string", + "operation": "equals", + "name": "filter.operator.equals" + } + } + ], + "combinator": "and" + } + } + ] + }, + "options": {} + }, + "type": "n8n-nodes-base.switch", + "typeVersion": 3.4, + "position": [ + 1104, + 2288 + ], + "id": "17143de2-2245-45a8-b5db-06d73aa2104f", + "name": "Es espanol o ingles" + }, + { + "parameters": { + "jsCode": "// 1. Obtener datos de la sesión del nodo \"Calcular sesion mas cercana4\"\nconst sessionNode = $('Calcular sesion mas cercana4').first();\nconst session = sessionNode?.json?.session || {};\nconst titulo = session.titulo || \"Sin título\";\nconst horaInicio = session.hora_inicio || \"--:--\";\nconst horaFin = session.hora_fin || \"--:--\";\nconst enlace = session.enlace_reunion || \"\";\n\n// 2. Contar participantes sumando los de todos los países de forma dinámica\nlet totalParticipantes = 0;\nif (session.participantes) {\n Object.keys(session.participantes).forEach(pais => {\n const listaPais = session.participantes[pais];\n if (Array.isArray(listaPais)) {\n totalParticipantes += listaPais.length;\n }\n });\n}\n\n// 3. Obtener los contactId del nodo anterior para generar las menciones\nlet menciones = \"\";\ntry {\n const itemsUnirDatos = $('Unir datos2').all();\n const idsUnicos = [...new Set(\n itemsUnirDatos\n .map(item => item.json.contactId)\n .filter(id => id !== undefined && id !== null && id !== \"\")\n )];\n menciones = idsUnicos.map(id => ``).join(\" \");\n} catch (error) {\n menciones = \"\";\n}\n\n// 4. Construir cuerpo del mensaje con el aviso de que no hay participantes\nconst body = {\n text: `🔔 *Aviso de sesión sin participantes* \\n\\nInstructor: ${menciones}`,\n cardsV2: [\n {\n cardId: \"session-reminder\",\n card: {\n header: {\n title: \"⚠️ Sesión de Capacitación\"\n },\n sections: [\n {\n widgets: [\n {\n textParagraph: {\n text: `Tema: ${titulo}
\\n` +\n `No se han registrado participantes para la sesión de hoy, por lo que no es necesario que te conectes.`\n }\n }\n ]\n }\n ]\n }\n }\n ]\n};\n\nreturn [{ json: body }];" + }, + "type": "n8n-nodes-base.code", + "typeVersion": 2, + "position": [ + 1296, + 2368 + ], + "id": "953f5fb0-8eea-40f7-8910-a1da77516176", + "name": "Formatear datos espanol1" + }, + { + "parameters": { + "jsCode": "// 1. Get session data from the \"Calcular sesion mas cercana4\" node\nconst sessionNode = $('Calcular sesion mas cercana4').first();\nconst session = sessionNode?.json?.session || {};\nconst titulo = session.titulo || \"Untitled\";\nconst horaInicio = session.hora_inicio || \"--:--\";\nconst horaFin = session.hora_fin || \"--:--\";\nconst enlace = session.enlace_reunion || \"\";\n\n// 2. Count participants by dynamically summing all countries\nlet totalParticipantes = 0;\nif (session.participantes) {\n Object.keys(session.participantes).forEach(pais => {\n const listaPais = session.participantes[pais];\n if (Array.isArray(listaPais)) {\n totalParticipantes += listaPais.length;\n }\n });\n}\n\n// 3. Get contactId from the previous node to generate mentions\nlet menciones = \"\";\ntry {\n const itemsUnirDatos = $('Unir datos2').all();\n const idsUnicos = [...new Set(\n itemsUnirDatos\n .map(item => item.json.contactId)\n .filter(id => id !== undefined && id !== null && id !== \"\")\n )];\n menciones = idsUnicos.map(id => ``).join(\" \");\n} catch (error) {\n menciones = \"\";\n}\n\n// 4. Build the message body with the notice of no participants\nconst body = {\n text: `🔔 *No participants for today's session* \\n\\nInstructor: ${menciones}`,\n cardsV2: [\n {\n cardId: \"session-reminder\",\n card: {\n header: {\n title: \"⚠️ Training Session\"\n },\n sections: [\n {\n widgets: [\n {\n textParagraph: {\n text: `Topic: ${titulo}
\\n` +\n `No participants have registered for today's session, so you do not need to connect.`\n }\n }\n ]\n }\n ]\n }\n }\n ]\n};\n\nreturn [{ json: body }];" + }, + "type": "n8n-nodes-base.code", + "typeVersion": 2, + "position": [ + 1296, + 2208 + ], + "id": "adb8c1b5-1696-49b1-aa2d-8b329846c007", + "name": "Formatear datos ingles1" + }, + { + "parameters": { + "method": "POST", + "url": "=https://chat.googleapis.com/v1/spaces/AAQAgX1mjaY/messages?key=AIzaSyDdI0hCZtE6vySjMm-WEfRq3CPzqKqqsHI&token=drBaE6ZeBbHhPKCmJd_odP3UcYcq4Ie64JXmbI29Vp8", + "sendBody": true, + "specifyBody": "json", + "jsonBody": "={{ $json }}", + "options": {} + }, + "type": "n8n-nodes-base.httpRequest", + "typeVersion": 4.2, + "position": [ + 1520, + 2128 + ], + "id": "db80a48f-bf0b-4b4e-a1d6-06c9da6c188c", + "name": "Enviar notifacion a glmway notificaciones", + "retryOnFail": true + }, + { + "parameters": { + "pollTimes": { + "item": [ + { + "mode": "everyMinute" + } + ] + }, + "calendarId": { + "__rl": true, + "value": "ethen@gomezleemarketing.com", + "mode": "list", + "cachedResultName": "ethen@gomezleemarketing.com" + }, + "triggerOn": "eventEnded", + "options": { + "matchTerm": "Entrenamiento #TheGLMWay" + } + }, + "type": "n8n-nodes-base.googleCalendarTrigger", + "typeVersion": 1, + "position": [ + -32, + 3040 + ], + "id": "5a3cf15f-3237-4520-86e0-cd4fcfb2e997", + "name": "Inicio evento español1", + "credentials": { + "googleCalendarOAuth2Api": { + "id": "yEmGG4av5RxOK7wu", + "name": "Eidan - Google Calendar account" + } + } + }, + { + "parameters": { + "operation": "get", + "tableId": "empleados_glm", + "filters": { + "conditions": [ + { + "keyName": "work_email", + "keyValue": "=jtrujillo@gomezleemarketing.com" + } + ] + } + }, + "type": "n8n-nodes-base.supabase", + "typeVersion": 1, + "position": [ + 240, + 3344 + ], + "id": "e4115807-580d-4075-8d62-de14c174c43a", + "name": "Actualizar estado a recordado3", + "credentials": { + "supabaseApi": { + "id": "2PlsR6rpK7rQTIEn", + "name": "Sofia test - Supabase account" + } + } + }, + { + "parameters": { + "method": "POST", + "url": "=https://chat.googleapis.com/v1/spaces/AAQAR2K6i8Y/messages?key=AIzaSyDdI0hCZtE6vySjMm-WEfRq3CPzqKqqsHI&token=yOTYTZ6rayK3NlOworCkaKMPCqssxjbokfKY3wFjeXg", + "sendBody": true, + "specifyBody": "json", + "jsonBody": "={{ $json }}", + "options": {} + }, + "type": "n8n-nodes-base.httpRequest", + "typeVersion": 4.2, + "position": [ + 2224, + 1360 + ], + "id": "5d50cef9-0ebb-4f28-8deb-69c7feb6f62e", + "name": "Enviar al espacio de prueba1", + "retryOnFail": true + }, + { + "parameters": { + "method": "POST", + "url": "=https://chat.googleapis.com/v1/spaces/AAQAR2K6i8Y/messages?key=AIzaSyDdI0hCZtE6vySjMm-WEfRq3CPzqKqqsHI&token=yOTYTZ6rayK3NlOworCkaKMPCqssxjbokfKY3wFjeXg", + "sendBody": true, + "specifyBody": "json", + "jsonBody": "={{ $json }}", + "options": {} + }, + "type": "n8n-nodes-base.httpRequest", + "typeVersion": 4.2, + "position": [ + 2224, + 1536 + ], + "id": "c83590cd-6e98-4e2d-81f6-6e2f204a948d", + "name": "Enviar al espacio de prueba2", + "retryOnFail": true + }, + { + "parameters": { + "jsCode": "// 1. Obtener datos de la sesión del nodo \"Calcular falta 48h o 24h1\"\nconst sessionNode = $('Calcular falta 48h o 24h1').first();\nconst sesion = sessionNode?.json?.sesion || {}; // Leído desde la raíz del JSON\n\n// 2. Contar participantes y construir de forma dinámica la lista por país\nlet totalParticipantes = 0;\nlet listaParticipantesTexto = \"\";\n\nif (sesion.participantes) {\n Object.keys(sesion.participantes).forEach(pais => {\n const listaPais = sesion.participantes[pais];\n if (Array.isArray(listaPais) && listaPais.length > 0) {\n totalParticipantes += listaPais.length;\n \n // Añadir el encabezado del país\n listaParticipantesTexto += `
📍 ${pais} (${listaPais.length}):
`;\n \n // Listar cada participante de ese país\n listaPais.forEach(p => {\n listaParticipantesTexto += `• ${p.nombre} (${p.departamento || 'Sin Depto'} | ${p.division || 'Sin Division'})
`;\n });\n }\n });\n}\n\n// 3. Obtener los contactId del nodo anterior para generar las menciones de los coordinadores\nlet menciones = \"\";\ntry {\n const itemsUnirDatos = $('Unir datos3').all(); // Asegúrate de verificar si tu nodo se llama Unir datos3 o similar\n const idsUnicos = [...new Set(\n itemsUnirDatos\n .map(item => item.json.contactId)\n .filter(id => id !== undefined && id !== null && id !== \"\")\n )];\n menciones = idsUnicos.map(id => ``).join(\" \");\n} catch (error) {\n menciones = \"\";\n}\n\n// 4. Construir cuerpo del mensaje con formato Google Chat Card\nconst body = {\n text: `🔔 *Aviso para Coordinadores RRHH* \\nEstimados ${menciones}, aquí está el listado de personas inscritas para la sesión de mañana.`,\n cardsV2: [\n {\n cardId: \"session-reminder-hr\",\n card: {\n header: {\n title: `🎓 Capacitación #TheGLMWay de mañana`,\n },\n sections: [\n {\n header: \"📈 Resumen de Asistencia\",\n widgets: [\n {\n textParagraph: {\n text: `Total inscritos: ${totalParticipantes} personas
` + \n listaParticipantesTexto\n }\n }\n ]\n }\n ]\n }\n }\n ]\n};\n\nreturn [{ json: body }];" + }, + "type": "n8n-nodes-base.code", + "typeVersion": 2, + "position": [ + 2048, + 1536 + ], + "id": "87ace248-4ea5-406f-89da-88d450ad413e", + "name": "Formatear datos espanol2" + }, + { + "parameters": { + "jsCode": "// 1. Obtener datos de la sesión del nodo \"Calcular sesion mas cercana4\"\nconst sessionNode = $('Calcular sesion mas cercana4').first();\nconst session = sessionNode?.json?.session || {};\nconst titulo = session.titulo || \"Untitled\";\nconst horaInicio = session.hora_inicio || \"--:--\";\nconst horaFin = session.hora_fin || \"--:--\";\nconst enlace = session.enlace_reunion || \"\";\n\n// 2. Contar participantes sumando los de todos los países de forma dinámica\nlet totalParticipantes = 0;\nif (session.participantes) {\n Object.keys(session.participantes).forEach(pais => {\n const listaPais = session.participantes[pais];\n if (Array.isArray(listaPais)) {\n totalParticipantes += listaPais.length;\n }\n });\n}\n\n// 3. Obtener los contactId del nodo anterior para generar las menciones\nlet menciones = \"\";\ntry {\n const itemsUnirDatos = $('Unir datos2').all();\n const idsUnicos = [...new Set(\n itemsUnirDatos\n .map(item => item.json.contactId)\n .filter(id => id !== undefined && id !== null && id !== \"\")\n )];\n menciones = idsUnicos.map(id => ``).join(\" \");\n} catch (error) {\n menciones = \"\";\n}\n\n// 4. Construir cuerpo del mensaje con los datos de la sesión\nconst body = {\n text: `🔔 *#TheGLMWay Reminder for today* \\n\\nInstructor: ${menciones}`,\n cardsV2: [\n {\n cardId: \"session-reminder\",\n card: {\n header: {\n title: \"🎓 Training Session\"\n },\n sections: [\n {\n widgets: [\n {\n textParagraph: {\n text: `Topic: ${titulo}
` +\n `Registered participants: ${totalParticipantes} people`\n }\n },\n {\n textParagraph: {\n text: `👉 Join the meeting here`\n }\n }\n ]\n }\n ]\n }\n }\n ]\n};\n\nreturn [{ json: body }];" + }, + "type": "n8n-nodes-base.code", + "typeVersion": 2, + "position": [ + 2048, + 1360 + ], + "id": "bb4cbe19-9364-4c83-a309-5594d9c5a26b", + "name": "Formatear datos ingles2" + }, + { + "parameters": { + "jsCode": "// Obtener todos los elementos que entran al nodo\nconst items = $input.all();\n\nconst hoy = new Date();\nhoy.setHours(0, 0, 0, 0);\n\nlet mejorItem = null;\nlet menorDiferencia = Infinity;\nlet mejorFechaHoyStr = '';\n\n// Recorrer cada sesión para calcular cuál es la más cercana\nfor (const item of items) {\n const fecha_sesion = item.json.fecha_sesion;\n if (!fecha_sesion) continue;\n\n // Crear la fecha de la sesión usando el año actual\n let sesion = new Date(`${fecha_sesion} ${hoy.getFullYear()}`);\n sesion.setHours(0, 0, 0, 0);\n\n // Si la fecha ya pasó este año, se toma la del año que viene\n if (sesion < hoy) {\n sesion = new Date(`${fecha_sesion} ${hoy.getFullYear() + 1}`);\n sesion.setHours(0, 0, 0, 0);\n }\n\n // Calcular diferencia en días\n const diferenciaDias = Math.floor((sesion - hoy) / (1000 * 60 * 60 * 24));\n\n // Si esta sesión es más cercana que las anteriores analizadas, la guardamos\n if (diferenciaDias < menorDiferencia) {\n menorDiferencia = diferenciaDias;\n mejorItem = item.json;\n mejorFechaHoyStr = hoy.toLocaleDateString('en-GB', {\n day: 'numeric',\n month: 'long'\n });\n }\n}\n\n// Si no se encontró ninguna sesión válida, no devuelve nada\nif (!mejorItem) return [];\n\n// Retorna únicamente la sesión más cercana encontrada\nreturn [\n {\n json: {\n sesion: mejorItem,\n fecha_hoy: mejorFechaHoyStr,\n diferenciaDias: menorDiferencia\n }\n }\n];" + }, + "type": "n8n-nodes-base.code", + "typeVersion": 2, + "position": [ + 0, + 1568 + ], + "id": "47542a5b-ebe1-4e85-8229-bb9aa7e1b744", + "name": "Calcular falta 48h o 24h1" + }, + { + "parameters": { + "operation": "get", + "contactId": "={{ $json.idLimpio }}", + "fields": [ + "emailAddresses", + "names" + ] + }, + "type": "n8n-nodes-base.googleContacts", + "typeVersion": 1, + "position": [ + 1504, + 1440 + ], + "id": "f49640d2-f7a0-43da-b9e1-1da5dbe93a22", + "name": "Get a contact1", + "credentials": { + "googleContactsOAuth2Api": { + "id": "Qmeljx6s3HU998tB", + "name": "Eidan - Google Contacts account" + } + } + }, + { + "parameters": { + "jsCode": "// 1. Obtenemos la lista de miembros del nodo anterior\n// Nota: Ajusta 'memberships' si tu JSON viene estructurado de otra forma\nconst memberships = $input.first().json.memberships || [];\n\n// 2. Mapeamos y limpiamos cada usuario\nconst usuariosLimpios = memberships.map(item => {\n const fullUserPath = item.member.name; // Ej: \"users/117120277440258194844\"\n \n // Reemplazamos \"users/\" por nada para dejar solo el número\n const idLimpio = fullUserPath.replace('users/', ''); \n \n return {\n json: {\n idOriginal: fullUserPath,\n idLimpio: idLimpio,\n role: item.role,\n type: item.member.type\n }\n };\n});\n\n// 3. Devolvemos la lista para que n8n los procese en lote\nreturn usuariosLimpios;" + }, + "type": "n8n-nodes-base.code", + "typeVersion": 2, + "position": [ + 1328, + 1440 + ], + "id": "c17d8ecc-45f9-4c03-a4d4-88d90ae8a3ec", + "name": "Limpiar id1" + }, + { + "parameters": { + "jsCode": "// 1. Forzar la lectura del nodo de coordinadores\nconst itemsCoordinadores = $('Matchear coordinador y pais inscrito').all();\n\n// 2. Obtener todos los contactos cargados de \"Get a contact1\"\nconst contacts = $('Get a contact1').all();\n\nconst resultado = [];\n\n// Función para limpiar tildes, espacios y pasarlo a minúsculas\nconst limpiarTexto = (texto) => \n texto ? texto.toLowerCase().normalize(\"NFD\").replace(/[\\u0300-\\u036f]/g, \"\").trim() : \"\";\n\n// 3. Procesar la lista de coordinadores\nfor (const item of itemsCoordinadores) {\n const coordinadorNombre = item.json.coordinador?.nombre;\n const paisCoordinador = item.json.pais; // Extraemos el país\n if (!coordinadorNombre) continue;\n\n const coordinadorClean = limpiarTexto(coordinadorNombre);\n\n // 4. Buscar coincidencias en los contactos de Google\n const matchingContacts = contacts.filter(c => {\n const displayName = c.json.names?.displayName;\n if (!displayName) return false;\n\n const displayNameClean = limpiarTexto(displayName);\n return displayNameClean === coordinadorClean || displayNameClean.includes(coordinadorClean) || coordinadorClean.includes(displayNameClean);\n });\n\n // 5. Guardar los resultados encontrados incluyendo el país\n for (const contactItem of matchingContacts) {\n resultado.push({\n json: {\n pais: paisCoordinador,\n nombre_detectado: contactItem.json.names.displayName,\n contactId: contactItem.json.contactId\n }\n });\n }\n}\n\nreturn resultado;" + }, + "type": "n8n-nodes-base.code", + "typeVersion": 2, + "position": [ + 1664, + 1440 + ], + "id": "73de340f-189b-4963-bdf6-9b1bfd603cd6", + "name": "Unir datos3" + }, + { + "parameters": { + "url": "=https://chat.googleapis.com/v1/spaces/AAQAQj1t9AA/members", + "authentication": "predefinedCredentialType", + "nodeCredentialType": "googleChatOAuth2Api", + "options": {} + }, + "type": "n8n-nodes-base.httpRequest", + "typeVersion": 4.2, + "position": [ + 1168, + 1440 + ], + "id": "949eb6ae-2aba-43d2-a262-f91313336d2f", + "name": "Obtener miembros RRHH Notificaciones", + "retryOnFail": true, + "credentials": { + "googleChatOAuth2Api": { + "id": "Tg9EZ8oKp4hqoWvX", + "name": "Eidan - Chat account" + } + } } ], "connections": { @@ -11758,24 +13036,12 @@ }, "Send a message espanol3": { "main": [ - [ - { - "node": "Actualizar estado a notificado", - "type": "main", - "index": 0 - } - ] + [] ] }, "Send a message ingles3": { "main": [ - [ - { - "node": "Actualizar estado a notificado", - "type": "main", - "index": 0 - } - ] + [] ] }, "Schedule Trigger3": { @@ -11792,38 +13058,26 @@ "Loop Over Items2": { "main": [ [], - [ - { - "node": "Calcular falta 48h o 24h", - "type": "main", - "index": 0 - } - ] + [] ] }, "Wait3": { "main": [ - [ - { - "node": "Loop Over Items2", - "type": "main", - "index": 0 - } - ] + [] ] }, "Pais?3": { "main": [ [ { - "node": "Send a message ingles3", + "node": "Formatear datos ingles2", "type": "main", "index": 0 } ], [ { - "node": "Send a message espanol3", + "node": "Formatear datos espanol2", "type": "main", "index": 0 } @@ -11832,13 +13086,7 @@ }, "Falta 48h para el evento?1": { "main": [ - [ - { - "node": "Hay inscritos en la sesion?", - "type": "main", - "index": 0 - } - ], + [], [] ] }, @@ -12092,41 +13340,18 @@ "main": [ [ { - "node": "Hay inscritos?", + "node": "Obtener miembros", "type": "main", "index": 0 } ] ] }, - "Es espanol o ingles": { - "main": [ - [ - { - "node": "Send a message ingles5", - "type": "main", - "index": 0 - } - ], - [ - { - "node": "Send a message espanol5", - "type": "main", - "index": 0 - } - ] - ] - }, - "Hay sesion?": { - "main": [ - [] - ] - }, "Obtener sesiones": { "main": [ [ { - "node": "Loop Over Items2", + "node": "Calcular falta 48h o 24h1", "type": "main", "index": 0 } @@ -12164,38 +13389,14 @@ "index": 0 } ], - [ - { - "node": "Wait3", - "type": "main", - "index": 0 - } - ] + [] ] }, "Matchear coordinador y pais inscrito": { "main": [ [ { - "node": "Loop Over Items3", - "type": "main", - "index": 0 - } - ] - ] - }, - "Loop Over Items3": { - "main": [ - [ - { - "node": "Wait3", - "type": "main", - "index": 0 - } - ], - [ - { - "node": "Pais?3", + "node": "Obtener miembros RRHH Notificaciones", "type": "main", "index": 0 } @@ -12204,13 +13405,7 @@ }, "Wait6": { "main": [ - [ - { - "node": "Loop Over Items3", - "type": "main", - "index": 0 - } - ] + [] ] }, "Actualizar estado a notificado": { @@ -12318,24 +13513,6 @@ ] ] }, - "Es espanol o ingles1": { - "main": [ - [ - { - "node": "Send a message ingles6", - "type": "main", - "index": 0 - } - ], - [ - { - "node": "Send a message espanol6", - "type": "main", - "index": 0 - } - ] - ] - }, "Cambiar zona horaria": { "main": [ [ @@ -12514,18 +13691,273 @@ } ] ] + }, + "Prueba1": { + "main": [ + [] + ] + }, + "Prueba": { + "main": [ + [ + { + "node": "Obtener conferenceRecord", + "type": "main", + "index": 0 + } + ] + ] + }, + "Obtener conferenceRecord": { + "main": [ + [ + { + "node": "Code in JavaScript", + "type": "main", + "index": 0 + } + ] + ] + }, + "HTTP Request5": { + "main": [ + [] + ] + }, + "Limpiar id": { + "main": [ + [ + { + "node": "Get a contact", + "type": "main", + "index": 0 + } + ] + ] + }, + "Get a contact": { + "main": [ + [ + { + "node": "Unir datos2", + "type": "main", + "index": 0 + } + ] + ] + }, + "Unir datos2": { + "main": [ + [ + { + "node": "Hay inscritos?", + "type": "main", + "index": 0 + } + ] + ] + }, + "Obtener miembros": { + "main": [ + [ + { + "node": "Limpiar id", + "type": "main", + "index": 0 + } + ] + ] + }, + "Formatear datos espanol": { + "main": [ + [ + { + "node": "Enviar notifacion a glmway notificaciones", + "type": "main", + "index": 0 + } + ] + ] + }, + "Formatear datos ingles": { + "main": [ + [ + { + "node": "Enviar notifacion a glmway notificaciones", + "type": "main", + "index": 0 + } + ] + ] + }, + "Es espanol o ingles1": { + "main": [ + [ + { + "node": "Formatear datos ingles", + "type": "main", + "index": 0 + } + ], + [ + { + "node": "Formatear datos espanol", + "type": "main", + "index": 0 + } + ] + ] + }, + "Es espanol o ingles": { + "main": [ + [ + { + "node": "Formatear datos ingles1", + "type": "main", + "index": 0 + } + ], + [ + { + "node": "Formatear datos espanol1", + "type": "main", + "index": 0 + } + ] + ] + }, + "Formatear datos ingles1": { + "main": [ + [ + { + "node": "Enviar notifacion a glmway notificaciones", + "type": "main", + "index": 0 + } + ] + ] + }, + "Formatear datos espanol1": { + "main": [ + [ + { + "node": "Enviar notifacion a glmway notificaciones", + "type": "main", + "index": 0 + } + ] + ] + }, + "Enviar al espacio de prueba2": { + "main": [ + [ + { + "node": "Actualizar estado a notificado", + "type": "main", + "index": 0 + } + ] + ] + }, + "Enviar al espacio de prueba1": { + "main": [ + [ + { + "node": "Actualizar estado a notificado", + "type": "main", + "index": 0 + } + ] + ] + }, + "Formatear datos ingles2": { + "main": [ + [ + { + "node": "Enviar al espacio de prueba1", + "type": "main", + "index": 0 + } + ] + ] + }, + "Formatear datos espanol2": { + "main": [ + [ + { + "node": "Enviar al espacio de prueba2", + "type": "main", + "index": 0 + } + ] + ] + }, + "Calcular falta 48h o 24h1": { + "main": [ + [ + { + "node": "Hay inscritos en la sesion?", + "type": "main", + "index": 0 + } + ] + ] + }, + "Get a contact1": { + "main": [ + [ + { + "node": "Unir datos3", + "type": "main", + "index": 0 + } + ] + ] + }, + "Limpiar id1": { + "main": [ + [ + { + "node": "Get a contact1", + "type": "main", + "index": 0 + } + ] + ] + }, + "Unir datos3": { + "main": [ + [ + { + "node": "Pais?3", + "type": "main", + "index": 0 + } + ] + ] + }, + "Obtener miembros RRHH Notificaciones": { + "main": [ + [ + { + "node": "Limpiar id1", + "type": "main", + "index": 0 + } + ] + ] } }, "authors": "Eidan Then", - "name": "Version e6f9b5db", + "name": "Version 69f1dcec", "description": "", - "autosaved": false, + "autosaved": true, "workflowPublishHistory": [ { - "createdAt": "2026-07-06T20:58:23.622Z", - "id": 2559, + "createdAt": "2026-07-21T15:16:50.970Z", + "id": 3286, "workflowId": "F1iPg8hktNAebZua", - "versionId": "e6f9b5db-0927-4fb3-8518-2c4a10541c76", + "versionId": "69f1dcec-ccc3-4ec2-9e89-7e8b63f7197a", "event": "activated", "userId": "de14e7e5-491b-4983-abb2-f88af42e92fd" }