Subir archivos a "/"
This commit is contained in:
@@ -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
|
||||
<div class="hello">¡Feliz Cumpleaños!</div>
|
||||
<!-- Saludo principal. Actualmente vacío. -->
|
||||
|
||||
<div class="message">Tu mensaje aquí...</div>
|
||||
<!-- Mensaje de felicitación. Actualmente vacío. -->
|
||||
|
||||
<div class="position">{{ cargo del empleado }}</div>
|
||||
<!-- Cargo/posición. Actualmente vacío. -->
|
||||
|
||||
<div class="team">Equipo GLM</div>
|
||||
<!-- Firma del equipo. Actualmente vacío. -->
|
||||
```
|
||||
|
||||
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": "<h1>Test</h1>", "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.
|
||||
Reference in New Issue
Block a user