# Dashboard Talento Humano — Faranda Hotels

Dashboard de RRHH (empleados, salarios, ingresos/retiros, nómina y P&G) para los hoteles del grupo Faranda. Frontend HTML puro + ECharts, servido por un proxy Python que resuelve CORS y consulta PostgreSQL para datos históricos.

## Stack

- **Frontend:** HTML + JS puro (`dashboard-empleados.html`) con [ECharts 5.4.3](https://echarts.apache.org/) — sin frameworks ni build step.
- **Backend / proxy:** `servidor.py` — `http.server.ThreadingHTTPServer` con `psycopg2.pool.ThreadedConnectionPool`. Sirve el HTML y expone endpoints `/proxy/*` que:
  - reenvían peticiones a la API externa de NominaApp (`https://api.innfinancial.cloud`) evitando CORS, o
  - consultan directamente PostgreSQL para datos históricos.
- **Base de datos:** PostgreSQL — local o nube, configurado por variables `PG_*`.

## Requisitos

- Python 3.9+
- PostgreSQL local o remoto con la base `Base de Datos Talento Humano`
- Dependencias Python:

```bash
pip install psycopg2-binary pandas openpyxl
```

## Configuración

La configuración sensible vive fuera del código. `servidor.py`, `cierre_mes.py` y `cargar_historico_nomina_pyg.py` leen `.env` local o variables de entorno mediante `app_config.py`.

1. Copia `.env.example` a `.env` para desarrollo local.
2. Completa `PG_HOST`, `PG_PORT`, `PG_DATABASE`, `PG_USER`, `PG_PASSWORD`.
3. Completa `PG_SCHEMA`; local y remoto correcto usan `public`.
4. Completa `NOMINA_API_KEY` y `PYG_API_KEY`.
5. En nube, guarda esos valores como Secrets del scheduler/runner, no en archivos versionados.

También se puede usar `DATABASE_URL` en vez de `PG_HOST`/`PG_*`. El destino remoto correcto es la base `Base de Datos Historicos Talento Humano` con `PG_SCHEMA=public`.

Controles de seguridad:
- `APP_VERIFY_SSL=true` por defecto; solo usar `false` en diagnóstico local controlado.
- `CORS_ALLOWED_ORIGINS` restringe qué orígenes pueden llamar el proxy desde navegador.
- `APP_REQUIRE_ADMIN_AUTH=true` protege endpoints que escriben en PostgreSQL.
- `ADMIN_API_KEY` debe enviarse como header `X-Admin-Key` para `/proxy/admin/*` y `/proxy/historico/cecos-sync`.
- `APP_DEBUG_ERRORS=false` evita devolver trazas internas al navegador.

## Cómo correr el servidor

```bash
python3 servidor.py
```

- Puerto **8080** en producción (rama `main`).
- Puerto **8081** en el worktree de desarrollo.
- Si el puerto 8080 está ocupado por otro proceso: `kill $(lsof -ti:8080)`.

Luego abre **http://localhost:8080** (o 8081 en dev) en el navegador.

## Estructura del proyecto

| Archivo / carpeta | Descripción |
|---|---|
| `dashboard-empleados.html` | Dashboard principal (SPA de un solo archivo) |
| `app_config.py` | Carga `.env`/variables de entorno, conexión PostgreSQL y llaves externas sin secretos en código |
| `servidor.py` | Servidor proxy + endpoints históricos sobre PostgreSQL |
| `cierre_mes.py` | Script de cierre mensual — carga empleados e ingresos/retiros del mes anterior a PostgreSQL. Se ejecuta vía LaunchAgents los días 1, 5 y 7 a las 5:00 AM |
| `cargar_historico_nomina_pyg.py` | Carga histórica de nómina y P&G a `historico_nomina_pyg`. Se ejecuta vía LaunchAgents los días 1, 5 y 7 a las 5:30 AM |
| `deploy/` | Guía y crontab ejemplo para ejecutar cierres en servidor/runner cloud |
| `historico_nomina_pyg.sql` | DDL de referencia para la tabla de caché histórico |
| `Unificacion_CECOs.xlsx` / `Unificacion_Hoteles.xlsx` / `Unificacion_Cargos.xlsx` | Mapeos maestros que se sincronizan a PostgreSQL vía endpoints `/proxy/admin/sync-*` |
| `Conceptos_Nomina_Mapeo.xlsx` | Mapeo de conceptos de nómina → tabla `nomina_conceptos` |
| `faranda-report/` | Guía de estilo y skill de reporte para Faranda Hotels |
| `CHANGELOG.md` | Historial de versiones del dashboard |

## Dashboard — tabs

1. 🔍 **Análisis** — vista general y gráficos
2. 👤 **Empleados** — tabla/tarjetas de empleados activos, filtros en cascada
3. 💰 **Salarios CECO** — salarios por centro de costo, drill-down a cargos/empleados
4. 🔄 **Ingresos y Retiros** — KPIs de rotación, causas de retiro, tendencias
5. 🩺 **Ausencias e Incapacidades** — ausentismo estimado desde días de nómina y conceptos clasificados
6. 💼 **Payroll** — reconciliación nómina vs P&G por hotel/período
7. 📊 **Estadísticas Hoteles** — métricas operativas, nómina, P&G y ratios por hotel

Filtros de header (aplican a todos los tabs): Razón Social → Centro de Costo → Cargo → Empleado → Operación → Período.

## Datos históricos vs. en vivo

- El período actual (o reciente) se consulta en vivo contra la API de NominaApp.
- Los períodos anteriores al corte (`_is_periodo_historico`, calculado dinámicamente desde `MAX(periodo)` en `historico_nomina_pyg`) se sirven desde PostgreSQL (`historico_empleados`, `historico_ir`, `historico_nomina_pyg`).
- El corte se recalcula automáticamente después de cada `cierre_mes.py`, sin necesidad de reiniciar el servidor.

## Automatización (LaunchAgents, macOS)

- `com.bia.dashboard-talento.plist` — arranca `servidor.py` al encender el equipo, se reinicia si falla.
- `com.bia.cierre-mes-dia1.plist` — corre `cierre_mes.py --empleados-activos-detalle` el día 1 a las 5:00 AM. Toma la foto viva de `GET /rrhh/empleados-activos-detalle` y la guarda como cierre del mes anterior.
- `com.bia.cierre-mes-dia5.plist`, `-dia7.plist` — corren `cierre_mes.py --solo-empleados-si-vacio` los días 5 y 7 a las 5:00 AM. Solo recargan empleados si el día 1 no dejó registros; IR se sigue refrescando con `DELETE + INSERT`.
- `com.bia.nomina-pyg-dia1.plist`, `-dia5.plist`, `-dia7.plist` — corren `cargar_historico_nomina_pyg.py --mes-anterior --fuente ambas` los días 1, 5 y 7 de cada mes a las 5:30 AM.

Logs en `logs/` (servidor) y `logs/cierres/` (cierre mensual).

## Automatización Cloud

La base remota correcta es `Base de Datos Historicos Talento Humano` en schema `public`.

Para instalar los cierres en un servidor/runner fuera de la Mac:

1. Clonar este repo en el servidor.
2. Configurar Secrets o `.env` privado con `DATABASE_URL`, `PG_SCHEMA=public`, `NOMINA_API_KEY` y `PYG_API_KEY`.
3. Ejecutar `deploy/install-cloud-cron.sh --dry-run`.
4. Instalar con `deploy/install-cloud-cron.sh --install`.
