diff --git a/hbdwsp-documentacion.md b/hbdwsp-documentacion.md new file mode 100644 index 0000000..f9224c5 --- /dev/null +++ b/hbdwsp-documentacion.md @@ -0,0 +1,413 @@ +# 🎂 Workflow: `hbdwsp` — Bot de Cumpleaños GLM (WhatsApp) + +**ID del Workflow:** `ZzH2eMPrsqlY7WPz` +**Autor:** Eidan Then (`ethen@gomezleemarketing.com`) +**Última actualización:** 12 de junio de 2026 +**Versión activa:** `2d27b5f7-f5c4-41f9-b008-d8f3a50557a5` (v251) +**Estado:** ✅ Activo +**Zona horaria:** America/Santo_Domingo (UTC-04:00) + +--- + +## Descripción General + +Este workflow automatiza el envío de tarjetas de cumpleaños personalizadas al grupo de WhatsApp corporativo de GLM. Cada día a las 10:00 AM, el sistema revisa los empleados registrados en BambooHR, filtra los que cumplen años ese día, genera una tarjeta visual personalizada con su foto y la envía al grupo correspondiente. + +El flujo excluye automáticamente a empleados de países no hispanos (Jamaica, Trinidad & Tobago, Barbados, etc.) y maneja casos donde el empleado no tiene fecha de cumpleaños o foto registrada. + +--- + +## Arquitectura del Flujo + +``` +Schedule Trigger (10am) + └── BambooHR (Reporte CSV #1509) + └── Google Drive (Guardar CSV) + └── Google Sheets (Leer datos) + └── Pais? (Filtrar hispanos) + ├── [TRUE] Obtener empleado (BambooHR) + │ └── Merge (unir datos Sheets + Bamboo) + │ └── Loop Over Items + │ └── Tiene fecha? + │ ├── [FALSE] → Wait3 → Loop (siguiente) + │ └── [TRUE] → Coincide con fecha de hoy? + │ ├── [FALSE] → Wait3 → Loop + │ └── [TRUE] → Tiene foto? + │ ├── [TRUE] → Foto Empleado URL + │ └── [FALSE] → URL si no tiene foto (bizcocho) + │ └── HTML (generar tarjeta) + │ └── HTTP Request (screenshot browserless) + │ └── Extract from File + │ └── Enviar imagen WhatsApp + │ └── Wait (3s) + │ └── Loop (siguiente) + └── [FALSE] Ignorado (país no hispano) +``` + +--- + +## Nodos del Workflow + +### 1. Schedule Trigger +- **Tipo:** `scheduleTrigger` +- **Configuración:** Se ejecuta todos los días a las **10:00 AM** (hora Santo Domingo, UTC-4). +- **Notas:** El trigger está pinned con fecha `2026-05-29` para pruebas manuales. + +--- + +### 2. BambooHR (Reporte CSV) +- **Tipo:** `bambooHr` — `companyReport` +- **Reporte ID:** `1509` +- **Formato:** CSV +- **Credencial:** `Eidan - BambooHR account` +- **Función:** Descarga el listado completo de empleados activos con sus datos (incluyendo Birthday, Location, EEID, Work Email). + +--- + +### 3. Google Drive (Guardar CSV) +- **Tipo:** `googleDrive` — `update` +- **Archivo destino:** `HBD.csv` (`1Jw9yOyIKB1QLcr9m8ObGP9PK0tC9z3n6`) +- **Credencial:** `Eidan - Google Drive account` +- **Función:** Actualiza el archivo CSV en Google Drive con los datos más recientes de BambooHR. Sirve como respaldo y fuente de verdad para Google Sheets. + +--- + +### 4. Google Sheets (Leer datos) +- **Tipo:** `googleSheets` — read +- **Spreadsheet:** `HBD` (`1p0bCvHAIHjobiPhDfmTshZWvRP6PWAmmTtSoX77lBmM`) +- **Hoja:** `HBD` (gid: `759771456`) +- **Credencial:** `Eidan - Google Sheets account` +- **Función:** Lee los datos procesados del spreadsheet. Aquí se encuentran campos adicionales como `Location` que se usa para el filtro de país. + +--- + +### 5. Pais? (Filtro de país) +- **Tipo:** `if` +- **Lógica:** `AND` de condiciones `notEquals` +- **Países excluidos (FALSE):** + - Jamaica + - Trinidad and Tobago / Trinidad & Tobago / Tobago + - Barbados + - Saint Thomas + - St. Croix +- **TRUE:** El empleado es de un país hispano → el flujo continúa. +- **FALSE:** El empleado es de un país no hispano → se ignora silenciosamente. + +--- + +### 6. Obtener empleado +- **Tipo:** `bambooHr` — `get` +- **Employee ID:** `{{ $json.EEID }}` +- **Credencial:** `Eidan - BambooHR account` +- **Configuración:** `retryOnFail: true` +- **Función:** Obtiene el perfil completo del empleado desde BambooHR, incluyendo `photoUrl` y `photoUploaded`. + +--- + +### 7. Merge +- **Tipo:** `merge` — combine (enrich) +- **Join por:** `workEmail` ↔ `Work Email` +- **Modo:** `enrichInput1` (enriquece los datos de Bamboo con los de Google Sheets) +- **Función:** Combina en un solo objeto los datos de BambooHR (foto, cargo, etc.) con los de Google Sheets (Location, Birthday, etc.). + +--- + +### 8. Loop Over Items +- **Tipo:** `splitInBatches` +- **Función:** Procesa cada empleado de forma individual y secuencial. Al terminar con uno, vuelve al siguiente. Cuando no quedan más ítems, el flujo termina. + +--- + +### 9. Tiene fecha? +- **Tipo:** `if` +- **Condición:** `!$json.Birthday` es `true` +- **TRUE (sin fecha):** → `Wait3` → vuelve al loop (siguiente empleado). +- **FALSE (tiene fecha):** → continúa hacia `Coincide con fecha de hoy?`. + +> ⚠️ **Nota:** La nota sticky original decía que el sistema avisaría a RRHH si falta la fecha, pero actualmente el `TRUE` solo hace un `Wait3` y continúa. Considerar agregar una notificación a RRHH. + +--- + +### 10. Coincide con fecha de hoy? +- **Tipo:** `if` +- **Condición:** `$json.Birthday` equals `$now.format('MMMM dd')` (con espacios) +- **Validación:** `loose` (tipos flexibles) +- **`onError`:** `continueRegularOutput` +- **TRUE:** La fecha coincide → continúa el flujo. +- **FALSE:** No es el cumpleaños hoy → `Wait3` → siguiente empleado. + +> ⚠️ **Importante:** El `rightValue` tiene un espacio al final: `{{ $now.format('MMMM dd') }} `. Asegurarse de que los datos de Birthday en el CSV también tengan ese formato (`MMMM dd`) para evitar falsos negativos. + +--- + +### 11. Tiene foto? +- **Tipo:** `if` +- **Condición:** `$json.photoUploaded == true` es `true` +- **TRUE:** → `Foto Empleado URL` (usa la foto real del empleado) +- **FALSE:** → `URL si no tiene foto` (usa imagen de bizcocho) + +--- + +### 12. Foto Empleado URL / URL si no tiene foto +- **Tipo:** `set` +- **Foto real:** `{{ $json.photoUrl }}` (URL de BambooHR) +- **Foto fallback:** `https://gomezleemarketing.com/wp-content/uploads/2026/03/hbdcake.png` +- **Output:** Campo `photoUrl` que se pasa al nodo HTML. + +--- + +### 13. HTML (Generación de tarjeta) +- **Tipo:** `html` +- **Dimensiones:** 1080 × 1920 px (formato Instagram Stories / WhatsApp) +- **Background:** `https://gomezleemarketing.com/wp-content/uploads/2026/03/Comunicacion-de-Cumpleanos-Background.jpg` +- **Contenido dinámico:** + - Foto del empleado (circular, 530px) + - Nombre del empleado (`firstName`) + - Fecha de cumpleaños formateada en español (ej: "12 de junio") +- **Nota:** Los divs `.hello`, `.message`, `.position` y `.team` están vacíos en la versión actual. Pueden ser rellenados con texto personalizado. + +--- + +### 14. HTTP Request (Screenshot) +- **Tipo:** `httpRequest` POST +- **URL:** `https://pruebadetemplate-browserless.k11ytw.easypanel.host/chromium/screenshot` +- **Token:** `8d66338953f117a7c29c55364c8c9e6d` +- **Viewport:** `1080 × 1920` +- **Response format:** `file` (binario) +- **Función:** Convierte el HTML generado en una imagen PNG usando Browserless (Chromium headless) alojado en Easypanel. + +--- + +### 15. Extract from File +- **Tipo:** `extractFromFile` — `binaryToPropery` +- **Función:** Convierte el binario de la imagen en base64 (`data`) para enviarlo a la API de WhatsApp. + +--- + +### 16. Enviar mensaje al whatsapp imagen +- **Tipo:** `httpRequest` POST +- **URL:** `https://wsp.gomezleemarketing.com/message/sendMedia/botsoporte` +- **API Key:** `C267126ABB45-4C12-B626-6BAB1833F5D7` +- **Número destino:** `120363404268176806@g.us` (Grupo oficial Motorola) +- **Tipo de media:** `image` +- **Media:** `{{ $json.data }}` (base64) +- **Delay:** 2000ms + +--- + +### 17. Wait (entre empleados) +- **Tipo:** `wait` +- **Duración:** 3 segundos +- **Función:** Pausa entre el envío y la vuelta al loop para no saturar la API de WhatsApp. + +### Wait3 (skip al siguiente) +- **Tipo:** `wait` +- **Duración:** 1 segundo +- **Función:** Pequeña pausa antes de saltar al siguiente empleado cuando no cumple años o no tiene fecha. + +--- + +## Subworkflow: Respaldo en Gitea + +Este subworkflow es independiente (trigger manual) y guarda/actualiza el JSON del workflow en Gitea como respaldo de versión. + +### Nodos: +| Nodo | Función | +|------|---------| +| `Valores` | Define `repo_name: wsp-cumpleanos` y `file_name: hbd-panama-motorola` | +| `Obtener archivo` | GET al repo Gitea para obtener el SHA actual del archivo | +| `Get a workflow1/2` | Obtiene el JSON del propio workflow (`ZzH2eMPrsqlY7WPz`) vía API de n8n | +| `Code in JavaScript` | Prepara payload con SHA para **actualizar** (PUT) | +| `Code in JavaScript1` | Prepara payload sin SHA para **crear** (POST) | +| `Actualizar archivo` | PUT al endpoint de Gitea (actualiza si ya existe) | +| `Subir archivo` | POST al endpoint de Gitea (crea si no existe) | + +**Repositorio:** `https://git.digitalcompass.agency/EidanThen/wsp-cumpleanos` + +--- + +## Requisitos de Instalación + +### Servicios externos requeridos + +| Servicio | Uso | Credencial | +|----------|-----|------------| +| **BambooHR** | Fuente de datos de empleados | `Eidan - BambooHR account` | +| **Google Drive** | Almacenamiento del CSV actualizado | `Eidan - Google Drive account` | +| **Google Sheets** | Lectura de datos procesados | `Eidan - Google Sheets account` | +| **Browserless** (Easypanel) | Renderizado HTML → PNG | Token en URL | +| **EvolutionAPI** (WhatsApp) | Envío de imágenes al grupo | API Key en header | +| **Gitea** (opcional) | Respaldo del workflow JSON | `Eidan - gitea` | +| **n8n API** (opcional) | Leer JSON del workflow para backup | `Eidan - n8n account` | + +--- + +### Paso 1: Configurar credenciales en n8n + +1. Ve a **Settings → Credentials** en n8n. +2. Crea las siguientes credenciales: + +#### BambooHR +- **Tipo:** BambooHR API +- **API Key:** (tu API key de BambooHR) +- **Subdomain:** `gomezleemarketing` + +#### Google Drive / Sheets +- **Tipo:** Google OAuth2 +- Autoriza con la cuenta `ethen@gomezleemarketing.com` +- Aplica a ambos nodos (Drive y Sheets) + +#### Gitea (Header Auth) +- **Tipo:** Header Auth +- **Name:** `Authorization` +- **Value:** `token TU_TOKEN_GITEA` + +--- + +### Paso 2: Configurar Google Sheets + +El spreadsheet `HBD` debe tener al menos las columnas: + +| Columna | Descripción | +|---------|-------------| +| `EEID` | ID del empleado en BambooHR | +| `Work Email` | Email corporativo (clave de join con Bamboo) | +| `Birthday` | Fecha en formato `MMMM dd` (ej: `June 12`) | +| `Location` | País del empleado (ej: `Dominican Republic`) | +| `firstName` | Nombre del empleado | + +--- + +### Paso 3: Configurar Browserless + +El workflow usa una instancia de Browserless alojada en Easypanel: + +``` +URL: https://pruebadetemplate-browserless.k11ytw.easypanel.host +Token: 8d66338953f117a7c29c55364c8c9e6d +``` + +Si se despliega una nueva instancia, actualizar la URL y el token en el nodo **HTTP Request** (screenshot). + +**Para desplegar Browserless en Docker:** +```yaml +services: + browserless: + image: ghcr.io/browserless/chromium:latest + ports: + - "3000:3000" + environment: + - TOKEN=tu_token_aqui +``` + +--- + +### Paso 4: Configurar EvolutionAPI (WhatsApp) + +El workflow usa EvolutionAPI como intermediario para WhatsApp: + +- **Base URL:** `https://wsp.gomezleemarketing.com` +- **Instancia:** `botsoporte` +- **API Key:** configurada en el header `apikey` + +Asegúrate de que la instancia `botsoporte` esté conectada y activa antes de ejecutar el workflow. + +--- + +### Paso 5: Importar el workflow en n8n + +1. En n8n, ve a **Workflows → Import from file/URL**. +2. Pega el JSON del workflow o importa desde Gitea. +3. Asigna las credenciales correctas a cada nodo. +4. Activa el workflow con el toggle. + +--- + +## Configuración del Grupo de WhatsApp + +| Entorno | Número del grupo | +|---------|-----------------| +| **Producción (Motorola)** | `120363404268176806@g.us` | +| **Pruebas** | `120363426353723539@g.us` | + +Para cambiar el grupo destino, editar el campo `number` en el nodo **Enviar mensaje al whatsapp imagen**. + +--- + +## Personalización de la Tarjeta HTML + +La tarjeta visual se genera en el nodo `HTML`. Los siguientes divs están disponibles para personalización: + +```html +
¡Feliz Cumpleaños!
+ + +
Tu mensaje aquĂ­...
+ + +
{{ cargo del empleado }}
+ + +
Equipo GLM
+ +``` + +Para agregar el cargo dinámico, incluir en el nodo `Obtener empleado` el campo `jobTitle` y referenciarlo con `{{ $json.jobTitle }}`. + +--- + +## Solución de Problemas + +### El workflow no envía tarjetas aunque es el cumpleaños del empleado + +**Causa probable:** El formato de la fecha en Google Sheets no coincide con `$now.format('MMMM dd')`. + +**Solución:** Asegúrate de que el campo `Birthday` en el CSV/Sheets tenga el formato `June 12` (no `06/12` ni `12-06-1990`). El nodo `Coincide con fecha de hoy?` también tiene un espacio trailing en el `rightValue`; revisar que no cause falsos negativos. + +--- + +### La imagen no se genera (error en Browserless) + +**Causa probable:** La instancia de Browserless está caída o el token expiró. + +**Solución:** +1. Verificar que el contenedor de Browserless esté corriendo en Easypanel. +2. Probar manualmente con curl: +```bash +curl -X POST "https://pruebadetemplate-browserless.k11ytw.easypanel.host/chromium/screenshot?token=8d66338953f117a7c29c55364c8c9e6d" \ + -H "Content-Type: application/json" \ + -d '{"html": "

Test

", "viewport": {"width": 1080, "height": 1920}}' +``` + +--- + +### El mensaje no llega al grupo de WhatsApp + +**Causa probable:** La instancia `botsoporte` de EvolutionAPI no está conectada. + +**Solución:** +1. Ir al panel de EvolutionAPI en `https://wsp.gomezleemarketing.com`. +2. Verificar que la instancia `botsoporte` muestra estado `open`. +3. Si está desconectada, escanear el QR de WhatsApp nuevamente. + +--- + +### Empleados de países no hispanos reciben tarjetas + +**Causa probable:** El campo `Location` en Google Sheets tiene un valor diferente al esperado (ej: `Trinidad` en vez de `Trinidad and Tobago`). + +**Solución:** Revisar el nodo `Pais?` y agregar las variantes del nombre del país en las condiciones `notEquals`. + +--- + +## Flujo de Error + +El workflow tiene configurado el workflow de error `lX5ITf9s4TSQglsM`. Ante un error crítico no manejado, se disparará ese workflow de manejo de errores. + +--- + +## Notas de Mantenimiento + +- El reporte de BambooHR (#1509) debe incluir los campos `Birthday`, `Location`, `EEID`, y `Work Email`. +- La imagen de fondo y el fallback de bizcocho están alojadas en el servidor de WordPress de GLM. Si cambian de dominio, actualizar las URLs en el nodo `HTML` y en el nodo `URL si no tiene foto`. +- El workflow respalda su propio JSON en Gitea bajo `EidanThen/wsp-cumpleanos/hbd-panama-motorola.json`. Ejecutar el subworkflow manual periódicamente o tras cambios importantes.