# Plan — Rendición de Viáticos y Anticipos a Empleados

## Descripción funcional

Registrar el ciclo completo de anticipos que la empresa entrega a empleados de RRHH para gastos de viaje (viáticos), su rendición con facturas y comprobantes al retorno, y el cierre con devolución del sobrante o reintegro del faltante.

### Flujo canónico

```
1) ANTICIPO                    2) GASTOS EN CURSO             3) CIERRE
   Empresa → empleado             Empleado acumula:              Administrativo cierra:
   1 o N transferencias/            - N facturas con IVA           - Suma gastos totales
   cheques/efectivo                 - N comprobantes sin fact      - Compara con adelanto
   por rendición                    (solo descripción + monto)     - Genera devolución
                                                                     o reintegro (ahora
                                                                     o diferido)
```

### Objetivos

- Cubrir la operación real: adelantos múltiples, gastos con y sin factura, cierre configurable.
- Trazabilidad contable end-to-end: cada evento genera asiento + movimiento de tesorería.
- Cuenta corriente por empleado (saldo pendiente de rendir).
- Cumplir con SIFEN: facturas legales van al Libro IVA Compras normalmente.
- Integrarse con módulos existentes (Gastos, Tesorería, Contabilidad, RRHH).

### No objetivos (fuera de alcance)

- Notificaciones automáticas por email/push (fase futura).
- Aprobación multi-nivel (usa el workflow simple: config + umbral).
- Reembolsos sin viaje previo — se cubre con "rendición sin adelanto" (misma entidad, adelanto=0).
- Foto/PDF adjunto a comprobantes internos — gastos sin factura solo llevan descripción + monto.
- Reversibilidad post-cierre — una rendición cerrada es inmutable (solo se puede anular completa).

---

## Decisiones de diseño (base del plan)

| # | Tema | Decisión |
|---|------|----------|
| 1 | Funcionario | Empleado RRHH (`rrhh_empleados`) exclusivamente. |
| 2 | Cuenta contable | Cuenta única `1.01.03.03.04 - Anticipo para Viáticos` + reporte auxiliar de saldo por empleado. |
| 3 | Adelantos múltiples | Una rendición puede tener N filas de adelanto (`rendicion_adelanto`). |
| 4 | Aprobación previa | Configurable por empresa (`anticipo_viatico_requiere_aprobacion` + `anticipo_viatico_umbral_aprobacion`). |
| 5 | Devolución del saldo | UI inicial: una sola cuenta destino. Modelo: N filas para permitir split futuro. |
| 6 | Reintegro | Elegible en el cierre: **pagar ahora** (movimiento inmediato) o **diferir** (CxP al empleado). Default configurable. |
| 7 | Gastos sin factura | Solo descripción libre + tipo de gasto + monto + fecha. `deducible=false`. |
| 8 | IVA con factura | Mismas cuentas contables que gasto normal. Distinción vía `rendicion_viatico_id`. |
| 9 | Reversibilidad | Inmutable al cerrar. Solo se puede anular completa. |
| 10 | Origen de gastos | Se crean **exclusivamente** desde el form de la rendición. Sin vinculación posterior de gastos sueltos. |
| 11 | Rendición sin adelanto | Permitida (checkbox "sin adelanto previo"). Saldo queda 100% en contra de la empresa. |
| 12 | Menú | Doble acceso: `RRHH → Anticipos y Rendiciones` + `Finanzas → Anticipos a Empleados`. Mismo componente. |
| 13 | Notificaciones | Solo listado con columna "días sin rendir" + destacado visual. Sin emails ni badges. |

---

## Modelo de datos

### Nuevas tablas

#### `rendicion_viatico` (cabecera)

```
id                          UUID PK
empresa_id                  UUID FK empresas
empleado_id                 UUID FK rrhh_empleados
numero_rendicion            VARCHAR(20)  -- ej. RVI-2026-00042 (secuencia por empresa)
concepto                    VARCHAR(200) -- "Viaje a CDE del 10 al 12/07"
fecha_inicio                DATE
fecha_fin                   DATE
sin_adelanto                BOOLEAN DEFAULT false
moneda_id                   UUID FK moneda
cotizacion                  DECIMAL(18,6) DEFAULT 1
monto_adelanto_total        DECIMAL(18,2) DEFAULT 0    -- calc, suma de adelantos
monto_rendido_total         DECIMAL(18,2) DEFAULT 0    -- calc, suma de gastos
saldo                       DECIMAL(18,2) DEFAULT 0    -- calc: adelanto - rendido
                                                       -- positivo = devolver, negativo = reintegrar
estado                      VARCHAR(30) DEFAULT 'BORRADOR'
                            -- BORRADOR | PENDIENTE_APROBACION | ADELANTO_PAGADO
                            -- | SIN_ADELANTO | RENDIDA | CERRADA | ANULADA
tipo_cierre_reintegro       VARCHAR(20)  -- INMEDIATO | DIFERIDO (null si no aplica)
observaciones               TEXT
creado_por                  UUID FK usuario
aprobado_por                UUID FK usuario  (null si no requirió aprobación)
fecha_aprobacion            TIMESTAMPTZ
cerrado_por                 UUID FK usuario
fecha_cierre                TIMESTAMPTZ
anulado_por                 UUID FK usuario
fecha_anulacion             TIMESTAMPTZ
motivo_anulacion            TEXT
activo                      BOOLEAN DEFAULT true
created_at, updated_at
```

Índices:
- `(empresa_id, numero_rendicion)` UNIQUE
- `(empresa_id, empleado_id, estado)` — para consultas de saldo por empleado
- `(empresa_id, estado, fecha_fin)` — para listado con filtros de días sin rendir

#### `rendicion_adelanto` (N adelantos por rendición)

```
id                          UUID PK
rendicion_viatico_id        UUID FK rendicion_viatico ON DELETE CASCADE
empresa_id                  UUID FK empresas
monto                       DECIMAL(18,2) NOT NULL
fecha                       DATE NOT NULL
medio_pago_id               UUID FK medio_pago
tes_cuenta_id               UUID FK tes_cuentas       -- cuenta origen
numero_operacion            VARCHAR(100)              -- nº transferencia / cheque
banco_id                    UUID FK bancos (opcional)
tes_movimiento_id           UUID FK tes_movimientos   -- movimiento generado
cont_documento_id           UUID FK cont_documentos   -- asiento generado
observaciones               TEXT
created_at, updated_at
```

Índices:
- `(rendicion_viatico_id)`
- `(empresa_id, fecha)`

#### `rendicion_devolucion` (N filas, aunque UI inicial siempre crea 1)

```
id                          UUID PK
rendicion_viatico_id        UUID FK rendicion_viatico ON DELETE CASCADE
empresa_id                  UUID FK empresas
tipo                        VARCHAR(20)  -- DEVOLUCION | REINTEGRO
monto                       DECIMAL(18,2) NOT NULL
fecha                       DATE NOT NULL
medio_pago_id               UUID FK medio_pago
tes_cuenta_id               UUID FK tes_cuentas       -- destino (devolución) u origen (reintegro)
numero_operacion            VARCHAR(100)
tes_movimiento_id           UUID FK tes_movimientos
cont_documento_id           UUID FK cont_documentos
diferido                    BOOLEAN DEFAULT false     -- true = reintegro que quedó como CxP
cxp_empleado_id             UUID FK cuentas_pagar_empleado (opcional, solo si diferido=true)
observaciones               TEXT
created_at, updated_at
```

#### `cuentas_pagar_empleado` (nueva, para reintegros diferidos)

Alternativa: reutilizar `cuentas_pagar` con un flag `es_empleado` o con `origen_tipo='reintegro_viatico'`. Analizar en la fase de implementación cuál es más limpio.

Si es tabla nueva:

```
id                          UUID PK
empresa_id                  UUID FK empresas
empleado_id                 UUID FK rrhh_empleados
origen_tipo                 VARCHAR(30)  -- 'reintegro_viatico'
origen_id                   UUID         -- rendicion_devolucion.id
monto_original              DECIMAL(18,2)
monto_pagado                DECIMAL(18,2) DEFAULT 0
saldo_pendiente             DECIMAL(18,2)
estado                      VARCHAR(20)  -- pendiente | parcial | pagada | anulada
fecha_generacion            DATE
observaciones               TEXT
activo                      BOOLEAN DEFAULT true
created_at, updated_at
```

### Modificaciones a tablas existentes

#### `gasto_cab`

Agregar columna:
```
rendicion_viatico_id        UUID? FK rendicion_viatico (nullable)
```

- Cuando `!= NULL`: el gasto pertenece a una rendición. `forma_pago='ANTICIPO_PERSONAL'` (ya existe).
- Cuando `NULL`: gasto normal (flujo actual, sin cambios).

Índice: `(rendicion_viatico_id)`.

#### `config_rrhh` (o `empresas` si no existe config aparte)

Agregar columnas:
```
anticipo_viatico_requiere_aprobacion    BOOLEAN DEFAULT false
anticipo_viatico_umbral_aprobacion      DECIMAL(18,2) DEFAULT 0
                                        -- 0 = siempre requiere si el flag está ON
                                        -- >0 = solo si monto > umbral
reintegro_viatico_default               VARCHAR(20) DEFAULT 'INMEDIATO'
                                        -- INMEDIATO | DIFERIDO
viatico_dias_alerta                     INT DEFAULT 15
                                        -- para destacado visual en el listado
```

#### `medio_pago` — asegurar que existe `ANTICIPO_PERSONAL`

Ya existe según `guia-gastos.md`. Verificar en implementación.

---

## Diagrama de estados

```
                       ┌──────────────────────────┐
                       │  BORRADOR                │
                       │  (rendición creada,      │
                       │   sin adelanto pagado    │
                       │   todavía)               │
                       └──────────┬───────────────┘
                                  │
              ┌───────────────────┴────────────────────┐
              │                                        │
   requiere_aprobacion=true                requiere_aprobacion=false
   Y monto > umbral                        O monto ≤ umbral
              │                                        │
              ▼                                        │
   ┌──────────────────────┐                            │
   │ PENDIENTE_APROBACION │                            │
   │                      │                            │
   └─────┬────────────┬───┘                            │
         │            │                                │
     aprobar      rechazar                             │
         │            │                                │
         ▼            ▼                                ▼
                  ┌────────┐             ┌──────────────────────┐
                  │ANULADA │             │ ADELANTO_PAGADO      │
                  └────────┘             │ (o SIN_ADELANTO si   │
                                         │  sin_adelanto=true)  │
                                         └──────────┬───────────┘
                                                    │
                                          cargar gastos + cerrar
                                                    │
                                                    ▼
                                         ┌──────────────────────┐
                                         │ CERRADA (inmutable)  │
                                         └──────────┬───────────┘
                                                    │
                                                anular
                                                    │
                                                    ▼
                                              ┌────────┐
                                              │ANULADA │
                                              └────────┘
```

Transiciones válidas:
- `BORRADOR → PENDIENTE_APROBACION` (si requiere aprobación).
- `BORRADOR → ADELANTO_PAGADO` (si no requiere; genera asiento + tes_movimiento del primer adelanto).
- `BORRADOR → SIN_ADELANTO` (si el checkbox "sin adelanto previo" está tildado).
- `PENDIENTE_APROBACION → ADELANTO_PAGADO` (al aprobar).
- `PENDIENTE_APROBACION → ANULADA` (rechazada).
- `ADELANTO_PAGADO / SIN_ADELANTO → CERRADA` (al ejecutar el cierre).
- `CERRADA → ANULADA` (con permiso avanzado; revierte todo).
- `ADELANTO_PAGADO / SIN_ADELANTO → ANULADA` (antes del cierre; permite corregir).

---

## Impacto contable (asientos por evento)

Todos los asientos van a `cont_documentos` + `cont_asientos` con `origen_tipo` específico. Cuenta única: **`1.01.03.03.04 - Anticipo para Viáticos`** (concepto contable `ANTICIPO_VIATICO`).

### 1. Al pagar un adelanto (`rendicion_adelanto`)

```
DEBE   1.01.03.03.04  Anticipo para Viáticos       500.000
HABER  <cuenta_tesoreria del medio de pago>        500.000
```

- Descripción del asiento: `"Anticipo viáticos <numero_rendicion> - <nombre_empleado>"`.
- Glosa incluye el UUID del empleado para el reporte auxiliar.

### 2. Al registrar gasto CON factura legal (deducible)

Igual que un gasto normal, pero `HABER` va a Anticipo para Viáticos en vez de Caja/Banco/Proveedor:

```
DEBE   6.1.2.12  Viáticos y Movilidad (o tipo específico)   X
DEBE   1.1.3.01  IVA Crédito Fiscal 10%                     IVA10
DEBE   1.1.3.02  IVA Crédito Fiscal 5%                      IVA5
HABER  1.01.03.03.04  Anticipo para Viáticos                X + IVA
```

- Aparece en Libro IVA Compras con el timbrado del proveedor (hotel/restaurante/etc.).
- Aparece en Marangatu.

### 3. Al registrar gasto SIN factura (no deducible)

```
DEBE   6.1.2.12  Viáticos y Movilidad          Y
HABER  1.01.03.03.04  Anticipo para Viáticos   Y
```

- No aparece en Libro IVA (deducible=false).
- Tipo de gasto determina la cuenta específica de DEBE.

### 4. Al cerrar con saldo a favor de empresa (funcionario devuelve)

```
DEBE   <cuenta_tesoreria destino>              Sobra
HABER  1.01.03.03.04  Anticipo para Viáticos   Sobra
```

### 5. Al cerrar con saldo en contra (reintegro) — modo INMEDIATO

```
DEBE   1.01.03.03.04  Anticipo para Viáticos   Falta
HABER  <cuenta_tesoreria origen>               Falta
```

### 6. Al cerrar con saldo en contra (reintegro) — modo DIFERIDO

```
DEBE   1.01.03.03.04  Anticipo para Viáticos                          Falta
HABER  2.1.3.99  Reintegros a Empleados Pendientes                    Falta
```

- Cuenta `2.1.3.99` (o similar) nueva en el plan de cuentas — concepto `REINTEGRO_EMPLEADO_PENDIENTE`.
- Alternativa: reutilizar `2.1.3.04 Sueldos y Jornales a Pagar` (a discusión con contadores).

Al pagar la CxP diferida después (flujo aparte):
```
DEBE   2.1.3.99  Reintegros a Empleados Pendientes    Falta
HABER  <cuenta_tesoreria>                             Falta
```

### 7. Al anular rendición cerrada

Contra-asiento de todos los eventos anteriores (adelantos, gastos, devolución/reintegro). Usa `revertirDocumento` de contabilidad para cada `cont_documentos` con `origen_tipo` matcheable. Actualiza tesorería (movimientos → `ANULADO`).

---

## Impacto en Tesorería

### Reglas nuevas en `tes_reglas`

- **`ANTICIPO_VIATICO`** — cuenta origen del adelanto. Por defecto sin cuenta configurada; el usuario elige por adelanto en el form.
- **`DEVOLUCION_VIATICO`** — cuenta destino del sobrante. Idem, elegible por rendición.
- **`REINTEGRO_VIATICO`** — cuenta origen del reintegro inmediato. Idem.

Coherente con la cascada actual: prioridad al elegido en el form del pago concreto; si no viene, cae a la regla.

### Movimientos generados

- Adelanto: `EGRESO` en cuenta origen, `origen_tipo='rendicion_adelanto'`, `origen_id=<adelanto.id>`.
- Devolución: `INGRESO` en cuenta destino, `origen_tipo='rendicion_devolucion'`.
- Reintegro inmediato: `EGRESO` en cuenta origen, `origen_tipo='rendicion_devolucion'` (tipo=REINTEGRO).
- Reintegro diferido: no genera `tes_movimientos` al cerrar. Se genera cuando efectivamente se paga la CxP.

Reversa al anular: como en OP — `tes_movimientos.estado = 'ANULADO'` y saldo de la cuenta se recompone.

---

## Endpoints backend (REST v1)

Módulo nuevo: `src/rendicion-viaticos/`.

### Rendiciones

- `POST /rendicion-viaticos` — crear rendición (opcionalmente con adelanto inicial en el mismo payload).
- `GET /rendicion-viaticos` — listado paginado con filtros (empleado, estado, fechas, días sin rendir).
- `GET /rendicion-viaticos/:id` — detalle completo (adelantos + gastos + devolución/reintegro).
- `PATCH /rendicion-viaticos/:id` — editar cabecera (solo en BORRADOR).
- `POST /rendicion-viaticos/:id/aprobar` — aprobar (si estaba en PENDIENTE_APROBACION).
- `POST /rendicion-viaticos/:id/rechazar` — rechazar (transiciona a ANULADA).
- `POST /rendicion-viaticos/:id/cerrar` — cerrar rendición (calcula saldo, genera devolución/reintegro).
- `POST /rendicion-viaticos/:id/anular` — anular rendición completa (revierte todo).

### Adelantos

- `POST /rendicion-viaticos/:id/adelantos` — agregar un nuevo adelanto (adicional). Solo si estado ∈ {ADELANTO_PAGADO, SIN_ADELANTO}.
- `DELETE /rendicion-viaticos/:id/adelantos/:adelantoId` — eliminar adelanto (solo en BORRADOR).

### Gastos

- `POST /rendicion-viaticos/:id/gastos` — crear gasto vinculado (con o sin factura). Reutiliza internamente `GastosService.create` pero con `rendicion_viatico_id` seteado.
- `DELETE /rendicion-viaticos/:id/gastos/:gastoId` — eliminar gasto (solo si la rendición no está CERRADA/ANULADA).

### Reportes

- `GET /rendicion-viaticos/saldo-por-empleado` — cuenta corriente por empleado (saldo pendiente de rendir).
- `GET /rendicion-viaticos/dashboard` — resumen: cantidad por estado, monto total pendiente, promedio días sin rendir.

### CxP diferida (reintegros)

- `GET /cuentas-pagar-empleado` — listado de reintegros pendientes de pagar.
- `POST /cuentas-pagar-empleado/:id/pagar` — pagar reintegro diferido (elige cuenta + medio).

---

## Pantallas frontend

### Ubicación

- `/rrhh/anticipos-viaticos` — desde RRHH.
- `/finanzas/anticipos-empleados` — desde Finanzas.

Ambas rutas renderizan el mismo componente `RendicionViaticosScreen`.

### Layout general (aplica `docs/ui-standards.md`)

```
[ScreenGuia colapsable]
[Header: "Anticipos y Rendiciones" + botón "Nueva rendición" a la derecha]
[Paper con filtros: Estado / Empleado / Rango fechas / Sólo pendientes > N días]
[Resumen: KPIs (rendiciones abiertas | monto pendiente | días promedio sin rendir)]
[Tabla con StandardTable]
  Columnas: Nº | Empleado | Concepto | Fecha inicio | Días sin rendir | Adelanto | Rendido | Saldo | Estado | Acciones
  Fila roja si días_sin_rendir > umbral (config)
[Paginación 3 cols]
```

### Diálogo "Nueva rendición"

Form básico:
- Empleado (autocomplete con búsqueda de `rrhh_empleados`).
- Concepto (texto libre).
- Fecha inicio, fecha fin (default: hoy y +3 días).
- Moneda + cotización (si aplica, con hook `useCotizacionVigente`).
- Checkbox "Sin adelanto previo (empresa reembolsa al final)".
- Si NO checkbox: sección "Primer adelanto" con:
  - Monto, medio de pago, cuenta origen, nº operación, fecha.

Al guardar:
- Si `sin_adelanto=true`: estado inicial `SIN_ADELANTO`.
- Sino, si `requiere_aprobacion && monto > umbral`: estado `PENDIENTE_APROBACION`.
- Sino: estado `ADELANTO_PAGADO` + genera asiento + tes_movimiento del adelanto.

### Detalle de rendición (tabs)

```
[Header: Nº - Empleado - Estado (chip)]
[KPIs: Adelanto Gs X | Rendido Gs Y | Saldo Gs Z (con color según signo)]
[Tabs]
  ├─ Anticipos       (tabla de adelantos con botón "+ Nuevo adelanto")
  ├─ Gastos          (tabla de gastos con botón "+ Nuevo gasto")
  ├─ Cierre          (visible solo si estado ∈ {ADELANTO_PAGADO, SIN_ADELANTO, CERRADA})
  └─ Historial       (auditoría: quién creó, quién aprobó, cuándo se cerró, etc.)
```

**Tab Gastos**: reutiliza el form actual de `Gastos` (mismo `GastosTemplate.jsx`) con:
- `rendicion_viatico_id` pre-seteado.
- `forma_pago` fijo en `ANTICIPO_PERSONAL` (readonly).
- Toggle visible **"Con factura legal / Sin factura"** que activa/desactiva la sección documento fiscal.
- Selector "Tipo de gasto" con opciones específicas del catálogo (Hotel, Traslado, Comida, Combustible, Peaje, Otro).

**Tab Cierre**:
- Muestra `Saldo = Adelanto - Rendido`.
- Si saldo > 0 (funcionario devuelve): dropdown "Cuenta destino" + medio de pago + nº operación.
- Si saldo < 0 (empresa reintegra): dropdown "Modo de reintegro" (`INMEDIATO` / `DIFERIDO`).
  - Si INMEDIATO: pedir cuenta origen + medio de pago.
  - Si DIFERIDO: solo confirma (genera CxP al empleado).
- Botón "Cerrar rendición" con confirmación.

### Reporte "Saldo por empleado"

`/rrhh/anticipos-viaticos/saldo-por-empleado`:
- Tabla: Empleado | Rendiciones abiertas | Monto adelantado | Monto rendido | Saldo pendiente | Días desde último movimiento.
- Filtros: solo con saldo pendiente, ordenar por saldo desc.
- Exportable a CSV/XLSX.

---

## Permisos

Módulo `RRHH` — nuevos submódulos:
- `RRH_ANTICIPO_VIATICO` (base).
- Privilegios:
  - `RRH_ANT_VER` — ver rendiciones propias + otras (según rol).
  - `RRH_ANT_CREAR` — crear rendición y adelantos.
  - `RRH_ANT_APROBAR` — aprobar/rechazar (si requiere aprobación).
  - `RRH_ANT_CERRAR` — cerrar rendición.
  - `RRH_ANT_ANULAR` — anular (incluso cerradas — permiso alto).

Módulo `FINANZAS` — acceso al mismo módulo con permiso equivalente `FIN_ANT_EMP_*`.

Los empleados-usuario (con `usuario.empleado_id`) solo ven sus propias rendiciones automáticamente.

---

## Configuración por empresa

Agregar a `config_rrhh` (o crear si no existe):

```
anticipo_viatico_requiere_aprobacion    BOOLEAN DEFAULT false
anticipo_viatico_umbral_aprobacion      DECIMAL(18,2) DEFAULT 0
reintegro_viatico_default               VARCHAR(20) DEFAULT 'INMEDIATO'
viatico_dias_alerta                     INT DEFAULT 15
```

UI: `Configuración → RRHH → Anticipos y Viáticos`.

---

## Reportes

1. **Cuenta corriente por empleado** — saldo pendiente por empleado consolidado.
2. **Rendiciones por período** — todas las rendiciones cerradas en un rango, con total gastado.
3. **Rendiciones pendientes** — abiertas ordenadas por días sin rendir.
4. **Detalle de gastos por rendición** — PDF exportable con todos los ítems + comprobantes (opcional foto adjunta en fase futura).

---

## Plan por fases (recomendado)

### Fase 1 — Modelo + Adelantos ✅ COMPLETADA
- ✅ Migración `20260710_rendicion_viaticos`: `rendicion_viatico`, `rendicion_adelanto`, `rendicion_devolucion`, `cuentas_pagar_empleado`, `config_rrhh`, columna `gasto_cab.rendicion_viatico_id`.
- ✅ Seed extendido: conceptos `ANTICIPO_VIATICO` (`1.01.03.03.04`) y `REINTEGRO_EMPLEADO_PENDIENTE` (`2.1.3.04`).
- ✅ Módulo backend `src/rendicion-viaticos/`:
  - `RendicionViaticosService` — crear, listar, ver, editar, aprobar, rechazar, anular, agregar adelanto.
  - `RendicionViaticosContabilidadService` — asiento de adelanto (DEBE Anticipo / HABER cuenta caja/banco) + reversa al anular.
  - `RendicionViaticosTesoreriaService` — `tes_movimientos` EGRESO + recomposición de saldos al anular.
  - Numeración automática `RVI-YYYY-NNNNN`.
  - Estados: BORRADOR → PENDIENTE_APROBACION → ADELANTO_PAGADO / SIN_ADELANTO → CERRADA / ANULADA.
  - Endpoints REST: GET/POST/PATCH `/rendicion-viaticos`, `/rendicion-viaticos/:id`, `:id/aprobar`, `:id/rechazar`, `:id/anular`, `:id/adelantos`, `/config`.
- ✅ Frontend (`pos-ventas`):
  - `api/rendicion-viaticos.service.js` + hooks TanStack en `tanstack/RendicionViaticosStack.jsx`.
  - Enum de estados en `_standards/enums/estadosRendicionViatico.js`.
  - `pages/RendicionViaticosPage.jsx` — listado con filtros (estado, atrasadas > N días, búsqueda) + KPIs (total, abiertas, saldo pendiente multi-moneda, días promedio sin rendir) + tabla responsive.
  - `pages/RendicionViaticoDetallePage.jsx` — detalle con KPIs + tabs (Anticipos activo, Gastos/Cierre placeholders para Fase 2/3) + botones aprobar/rechazar/anular con `useConfirmDialog`.
  - Diálogos `NuevaRendicionDialog.jsx` (con checkbox "sin adelanto previo" + integración con `useCotizacionVigente` para multi-moneda) y `AgregarAdelantoDialog.jsx`.
  - Rutas `/rendicion-viaticos` y `/rendicion-viaticos/:id`.
  - Doble acceso: tab "Anticipos a Empleados" en Finanzas (`Tesoreria.jsx`), y pendiente sumar en pantalla RRHH.
- **Entregable**: se pueden crear rendiciones y pagar adelantos con impacto contable + tesorería.
- **Pendiente Fase 2**: form de gastos vinculados (con y sin factura).
- **Pendiente Fase 3**: tab de Cierre con devolución/reintegro (inmediato o diferido).

### Fase 2 — Gastos vinculados ✅ COMPLETADA
- ✅ `CreateGastoDto` extendido con `forma_pago='ANTICIPO'` + `rendicion_viatico_id`.
- ✅ `gasto_cab` persiste `rendicion_viatico_id`.
- ✅ `RendicionViaticosService.agregarGasto` — reutiliza `GastosService.create` con `forma_pago='ANTICIPO'` + `rendicion_viatico_id`. Modo con_factura=true → flujo fiscal completo; modo con_factura=false → items con IVA=0 y sin datos de proveedor.
- ✅ `RendicionViaticosService.quitarGasto` — anula el gasto y revierte asiento.
- ✅ `recalcularTotales` — actualiza `monto_rendido_total` y `saldo` al agregar/quitar gastos.
- ✅ Endpoints `POST /rendicion-viaticos/:id/gastos` y `DELETE /rendicion-viaticos/:id/gastos/:gastoId`.
- ✅ Frontend `AgregarGastoRendicionDialog.jsx` — toggle con/sin factura, autocomplete de proveedor, timbrado + establecimiento + punto exp + Nº factura solo si con factura; tabla de items con tipo_gasto + descripción + cantidad + precio + IVA (deshabilitado sin factura) + subtotal; total en vivo.
- ✅ Tab "Gastos" activo en la página de detalle con tabla + botón "Nuevo gasto" + acción anular con confirmación.
- **Entregable**: registrar gastos con y sin factura vinculados a la rendición.

### Fase 3 — Cierre y devolución/reintegro ✅ COMPLETADA
- ✅ DTO `CerrarRendicionDto` con validación de campos según modo.
- ✅ `RendicionViaticosService.cerrar` — calcula saldo, crea `rendicion_devolucion` (tipo DEVOLUCION o REINTEGRO), genera CxP al empleado si diferido, marca rendición como CERRADA (inmutable).
- ✅ `RendicionViaticosContabilidadService.registrarDevolucion` — 3 asientos según caso:
  - DEVOLUCION: `DEBE cuenta tesorería / HABER Anticipo Viáticos`.
  - REINTEGRO INMEDIATO: `DEBE Anticipo Viáticos / HABER cuenta tesorería`.
  - REINTEGRO DIFERIDO: `DEBE Anticipo Viáticos / HABER Reintegros Pendientes` (`2.1.3.04`).
- ✅ `RendicionViaticosTesoreriaService.registrarDevolucion` — INGRESO en devolución, EGRESO en reintegro inmediato, sin movimiento si diferido.
- ✅ `anular` extendido: revierte adelantos + gastos + devoluciones + CxP empleado (transacción atómica).
- ✅ Endpoint `POST /rendicion-viaticos/:id/cerrar`.
- ✅ Frontend `CerrarRendicionDialog.jsx` con:
  - Resumen visual del saldo (adelantado / rendido / diferencia con color semántico).
  - Alerta según modo (SIN_SALDO / DEVOLUCION / REINTEGRO).
  - Cards seleccionables "Pagar ahora" vs "Diferir CxP" cuando hay reintegro.
  - Campos de cuenta + medio de pago solo si aplica.
  - Aviso final: "una vez cerrada, es inmutable".
- ✅ Tab "Cierre" activo — muestra tabla de devoluciones/reintegros si CERRADA, o CTA "Cerrar rendición" si abierta.
- ✅ Botón "Cerrar rendición" en la barra de acciones del detalle.
- **Entregable**: rendición completa end-to-end con cierre.

### Fase 4 — Reportes + CxP a empleados ✅ COMPLETADA
- ✅ `RendicionViaticosService.reporteSaldosPorEmpleado` — agrega rendiciones abiertas + CxP diferidas por empleado, calcula `saldo_a_favor_empresa` (empleado debe) y `saldo_a_favor_empleado` (empresa debe), retorna `{items, totales}` ordenado por saldo absoluto.
- ✅ `RendicionViaticosService.listarCxpEmpleados` — listado con filtros de empleado + estado.
- ✅ `RendicionViaticosService.pagarCxpEmpleado` — registra pago total o parcial: crea EGRESO en `tes_movimientos`, actualiza saldo de `tes_cuenta` y de la CxP, marca `parcial` o `pagada` según corresponda, mejor esfuerzo para asiento contable.
- ✅ Endpoints `GET /rendicion-viaticos/reporte-saldos-empleado`, `GET /rendicion-viaticos/cxp-empleados`, `POST /rendicion-viaticos/cxp-empleados/:cxpId/pagar` (registrados antes de `:id` para evitar colisión de rutas).
- ✅ Frontend:
  - API + hooks `useReporteSaldosPorEmpleadoQuery`, `useCxpEmpleadosQuery`, `usePagarCxpEmpleadoMutation`.
  - `pages/RendicionSaldosPorEmpleadoPage.jsx` — filtros por empleado + "solo con saldo", KPIs totales, tabla con chips accionables hacia CxP.
  - `pages/CxpEmpleadosPage.jsx` — listado con filtro estado, KPIs, botón "Pagar" por fila.
  - `components/organismos/RendicionViaticosDesign/PagarCxpEmpleadoDialog.jsx` — validación de monto ≤ saldo pendiente, MonedaInput, selector de tes_cuenta y medio de pago.
  - Rutas `/rendicion-viaticos/reportes/saldos-empleado` y `/rendicion-viaticos/cxp-empleados` (antes del `:id`).
  - Menú: nueva pestaña "Viáticos" en `RRHHTemplate` + entradas "CxP a Empleados" y "Saldos por Empleado" en `Tesoreria.jsx`.
- **Entregable**: reporte auxiliar + gestión completa de reintegros diferidos.

### Fase 5 — Documentación ✅ COMPLETADA
- ✅ Guía funcional en `pos-ventas/docs/guia-rendicion-viaticos.md` — flujo completo, estados, contabilización resumida, configuración.
- **Entregable**: módulo listo para producción.

### Fase 6 — Cheques + refinamiento UX ✅ COMPLETADA
- ✅ Migraciones `20260722_rendicion_adelanto_cheque` y `20260723_rendicion_devolucion_cheque` — columnas `numero_cheque`, `banco_emisor`, `titular_cheque`, `fecha_emision_cheque`, `fecha_vencimiento_cheque`, `tes_cheque_id` en `rendicion_adelanto` y `rendicion_devolucion`.
- ✅ DTOs extendidos (`CreateAdelantoDto`, `CreateAdelantoAdicionalDto`, `CerrarRendicionDto`, pago CxP) con datos de cheque opcionales.
- ✅ `RendicionViaticosTesoreriaService.registrarAdelanto` y `registrarDevolucion` detectan cheque por `codigo=2` o descripcion `contains 'cheque'` en `medio_pago` y crean el instrumento en `tes_cheques` (`tipo=EMITIDO` o `RECIBIDO`, `estado=EN_CARTERA` o `DIFERIDO` según vencimiento), enlazando con el `tes_movimientos` y el registro de rendición/devolución.
- ✅ `pagarCxpEmpleado` también crea `tes_cheques` cuando corresponde y ahora genera el asiento contable completo via `RendicionViaticosContabilidadService.registrarPagoCxpEmpleado` (`DEBE REINTEGRO_EMPLEADO_PENDIENTE / HABER cuenta tesorería/BANCO`) usando `AsientosService.crearConfirmado`, con auditoría automática si el asiento falla.
- ✅ Frontend: bloque condicional "DATOS DEL CHEQUE" en `NuevaRendicionDialog`, `AgregarAdelantoDialog`, `CerrarRendicionDialog` y `PagarCxpEmpleadoDialog` con validación completa (Nº cheque, banco emisor, titular, fecha emisión, fecha cobro con hint diferido/en cartera).
- ✅ Cuando el medio de pago es Efectivo (codigo=1 o descripcion `contains 'efectivo'/'contado'`), los formularios ocultan Nº operación + Banco destino y filtran `tes_cuentas` a solo cajas (`CAJA_CHICA`, `FONDO_FIJO`, `BILLETERA`), renombrando el label a "Caja".
- ✅ Diálogos de confirmación previos (`useConfirmDialog`) al crear rendición, agregar adelanto y cerrar rendición — muestran resumen antes de disparar la acción.
- **Entregable**: soporte completo de cheque + UX pulida.

### Fase 7 — Reportes + PDFs + comprobantes ✅ COMPLETADA
- ✅ Renderers msv-kude (formato A4 moderno, paleta `primary/accent/bgAccent`, header con logo + caja destacada + estado en chip semaforizado):
  - `msv-kude/src/rendicion-viaticos/rendicion_viatico_a4.js` — comprobante de rendición (empleado, período, tabla anticipos, tabla gastos con/sin factura, caja resumen adelantado/rendido/saldo con color semántico, tabla cierre, 3 firmas).
  - `msv-kude/src/rendicion-viaticos/cxp_empleado_a4.js` — comprobante de pago CxP (empleado, origen rendición, resumen monto/pagado/saldo, historial de pagos, 2 firmas).
  - `msv-kude/src/rendicion-viaticos/reporte_saldos_a4.js` — reporte apaisado A4 con 8 columnas + chip semaforizado en "Últ. act.", paginación automática.
- ✅ Rutas `POST /api/rendicion-viatico/generate-pdf`, `POST /api/cxp-empleado/generate-pdf`, `POST /api/rendicion-viaticos/saldos-empleado/generate-pdf` registradas en `msv-kude/src/app.js`.
- ✅ Endpoints backend `GET /rendicion-viaticos/:id/pdf`, `GET /rendicion-viaticos/cxp-empleados/:cxpId/pdf`, `GET /rendicion-viaticos/reporte-saldos-empleado/pdf`.
- ✅ Frontend: componente reusable `PDFPreviewDialog` (`src/components/_standards/`) con iframe embebido, botones **Cerrar / Abrir en pestaña / Descargar** y manejo de `objectURL`.
- ✅ Export XLSX en `RendicionViaticosPage` (todas las columnas del listado) y en `RendicionSaldosPorEmpleadoPage` (12 columnas + días sin actividad).
- ✅ Drill-down por empleado en el reporte de saldos: click en la fila abre `DetalleEmpleadoSaldoDialog` con rendiciones abiertas + CxP pendientes, cada una linkeada al detalle correspondiente.
- ✅ Columna "Última actividad" con chip semáforo (verde ≤15d, amarillo 16-30d, rojo >30d).
- ✅ Mapeo de cuentas — en `MapeoCuentasTab` (contabilidad) se agregó la sección **"Rendición de Viáticos"** con `ANTICIPO_VIATICO` y `REINTEGRO_EMPLEADO_PENDIENTE` editables por el contador + chip de advertencia "OLD" cuando la cuenta mapeada tiene código `OLD-`. El servicio contable hace fallback al mapeo `BANCO`/`CAJA_GENERAL` si la `tes_cuenta.cuenta_contable_id` apunta a una cuenta `OLD-`/inactiva.
- **Entregable**: producto listo con outputs impresos completos.

### Fase 8 — Seguridad y submódulo ✅ COMPLETADA
- ✅ Nuevo submódulo `RRHH_VIATICOS` en `seguridad.seed-data.ts` con 8 privilegios:
  - `RH_VIA_RENDICION_VER` — lectura general
  - `RH_VIA_RENDICION_CREAR` — crear/editar rendiciones y adelantos
  - `RH_VIA_RENDICION_APROBAR` — supervisor (aprueba/rechaza)
  - `RH_VIA_RENDICION_ANULAR` — anular rendición
  - `RH_VIA_GASTO_CARGAR` — cargar/anular gastos rendidos
  - `RH_VIA_CIERRE_EJECUTAR` — cerrar rendición (devolución/reintegro)
  - `RH_VIA_CXP_PAGAR` — pagar CxP diferida
  - `RH_VIA_CONFIG_EDITAR` — editar la configuración de viáticos
- ✅ `RendicionViaticosController` protegido con `@UseGuards(AuthGuard('jwt'), ModuleGuard, PermissionGuard)` + `@RequireModule('RRHH')` a nivel clase, y `@RequirePermission('RRHH', 'RH_VIA_...')` en cada endpoint.
- ✅ Frontend: `usePermission("RRHH")` en `RendicionViaticosPage`, `RendicionViaticoDetallePage`, `CxpEmpleadosPage`, `RRHHTemplate` y `Tesoreria` — los botones y pestañas aparecen solo si el usuario tiene el privilegio correspondiente. Los estados que gobiernan botones (`puedeAgregarAdelanto`, `puedeCerrar`, etc.) combinan estado + permiso.
- ✅ Filtro `activo:true` removido del listado — al anular no se ocultaba pero ahora sí aparece con estado `ANULADA` tachado.
- ✅ Modal de configuración por empresa (`ConfigViaticosDialog`) con los 4 parámetros (`requiere_aprobacion`, `umbral`, `reintegro_default`, `dias_alerta`), accesible desde el botón "Configuración" del listado sólo con `RH_VIA_CONFIG_EDITAR`.
- ✅ Guía de usuario en `pos-ventas/docs/guia-rendicion-viaticos.md` — sección **"Roles y permisos"** con tabla de privilegios y explicación del rol supervisor.
- ✅ Guía IA en `smartfactvoice-backend/docs/guias/guia-rendicion-viaticos.md`.
- **Pendiente de ejecución manual**: `POST /seguridad/seed-maestro` (o restart) para crear el submódulo + privilegios; habilitar `RRHH_VIATICOS` en el plan de cada empresa; asignar privilegios a los perfiles.
- **Entregable**: módulo con guardas de seguridad completas + documentación.

**Total estimado**: 8-11 días.

Gate entre fases: tests en verde + build backend/frontend OK.

---

## Plan de pruebas

1. **Unit backend** (Jest):
   - `RendicionViaticosService.crear` con y sin adelanto.
   - `RendicionViaticosService.aprobar` con umbral configurado.
   - Cálculo de saldo: adelanto múltiple - gastos = saldo.
   - Cierre modo INMEDIATO: genera 1 asiento + 1 tes_movimiento.
   - Cierre modo DIFERIDO: genera CxP al empleado (sin tes_movimiento).
   - Anulación completa: revierte todo (adelantos + gastos + cierre).

2. **Integración**:
   - Empresa sin módulo RRHH → endpoints devuelven 403.
   - Empresa sin módulo Contabilidad → asientos se omiten silenciosamente (mismo patrón que compras/gastos).
   - `sin_adelanto=true`: saldo siempre en contra al cerrar.

3. **E2E flujo completo**:
   - Crear rendición con adelanto Gs 500k.
   - Cargar 3 gastos (2 con factura, 1 sin) totalizando Gs 380k.
   - Cerrar con devolución de Gs 120k a Caja General.
   - Verificar asientos: 1 adelanto + 3 gastos + 1 devolución.
   - Verificar tes_movimientos: 1 EGRESO adelanto + 1 INGRESO devolución.
   - Verificar saldo del empleado en el reporte auxiliar = 0.

4. **QA manual UI**:
   - Crear rendición sin adelanto → cargar gastos → cerrar con reintegro diferido.
   - Verificar que aparece la CxP al empleado en el listado.
   - Pagar la CxP diferida y verificar que queda saldada.
   - Anular una rendición cerrada y verificar que el saldo del empleado vuelve al estado previo.

---

## Riesgos y mitigaciones

| Riesgo | Mitigación |
|--------|------------|
| Empleado con múltiples rendiciones abiertas → saldo agregado en el reporte auxiliar puede ser confuso | El reporte muestra detalle por rendición + total consolidado |
| Anular rendición con muchos gastos → cadena larga de reversas contables | Transacción única, con rollback total si falla algún paso |
| Cuenta `1.01.03.03.04` no existe en el plan de la empresa | Al crear la rendición, verificar mapeo `ANTICIPO_VIATICO`; si falta, warning con link a Contabilidad → Mapeo (mismo patrón que Tesorería) |
| Empleado no tiene usuario asociado → no puede ver sus rendiciones | El empleado sin usuario no accede al ERP igual; la restricción es "usuario_id opcional". Reportes internos usan `empleado_id` |
| Un mismo empleado tiene rendición en USD y otra en PYG simultáneas | Saldo por empleado se muestra separado por moneda (mismo patrón que compras multi-moneda) |
| Emitir un adelanto suplementario con moneda distinta al primero | Bloqueo: todos los adelantos de una rendición deben ser de la misma moneda (validación backend) |

---

## Documentación asociada

Al completar la implementación:
- `docs/plan-rendicion-viaticos.md` — este documento (mantener actualizado con estado por fase).
- `docs/guias/guia-rrhh-anticipos-viaticos.md` — guía funcional para el usuario final.
- Referencia cruzada en `docs/guias/guia-gastos.md` (existente) — sección "Gastos vinculados a rendiciones".
- Referencia cruzada en `docs/guias/guia-tesoreria-bancos.md` — reglas nuevas `ANTICIPO_VIATICO` etc.
