# Plan: Módulo Tesorería y Bancos

## Decisiones de diseño confirmadas

| Decisión | Valor |
|---|---|
| Relación con Caja del Día | **Separado** — Caja del Día es del módulo Ventas/Cobros, Tesorería maneja fondos formales |
| Tipos de cuenta | Todos (banco CC, banco CA, caja chica, fondo fijo, billetera virtual, moneda extranjera) — **configurable** |
| Movimientos automáticos | **Configurable por tipo de operación**: automático o requiere confirmación del usuario |
| Reglas de origen/destino | Pantalla de **"Reglas de Tesorería"** por tipo de operación → cuenta origen/destino |
| Categorías de movimiento | **Híbrido**: base predefinida (intocable) + categorías custom por empresa, cada una con cuenta contable |
| Conciliación bancaria | **Fase posterior** — arquitectura preparada desde el inicio (tablas, partidas pendientes) |
| Formato extracto bancario | Flexible / configurable por banco, escalable para IA en el futuro |
| Cheques diferidos | ✅ Soportado (posfechados con fecha futura) |
| Listado cheques por vencer | ✅ Sí |
| Rechazo cheque → reversa CxC | ✅ Automático |
| Cheques | ✅ En scope inicial |
| Integración contable | Cada movimiento genera asiento automático vía `integracion.service.ts` + guard `tieneModuloContabilidad()` |
| Permisos | Sistema existente `@RequirePermission('TESORERIA', 'TES_XXX')` |

---

## Permisos del módulo `TESORERIA`

### Códigos de permiso

| Código | Descripción | Roles sugeridos |
|---|---|---|
| `TES_VER` | Ver cuentas, saldos y movimientos | Cajero, Tesorero, Gerente, Contador |
| `TES_REGISTRAR_MOVIMIENTO` | Crear movimiento manual (ingreso/egreso) | Cajero, Tesorero, Gerente |
| `TES_ANULAR_MOVIMIENTO` | Anular un movimiento registrado | Tesorero, Gerente |
| `TES_APROBAR_MOVIMIENTO` | Aprobar movimientos que superan el monto umbral configurado | Tesorero, Gerente |
| `TES_TRANSFERIR` | Transferencia entre cuentas propias | Tesorero, Gerente |
| `TES_GESTIONAR_CHEQUES` | Emitir/recibir/depositar/anular cheques | Tesorero, Gerente |
| `TES_VER_REPORTES` | Ver reportes: cash flow, movimientos, saldos | Tesorero, Gerente, Contador |
| `TES_CONCILIAR` | Realizar conciliación bancaria | Tesorero, Contador |
| `TES_CONFIG` | Configurar cuentas, categorías y reglas de tesorería | Gerente, Admin |

### Asignación por rol sugerida

| Permiso | Admin | Gerente | Tesorero | Cajero | Contador | Vendedor |
|---|---|---|---|---|---|---|
| `TES_VER` | ✅ | ✅ | ✅ | ✅ | ✅ | — |
| `TES_REGISTRAR_MOVIMIENTO` | ✅ | ✅ | ✅ | ✅ | — | — |
| `TES_ANULAR_MOVIMIENTO` | ✅ | ✅ | ✅ | — | — | — |
| `TES_APROBAR_MOVIMIENTO` | ✅ | ✅ | ✅ | — | — | — |
| `TES_TRANSFERIR` | ✅ | ✅ | ✅ | — | — | — |
| `TES_GESTIONAR_CHEQUES` | ✅ | ✅ | ✅ | — | — | — |
| `TES_VER_REPORTES` | ✅ | ✅ | ✅ | — | ✅ | — |
| `TES_CONCILIAR` | ✅ | ✅ | ✅ | — | ✅ | — |
| `TES_CONFIG` | ✅ | ✅ | — | — | — | — |

> **Nota**: Los permisos se asignan desde el panel de Roles del sistema, igual que todos los módulos. Esta tabla es la asignación por defecto sugerida al crear un rol nuevo.

---

## Cuentas contables puente (ya en seed + migración)

| Código | Descripción | Uso |
|---|---|---|
| `1.1.1.06` | Cheques en Cartera | Al recibir cheque de cliente |
| `1.1.1.07` | Cheques Depositados en Tránsito | Al depositar cheque antes de acreditar en banco |
| `1.1.1.08` | Fondo Fijo / Caja Chica | Fondo de caja chica con reposición |
| `2.1.1.04` | Cheques a Pagar | Al emitir cheque propio (diferido o no) |
| `4.2.1.02` | Diferencia de Cambio Ganada | Ya existía en seed |
| `6.3.1.01` | Intereses Bancarios | Ya existía en seed |
| `6.3.1.02` | Comisiones Bancarias | Ya existía en seed |
| `6.3.1.03` | Diferencia de Cambio Perdida | Ya existía en seed |

---

## Transferencias entre cuentas propias

### Estado actual de implementación ✅ COMPLETADO (2026-04-21)

**Lo que está implementado:**

```
[CONFIRMADO] → [ANULADO]
```

- Al crear una transferencia, ambos saldos se actualizan de **inmediato** (sin borrador ni tránsito)
- Se generan 2 movimientos en `tes_movimientos` vinculados por `transferencia_id` (UUID compartido):
  - `origen_tipo = 'TRANSFERENCIA_ORIGEN'` — EGRESO en cuenta origen
  - `origen_tipo = 'TRANSFERENCIA_DESTINO'` — INGRESO en cuenta destino
- Estado directo: ambos movimientos nacen en `CONFIRMADO`
- Al anular: `updateMany` pone ambos movimientos en ANULADO y revierte los saldos en `$transaction`
- Requiere permiso `TES_TRANSFERIR`

**Transferencias multi-moneda (PYG ↔ USD / otras) — implementación actual:**

- Si origen y destino tienen `moneda` distinta → el campo `tipo_cambio` es **obligatorio**
- `monto_destino = monto_origen × tipo_cambio` (calculado en backend)
- La cuenta origen egresa `monto` en su moneda; la cuenta destino acredita `monto × tipo_cambio` en la suya
- El campo `tipo_cambio` aparece automáticamente en el formulario al detectar monedas distintas
- El backend valida: si monedas difieren y `tipo_cambio` no viene o es 0 → rechaza con `BadRequestException`

**Asiento contable actual (mismo-moneda):**
- DEBE: cuenta contable de la cuenta destino
- HABER: cuenta contable de la cuenta origen
- Si alguna cuenta no tiene `cuenta_contable_id` o no hay módulo Contabilidad: se omite el asiento en silencio

**⚠️ Limitación conocida — movimientos en cuentas no-PYG:**
- `integrarMovimientoTesoreria` usa `det.monto` directamente, sin conversión a PYG
- Un ingreso de USD 500 genera asiento con 500 como si fueran Gs. 500 — distorsión contable
- Pendiente: ver sección "Rediseño multi-moneda" abajo
- Workaround hasta entonces: no asignar `cuenta_contable_id` a cuentas no-PYG

### Pendiente / Fase futura

| Feature | Estado | Notas |
|---|---|---|
| Rediseño formulario multi-moneda (monto_origen + monto_destino) | ✅ Implementado | Campo TC + preview monto destino + TC referencia inline |
| Asiento de 3 patas para diferencia de cambio | ✅ Implementado | TC banco vs TC sistema, cuentas 4.2.1.02 / 6.3.1.03 |
| TC pre-cargado desde módulo Contabilidad → Tipo de Cambio | ✅ Implementado | `GET /contabilidad/tipo-cambio/vigente` |
| Modo EN_TRANSITO (acreditación diferida) | ❌ Pendiente | Para transferencias interbancarias con demora |

---

### Rediseño multi-moneda (fase futura)

#### Fuente de tipo de cambio

El sistema ya cuenta con el módulo **Contabilidad → Tipo de Cambio** (`cont_tipo_cambio`) donde
se registra la tasa diaria por moneda. Esa tabla es la **única fuente de verdad** para TC de referencia.
No se crea una tabla separada en Tesorería.

```typescript
// Al abrir el formulario de transferencia con monedas distintas:
const tcSistema = await prisma.cont_tipo_cambio.findFirst({
  where: { empresa_id, moneda: monedaExtranjera, fecha: transferencia.fecha },
  orderBy: { created_at: 'desc' },
});
// Si no existe → no bloquear, pero el asiento será de 2 patas (sin diferencia de cambio)
```

#### Nuevo diseño del formulario multi-moneda

En lugar de un campo "Tipo de cambio" que el usuario ingresa para calcular el monto destino,
el formulario expone **ambos montos directamente** y calcula el TC como resultado:

```
┌─────────────────────────────────────────────────────────┐
│  Cuenta origen:   [BNF Cuenta PYG ▼]    Saldo: Gs. 5.000.000  │
│  Monto que sale:  [Gs. 3.000.000    ]                          │
│                                                                │
│  Cuenta destino:  [Itaú Cuenta USD ▼]   Saldo: USD 1.200,00  │
│  Monto que llega: [USD 396,83       ]   ← usuario ingresa     │
│                                                                │
│  ┌──────────────────────────────────────────────────┐        │
│  │ TC efectivo (banco):    Gs. 7.561  (calculado)   │        │
│  │ TC referencia (sistema): Gs. 7.850  (18/04/2026) │        │
│  │ Diferencia de cambio:   Gs. 114.877 PERDIDA  ⚠  │        │
│  └──────────────────────────────────────────────────┘        │
│                                                                │
│  Fecha:       [21/04/2026]                                    │
│  Descripción: [Compra de divisas para pago proveedor]         │
│                                                                │
│            [Cancelar]  [Confirmar transferencia]              │
└─────────────────────────────────────────────────────────┘
```

**Reglas del formulario:**
- `TC efectivo = monto_origen / monto_destino` (calculado en tiempo real, solo lectura)
- `TC referencia` se pre-carga desde `cont_tipo_cambio` para la fecha seleccionada
- Si no hay TC en sistema para esa fecha → se oculta la sección de diferencia de cambio, la transferencia procede igual
- `Diferencia = |TC_efectivo - TC_referencia| × monto_destino` — se indica si es ganancia o pérdida
- El saldo disponible de cada cuenta se muestra junto al selector para contexto inmediato
- Si `monto_origen > saldo_disponible` → aviso inline en rojo debajo del campo (no esperar al submit)

#### Asiento contable multi-moneda (3 patas)

**Caso A — Hay TC en sistema:**
```
HABER: Cuenta origen (PYG)              → Gs. 3.000.000   (monto_origen)
DEBE:  Cuenta destino (USD → PYG)       → Gs. 2.975.625   (396,83 × TC_sistema 7.500)
DEBE:  Diferencia de Cambio Perdida     → Gs.    24.375   (residuo)
```
Si el TC efectivo es mejor que el de sistema → HABER en `Diferencia de Cambio Ganada (4.2.1.02)`.

**Caso B — Sin TC en sistema para esa fecha:**
```
HABER: Cuenta origen (PYG)              → Gs. 3.000.000
DEBE:  Cuenta destino (valorizado al TC efectivo) → Gs. 3.000.000
```
Asiento de 2 patas. Sin diferencia de cambio. Se registra una nota en la glosa:
`"Transferencia multi-moneda — TC referencia no disponible para esta fecha"`.

#### Flujo EN_TRANSITO (cuando se implemente)
```
CONFIRMADO (origen egresa) → EN_TRANSITO → ACREDITADO (destino entra) → (ANULADO)
```
- Útil para transferencias interbancarias donde la acreditación demora 1-2 días hábiles
- **No aplica** para compra/venta de divisas (el monto destino se conoce al momento)
- En el dashboard: badge "X transferencia(s) en tránsito — pendiente de acreditación"

#### Principios UX del formulario multi-moneda

- **Feedback inmediato**: TC efectivo y diferencia de cambio se recalculan mientras el usuario escribe
- **Saldo visible**: cada cuenta muestra su saldo disponible junto al selector — el usuario no tiene que salir a verificarlo
- **Aviso inline de saldo insuficiente**: aparece debajo del campo antes del submit, no como toast
- **Diferencia de cambio destacada**: si es significativa (> 0.5% del monto) se resalta en naranja/rojo
- **Sin TC en sistema**: la sección de diferencia simplemente desaparece — no aparece un error confuso
- **Responsive**: en mobile los dos paneles (origen/destino) se apilan verticalmente con flecha entre ellos
- **Texto de ayuda contextual**: debajo del TC efectivo: "Este es el tipo de cambio real que aplicó tu banco. El sistema lo calculó automáticamente."

## Asientos contables automáticos por operación

| Evento | DEBE | HABER |
|---|---|---|
| Depósito en cuenta bancaria | Banco (cuenta destino) | Caja General / CxC |
| Pago con transferencia a proveedor | Proveedores | Banco (cuenta origen) |
| Gasto con caja chica | Cuenta de gasto (categoría) | Fondo Fijo / Caja Chica |
| Reposición fondo fijo | Fondo Fijo / Caja Chica | Banco |
| Cheque propio emitido | Proveedores / Acreedor | **Cheques a Pagar** |
| Cheque propio cobrado por banco | Cheques a Pagar | Banco |
| Cheque propio rechazado por banco | Banco (reversión) | Cheques a Pagar → proveedor |
| Cheque tercero recibido | **Cheques en Cartera** | CxC Cliente |
| Cheque tercero depositado | **Cheques Depositados en Tránsito** | Cheques en Cartera |
| Cheque tercero acreditado en banco | Banco | Cheques Depositados en Tránsito |
| Cheque tercero rechazado | CxC Cliente | Banco + Gasto rechazo |
| Transferencia entre cuentas propias | Cuenta destino | Cuenta origen |
| Comisión / gasto bancario | Comisiones Bancarias | Banco |
| Interés cobrado por banco | Banco | Intereses Bancarios |
| Diferencia de cambio positiva | Banco (moneda local) | Diferencia de Cambio Ganada |
| Diferencia de cambio negativa | Diferencia de Cambio Perdida | Banco (moneda local) |

---

## Cheques: al día vs diferidos — consideraciones operativas

### Diferenciación

| Concepto | Cheque al día | Cheque diferido (posfechado) |
|---|---|---|
| `fecha_vencimiento` | ≤ hoy (o sin fecha) | > hoy |
| Estado inicial al registrarse | `EN_CARTERA` | `DIFERIDO` |
| Transición a `EN_CARTERA` | — | Automática al alcanzarse `fecha_vencimiento` |
| Disponible para depositar | Sí, inmediato | No hasta que pase a `EN_CARTERA` |
| Aparece en cartera (reporte) | Sí | Sí, con badge "Diferido" |
| Aparece en "Cheques por vencer" (≤ N días) | Si vence pronto | Cuenta atrás hasta `fecha_vencimiento` |

### Origen del cheque en el sistema

1. **Recepción directa** (módulo Cheques → Registrar cheque recibido) — flujo legacy, asiento al depositar.
2. **Como medio de pago en Recibo Multi-Factura** (módulo Cobros) — flujo nuevo. Se crea `tes_cheques` + `tes_movimientos` confirmado + asiento del recibo en una sola transacción. **Saldo de la cuenta de tesorería sube de inmediato incluso si el cheque es DIFERIDO** — esto refleja la convención contable PY (reconocer pago al recibir el documento) pero distorsiona la posición de caja "líquida". Para análisis de caja real filtrar cartera por estado.
3. **Emisión propia para pagar a proveedor** (módulo OP / Cheques) — `tes_cheques` con `tipo=EMITIDO`.

### Impactos cruzados

- **CxC del cliente** se cierra cuando se confirma el Recibo Multi, **independientemente** de si el cheque es al día o diferido. Es decir, un cliente con cheques diferidos largos figura "sin deuda" antes de que el banco efectivamente debite. Para morosidad real: cruzar `factura_cab.saldo_pendiente` con `tes_cheques` en estado `DIFERIDO` del mismo cliente.
- **Rechazo de cheque** (al día o diferido) **NO** revierte automáticamente la CxC ni el recibo. Workaround actual: anular el recibo multi desde *Cobros → Recibos Multi → Anular* (revierte facturas + saldo tesorería + asiento), luego registrar el cheque como rechazado. Pendiente: automatizar la reversa CxC al marcar cheque rechazado.
- **Anular recibo multi con cheques fuera de cartera** (DEPOSITADO/ACREDITADO/RECHAZADO/DEBITADO) está bloqueado — el service obliga a reversar el cheque primero desde Tesorería. Mensaje claro al usuario con el listado de cheques bloqueantes.
- **Cheques diferidos en posición de caja**: el reporte de posición muestra el saldo bruto de la cuenta — incluye los cheques diferidos. Para "caja líquida real" usar *Cartera de cheques* y restar mentalmente el total `DIFERIDO`. Sugerencia v2: tarjeta separada "Cheques diferidos por cobrar" en el dashboard.
- **Validación pendiente**: en el wizard de Recibo Multi, `fecha_vencimiento` no es obligatoria para `medio=CHEQUE`. Si el operador la omite, el cheque entra como `EN_CARTERA` aunque la intención sea diferida. Hay que volverla required en el DTO `ChequeDataDto` cuando `medio=CHEQUE`.

---

## Reglas de Tesorería — configuración por tipo de operación

Pantalla en `Configuración > Tesorería > Reglas`:

| Tipo de operación | Cuenta por defecto | Modo | Configurable |
|---|---|---|---|
| Cobro depositado (desde CxC) | Banco PYG | Automático | ✅ |
| Pago a proveedor (desde CxP) | Banco PYG | Pide confirmación | ✅ |
| Pago con cheque propio | Banco PYG | Pide confirmación | ✅ |
| Recepción de cheque de cliente | Cheques en Cartera | Automático | ✅ |
| Gasto de caja chica | Fondo Fijo / Caja Chica | Manual | ✅ |
| Transferencia entre cuentas | — (usuario elige) | Manual | — |

---

## Categorías base del sistema (intocables)

| Código interno | Nombre | Tipo | Cuenta contable |
|---|---|---|---|
| `DEP_BANCARIO` | Depósito bancario | Ingreso | Banco destino |
| `RETIRO_EFECTIVO` | Retiro de efectivo | Egreso | Caja General |
| `TRANSFERENCIA_PROPIA` | Transferencia entre cuentas propias | — | Cuenta destino/origen |
| `GASTO_BANCARIO` | Gasto bancario / comisión | Egreso | `6.3.1.02` |
| `INTERES_BANCARIO` | Interés bancario cobrado | Ingreso | `4.2.1.01` |
| `PAGO_IMPUESTO` | Pago de impuesto | Egreso | Cuenta de impuesto |
| `REPOSICION_CAJA_CHICA` | Reposición de fondo fijo | — | Fondo Fijo / Banco |
| `INGRESO_OTRO` | Otro ingreso no clasificado | Ingreso | `4.2.1.04` |
| `EGRESO_OTRO` | Otro egreso no clasificado | Egreso | `6.1.2.10` |

---

## Tablas de base de datos necesarias

```
bancos                   -- YA EXISTE — se extiende con seed de bancos de Paraguay (empresa_id IS NULL = sistema)
tes_cuentas              -- Cuentas de tesorería (banco, caja, billetera, etc.) → referencia bancos.id
tes_movimientos          -- Movimientos de ingreso/egreso con estado
tes_movimiento_det       -- Detalle por categoría (si un mov. tiene múltiples categorías)
tes_categorias           -- Categorías de movimiento (base + custom)
tes_reglas               -- Reglas automáticas por tipo de operación
tes_cheques              -- Cheques propios y de terceros
tes_extracto_bancario    -- Líneas del extracto bancario importado (conciliación)
tes_conciliacion         -- Cruce extracto ↔ movimiento (partidas pendientes)
```

### Campos de `tes_cuentas`
| Campo | Tipo | Descripción |
|---|---|---|
| `id` | UUID | PK |
| `empresa_id` | UUID | FK empresas |
| `nombre` | VARCHAR(100) | Nombre descriptivo ("BNF CTA CTE Principal") |
| `tipo` | VARCHAR(20) | `BANCO_CC`, `BANCO_CA`, `CAJA_CHICA`, `FONDO_FIJO`, `BILLETERA`, `MONEDA_EXT` |
| `moneda` | VARCHAR(3) | `PYG`, `USD`, `BRL`, etc. |
| `saldo_inicial` | DECIMAL(18,2) | Saldo al dar de alta |
| `saldo_actual` | DECIMAL(18,2) | Calculado en tiempo real |
| `cuenta_contable_id` | UUID | FK cont_plan_cuentas |
| `banco_id` | UUID? | FK bancos (solo si tipo es BANCO_*) |
| `numero_cuenta` | VARCHAR(50)? | Número real del banco |
| `cbu_iban` | VARCHAR(50)? | Para transferencias internacionales |
| `titular` | VARCHAR(100)? | Si difiere del nombre de la empresa |
| `saldo_minimo_alerta` | DECIMAL(18,2)? | Alerta cuando saldo baja de este valor |
| `activo` | BOOLEAN | Para desactivar sin borrar |
| `created_at` | TIMESTAMP | — |

---

## Reportes de Tesorería

Todos con exportación PDF (msv-kude, mismo diseño base que Contabilidad) y Excel.

| Reporte | Descripción | Notas |
|---|---|---|
| **Extracto de cuenta** | Movimientos de una cuenta con saldo acumulado por período | PDF tipo estado de cuenta bancario |
| **Posición de caja** | Saldo actual de todas las cuentas agrupado por moneda y tipo | Snapshot del momento |
| **Flujo de caja real** | Ingresos vs egresos reales registrados por período y categoría | Gráfico + tabla |
| **Flujo de caja proyectado** | Real + vencimientos pendientes de CxC (cobros esperados) y CxP (pagos esperados) | Cruza con `cuentas_cobrar` y `orden_pago_proveedor_cab` |
| **Movimientos por categoría** | Totales agrupados por categoría en un período | Detectar dónde se gasta más |
| **Cartera de cheques** | Todos los cheques activos con estado y fecha de vencimiento | Propios y de terceros separados |
| **Cheques por vencer** | Cheques con vencimiento en los próximos N días (configurable) | Alerta de gestión |
| **Rendición de caja chica** | Detalle de gastos del fondo fijo para aprobar reposición | Por período o por rendición |
| **Conciliación bancaria** | Diferencias entre movimientos del sistema y extracto bancario importado | Fase incluida en scope inicial |

### PDF de Tesorería
- Mismo motor: msv-kude
- Mismo diseño base (cabecera, paleta, tipografía) que Contabilidad
- Mejoras opcionales: color de acento diferente por tipo de reporte (extracto = azul, cheques = naranja, cash flow = verde)

## Tab "Movimientos" — Vistas y filtros

### Dos vistas disponibles (toggle)
1. **Vista Global**: tabla unificada con todos los movimientos de todas las cuentas, columna "Cuenta" visible, ordenable y filtrable
2. **Vista Extracto**: se selecciona una cuenta → listado cronológico con **saldo acumulado línea a línea** (igual a un estado de cuenta bancario)

### Filtros disponibles
| Filtro | Vista Global | Vista Extracto |
|---|---|---|
| Rango de fechas | ✅ | ✅ |
| Cuenta de tesorería | ✅ | — (ya está seleccionada) |
| Tipo (ingreso/egreso/transferencia) | ✅ | ✅ |
| Categoría | ✅ | ✅ |
| Estado (borrador/confirmado/anulado) | ✅ | ✅ |
| Monto desde/hasta | ✅ | ✅ |
| Usuario que registró | ✅ | ✅ |
| Tiene comprobante adjunto | ✅ | ✅ |

### Exportación
- **Excel**: movimientos filtrados con todas las columnas
- **PDF** (via msv-kude): reporte tipo extracto con encabezado de empresa, filtros aplicados, totales y saldo acumulado
- Disponible en ambas vistas

## Flujo de movimientos manuales

### Estados
```
[BORRADOR] → [CONFIRMADO] → [ANULADO]
```
- **BORRADOR**: registrado, sin impacto en saldo ni contabilidad. Editable.
- **CONFIRMADO**: impacta saldo de `tes_cuentas.saldo_actual` + genera asiento contable automático. Solo anulable, no editable.
- **ANULADO**: genera asiento de reversión automático. El usuario puede crear uno nuevo desde cero.

### Aprobación por monto
- Configurable por empresa: monto umbral en `tes_config`
- Movimientos **≥ umbral**: requieren aprobación de usuario con `TES_APROBAR_MOVIMIENTO` antes de confirmar
- Movimientos **< umbral**: se confirman directamente si el usuario tiene `TES_REGISTRAR_MOVIMIENTO`
- Permiso adicional: `TES_APROBAR_MOVIMIENTO` (Tesorero, Gerente)

### Comprobantes adjuntos
- Campo `comprobante_url` en `tes_movimientos` — almacena ruta del archivo subido
- Formatos: imagen (JPG, PNG) o PDF
- Opcional al registrar, requerido configurable por categoría
- Visible en el detalle del movimiento y en auditoría

### Anulación
- Solo usuarios con `TES_ANULAR_MOVIMIENTO`
- Genera asiento de reversión automático vía `revertirDocumento()` existente
- Requiere motivo de anulación (campo texto obligatorio)
- El movimiento anulado queda visible en el historial con estado ANULADO

## Tab "Configuración"

### A — Cuentas de tesorería (ABM)
Crear, editar, activar/desactivar cuentas bancarias y cajas. Incluye selector de banco de la tabla `bancos`.

### B — Categorías de movimiento (ABM)
- Categorías base del sistema: visibles, **solo lectura** (no se pueden borrar ni editar)
- Categorías de la empresa: crear/editar/eliminar, cada una con cuenta contable asociada (`cont_plan_cuentas`)
- Campo "requiere comprobante": si está activo, el adjunto es obligatorio al registrar

### C — Reglas de integración automática
Por tipo de operación predefinida → configurar:
- Cuenta de tesorería por defecto (origen o destino)
- Modo: `AUTOMATICO` (sin intervención) o `CONFIRMACION` (usuario aprueba antes de confirmar)

### D — Parámetros generales
| Parámetro | Tipo | Default |
|---|---|---|
| Monto umbral de aprobación | Decimal | 0 (desactivado) |
| Días alerta cheques por vencer | Entero | 7 |
| Moneda base de reportes | VARCHAR(3) | PYG |
| Formato CSV extracto por banco | JSON configurable | — |

### E — Bancos (ABM)
- Bancos del sistema (`empresa_id IS NULL`): visibles, **solo lectura**
- Bancos propios de la empresa: crear/editar/eliminar si falta alguno en la lista del sistema

---

## Fases de implementación

## Dashboard — Tab "Cuentas" (pantalla de inicio)

- Tarjetas por cuenta activa: nombre, tipo, moneda, saldo actual, variación del día
- Alerta visual si saldo < saldo_minimo_alerta
- **Acceso rápido** desde cada tarjeta: botones [+ Ingreso] [+ Egreso] [Ver movimientos]
- Totales al pie **separados por moneda** (PYG, USD, BRL, etc.) — NO conversión cruzada
- Cuentas inactivas: **ocultas** del dashboard (visibles solo en Configuración)
- Panel de alertas: cheques por vencer, saldos bajo mínimo

## Ubicación en el sistema

- **Módulo propio** en el menú lateral: `Tesorería y Bancos`
- Ruta base: `/tesoreria-bancos`
- Sub-tabs internos: `[Cuentas y Saldos]` `[Movimientos]` `[Cheques]` `[Transferencias]` `[Reportes]`
- Configuración en: `Configuración → Tesorería y Bancos` (Cuentas, Categorías, Bancos, Parámetros)

---

### Fase 1 — Base ✅ COMPLETADA (2026-04-20)
- [x] Tablas BD: `tes_cuentas`, `tes_movimientos`, `tes_movimiento_det`, `tes_categorias`, `tes_reglas`, `tes_config`
- [x] Migración: seed bancos Paraguay (`bancos` tabla existente)
- [x] Migración: seed cuentas contables tesorería (`cont_plan_cuentas`)
- [x] Backend: CRUD cuentas de tesorería con `banco_id` → `bancos`
- [x] Backend: Registro movimientos manuales (estados BORRADOR → CONFIRMADO → ANULADO)
- [x] Backend: Aprobación por monto umbral (`TES_APROBAR_MOVIMIENTO`)
- [x] Backend: Integración contable automática al confirmar (`integrarMovimientoTesoreria`) — omite si la empresa no tiene módulo CONTABILIDAD
- [x] Backend: Reversión contable al anular (`revertirDocumento`) — omite si no hay asiento previo
- [x] Backend: `getCuentaContableId` / `cuenta_contable_id` visible en ABM de cuentas y categorías
- [x] Backend: Vista Extracto — endpoint `GET /tes/movimientos/extracto?cuentaId=&fechaDesde=&fechaHasta=` con saldo acumulado
- [ ] **PENDIENTE**: Backend: Subida de comprobantes adjuntos (imagen/PDF)
- [ ] **PENDIENTE**: Backend: Reglas de tesorería — tabla creada, lógica no implementada aún
- [x] Frontend: Módulo "Tesorería y Bancos" en menú lateral (ruta `/tesoreria-bancos`)
- [x] Frontend: Dashboard cuentas con tarjetas, saldos por moneda, alertas de saldo mínimo
- [x] Frontend: ABM de cuentas con selector de cuenta contable (Configuración → Tesorería y Bancos)
- [x] Frontend: ABM de categorías con selector de cuenta contable y columna de mapeo
- [x] Frontend: Vista Global de movimientos con filtros y paginación
- [x] Frontend: Vista Extracto (toggle en tab Movimientos — saldo acumulado línea a línea por cuenta)
- [x] Frontend: Exportación Excel de movimientos (filtros aplicados, todas las columnas)

### Fase 1.5 — Transferencias entre cuentas ✅ COMPLETADA (2026-04-21)
- [x] Tabla BD: campo `transferencia_id` (UUID) + `origen_tipo` en `tes_movimientos`
- [x] Backend: `TesTransferenciasService` — crear, listar, anular
- [x] Backend: Validación cuentas distintas, saldo suficiente, tipo_cambio obligatorio si monedas difieren
- [x] Backend: Multi-moneda — `monto_destino = monto × tipo_cambio`, saldos actualizados en moneda propia de cada cuenta
- [x] Backend: Asiento contable básico (2 patas: DEBE cuenta destino / HABER cuenta origen)
- [x] Backend: Anulación con reversión de saldos en `$transaction`
- [x] Backend: AuditService — logs de creación y anulación
- [x] Migración: permisos `TESORERIA` / `TES_TRANSFERIR` + módulo en `modulos` y `suscripciones`
- [x] Frontend: Tab "Transferencias" en Tesorería y Bancos (tabla desktop + cards mobile + paginación)
- [x] Frontend: Modal nueva transferencia — campo tipo_cambio aparece automáticamente si monedas difieren, preview monto destino
- [x] Frontend: Modal anulación con detalle de cuentas afectadas
- [x] Frontend: Exportación Excel (`xlsx`) con todos los filtros aplicados
- [x] Asiento de 3 patas para diferencia de cambio (TC banco vs TC sistema) — `integrarTransferenciaTes` con cuentas 4.2.1.02 / 6.3.1.03
- [x] TC de referencia pre-cargado desde `cont_tipo_cambio` — mostrado en formulario con preview de diferencia de cambio
- [ ] **PENDIENTE**: Modo EN_TRANSITO (acreditación diferida en cuenta destino)

### Fase 2 — Cheques ✅ COMPLETADA (2026-04-21)
- [x] Tabla BD: `tes_cheques`
- [x] Backend: Flujo cheques recibidos (EN_CARTERA → DEPOSITADO / RECHAZADO / DEVUELTO)
- [x] Backend: Flujo cheques emitidos (EN_CARTERA → DEBITADO / RECHAZADO / ANULADO)
- [x] Backend: Cheques diferidos (posfechados con `fecha_vencimiento` futura) — estado inicial `DIFERIDO`, transita a `EN_CARTERA` al llegar la fecha
- [x] Backend: Integración con **Recibos Multi-Factura** — `medio=CHEQUE` en un recibo crea automáticamente la fila en `tes_cheques` (estado `DIFERIDO` si `fecha_vencimiento > hoy`, `EN_CARTERA` en caso contrario)
- [x] Backend: Al depositar/debitar → crea movimiento `CONFIRMADO` automático en `tes_movimientos`
- [x] Backend: Integración contable al depositar/debitar (categorías sistema "Cheque Depositado" / "Cheque Debitado")
- [x] Backend: AuditService en todas las acciones de cheques
- [x] Frontend: Tab "Cheques" con lista/tabla, toggle Recibidos/Emitidos, buscador, filtros estado/cuenta
- [x] Frontend: Resumen de cartera (total en cartera, cheques próximos a vencer)
- [x] Frontend: Alertas de vencimiento próximo (≤ 3 días) — badge en fila + banner
- [x] Frontend: Exportación Excel del listado filtrado
- [x] Frontend: Paginación (20 por página) responsive (tabla desktop / cards mobile)
- [ ] **PENDIENTE**: Reversa automática de CxC al rechazar cheque de tercero
- [ ] **PENDIENTE**: Listado cheques por vencer configurable (N días desde parámetros)

### Fase 3 — Reportes y Conciliación

#### 3.1 — Reportes ✅ (mayormente completo)
- [x] Backend: 5 endpoints de reportes (`posicion-caja`, `cash-flow-real`, `cash-flow-proyectado`, `extracto-cuenta`, `cartera-cheques`)
- [x] Backend: Cash flow real — ingresos/egresos confirmados agrupados por categoría con filtros fecha/cuenta/moneda
- [x] Backend: Cash flow proyectado — real + CxC pendientes (`cuentas_cobrar`) + órdenes de pago (`orden_pago_proveedor_cab`)
- [x] Backend: Extracto de cuenta — saldo acumulado línea a línea con saldo anterior calculado
- [x] Backend: Cartera de cheques — filtros por tipo/estado/cuenta/fecha con resumen
- [x] Backend: Corrección timezone (fechas UTC con +1 día para cubrir el día completo)
- [x] Backend: Corrección NULL en NOT IN (OR explícito para excluir transferencias)
- [x] Frontend: Tab "Reportes" con 4 sub-vistas (Posición de Caja, Flujo Real, Flujo Proyectado, Extracto, Cartera Cheques)
- [x] Frontend: Buscador + columnas redimensionables en Extracto y Cartera de Cheques
- [ ] **PENDIENTE**: Exportación PDF/Excel de reportes (posición, flujo, extracto, cartera)

#### 3.2 — Privilegios TES_ ✅ (completo)
- [x] Agregados a `seed.ts` y a BD: `TES_VER`, `TES_REGISTRAR_MOVIMIENTO`, `TES_APROBAR_MOVIMIENTO`, `TES_ANULAR_MOVIMIENTO`, `TES_TRANSFERIR`, `TES_VER_REPORTES`, `TES_CONCILIAR`, `TES_CONFIG`
- [x] Incluidos en `prisma/migrations/conciliacion_bancaria.sql` (idempotente)

#### 3.3 — Conciliación Bancaria ⚠️ (parcialmente completo)
- [x] Tablas BD: `tes_extracto_bancario` + `tes_extracto_lineas` (con enum `tes_extracto_estado`)
- [x] Migración SQL: `prisma/migrations/conciliacion_bancaria.sql`
- [x] Backend: `TesConciliacionService` — importar CSV, auto-match, conciliar, desconciliar, actualizar estado
- [x] Backend: Parser CSV genérico (separadores `;`/`,`, fechas DD/MM/YYYY o ISO, columnas por nombre)
- [x] Backend: Auto-match por monto + tipo (débito↔EGRESO, crédito↔INGRESO) + fecha ±2 días
- [x] Backend: Estado automático PENDIENTE → PARCIAL → CONCILIADO al conciliar/desconciliar
- [x] Backend: 7 endpoints bajo `/tes/conciliacion/*` con permiso `TES_CONCILIAR`
- [x] Frontend: Tab "Conciliación" en Tesorería y Bancos
- [x] Frontend: Panel izquierdo — lista de extractos con filtro por cuenta, estado chip, botón eliminar
- [x] Frontend: Modal de importación — selector cuenta, período, saldo inicial/final, upload CSV con preview de líneas
- [x] Frontend: Panel derecho — tabla de líneas con stats conciliadas/pendientes, buscador, columna de acción
- [x] Frontend: Conciliar manual — `Autocomplete` con búsqueda en tiempo real (fecha, monto, descripción)
- [x] Frontend: Desconciliar — botón LinkOff en líneas conciliadas
- [x] Frontend: Dark mode completo — `ExtractoCard`, `Tabla`, `LineaRow` adaptados al tema
- [x] Frontend: Botón eliminar extracto resaltado en rojo (color="error" + hover con fondo)
- [ ] **PENDIENTE**: Marcar línea como "sin correspondencia" — cerrar líneas sin movimiento vinculado (comisiones automáticas, etc.)
- [ ] **PENDIENTE**: Crear movimiento desde conciliación — registrar directamente un movimiento para una línea sin match
- [ ] **PENDIENTE**: Reporte de diferencias — líneas sin conciliar + movimientos del sistema que no aparecen en extracto (partidas en tránsito)
- [ ] **PENDIENTE**: Formatos CSV por banco — parsers específicos para Continental, Sudameris, BNF, Itaú (cada uno tiene columnas distintas)
- [x] ~~Importación inteligente de extractos PDF via IA~~ → ver Fase 3.4 (completado)

---

### Fase 3.4 — Importación Inteligente de Extractos PDF con IA 🤖

> **Objetivo**: El usuario sube el PDF del banco tal como lo descarga. El sistema lo lee, entiende y carga las transacciones automáticamente. Cero configuración de columnas, cero mapeo manual.

#### Principio de diseño UX central
Cada paso debe responder: **¿esto hace la vida del usuario más fácil y rápida?**
- **Mínima fricción**: 2 acciones del usuario (subir PDF → confirmar) → extracto listo
- **Feedback inmediato**: spinner animado con mensaje contextual mientras la IA procesa
- **Transparencia inteligente**: mostrar qué encontró la IA antes de confirmar (preview editable)
- **Siempre hay salida**: si la IA falla o no hay API key → el CSV manual sigue disponible

---

#### Flujo del usuario (UX detallado)

```
┌─────────────────────────────────────────────────────────────────────────────┐
│  Tab "Conciliación"                                                         │
│                                                                             │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │  [+ Nuevo extracto]  ← botón principal, siempre visible             │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────────────────┘

Al hacer clic → Modal "Importar extracto bancario":

┌─────────────────────────────────────────────────────────────────────────────┐
│  Importar extracto bancario                                           [×]   │
│                                                                             │
│  Cuenta bancaria:  [BNF Cuenta Corriente PYG              ▼]               │
│                                                                             │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │                                                                     │   │
│  │        📄  Arrastrá tu extracto aquí                                │   │
│  │            o hacé clic para seleccionar                             │   │
│  │                                                                     │   │
│  │        Formatos aceptados: PDF  ·  CSV  ·  Excel                   │   │
│  │                                                                     │   │
│  │   ✨ Los PDFs son procesados automáticamente por IA                 │   │
│  │      (Banco Continental, Ueno, BNF, Sudameris y más)               │   │
│  │                                                                     │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
│                                                                             │
│                              [Cancelar]                                     │
└─────────────────────────────────────────────────────────────────────────────┘

→ Usuario sube PDF → Estado: PROCESANDO

┌─────────────────────────────────────────────────────────────────────────────┐
│  Importar extracto bancario                                           [×]   │
│                                                                             │
│  ┌─────────────────────────────────────────────────────────────────────┐   │
│  │                                                                     │   │
│  │     🤖  Analizando extracto con Inteligencia Artificial...         │   │
│  │         Leyendo movimientos del Banco Continental                   │   │
│  │                        ████████████░░░░  75%                       │   │
│  │                                                                     │   │
│  │     Esto puede tomar unos segundos                                  │   │
│  │                                                                     │   │
│  └─────────────────────────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────────────────────────┘

→ IA procesa → Estado: PREVIEW

┌─────────────────────────────────────────────────────────────────────────────┐
│  Importar extracto bancario                                           [×]   │
│                                                                             │
│  ✅ IA detectó 13 movimientos · Banco Continental · 01/04 – 22/04/2026     │
│                                                                             │
│  Revisá y confirmá antes de importar:                                       │
│                                                                             │
│  Fecha        Concepto                          Tipo      Importe           │
│  ─────────────────────────────────────────────────────────────────────      │
│  02/04/2026   TRF.INTRBN.SPI-TUFIPYPA...        CRÉDITO   + 400.000        │
│  02/04/2026   Mov.ATM: BNF COMISARIA CARAGUA     DÉBITO   - 400.000        │
│  04/04/2026   TRF.INTRBN.SPI-TUFIPYPA...        CRÉDITO   + 200.000        │
│  06/04/2026   SIPAP-2604063000659 NC159579       CRÉDITO + 18.500.000      │
│  ...          (9 más)                                                       │
│                                                                             │
│  ⚠️ Revisá los importes — si alguno no coincide con tu PDF, editalo antes  │
│     de confirmar.                                     [Ver todos (13)]      │
│                                                                             │
│  Saldo inicial (opcional): [________________]                               │
│  Saldo final   (opcional): [________________]                               │
│                                                                             │
│             [Cancelar]          [✔ Confirmar e importar (13 mov.)]         │
└─────────────────────────────────────────────────────────────────────────────┘

→ Confirmado → Banner en tab Conciliación:

  ✅ Extracto importado · 13 movimientos · 9 auto-conciliados · 4 pendientes de revisión
```

---

#### Diseño UX — principios aplicados

| Principio | Cómo se aplica |
|---|---|
| **Minimizar pasos** | Sube PDF → preview → confirmar. Solo 2 acciones de decisión |
| **Feedback inmediato** | Spinner con mensaje dinámico ("Leyendo movimientos del Banco X") durante el proceso IA |
| **Transparencia IA** | Preview editable antes de confirmar — el usuario siempre tiene control |
| **Mensajes contextuales** | Aviso "⚠️ Revisá los importes" en el preview; ayuda inline "¿Qué es saldo inicial?" |
| **Inteligencia visible** | Badge "✨ Procesado por IA" en extractos importados vía PDF — el usuario sabe que el ERP es inteligente |
| **Fallback claro** | Si la IA no está configurada o falla → botón "Importar CSV manualmente" siempre visible |
| **Responsive** | Drag & drop en desktop; botón "Seleccionar archivo" en mobile |
| **Accesibilidad** | Drag zone con borde punteado visible, texto alternativo, foco de teclado en todos los botones |
| **Velocidad** | El backend corre extracción + IA en paralelo cuando puede; timeout de 30s con mensaje claro |

---

#### Badge "IA" en extractos importados

En la lista del panel izquierdo de Conciliación, los extractos importados vía IA muestran un chip diferenciador:

```
  BNF CTA CTE    Abr 2026   ✨ IA   PARCIAL   8/13 conciliadas
  Ueno Ahorro    Mar 2026   ✨ IA   PENDIENTE  0/22 conciliadas
  BNF CTA CTE    Mar 2026   CSV    CONCILIADO 15/15 conciliadas
```

---

#### Arquitectura técnica

**Backend**: `POST /tes/conciliacion/importar-pdf`
- Multer para recibir el archivo PDF (máx 10 MB)
- `pdf-parse` (npm) para extraer texto plano — sin dependencias Python
- Preprocesamiento: aislar solo las líneas de transacciones del texto extraído
- `AiProviderService.completar()` con prompt estructurado:

```typescript
const systemPrompt = `Sos un extractor de datos bancarios. Recibís el texto de un extracto bancario de Paraguay y devolvés ÚNICAMENTE un JSON válido con el array de transacciones. Sin texto extra, sin markdown, solo el JSON.`;

const prompt = `Extraé las transacciones del siguiente extracto bancario.
Para cada transacción identificá: fecha (DD/MM/YYYY), comprobante (número de referencia si existe), concepto (descripción), importe (número positivo siempre), tipo ('DEBITO' si sale dinero, 'CREDITO' si entra dinero).
Ignorá totales, saldos, encabezados y texto legal.
Devolvé: { "banco": "nombre del banco", "periodo": { "desde": "DD/MM/YYYY", "hasta": "DD/MM/YYYY" }, "transacciones": [...] }

EXTRACTO:
${textoCrudo}`;
```

- Validación del JSON de respuesta (Zod schema)
- Si validación falla → retry con prompt más estricto (1 solo reintento)
- Inserción en `tes_extracto_bancario` + `tes_extracto_lineas`
- Auto-match inmediato (misma lógica que CSV)
- Respuesta incluye: `{ extractoId, totalLineas, autoMatcheadas, pendientes, banco, periodo }`

**Frontend**: `TesConciliacionTab.jsx` — ampliar modal de importación
- Estado `modo`: `idle` → `procesando` → `preview` → `confirmado`
- Drag & drop con `react-dropzone` (ya en deps del proyecto)
- Preview table con scroll si hay muchas líneas
- Campos opcionales saldo inicial/final para validación cruzada

**Fallback sin API key:**
```
[Tab "Conciliación"]
Botón "+ Nuevo extracto" → Modal → si empresa sin API key configurada →
  Icono IA con candado: "✨ Importación IA no disponible — configurá tu API key en IA Dashboard"
  Sección CSV visible de igual forma — el usuario puede seguir usando CSV
```

---

#### Items de implementación ✅ COMPLETADO (2026-04-22)

- [x] Backend: instalar `pdf-parse@1.1.1` + endpoint `POST /tes/conciliacion/importar-pdf`
- [x] Backend: extractor de texto PDF (`pdf-parse/lib/pdf-parse` vía require para evitar bug ts-node)
- [x] Backend: prompt IA estructurado + retry con prompt simplificado (sin Zod — JSON.parse + retry)
- [x] Backend: integración con flujo existente de `tes_extracto_bancario` + auto-match inmediato
- [x] Backend: IA extrae `saldo_inicial` y `saldo_final` del PDF — se usan como fallback si el usuario no los ingresa
- [x] Backend: `ia_meta` en respuesta: banco detectado, período, saldos detectados, total transacciones
- [x] Backend: manejo explícito de `NotFoundException` cuando empresa no tiene API key configurada → `BadRequestException` con mensaje claro
- [x] Backend: `AiConfigModule` + `AiProviderService` agregados a `TesoreriaModule`
- [x] Frontend: modal de importación unificado PDF + CSV con zona drag & drop adaptativa (dark mode)
- [x] Frontend: estado `procesando` con spinner, `LinearProgress` y mensaje "Analizando con IA..."
- [x] Frontend: estado `preview` con tabla de transacciones detectadas (chips auto-conciliado/pendiente)
- [x] Frontend: badge "✨ IA" en lista de extractos del panel izquierdo para PDFs
- [x] Frontend: error claro si empresa sin API key → toast con mensaje específico
- [x] Frontend: campos saldo inicial/final con helperText "Opcional — la IA lo detecta del PDF"
- [x] Frontend: "Saldo banco" muestra moneda de la cuenta seleccionada (`data.cuenta?.moneda`)
- [x] Frontend: selector "Movimiento vinculado" reemplazado por `Autocomplete` con búsqueda en tiempo real
- [x] Frontend: botón eliminar extracto con `color="error"` + fondo rojo en hover
- [x] Frontend: `ExtractoCard` y `Tabla`/`LineaRow` adaptados a dark mode

#### Pendientes Fase 3.4 / Conciliación

- [ ] **Marcar línea como "sin correspondencia"** — cerrar líneas sin movimiento vinculado (comisiones automáticas, cargos bancarios que no tienen movimiento en el sistema)
- [ ] **Crear movimiento directamente desde conciliación** — registrar movimiento para una línea sin match sin salir del tab
- [ ] **Reporte de diferencias** — líneas del extracto sin conciliar + movimientos del sistema que no aparecen en extracto (partidas en tránsito)
- [ ] **Preview editable** — editar importe/fecha de una transacción detectada por IA antes de confirmar
- [ ] **Formatos CSV por banco** — parsers específicos para Continental, Sudameris, BNF, Itaú (columnas distintas por banco)
