From cfebf0b646a9d4c2442ee4e8f65a3b3fbd1384c6 Mon Sep 17 00:00:00 2001 From: Isaac_Aracena Date: Sun, 23 Aug 2026 04:00:39 +0000 Subject: [PATCH] =?UTF-8?q?Update=20backup:=20Portal=20de=20Verificaci?= =?UTF-8?q?=C3=B3n=20de=20N=C3=B3mina=20-=20Reportar=20correcci=C3=B3n=20B?= =?UTF-8?q?ambooHR=20a=20RRHH?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...a-reportar-correccion-bamboohr-a-rrhh.json | 182 +++++++++--------- 1 file changed, 91 insertions(+), 91 deletions(-) diff --git a/portal-de-verificacion-de-nomina-reportar-correccion-bamboohr-a-rrhh.json b/portal-de-verificacion-de-nomina-reportar-correccion-bamboohr-a-rrhh.json index 25581aa..62db842 100644 --- a/portal-de-verificacion-de-nomina-reportar-correccion-bamboohr-a-rrhh.json +++ b/portal-de-verificacion-de-nomina-reportar-correccion-bamboohr-a-rrhh.json @@ -1,5 +1,5 @@ { - "updatedAt": "2026-08-11T18:48:49.761Z", + "updatedAt": "2026-08-19T14:20:00.099Z", "createdAt": "2026-08-11T18:47:42.698Z", "id": "0yaiagL1tWdhRUXy", "name": "Portal de Verificación de Nómina - Reportar corrección BambooHR a RRHH", @@ -17,10 +17,10 @@ "type": "n8n-nodes-base.webhook", "typeVersion": 2.1, "position": [ - 0, - 0 + 256, + 528 ], - "id": "7e321136-0268-4f7e-bde1-b3a7b1b60caf", + "id": "9f82287d-3017-4fb8-be43-3c3313f4e466", "name": "Webhook", "webhookId": "df5cb56b-75f3-4e8b-a1f2-f9a05c8ec317" }, @@ -31,10 +31,10 @@ "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ - 240, - 0 + 496, + 528 ], - "id": "507c0065-11d8-4693-86d7-acaaf826d8a0", + "id": "48884cdb-c052-4e9c-ac95-1d0eac8911f3", "name": "Preparar solicitud" }, { @@ -68,10 +68,10 @@ "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.4, "position": [ - 480, - 0 + 736, + 528 ], - "id": "9b9f3800-4182-4cc4-a6e3-11e200c44b1f", + "id": "3b5acfa4-19f9-41cf-943b-2dddf799b909", "name": "Validar acceso Supabase", "retryOnFail": true, "maxTries": 2, @@ -84,10 +84,10 @@ "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ - 720, - 0 + 976, + 528 ], - "id": "b20cb8fa-fa37-48a5-93aa-dd1740e8a6c0", + "id": "23a5aabe-20be-4f4d-92a2-e4d400b96d75", "name": "Validar usuario" }, { @@ -131,10 +131,10 @@ "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.4, "position": [ - 960, - 0 + 1216, + 528 ], - "id": "5dc107fa-c704-4643-9479-1f57e163d5fd", + "id": "07be5909-2a5b-47f4-96b2-466f2658f0db", "name": "Consultar empleado BambooHR", "retryOnFail": true, "maxTries": 3, @@ -148,15 +148,15 @@ }, { "parameters": { - "jsCode": "const request = $('Validar usuario').first().json || {};\nconst raw = $input.first().json || {};\n\nfunction clean(value) {\n return String(value ?? '').replace(/\\s+/g, ' ').trim();\n}\n\nfunction normalizeName(value) {\n return clean(value)\n .toLowerCase()\n .normalize('NFD')\n .replace(/[\\u0300-\\u036f]/g, '')\n .replace(/[^a-z0-9 ]/g, ' ')\n .replace(/\\s+/g, ' ')\n .trim();\n}\n\nfunction normalizeIdentifier(value) {\n return clean(value).toUpperCase().replace(/[^A-Z0-9]/g, '');\n}\n\nfunction countryMatches(employee) {\n const location = normalizeName(\n employee.location ||\n employee.jobInformationLocation ||\n employee.jobLocation ||\n employee.country ||\n ''\n );\n\n if (request.country === 'GT') {\n return location.includes('guatemala');\n }\n\n return location.includes('trinidad') || location.includes('tobago');\n}\n\nfunction employeeAliases(employee) {\n const first = clean(employee.firstName || employee.first_name);\n const middle = clean(employee.middleName || employee.middle_name);\n const last = clean(employee.lastName || employee.last_name);\n const display = clean(employee.displayName || employee.fullName || employee.full_name);\n\n return Array.from(new Set([\n display,\n [first, middle, last].filter(Boolean).join(' '),\n [first, last].filter(Boolean).join(' '),\n ].map(clean).filter(Boolean)));\n}\n\nconst employees = Array.isArray(raw.employees)\n ? raw.employees\n : Array.isArray(raw.data?.employees)\n ? raw.data.employees\n : [];\n\nif (!employees.length) {\n throw new Error('BambooHR no devolvió empleados para validar la corrección.');\n}\n\nconst candidates = employees.filter(countryMatches);\nif (!candidates.length) {\n throw new Error(`No se encontraron empleados de ${request.countryName} en BambooHR.`);\n}\n\nconst requestedNumber = normalizeIdentifier(request.bambooEmployeeNumber);\nlet matches = [];\nlet matchedBy = '';\n\nif (requestedNumber) {\n matches = candidates.filter((employee) =>\n normalizeIdentifier(employee.employeeNumber || employee.employee_number) === requestedNumber\n );\n matchedBy = 'employee_number';\n}\n\nif (!matches.length) {\n const targetName = normalizeName(request.bambooName);\n matches = candidates.filter((employee) =>\n employeeAliases(employee).some((alias) => normalizeName(alias) === targetName)\n );\n matchedBy = 'exact_bamboo_name';\n}\n\nif (matches.length !== 1) {\n if (matches.length > 1) {\n throw new Error('La identificación en BambooHR es ambigua. Indica el Employee Number para seleccionar una sola persona.');\n }\n\n throw new Error(\n 'No se encontró exactamente ese empleado en BambooHR para el país seleccionado. Revisa el nombre o indica el Employee Number.'\n );\n}\n\nconst employee = matches[0];\nconst aliases = employeeAliases(employee);\nconst actualName = clean(employee.displayName) || aliases[0] || request.bambooName;\nconst actualEmployeeNumber = clean(employee.employeeNumber || employee.employee_number);\nconst bambooId = clean(employee.employeeId || employee.id);\nconst now = new Date().toISOString();\n\nconst recipients = request.country === 'TT'\n ? ['lnicomejack@gomezleemarketing.com']\n : [\n 'pgamboa@gomezleemarketing.com',\n 'smeyer@gomezleemarketing.com',\n 'mjmorales@gomezleemarketing.com',\n ];\n\nconst aliasPayload = request.sourceNames.map((sourceName) => ({\n pais: request.country,\n nombre_origen: sourceName,\n nombre_origen_normalizado: normalizeName(sourceName),\n cuenta_bancaria: String(request.bankAccount || '').replace(/[^0-9A-Za-z]+/g, ''),\n bamboo_employee_number: actualEmployeeNumber || null,\n bamboo_employee_id: bambooId || null,\n bamboo_nombre: actualName,\n motivo: request.reason,\n comentario: request.comment || null,\n activo: true,\n validado_por_email: request.requestedByEmail,\n validado_por_nombre: request.requestedByName,\n last_reported_at: now,\n updated_at: now,\n}));\n\nreturn [{\n json: {\n request,\n matchedBy,\n employee: {\n bambooId,\n employeeNumber: actualEmployeeNumber,\n name: actualName,\n status: clean(employee.status),\n location: clean(employee.location),\n },\n recipients,\n aliasPayload,\n },\n}];" + "jsCode": "const request = $('Validar usuario').first().json || {};\nconst raw = $input.first().json || {};\n\nfunction clean(value) {\n return String(value ?? '').replace(/\\s+/g, ' ').trim();\n}\n\nfunction normalizeName(value) {\n return clean(value)\n .toLowerCase()\n .normalize('NFD')\n .replace(/[\\u0300-\\u036f]/g, '')\n .replace(/[^a-z0-9 ]/g, ' ')\n .replace(/\\s+/g, ' ')\n .trim();\n}\n\nfunction normalizeIdentifier(value) {\n return clean(value).toUpperCase().replace(/[^A-Z0-9]/g, '');\n}\n\nfunction countryMatches(employee) {\n const location = normalizeName(\n employee.location ||\n employee.jobInformationLocation ||\n employee.jobLocation ||\n employee.country ||\n ''\n );\n\n if (request.country === 'GT') {\n return location.includes('guatemala');\n }\n\n return location.includes('trinidad') || location.includes('tobago');\n}\n\nfunction employeeAliases(employee) {\n const first = clean(employee.firstName || employee.first_name);\n const middle = clean(employee.middleName || employee.middle_name);\n const last = clean(employee.lastName || employee.last_name);\n const display = clean(employee.displayName || employee.fullName || employee.full_name);\n\n return Array.from(new Set([\n display,\n [first, middle, last].filter(Boolean).join(' '),\n [first, last].filter(Boolean).join(' '),\n ].map(clean).filter(Boolean)));\n}\n\nconst employees = Array.isArray(raw.employees)\n ? raw.employees\n : Array.isArray(raw.data?.employees)\n ? raw.data.employees\n : [];\n\nif (!employees.length) {\n throw new Error('BambooHR no devolvió empleados para validar la corrección.');\n}\n\nconst candidates = employees.filter(countryMatches);\nif (!candidates.length) {\n throw new Error(`No se encontraron empleados de ${request.countryName} en BambooHR.`);\n}\n\nconst requestedNumber = normalizeIdentifier(request.bambooEmployeeNumber);\nlet matches = [];\nlet matchedBy = '';\n\nif (requestedNumber) {\n matches = candidates.filter((employee) =>\n normalizeIdentifier(employee.employeeNumber || employee.employee_number) === requestedNumber\n );\n matchedBy = 'employee_number';\n}\n\nif (!matches.length) {\n const targetName = normalizeName(request.bambooName);\n matches = candidates.filter((employee) =>\n employeeAliases(employee).some((alias) => normalizeName(alias) === targetName)\n );\n matchedBy = 'exact_bamboo_name';\n}\n\nif (matches.length !== 1) {\n if (matches.length > 1) {\n throw new Error('La identificación en BambooHR es ambigua. Indica el Employee Number para seleccionar una sola persona.');\n }\n\n throw new Error(\n 'No se encontró exactamente ese empleado en BambooHR para el país seleccionado. Revisa el nombre o indica el Employee Number.'\n );\n}\n\nconst employee = matches[0];\nconst aliases = employeeAliases(employee);\nconst actualName = clean(employee.displayName) || aliases[0] || request.bambooName;\nconst actualEmployeeNumber = clean(employee.employeeNumber || employee.employee_number);\nconst bambooId = clean(employee.employeeId || employee.id);\nconst now = new Date().toISOString();\n\nconst recipients = request.country === 'TT'\n ? ['lnicomejack@gomezleemarketing.com']\n : ['haguirre@gomezleemarketing.com'];\n\nconst aliasPayload = request.sourceNames.map((sourceName) => ({\n pais: request.country,\n nombre_origen: sourceName,\n nombre_origen_normalizado: normalizeName(sourceName),\n cuenta_bancaria: String(request.bankAccount || '').replace(/[^0-9A-Za-z]+/g, ''),\n bamboo_employee_number: actualEmployeeNumber || null,\n bamboo_employee_id: bambooId || null,\n bamboo_nombre: actualName,\n motivo: request.reason,\n comentario: request.comment || null,\n activo: true,\n validado_por_email: request.requestedByEmail,\n validado_por_nombre: request.requestedByName,\n last_reported_at: now,\n updated_at: now,\n}));\n\nreturn [{\n json: {\n request,\n matchedBy,\n employee: {\n bambooId,\n employeeNumber: actualEmployeeNumber,\n name: actualName,\n status: clean(employee.status),\n location: clean(employee.location),\n },\n recipients,\n aliasPayload,\n },\n}];" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ - 1200, - 0 + 1456, + 528 ], - "id": "504eed05-c6be-442e-9707-8cd4aca1d19c", + "id": "bb82de3a-cbbf-479c-a2da-96b677cb6eda", "name": "Resolver empleado BambooHR" }, { @@ -194,10 +194,10 @@ "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.4, "position": [ - 1440, - 0 + 1696, + 528 ], - "id": "6fc69ac2-6999-4810-9e8d-675c4c4d40ac", + "id": "062d8846-d24a-4887-9ef3-7de4a5d204d4", "name": "Guardar alias Supabase", "retryOnFail": true, "maxTries": 2, @@ -210,10 +210,10 @@ "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ - 1680, - 0 + 1936, + 528 ], - "id": "9d565bf5-a6df-4ac9-bad1-abe48a277c37", + "id": "3c1d6a0d-c096-4b31-9ba9-4ce2ec357f8e", "name": "Preparar auditoría" }, { @@ -251,10 +251,10 @@ "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.4, "position": [ - 1920, - 0 + 2176, + 528 ], - "id": "45f87d7b-a746-4eb2-a54e-d2de7645f854", + "id": "9cd76301-127f-449a-a8c5-1bcdfe79de9a", "name": "Guardar solicitud Supabase", "retryOnFail": true, "maxTries": 2, @@ -267,10 +267,10 @@ "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ - 2160, - 0 + 2416, + 528 ], - "id": "68be3c1d-42eb-4bc5-aa35-36333261f2a6", + "id": "6f05bfa0-78b5-4447-a440-19f90c6f7bba", "name": "Preparar correo RRHH" }, { @@ -285,10 +285,10 @@ "type": "n8n-nodes-base.gmail", "typeVersion": 2.2, "position": [ - 2400, - 0 + 2656, + 528 ], - "id": "28f7c657-0c5b-47c6-898b-f68f1cf21378", + "id": "9822f786-4c81-4a07-94ed-081e8485cbba", "name": "Enviar correo RRHH", "retryOnFail": true, "maxTries": 3, @@ -336,10 +336,10 @@ "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.4, "position": [ - 2640, - 0 + 2896, + 528 ], - "id": "87b7910e-0465-40b1-89d4-6b160726b7f7", + "id": "3e801286-89a6-4e29-a443-4c1f5e5afe14", "name": "Marcar correo enviado", "retryOnFail": true, "maxTries": 2, @@ -364,10 +364,10 @@ "type": "n8n-nodes-base.respondToWebhook", "typeVersion": 1.5, "position": [ - 2880, - 0 + 3136, + 528 ], - "id": "1db48431-4661-49de-a495-66c740b2aac1", + "id": "4359eea0-0f16-4241-840f-565d56700bb5", "name": "Respond to Webhook" } ], @@ -511,9 +511,9 @@ }, "staticData": null, "meta": null, - "versionId": "7e4daa40-244f-43ed-9d74-14a9cb589ddf", - "activeVersionId": "7e4daa40-244f-43ed-9d74-14a9cb589ddf", - "versionCounter": 5, + "versionId": "a190ab40-7527-4805-a7ac-cc26ed1e558b", + "activeVersionId": "a190ab40-7527-4805-a7ac-cc26ed1e558b", + "versionCounter": 8, "triggerCount": 1, "shared": [ { @@ -536,9 +536,9 @@ ], "tags": [], "activeVersion": { - "updatedAt": "2026-08-11T18:47:55.000Z", - "createdAt": "2026-08-11T18:47:42.715Z", - "versionId": "7e4daa40-244f-43ed-9d74-14a9cb589ddf", + "updatedAt": "2026-08-19T14:20:03.000Z", + "createdAt": "2026-08-19T14:20:00.103Z", + "versionId": "a190ab40-7527-4805-a7ac-cc26ed1e558b", "workflowId": "0yaiagL1tWdhRUXy", "nodes": [ { @@ -551,10 +551,10 @@ "type": "n8n-nodes-base.webhook", "typeVersion": 2.1, "position": [ - 0, - 0 + 256, + 528 ], - "id": "7e321136-0268-4f7e-bde1-b3a7b1b60caf", + "id": "9f82287d-3017-4fb8-be43-3c3313f4e466", "name": "Webhook", "webhookId": "df5cb56b-75f3-4e8b-a1f2-f9a05c8ec317" }, @@ -565,10 +565,10 @@ "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ - 240, - 0 + 496, + 528 ], - "id": "507c0065-11d8-4693-86d7-acaaf826d8a0", + "id": "48884cdb-c052-4e9c-ac95-1d0eac8911f3", "name": "Preparar solicitud" }, { @@ -602,10 +602,10 @@ "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.4, "position": [ - 480, - 0 + 736, + 528 ], - "id": "9b9f3800-4182-4cc4-a6e3-11e200c44b1f", + "id": "3b5acfa4-19f9-41cf-943b-2dddf799b909", "name": "Validar acceso Supabase", "retryOnFail": true, "maxTries": 2, @@ -618,10 +618,10 @@ "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ - 720, - 0 + 976, + 528 ], - "id": "b20cb8fa-fa37-48a5-93aa-dd1740e8a6c0", + "id": "23a5aabe-20be-4f4d-92a2-e4d400b96d75", "name": "Validar usuario" }, { @@ -665,10 +665,10 @@ "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.4, "position": [ - 960, - 0 + 1216, + 528 ], - "id": "5dc107fa-c704-4643-9479-1f57e163d5fd", + "id": "07be5909-2a5b-47f4-96b2-466f2658f0db", "name": "Consultar empleado BambooHR", "retryOnFail": true, "maxTries": 3, @@ -682,15 +682,15 @@ }, { "parameters": { - "jsCode": "const request = $('Validar usuario').first().json || {};\nconst raw = $input.first().json || {};\n\nfunction clean(value) {\n return String(value ?? '').replace(/\\s+/g, ' ').trim();\n}\n\nfunction normalizeName(value) {\n return clean(value)\n .toLowerCase()\n .normalize('NFD')\n .replace(/[\\u0300-\\u036f]/g, '')\n .replace(/[^a-z0-9 ]/g, ' ')\n .replace(/\\s+/g, ' ')\n .trim();\n}\n\nfunction normalizeIdentifier(value) {\n return clean(value).toUpperCase().replace(/[^A-Z0-9]/g, '');\n}\n\nfunction countryMatches(employee) {\n const location = normalizeName(\n employee.location ||\n employee.jobInformationLocation ||\n employee.jobLocation ||\n employee.country ||\n ''\n );\n\n if (request.country === 'GT') {\n return location.includes('guatemala');\n }\n\n return location.includes('trinidad') || location.includes('tobago');\n}\n\nfunction employeeAliases(employee) {\n const first = clean(employee.firstName || employee.first_name);\n const middle = clean(employee.middleName || employee.middle_name);\n const last = clean(employee.lastName || employee.last_name);\n const display = clean(employee.displayName || employee.fullName || employee.full_name);\n\n return Array.from(new Set([\n display,\n [first, middle, last].filter(Boolean).join(' '),\n [first, last].filter(Boolean).join(' '),\n ].map(clean).filter(Boolean)));\n}\n\nconst employees = Array.isArray(raw.employees)\n ? raw.employees\n : Array.isArray(raw.data?.employees)\n ? raw.data.employees\n : [];\n\nif (!employees.length) {\n throw new Error('BambooHR no devolvió empleados para validar la corrección.');\n}\n\nconst candidates = employees.filter(countryMatches);\nif (!candidates.length) {\n throw new Error(`No se encontraron empleados de ${request.countryName} en BambooHR.`);\n}\n\nconst requestedNumber = normalizeIdentifier(request.bambooEmployeeNumber);\nlet matches = [];\nlet matchedBy = '';\n\nif (requestedNumber) {\n matches = candidates.filter((employee) =>\n normalizeIdentifier(employee.employeeNumber || employee.employee_number) === requestedNumber\n );\n matchedBy = 'employee_number';\n}\n\nif (!matches.length) {\n const targetName = normalizeName(request.bambooName);\n matches = candidates.filter((employee) =>\n employeeAliases(employee).some((alias) => normalizeName(alias) === targetName)\n );\n matchedBy = 'exact_bamboo_name';\n}\n\nif (matches.length !== 1) {\n if (matches.length > 1) {\n throw new Error('La identificación en BambooHR es ambigua. Indica el Employee Number para seleccionar una sola persona.');\n }\n\n throw new Error(\n 'No se encontró exactamente ese empleado en BambooHR para el país seleccionado. Revisa el nombre o indica el Employee Number.'\n );\n}\n\nconst employee = matches[0];\nconst aliases = employeeAliases(employee);\nconst actualName = clean(employee.displayName) || aliases[0] || request.bambooName;\nconst actualEmployeeNumber = clean(employee.employeeNumber || employee.employee_number);\nconst bambooId = clean(employee.employeeId || employee.id);\nconst now = new Date().toISOString();\n\nconst recipients = request.country === 'TT'\n ? ['lnicomejack@gomezleemarketing.com']\n : [\n 'pgamboa@gomezleemarketing.com',\n 'smeyer@gomezleemarketing.com',\n 'mjmorales@gomezleemarketing.com',\n ];\n\nconst aliasPayload = request.sourceNames.map((sourceName) => ({\n pais: request.country,\n nombre_origen: sourceName,\n nombre_origen_normalizado: normalizeName(sourceName),\n cuenta_bancaria: String(request.bankAccount || '').replace(/[^0-9A-Za-z]+/g, ''),\n bamboo_employee_number: actualEmployeeNumber || null,\n bamboo_employee_id: bambooId || null,\n bamboo_nombre: actualName,\n motivo: request.reason,\n comentario: request.comment || null,\n activo: true,\n validado_por_email: request.requestedByEmail,\n validado_por_nombre: request.requestedByName,\n last_reported_at: now,\n updated_at: now,\n}));\n\nreturn [{\n json: {\n request,\n matchedBy,\n employee: {\n bambooId,\n employeeNumber: actualEmployeeNumber,\n name: actualName,\n status: clean(employee.status),\n location: clean(employee.location),\n },\n recipients,\n aliasPayload,\n },\n}];" + "jsCode": "const request = $('Validar usuario').first().json || {};\nconst raw = $input.first().json || {};\n\nfunction clean(value) {\n return String(value ?? '').replace(/\\s+/g, ' ').trim();\n}\n\nfunction normalizeName(value) {\n return clean(value)\n .toLowerCase()\n .normalize('NFD')\n .replace(/[\\u0300-\\u036f]/g, '')\n .replace(/[^a-z0-9 ]/g, ' ')\n .replace(/\\s+/g, ' ')\n .trim();\n}\n\nfunction normalizeIdentifier(value) {\n return clean(value).toUpperCase().replace(/[^A-Z0-9]/g, '');\n}\n\nfunction countryMatches(employee) {\n const location = normalizeName(\n employee.location ||\n employee.jobInformationLocation ||\n employee.jobLocation ||\n employee.country ||\n ''\n );\n\n if (request.country === 'GT') {\n return location.includes('guatemala');\n }\n\n return location.includes('trinidad') || location.includes('tobago');\n}\n\nfunction employeeAliases(employee) {\n const first = clean(employee.firstName || employee.first_name);\n const middle = clean(employee.middleName || employee.middle_name);\n const last = clean(employee.lastName || employee.last_name);\n const display = clean(employee.displayName || employee.fullName || employee.full_name);\n\n return Array.from(new Set([\n display,\n [first, middle, last].filter(Boolean).join(' '),\n [first, last].filter(Boolean).join(' '),\n ].map(clean).filter(Boolean)));\n}\n\nconst employees = Array.isArray(raw.employees)\n ? raw.employees\n : Array.isArray(raw.data?.employees)\n ? raw.data.employees\n : [];\n\nif (!employees.length) {\n throw new Error('BambooHR no devolvió empleados para validar la corrección.');\n}\n\nconst candidates = employees.filter(countryMatches);\nif (!candidates.length) {\n throw new Error(`No se encontraron empleados de ${request.countryName} en BambooHR.`);\n}\n\nconst requestedNumber = normalizeIdentifier(request.bambooEmployeeNumber);\nlet matches = [];\nlet matchedBy = '';\n\nif (requestedNumber) {\n matches = candidates.filter((employee) =>\n normalizeIdentifier(employee.employeeNumber || employee.employee_number) === requestedNumber\n );\n matchedBy = 'employee_number';\n}\n\nif (!matches.length) {\n const targetName = normalizeName(request.bambooName);\n matches = candidates.filter((employee) =>\n employeeAliases(employee).some((alias) => normalizeName(alias) === targetName)\n );\n matchedBy = 'exact_bamboo_name';\n}\n\nif (matches.length !== 1) {\n if (matches.length > 1) {\n throw new Error('La identificación en BambooHR es ambigua. Indica el Employee Number para seleccionar una sola persona.');\n }\n\n throw new Error(\n 'No se encontró exactamente ese empleado en BambooHR para el país seleccionado. Revisa el nombre o indica el Employee Number.'\n );\n}\n\nconst employee = matches[0];\nconst aliases = employeeAliases(employee);\nconst actualName = clean(employee.displayName) || aliases[0] || request.bambooName;\nconst actualEmployeeNumber = clean(employee.employeeNumber || employee.employee_number);\nconst bambooId = clean(employee.employeeId || employee.id);\nconst now = new Date().toISOString();\n\nconst recipients = request.country === 'TT'\n ? ['lnicomejack@gomezleemarketing.com']\n : ['haguirre@gomezleemarketing.com'];\n\nconst aliasPayload = request.sourceNames.map((sourceName) => ({\n pais: request.country,\n nombre_origen: sourceName,\n nombre_origen_normalizado: normalizeName(sourceName),\n cuenta_bancaria: String(request.bankAccount || '').replace(/[^0-9A-Za-z]+/g, ''),\n bamboo_employee_number: actualEmployeeNumber || null,\n bamboo_employee_id: bambooId || null,\n bamboo_nombre: actualName,\n motivo: request.reason,\n comentario: request.comment || null,\n activo: true,\n validado_por_email: request.requestedByEmail,\n validado_por_nombre: request.requestedByName,\n last_reported_at: now,\n updated_at: now,\n}));\n\nreturn [{\n json: {\n request,\n matchedBy,\n employee: {\n bambooId,\n employeeNumber: actualEmployeeNumber,\n name: actualName,\n status: clean(employee.status),\n location: clean(employee.location),\n },\n recipients,\n aliasPayload,\n },\n}];" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ - 1200, - 0 + 1456, + 528 ], - "id": "504eed05-c6be-442e-9707-8cd4aca1d19c", + "id": "bb82de3a-cbbf-479c-a2da-96b677cb6eda", "name": "Resolver empleado BambooHR" }, { @@ -728,10 +728,10 @@ "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.4, "position": [ - 1440, - 0 + 1696, + 528 ], - "id": "6fc69ac2-6999-4810-9e8d-675c4c4d40ac", + "id": "062d8846-d24a-4887-9ef3-7de4a5d204d4", "name": "Guardar alias Supabase", "retryOnFail": true, "maxTries": 2, @@ -744,10 +744,10 @@ "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ - 1680, - 0 + 1936, + 528 ], - "id": "9d565bf5-a6df-4ac9-bad1-abe48a277c37", + "id": "3c1d6a0d-c096-4b31-9ba9-4ce2ec357f8e", "name": "Preparar auditoría" }, { @@ -785,10 +785,10 @@ "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.4, "position": [ - 1920, - 0 + 2176, + 528 ], - "id": "45f87d7b-a746-4eb2-a54e-d2de7645f854", + "id": "9cd76301-127f-449a-a8c5-1bcdfe79de9a", "name": "Guardar solicitud Supabase", "retryOnFail": true, "maxTries": 2, @@ -801,10 +801,10 @@ "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ - 2160, - 0 + 2416, + 528 ], - "id": "68be3c1d-42eb-4bc5-aa35-36333261f2a6", + "id": "6f05bfa0-78b5-4447-a440-19f90c6f7bba", "name": "Preparar correo RRHH" }, { @@ -819,10 +819,10 @@ "type": "n8n-nodes-base.gmail", "typeVersion": 2.2, "position": [ - 2400, - 0 + 2656, + 528 ], - "id": "28f7c657-0c5b-47c6-898b-f68f1cf21378", + "id": "9822f786-4c81-4a07-94ed-081e8485cbba", "name": "Enviar correo RRHH", "retryOnFail": true, "maxTries": 3, @@ -870,10 +870,10 @@ "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.4, "position": [ - 2640, - 0 + 2896, + 528 ], - "id": "87b7910e-0465-40b1-89d4-6b160726b7f7", + "id": "3e801286-89a6-4e29-a443-4c1f5e5afe14", "name": "Marcar correo enviado", "retryOnFail": true, "maxTries": 2, @@ -898,10 +898,10 @@ "type": "n8n-nodes-base.respondToWebhook", "typeVersion": 1.5, "position": [ - 2880, - 0 + 3136, + 528 ], - "id": "1db48431-4661-49de-a495-66c740b2aac1", + "id": "4359eea0-0f16-4241-840f-565d56700bb5", "name": "Respond to Webhook" } ], @@ -1040,15 +1040,15 @@ } }, "authors": "Isaac Aracena", - "name": "Version 7e4daa40", + "name": "Version a190ab40", "description": "", "autosaved": true, "workflowPublishHistory": [ { - "createdAt": "2026-08-11T18:47:55.639Z", - "id": 4454, + "createdAt": "2026-08-19T14:20:03.066Z", + "id": 4943, "workflowId": "0yaiagL1tWdhRUXy", - "versionId": "7e4daa40-244f-43ed-9d74-14a9cb589ddf", + "versionId": "a190ab40-7527-4805-a7ac-cc26ed1e558b", "event": "activated", "userId": "0a88c0b1-928e-4412-896e-c5d1c99b2029" }