Update glmway-workflow.json

This commit is contained in:
2026-07-02 17:54:46 +00:00
parent 18e1d6c9f4
commit 4566a2d77c
+260 -90
View File
@@ -1,6 +1,6 @@
{
"$json": {
"updatedAt": "2026-07-02T16:33:12.932Z",
"updatedAt": "2026-07-02T17:25:55.366Z",
"createdAt": "2026-06-08T13:50:12.174Z",
"id": "F1iPg8hktNAebZua",
"name": "GLMWay",
@@ -1162,7 +1162,7 @@
"parameters": {
"content": "## Recordatorio a nuevo ingreso 24 horas antes de la sesion\n",
"height": 464,
"width": 1728,
"width": 2224,
"color": 6
},
"type": "n8n-nodes-base.stickyNote",
@@ -1210,7 +1210,7 @@
"parameters": {
"content": "## Notificacion inicial\n\nEnvia notificacion de sesion en el primer dia de trabajo del empleado",
"height": 608,
"width": 3008,
"width": 3216,
"color": 6
},
"type": "n8n-nodes-base.stickyNote",
@@ -1752,7 +1752,7 @@
"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{{ $json.conferenceData.entryPoints[0].uri }}",
"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 }}",
"options": {
"appendAttribution": false
}
@@ -1760,7 +1760,7 @@
"type": "n8n-nodes-base.gmail",
"typeVersion": 2.2,
"position": [
800,
1296,
736
],
"id": "10b2cb4e-274d-4913-9345-2c024c071f4c",
@@ -1771,15 +1771,14 @@
"id": "QWNicjw1khRm5BVI",
"name": "Eidan - Gmail account"
}
},
"disabled": true
}
},
{
"parameters": {
"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{{ $json.conferenceData.entryPoints[0].uri }}",
"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 }}",
"options": {
"appendAttribution": false
}
@@ -1787,7 +1786,7 @@
"type": "n8n-nodes-base.gmail",
"typeVersion": 2.2,
"position": [
800,
1296,
944
],
"id": "1dc76989-8c58-4ffe-9e1c-5113a59d346c",
@@ -1798,8 +1797,7 @@
"id": "QWNicjw1khRm5BVI",
"name": "Eidan - Gmail account"
}
},
"disabled": true
}
},
{
"parameters": {
@@ -1956,7 +1954,7 @@
"type": "n8n-nodes-base.wait",
"typeVersion": 1.1,
"position": [
1200,
1680,
1072
],
"id": "ee5bb9bc-b8cb-493f-8463-ae0a24cf1f0d",
@@ -1991,7 +1989,7 @@
"type": "n8n-nodes-base.if",
"typeVersion": 2.2,
"position": [
608,
752,
832
],
"id": "4d94c907-8ab1-4213-be20-9e24173cf0a3",
@@ -2687,7 +2685,7 @@
"type": "n8n-nodes-base.supabase",
"typeVersion": 1,
"position": [
1008,
1504,
848
],
"id": "ddf0a273-d3bc-44cc-888b-d789ce72ff77",
@@ -3925,30 +3923,6 @@
}
}
},
{
"parameters": {
"operation": "getAll",
"tableId": "sesiones_glmway",
"returnAll": true,
"filters": {
"conditions": []
}
},
"type": "n8n-nodes-base.supabase",
"typeVersion": 1,
"position": [
-176,
2144
],
"id": "d34e225b-25bb-4a0a-845c-b9e274529000",
"name": "Get many rows",
"credentials": {
"supabaseApi": {
"id": "2PlsR6rpK7rQTIEn",
"name": "Sofia test - Supabase account"
}
}
},
{
"parameters": {
"jsCode": "const months = [\"January\",\"February\",\"March\",\"April\",\"May\",\"June\",\"July\",\"August\",\"September\",\"October\",\"November\",\"December\"];\n\nfunction formatearFecha(dateTimeStr) {\n if (!dateTimeStr) return null;\n const datePart = dateTimeStr.split('T')[0];\n const [year, month, day] = datePart.split('-');\n return `${parseInt(day, 10)} ${months[parseInt(month, 10) - 1]}`;\n}\n\nfunction detectarIdioma(summary) {\n if (!summary) return null;\n if (summary.includes(\"#TheGLMWay Training\")) return \"EN\";\n if (summary.includes(\"Entrenamiento #TheGLMWay\")) return \"ES\";\n return null;\n}\n\nfunction formatearHora(dateTimeStr) {\n if (!dateTimeStr) return null;\n const timePart = dateTimeStr.split('T')[1];\n if (!timePart) return null;\n return timePart.substring(0, 5);\n}\n\nconst output = [];\n\nfor (const item of $input.all()) {\n const event = item.json;\n\n const startRaw = event.start?.dateTime || event.start?.date;\n const endRaw = event.end?.dateTime || event.end?.date;\n const url = event.conferenceData?.entryPoints?.[0]?.uri || null;\n const idioma = detectarIdioma(event.summary);\n\n // Ignorar eventos vacíos o sin datos esenciales\n if (!event.summary || !startRaw) {\n console.log(\"Evento ignorado (vacío):\", JSON.stringify(event));\n continue;\n }\n\n output.push({\n json: {\n id: event.id,\n titulo: event.summary,\n idioma: idioma,\n fecha: formatearFecha(startRaw),\n hora_inicio: formatearHora(startRaw),\n hora_fin: formatearHora(endRaw),\n url: url,\n descripcion: event.description || null\n }\n });\n}\n\nconsole.log(`Sesiones procesadas: ${output.length}`);\nreturn output;\n\n// Agrega esto antes del return output\nconst resumen = output.map(i => ({\n meet_id: i.json.meet_id,\n titulo: i.json.titulo,\n fecha_sesion: i.json.fecha_sesion,\n hora_inicio: i.json.hora_inicio,\n hora_fin: i.json.hora_fin,\n enlace_reunion: i.json.enlace_reunion,\n idioma: i.json.idioma\n}));\nconsole.log(JSON.stringify(resumen));"
@@ -4003,10 +3977,10 @@
},
{
"parameters": {
"sendTo": "eidan.then14@gmail.com",
"sendTo": "={{ $json.session.correo_instructor }}",
"subject": "Entrenamiento #TheGLMWay",
"emailType": "text",
"message": "=Hola,\n\nTe escribo para informarte que, hasta el momento, no hay personas inscritas para la actividad de hoy.\n\nSaludos.\n\nEste es un mensaje automático generado por el sistema de gestión de inscripciones.",
"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
}
@@ -4030,7 +4004,7 @@
},
{
"parameters": {
"sendTo": "eidan.then14@gmail.com",
"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.",
@@ -4067,7 +4041,7 @@
"conditions": [
{
"id": "df25aa3e-d48f-4e52-ae1f-47678e954d52",
"leftValue": "={{ $json.session.idioma }}",
"leftValue": "={{ $('Obtener sesion1').item.json.idioma }}",
"rightValue": "EN",
"operator": {
"type": "string",
@@ -4579,7 +4553,7 @@
},
{
"parameters": {
"sendTo": "eidan.then14@gmail.com",
"sendTo": "=eidan.then14@gmail.com",
"subject": "Entrenamiento #TheGLMWay",
"emailType": "text",
"message": "=<div style=\"font-family: 'Segoe UI', Arial, sans-serif; background-color:#f4f6f8; padding:24px;\">\n <table role=\"presentation\" width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" style=\"max-width:600px;margin:0 auto;background:#ffffff;border-radius:12px;overflow:hidden;box-shadow:0 2px 8px rgba(0,0,0,0.08);\">\n\n <!-- HEADER -->\n <tr>\n <td style=\"background:linear-gradient(135deg,#4f46e5,#7c3aed);padding:28px 32px;\">\n <p style=\"margin:0;color:#e0e7ff;font-size:13px;letter-spacing:1px;text-transform:uppercase;\">Sesión de entrenamiento</p>\n <h1 style=\"margin:6px 0 0;color:#ffffff;font-size:22px;\">{{ $json.session.titulo }}</h1>\n </td>\n </tr>\n\n <!-- INFO SESION -->\n <tr>\n <td style=\"padding:20px 32px;background:#f9fafb;border-bottom:1px solid #eee;\">\n <p style=\"margin:0 0 4px;font-size:14px;color:#374151;\">📅 <strong>{{ $json.session.fecha_sesion }}</strong> &nbsp;|&nbsp; 🕒 {{ $json.session.hora_inicio }} - {{ $json.session.hora_fin }}</p>\n <p style=\"margin:0 0 4px;font-size:14px;color:#374151;\">🎤 Instructor: <strong>{{ $json.session.instructor }}</strong></p>\n <p style=\"margin:0;font-size:14px;\"><a href=\"{{ $json.session.enlace_reunion }}\" style=\"color:#4f46e5;text-decoration:none;font-weight:600;\">🔗 Unirse a la reunión</a></p>\n </td>\n </tr>\n\n <!-- SALUDO -->\n <tr>\n <td style=\"padding:24px 32px 8px;\">\n <p style=\"margin:0;color:#111827;font-size:15px;\">Hola,</p>\n <p style=\"margin:8px 0 0;color:#374151;font-size:15px;\">Aquí tienes el listado de participantes para la sesión de hoy:</p>\n </td>\n </tr>\n\n <!-- LISTADO POR PAIS -->\n <tr>\n <td style=\"padding:8px 32px 24px;\">\n {{ (function(){\n const data = $json.session.participantes || {};\n const colores = ['#4f46e5','#0891b2','#059669','#d97706','#dc2626','#7c3aed','#db2777'];\n let i = 0;\n let html = '';\n\n for (const pais in data) {\n const nombrePais = pais && pais.trim() !== '' ? pais : 'Sin país asignado';\n const color = colores[i % colores.length];\n i++;\n const lista = data[pais];\n\n html += `\n <table role=\"presentation\" width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" style=\"margin-bottom:18px;border:1px solid #e5e7eb;border-radius:10px;overflow:hidden;\">\n <tr>\n <td style=\"background:${color}15;border-left:4px solid ${color};padding:10px 16px;\">\n <span style=\"font-size:14px;font-weight:700;color:${color};\">${nombrePais}</span>\n <span style=\"font-size:12px;color:#6b7280;margin-left:6px;\">(${lista.length} participante${lista.length !== 1 ? 's' : ''})</span>\n </td>\n </tr>`;\n\n lista.forEach((p, idx) => {\n const bg = idx % 2 === 0 ? '#ffffff' : '#fafafa';\n html += `\n <tr>\n <td style=\"padding:10px 16px;background:${bg};border-top:1px solid #f0f0f0;\">\n <p style=\"margin:0;font-size:14px;color:#111827;font-weight:600;\">${p.nombre}</p>\n <p style=\"margin:2px 0 0;font-size:13px;color:#6b7280;\">${p.correo}${p.division ? ' &nbsp;•&nbsp; ' + p.division : ''}${p.departamento ? ' &nbsp;•&nbsp; ' + p.departamento : ''}</p>\n </td>\n </tr>`;\n });\n\n html += `</table>`;\n }\n\n return html || '<p style=\"color:#6b7280;\">No hay participantes registrados.</p>';\n })() }}\n </td>\n </tr>\n\n <!-- FOOTER -->\n <tr>\n <td style=\"padding:20px 32px;background:#f9fafb;border-top:1px solid #eee;\">\n <p style=\"margin:0;font-size:13px;color:#9ca3af;\">Saludos,<br>#TheGLMWay</p>\n </td>\n </tr>\n\n </table>\n</div>",
@@ -4606,7 +4580,7 @@
},
{
"parameters": {
"sendTo": "eidan.then14@gmail.com",
"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.",
@@ -4716,6 +4690,84 @@
],
"id": "677acc91-b856-482e-aa2c-9b329221918a",
"name": "Cambiar zona horaria3"
},
{
"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 = \"19:00\";\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 = $('Loop Over Items1').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});"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1104,
736
],
"id": "67785f93-1b98-43f4-a72b-c94072ca22e6",
"name": "Cambiar zona horaria4"
},
{
"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 = \"19:00\";\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 = $('Loop Over Items1').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});"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1104,
944
],
"id": "b574514b-817a-4798-a44b-2eae1077e118",
"name": "Cambiar zona horaria5"
},
{
"parameters": {
"operation": "get",
"tableId": "sesiones_glmway",
"filters": {
"conditions": [
{
"keyName": "fecha_sesion",
"keyValue": "={{ $json.fecha_sesion }}"
}
]
}
},
"type": "n8n-nodes-base.supabase",
"typeVersion": 1,
"position": [
608,
832
],
"id": "45d7c217-bfee-4ae8-97b1-b158ee7e3548",
"name": "Obtener sesion",
"credentials": {
"supabaseApi": {
"id": "2PlsR6rpK7rQTIEn",
"name": "Sofia test - Supabase account"
}
}
},
{
"parameters": {
"operation": "getAll",
"tableId": "sesiones_glmway",
"returnAll": true,
"filters": {
"conditions": []
}
},
"type": "n8n-nodes-base.supabase",
"typeVersion": 1,
"position": [
-176,
2144
],
"id": "d34e225b-25bb-4a0a-845c-b9e274529000",
"name": "Obtener sesion1",
"credentials": {
"supabaseApi": {
"id": "2PlsR6rpK7rQTIEn",
"name": "Sofia test - Supabase account"
}
}
}
],
"connections": {
@@ -5140,14 +5192,14 @@
"main": [
[
{
"node": "Send a message espanol2",
"node": "Cambiar zona horaria4",
"type": "main",
"index": 0
}
],
[
{
"node": "Send a message ingles2",
"node": "Cambiar zona horaria5",
"type": "main",
"index": 0
}
@@ -5406,7 +5458,7 @@
"main": [
[
{
"node": "Pais?2",
"node": "Obtener sesion",
"type": "main",
"index": 0
}
@@ -5796,7 +5848,7 @@
"main": [
[
{
"node": "Get many rows",
"node": "Obtener sesion1",
"type": "main",
"index": 0
}
@@ -5814,17 +5866,6 @@
]
]
},
"Get many rows": {
"main": [
[
{
"node": "Calcular sesion mas cercana4",
"type": "main",
"index": 0
}
]
]
},
"Es espanol o ingles": {
"main": [
[
@@ -6117,6 +6158,50 @@
}
]
]
},
"Cambiar zona horaria5": {
"main": [
[
{
"node": "Send a message ingles2",
"type": "main",
"index": 0
}
]
]
},
"Cambiar zona horaria4": {
"main": [
[
{
"node": "Send a message espanol2",
"type": "main",
"index": 0
}
]
]
},
"Obtener sesion": {
"main": [
[
{
"node": "Pais?2",
"type": "main",
"index": 0
}
]
]
},
"Obtener sesion1": {
"main": [
[
{
"node": "Calcular sesion mas cercana4",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
@@ -6141,19 +6226,19 @@
"recurrenceRules": []
},
"node:Comenzo evento ingles": {
"lastTimeChecked": "2026-07-02T16:33:14Z"
"lastTimeChecked": "2026-07-02T17:09:26Z"
},
"node:Comenzo evento español": {
"lastTimeChecked": "2026-07-02T16:33:14Z"
"lastTimeChecked": "2026-07-02T17:09:26Z"
},
"node:Termino evento español": {
"lastTimeChecked": "2026-07-02T16:33:15Z"
"lastTimeChecked": "2026-07-02T17:09:26Z"
},
"node:Termino evento ingles": {
"lastTimeChecked": "2026-07-02T16:33:15Z"
"lastTimeChecked": "2026-07-02T17:09:26Z"
},
"node:Prueba": {
"lastTimeChecked": "2026-07-02T16:33:15Z"
"lastTimeChecked": "2026-07-02T17:09:26Z"
},
"node:Schedule Trigger2": {
"recurrenceRules": []
@@ -6498,9 +6583,9 @@
}
]
},
"versionId": "b081672b-1753-46b8-8436-25841f941414",
"activeVersionId": "b081672b-1753-46b8-8436-25841f941414",
"versionCounter": 3895,
"versionId": "a0c36c4a-88e6-4aa0-bc8f-d89186085616",
"activeVersionId": "ed31a19f-9dc8-454f-bf44-dd17635297b2",
"versionCounter": 3987,
"triggerCount": 13,
"shared": [
{
@@ -6523,9 +6608,9 @@
],
"tags": [],
"activeVersion": {
"updatedAt": "2026-07-02T16:33:15.000Z",
"createdAt": "2026-07-02T16:33:12.947Z",
"versionId": "b081672b-1753-46b8-8436-25841f941414",
"updatedAt": "2026-07-02T17:09:27.000Z",
"createdAt": "2026-07-02T17:02:32.430Z",
"versionId": "ed31a19f-9dc8-454f-bf44-dd17635297b2",
"workflowId": "F1iPg8hktNAebZua",
"nodes": [
{
@@ -7682,7 +7767,7 @@
"parameters": {
"content": "## Recordatorio a nuevo ingreso 24 horas antes de la sesion\n",
"height": 464,
"width": 1728,
"width": 2224,
"color": 6
},
"type": "n8n-nodes-base.stickyNote",
@@ -8272,7 +8357,7 @@
"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{{ $json.conferenceData.entryPoints[0].uri }}",
"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{{ $('Obtener sesion').item.json.enlace_reunion }}",
"options": {
"appendAttribution": false
}
@@ -8280,7 +8365,7 @@
"type": "n8n-nodes-base.gmail",
"typeVersion": 2.2,
"position": [
800,
1296,
736
],
"id": "10b2cb4e-274d-4913-9345-2c024c071f4c",
@@ -8291,15 +8376,14 @@
"id": "QWNicjw1khRm5BVI",
"name": "Eidan - Gmail account"
}
},
"disabled": true
}
},
{
"parameters": {
"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{{ $json.conferenceData.entryPoints[0].uri }}",
"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{{ $('Obtener sesion').item.json.enlace_reunion }}",
"options": {
"appendAttribution": false
}
@@ -8307,7 +8391,7 @@
"type": "n8n-nodes-base.gmail",
"typeVersion": 2.2,
"position": [
800,
1296,
944
],
"id": "1dc76989-8c58-4ffe-9e1c-5113a59d346c",
@@ -8318,8 +8402,7 @@
"id": "QWNicjw1khRm5BVI",
"name": "Eidan - Gmail account"
}
},
"disabled": true
}
},
{
"parameters": {
@@ -8476,7 +8559,7 @@
"type": "n8n-nodes-base.wait",
"typeVersion": 1.1,
"position": [
1200,
1680,
1072
],
"id": "ee5bb9bc-b8cb-493f-8463-ae0a24cf1f0d",
@@ -8511,7 +8594,7 @@
"type": "n8n-nodes-base.if",
"typeVersion": 2.2,
"position": [
608,
752,
832
],
"id": "4d94c907-8ab1-4213-be20-9e24173cf0a3",
@@ -9207,7 +9290,7 @@
"type": "n8n-nodes-base.supabase",
"typeVersion": 1,
"position": [
1008,
1504,
848
],
"id": "ddf0a273-d3bc-44cc-888b-d789ce72ff77",
@@ -11236,6 +11319,60 @@
],
"id": "677acc91-b856-482e-aa2c-9b329221918a",
"name": "Cambiar zona horaria3"
},
{
"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 = \"19:00\";\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 = $('Loop Over Items1').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});"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1104,
736
],
"id": "67785f93-1b98-43f4-a72b-c94072ca22e6",
"name": "Cambiar zona horaria4"
},
{
"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 = \"19:00\";\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 = $('Loop Over Items1').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});"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1104,
944
],
"id": "b574514b-817a-4798-a44b-2eae1077e118",
"name": "Cambiar zona horaria5"
},
{
"parameters": {
"operation": "get",
"tableId": "sesiones_glmway",
"filters": {
"conditions": [
{
"keyName": "fecha_sesion",
"keyValue": "={{ $json.fecha_sesion }}"
}
]
}
},
"type": "n8n-nodes-base.supabase",
"typeVersion": 1,
"position": [
608,
832
],
"id": "45d7c217-bfee-4ae8-97b1-b158ee7e3548",
"name": "Obtener sesion",
"credentials": {
"supabaseApi": {
"id": "2PlsR6rpK7rQTIEn",
"name": "Sofia test - Supabase account"
}
}
}
],
"connections": {
@@ -11660,14 +11797,14 @@
"main": [
[
{
"node": "Send a message espanol2",
"node": "Cambiar zona horaria4",
"type": "main",
"index": 0
}
],
[
{
"node": "Send a message ingles2",
"node": "Cambiar zona horaria5",
"type": "main",
"index": 0
}
@@ -11926,7 +12063,7 @@
"main": [
[
{
"node": "Pais?2",
"node": "Obtener sesion",
"type": "main",
"index": 0
}
@@ -12637,18 +12774,51 @@
}
]
]
},
"Cambiar zona horaria5": {
"main": [
[
{
"node": "Send a message ingles2",
"type": "main",
"index": 0
}
]
]
},
"Cambiar zona horaria4": {
"main": [
[
{
"node": "Send a message espanol2",
"type": "main",
"index": 0
}
]
]
},
"Obtener sesion": {
"main": [
[
{
"node": "Pais?2",
"type": "main",
"index": 0
}
]
]
}
},
"authors": "Eidan Then",
"name": "Version b081672b",
"name": "Version ed31a19f",
"description": "",
"autosaved": false,
"autosaved": true,
"workflowPublishHistory": [
{
"createdAt": "2026-07-02T16:33:15.612Z",
"id": 2278,
"createdAt": "2026-07-02T17:09:27.085Z",
"id": 2280,
"workflowId": "F1iPg8hktNAebZua",
"versionId": "b081672b-1753-46b8-8436-25841f941414",
"versionId": "ed31a19f-9dc8-454f-bf44-dd17635297b2",
"event": "activated",
"userId": "de14e7e5-491b-4983-abb2-f88af42e92fd"
}