# Plan — Conciliación Bancaria con IA (módulo independiente)

> Estructura basada en `plan-conciliacion-contable.md` (patrón de registry, diagnóstico, fases, permisos, plan de pruebas). Contenido funcional basado en la Fase 3.3/3.4 de `plan-tesoreria-bancos.md` (motor de conciliación y parser IA ya construidos), generalizados para funcionar como módulo standalone.
>
> **Nota sobre el archivo original subido** (`ranking-alternativas-vapi.md`): no tenía relación con este módulo — era una comparativa de plataformas de voz IA. Se descartó y se usó en su lugar `plan-tesoreria-bancos.md` (encontrado en el proyecto) y `plan-conciliacion-contable.md` (subido después) como base real.

## Descripción funcional

Hoy, la conciliación bancaria (Fase 3.3/3.4 de Tesorería) compara los movimientos que **ya están cargados en `tes_movimientos`** contra un extracto bancario subido (PDF/CSV/Excel, interpretado por IA). Requiere que la empresa use el módulo Tesorería completo.

Este plan adapta esa misma capacidad a un **módulo independiente** donde ningún lado depende de datos ya cargados en el sistema:

1. **Archivo A — "Mis movimientos"**: la empresa sube un archivo con sus propios registros bancarios, en **cualquier formato** (Word, Excel, TXT, CSV, PDF). Puede ser un export de otro sistema, una planilla armada a mano, o un libro banco.
2. **Archivo B — "Extracto del banco"**: se sube el extracto oficial, también en cualquier formato.
3. La IA **interpreta el contenido** de ambos (no depende de que tengan columnas prolijas), normaliza cada uno a una lista de movimientos, y el motor de conciliación los cruza automáticamente.
4. Se presenta un **documento de resultado** (PDF ejecutivo + Excel detallado) con conciliadas, pendientes de cada lado y diferencias.

### Flujo canónico

```
1) INTERPRETACIÓN IA              2) CRUCE AUTOMÁTICO            3) RESULTADO
   Archivo A (mis registros)         Match por monto + tipo         Documento final:
   Archivo B (extracto banco)        + fecha ±N días entre            - Conciliadas
   → texto/tabla cruda según           A y B                          - Pendientes lado A
     tipo de archivo                 Líneas de baja confianza         - Pendientes lado B
   → mapeo directo si hay              o sin match → quedan            - Diferencias de importe
     columnas reconocibles             para revisión manual            PDF + Excel
   → si no, prompt IA → JSON
     normalizado
```

### Objetivos

- Conciliar bancos **sin depender** de que la empresa opere con el módulo Tesorería completo — sirve para empresas que llevan sus movimientos en Excel/Word propio, contadores externos, auditorías puntuales, o como paso previo a migrar a Tesorería.
- Aceptar **cualquier formato de entrada en ambos lados** (Word, Excel, TXT, CSV, PDF) — la IA decide cómo interpretarlo, igual que ya hace hoy solo con el lado banco en PDF.
- **No duplicar lógica**: reutilizar el motor de auto-match y el parser IA ya construidos en Tesorería (Fase 3.3/3.4), extrayéndolos a servicios compartidos.
- Producir siempre un **documento de resultado descargable** (PDF + Excel), autocontenido, apto para entregar a un tercero (gerencia, auditor, contador externo).

### No objetivos (fuera de alcance)

- No reemplaza la conciliación integrada de Tesorería (que sigue leyendo `tes_movimientos` automáticamente) — convive como flujo alternativo.
- No genera asientos contables ni movimientos de tesorería — es un módulo de comparación y reporte, de solo lectura respecto al resto del sistema.
- No corrige los archivos originales del usuario — solo los interpreta y muestra un preview editable antes de confirmar.
- No garantiza 100% de precisión en archivos muy narrativos (ej. un Word con texto libre sin estructura tabular) — esas líneas quedan marcadas para revisión manual obligatoria, nunca se auto-concilian a ciegas.

---

## Decisiones de diseño (propuestas — a confirmar con Marcelo)

| # | Tema | Decisión propuesta |
|---|------|----------|
| 1 | Relación con Tesorería | Módulo independiente. Comparte motor (auto-match + parser IA) con `TesConciliacionService`, pero no depende de `tes_cuentas` ni `tes_movimientos`. |
| 2 | Identificación de cuenta | Campo de texto libre (nombre de cuenta/banco), no un FK obligatorio — para que funcione aunque la empresa no tenga Tesorería configurada. |
| 3 | Alcance por sesión | Una cuenta bancaria por sesión (un par de archivos = un período/cuenta). Multi-cuenta detectada dentro de un mismo archivo queda para una fase posterior. |
| 4 | Parser universal | Se extrae el parser IA de PDF ya construido (`pdf-parse` + `AiProviderService`) a un servicio único `ArchivoMovimientosParserService`, que suma DOCX (mammoth), XLSX/CSV (mapeo directo si hay columnas reconocibles, IA si no) y TXT (heurística tabular, IA si falla). |
| 5 | Confianza IA | Cada línea interpretada por IA lleva un score de confianza; las de baja confianza se destacan en el preview y requieren revisión antes de conciliar. |
| 6 | Auto-match | Mismo algoritmo ya construido: monto + tipo compatible (débito↔egreso, crédito↔ingreso) + fecha ±2 días configurable. Se suma tolerancia de importe configurable (± %) para comisiones incluidas. |
| 7 | Estados de sesión | `CREADA → ARCHIVOS_CARGADOS → INTERPRETADA → CONCILIANDO → FINALIZADA`. Editable hasta `FINALIZADA`. |
| 8 | Documento de resultado | PDF ejecutivo + Excel detallado, mismo motor msv-kude que el resto del sistema. |
| 9 | Persistencia | Se guarda la sesión completa (líneas interpretadas + matches) para poder reabrir/reexportar sin volver a subir archivos. |
| 10 | Permisos | Módulo propio `CONCILIACION_BANCARIA_IA`, privilegios independientes de `TESORERIA`. |
| 11 | Multiempresa | Cada sesión pertenece a una `empresa_id`, igual que el resto del sistema. |
| 12 | Reutilización | El auto-match y el prompt IA se extraen a servicios compartidos, consumidos tanto por Tesorería (Fase 3.3/3.4) como por este módulo nuevo — cero lógica duplicada. |

---

## Modelo de datos

### Tablas nuevas

```prisma
model conc_ia_sesiones {
  id                    String   @id @default(dbgenerated("uuid_generate_v4()")) @db.Uuid
  empresa_id            String   @db.Uuid
  nombre_cuenta         String   @db.VarChar(120)  // texto libre, ej. "BNF CTA CTE Principal"
  banco                 String?  @db.VarChar(80)
  moneda                String   @db.VarChar(3) @default("PYG")
  periodo_desde         DateTime
  periodo_hasta         DateTime
  saldo_inicial_propio  Decimal? @db.Decimal(18,2)
  saldo_final_propio    Decimal? @db.Decimal(18,2)
  saldo_inicial_banco   Decimal? @db.Decimal(18,2)
  saldo_final_banco     Decimal? @db.Decimal(18,2)
  estado                String   @db.VarChar(20)  // CREADA, ARCHIVOS_CARGADOS, INTERPRETADA, CONCILIANDO, FINALIZADA
  archivo_propio_nombre String?  @db.VarChar(200)
  archivo_banco_nombre  String?  @db.VarChar(200)
  usuario_id            String   @db.Uuid
  created_at            DateTime @default(now())
  updated_at            DateTime @default(now())
}

model conc_ia_movimientos {
  id           String   @id @default(dbgenerated("uuid_generate_v4()")) @db.Uuid
  sesion_id    String   @db.Uuid
  origen       String   @db.VarChar(10)   // PROPIO | BANCO
  fecha        DateTime
  concepto     String   @db.VarChar(300)
  tipo         String   @db.VarChar(10)   // DEBITO | CREDITO
  importe      Decimal  @db.Decimal(18,2)
  referencia   String?  @db.VarChar(100)
  confianza_ia Decimal? @db.Decimal(4,2)  // 0.00–1.00, null si vino de mapeo directo (sin IA)
  estado       String   @db.VarChar(20)   // PENDIENTE | CONCILIADO | SIN_CORRESPONDENCIA
  created_at   DateTime @default(now())
}

model conc_ia_matches {
  id                    String   @id @default(dbgenerated("uuid_generate_v4()")) @db.Uuid
  sesion_id             String   @db.Uuid
  movimiento_propio_id  String   @db.Uuid
  movimiento_banco_id   String   @db.Uuid
  tipo_match            String   @db.VarChar(10)  // AUTO | MANUAL
  diferencia_importe    Decimal  @default(0) @db.Decimal(18,2)
  usuario_id            String?  @db.Uuid
  created_at            DateTime @default(now())
}
```

No hay tabla de "resultado" persistida aparte: el resumen para pantalla/PDF/Excel se calcula en vivo a partir de `conc_ia_movimientos` + `conc_ia_matches`, igual que el criterio ya usado en `plan-conciliacion-contable.md` ("sin tabla de pendientes", cero desincronización).

---

## Endpoints (backend)

Base: `/conciliacion-bancaria-ia`, módulo propio `CONCILIACION_BANCARIA_IA`.

| Método | Path | Privilegio | Descripción |
|--------|------|-----------|-------------|
| POST | `/sesiones` | `CONC_IA_CREAR` | Crear sesión (cuenta, banco, moneda, período). |
| GET | `/sesiones` | `CONC_IA_VER` | Historial de sesiones. |
| POST | `/sesiones/:id/archivo-propio` | `CONC_IA_CARGAR` | Subir + interpretar Archivo A (cualquier formato). |
| POST | `/sesiones/:id/archivo-banco` | `CONC_IA_CARGAR` | Subir + interpretar Archivo B. |
| PATCH | `/sesiones/:id/movimiento/:movId` | `CONC_IA_CARGAR` | Corregir una línea interpretada antes de conciliar. |
| POST | `/sesiones/:id/conciliar-auto` | `CONC_IA_CONCILIAR` | Ejecuta el auto-match. |
| POST | `/sesiones/:id/match-manual` | `CONC_IA_CONCILIAR` | Conciliar un par específico a mano. |
| DELETE | `/sesiones/:id/match/:matchId` | `CONC_IA_CONCILIAR` | Desconciliar. |
| PATCH | `/sesiones/:id/movimiento/:movId/sin-correspondencia` | `CONC_IA_CONCILIAR` | Cerrar línea sin match (comisión no registrada, etc.). |
| GET | `/sesiones/:id/resultado` | `CONC_IA_VER` | Resumen + detalle para pantalla. |
| GET | `/sesiones/:id/resultado/pdf` | `CONC_IA_VER` | Documento PDF ejecutivo. |
| GET | `/sesiones/:id/resultado/excel` | `CONC_IA_VER` | Excel detallado. |
| DELETE | `/sesiones/:id` | `CONC_IA_ELIMINAR` | Eliminar sesión. |

---

## Arquitectura del servicio

```
ArchivoMovimientosParserService (NUEVO — compartido con Tesorería)
├── interpretar(buffer, mimeType, contexto) → MovimientoNormalizado[]
│    1. Detecta tipo por mimeType/extensión
│    2. PDF        → pdf-parse (ya existe en Tesorería, se reutiliza tal cual)
│    3. DOCX        → mammoth → texto plano → mismo pipeline que PDF
│    4. XLSX / CSV  → xlsx / papaparse: si hay columnas fecha/monto/concepto
│                     reconocibles → mapeo directo (sin IA, rápido y determinístico)
│                     si no → concatena celdas como texto y cae a IA
│    5. TXT         → heurística de columnas por separadores; si falla, cae a IA
│    6. Fallback IA → AiProviderService.completar() con el mismo prompt
│                     estructurado ya usado en Tesorería (banco, período,
│                     transacciones[]), agregando "confianza" por línea
│    7. Devuelve [{fecha, concepto, tipo, importe, referencia, confianza}]

ConciliacionMatchEngine (EXTRAÍDO de TesConciliacionService — compartido)
├── autoMatch(movimientosPropios[], movimientosBanco[], opts)
│     monto (± tolerancia) + tipo compatible + fecha ±N días
└── usado por TesConciliacionService (Fase 3.3/3.4) y por este módulo nuevo

ConciliacionBancariaIaService (NUEVO)
├── crearSesion(empresaId, dto)
├── cargarArchivo(sesionId, origen: 'PROPIO'|'BANCO', file)
│     → ArchivoMovimientosParserService.interpretar()
│     → guarda en conc_ia_movimientos
├── autoConciliar(sesionId)
│     → ConciliacionMatchEngine.autoMatch()
├── matchManual(sesionId, movPropioId, movBancoId)
├── desconciliar(matchId)
├── marcarSinCorrespondencia(movId)
└── obtenerResultado(sesionId) → { resumen, conciliadas[], pendientesPropio[], pendientesBanco[] }
```

**Punto clave de arquitectura**: extraer `ArchivoMovimientosParserService` y `ConciliacionMatchEngine` del código actual de `TesConciliacionService` (Fase 3.3/3.4) es la única forma de evitar mantener dos implementaciones del mismo prompt IA y del mismo algoritmo de matching. Este refactor es prerequisito de la Fase 2 de este plan.

---

## UI (frontend)

Ruta: `/conciliacion-bancaria-ia` — módulo propio en el menú lateral, fuera de Tesorería y Bancos.

```
┌───────────────────────────────────────────────────────────────────┐
│  Conciliación Bancaria (IA)                    [+ Nueva sesión]    │
├───────────────────────────────────────────────────────────────────┤
│  Historial de sesiones                                              │
│  BNF CTA CTE   Abr 2026   FINALIZADA    93% conciliado   [Ver][PDF]│
│  Ueno Ahorro   Mar 2026   INTERPRETADA  pendiente conciliar  [Ver] │
└───────────────────────────────────────────────────────────────────┘

Nueva sesión → wizard de 3 pasos:

Paso 1 — Datos de la sesión
  Nombre cuenta: [____]   Banco: [____]   Moneda: [PYG ▼]   Período: [Desde][Hasta]

Paso 2 — Subir ambos archivos
  ┌──────────────────────────────┐   ┌──────────────────────────────┐
  │ 📄 Mis movimientos            │   │ 🏦 Extracto del banco          │
  │ (Word, Excel, TXT, CSV, PDF)  │   │ (PDF, CSV, Excel)              │
  │ [Arrastrar o seleccionar]     │   │ [Arrastrar o seleccionar]      │
  └──────────────────────────────┘   └──────────────────────────────┘
  ✨ Ambos se interpretan automáticamente con IA si no tienen
     columnas reconocibles — igual que ya pasa hoy con los PDF
     de extracto bancario en Tesorería.

  → tras subir cada uno: preview editable de las líneas detectadas,
    con aviso ⚠ en las de baja confianza IA

Paso 3 — Conciliar y ver resultado
  [Conciliar automáticamente]
  ✅ 42 conciliadas · ⚠ 5 pendientes (mis registros) · ⚠ 3 pendientes (banco)

  Pestañas: Conciliadas | Pendientes (mis registros) | Pendientes (banco)
  Cada pendiente: [Conciliar manualmente]  [Marcar sin correspondencia]

  [Descargar PDF]   [Descargar Excel]   [Finalizar sesión]
```

Principios UX (mismos ya validados en Fase 3.4 de Tesorería): mínima fricción (subir → preview → conciliar), feedback inmediato (spinner con mensaje contextual durante el procesamiento IA), transparencia IA (preview siempre editable antes de confirmar), fallback claro (si no hay API key de IA configurada, igual funciona con CSV/Excel de columnas reconocibles).

---

## Módulo y seguridad

Nuevo submódulo `CONCILIACION_BANCARIA_IA`:

```typescript
{
  codigo: 'CONCILIACION_BANCARIA_IA',
  descripcion: 'Conciliación Bancaria con IA',
  icono: 'mdi:file-compare',
  privilegios: [
    { codigo: 'CONC_IA_VER',        desc: 'Ver sesiones y resultados',              recurso: 'CONC_IA', accion: 'VER' },
    { codigo: 'CONC_IA_CREAR',      desc: 'Crear sesión de conciliación',           recurso: 'CONC_IA', accion: 'CREAR' },
    { codigo: 'CONC_IA_CARGAR',     desc: 'Subir y corregir archivos interpretados',recurso: 'CONC_IA', accion: 'CARGAR' },
    { codigo: 'CONC_IA_CONCILIAR',  desc: 'Conciliar/desconciliar movimientos',     recurso: 'CONC_IA', accion: 'PROCESAR' },
    { codigo: 'CONC_IA_ELIMINAR',   desc: 'Eliminar sesión',                        recurso: 'CONC_IA', accion: 'ELIMINAR' },
  ],
}
```

### Roles típicos

| Rol | Ver | Crear/Cargar | Conciliar | Eliminar |
|---|---|---|---|---|
| Contador | ✓ | ✓ | ✓ | ✓ |
| Tesorero | ✓ | ✓ | ✓ | — |
| Gerente / Admin | ✓ | — | — | ✓ |
| Operativo | — | — | — | — |

---

## Catálogo de motivos de línea pendiente

| Código | Descripción | Resolución |
|--------|-------------|------------|
| `SIN_MATCH_MONTO` | No hay ninguna línea del otro lado con importe compatible | Revisar si falta cargar el movimiento, o si el importe difiere por comisión |
| `SIN_MATCH_FECHA` | Hay candidato por monto pero fuera del rango de fecha configurado | Ampliar tolerancia de fecha o conciliar manualmente |
| `BAJA_CONFIANZA_IA` | La IA interpretó la línea con score bajo (archivo narrativo o de mala calidad) | Corregir manualmente el dato en el preview antes de conciliar |
| `POSIBLE_DUPLICADO` | Dos líneas del mismo lado con fecha/monto idénticos | Confirmar si son movimientos distintos o error de carga |
| `SIN_CORRESPONDENCIA` | Marcado manualmente como cerrado sin match (ej. comisión bancaria no registrada en los propios) | Queda documentado en el reporte final, no bloquea el cierre de la sesión |

---

## Plan por fases

### Fase 1 — Base: sesiones + upload dual sin IA
- Tablas `conc_ia_sesiones`, `conc_ia_movimientos`, `conc_ia_matches`.
- CRUD de sesión, endpoints básicos.
- Parseo directo únicamente (XLSX/CSV con columnas reconocibles) — sin IA todavía.
- UI: wizard pasos 1-2 (sin preview IA, solo tabla mapeada directo).
- **Entregable**: se puede crear una sesión, subir dos Excel/CSV bien formados y ver las líneas cargadas.

### Fase 2 — Integración IA (parser universal)
- Extraer `ArchivoMovimientosParserService` desde el parser de PDF ya construido en Tesorería (Fase 3.4).
- Sumar DOCX (mammoth), TXT (heurística + fallback IA), XLSX/CSV no estructurado (fallback IA).
- Score de confianza por línea + preview editable con aviso visual en baja confianza.
- **Entregable**: se puede subir Word/TXT/PDF libres y la IA los interpreta igual que hoy hace con extractos PDF.

### Fase 3 — Motor de conciliación compartido
- Extraer `ConciliacionMatchEngine` desde `TesConciliacionService`.
- Ambos módulos (Tesorería y este nuevo) consumen el mismo motor — sin duplicar el algoritmo de auto-match.
- Endpoints de conciliar-auto, match-manual, desconciliar, marcar sin correspondencia.
- **Entregable**: el auto-match funciona igual de bien que en Tesorería, sin reescribir lógica.

### Fase 4 — Documento de resultado
- PDF ejecutivo vía msv-kude (mismo estilo visual que Tesorería/Contabilidad): resumen + tabla de conciliadas/pendientes/diferencias.
- Excel con hojas separadas: Conciliadas, Pendientes (propio), Pendientes (banco), Resumen.
- UI: pantalla de resultados con pestañas + botones de descarga.
- **Entregable**: al finalizar una sesión, se descarga un documento completo listo para entregar.

### Fase 5 — Pulido
- Historial de sesiones, reabrir sesión finalizada, reexportar sin volver a subir archivos.
- Multi-cuenta detectada dentro de un mismo archivo (fase avanzada, opcional).
- Permisos finos, auditoría de cada acción (`AuditService`, mismo patrón que `plan-conciliacion-contable.md`).

---

## Plan de pruebas

### Unit (backend, Jest)
- `ArchivoMovimientosParserService.interpretar` por cada tipo de archivo (PDF, DOCX, XLSX estructurado, XLSX no estructurado, TXT, CSV) con fixtures reales.
- `ConciliacionMatchEngine.autoMatch` — casos: match exacto, match con tolerancia de importe, sin match por fecha, duplicados.
- Idempotencia: re-conciliar no duplica matches.

### E2E (backend, Supertest)
- Flujo completo: crear sesión → subir ambos archivos → auto-conciliar → generar PDF/Excel.
- Archivo con baja confianza IA → línea marcada correctamente, no se auto-concilia sin revisión.
- Archivo sin API key de IA configurada → fallback a CSV/Excel estructurado sigue funcionando.

### Manual (contador de referencia)
- Probar con extractos reales de bancos paraguayos (Continental, Ueno, BNF, Sudameris) y con un Word/Excel armado a mano por el propio usuario.
- Validar que el documento de resultado final es entendible sin necesitar explicación adicional.

---

## Riesgos y mitigaciones

| Riesgo | Mitigación |
|--------|-----------|
| Costo/latencia de IA en archivos grandes (100+ líneas) | Procesar en chunks, en paralelo cuando el proveedor lo permite; timeout con mensaje claro |
| Precisión baja en Word muy narrativo (texto libre sin estructura) | Score de confianza visible + revisión manual obligatoria antes de conciliar esas líneas |
| Sin `tes_cuentas` de referencia (módulo standalone) → no valida saldo contra nada del sistema | Los saldos inicial/final son solo informativos; se documenta explícitamente en la UI |
| Duplicar lógica entre Tesorería y este módulo si no se extraen los servicios compartidos | Fase 2 y 3 son requisito explícito antes de construir features nuevas — no se permite copiar/pegar el parser o el matcher |
| Archivos con datos sensibles (movimientos bancarios) subidos sin control de acceso | Permisos dedicados (`CONC_IA_*`) + los archivos originales y sus interpretaciones quedan atados a `empresa_id` |

---

## Métricas de éxito

- % de líneas auto-conciliadas sin intervención manual (meta inicial: > 70% en extractos de bancos ya soportados, > 40% en archivos narrativos/Word).
- Tiempo total del flujo (subir ambos archivos → resultado descargable) < 3 minutos para sesiones de hasta 100 líneas por lado.
- Cero duplicación de código entre el motor de este módulo y el de Tesorería (verificable: ambos importan del mismo paquete compartido).

---

## Documentos relacionados

- `plan-tesoreria-bancos.md` (Fase 3.3/3.4) — motor de conciliación y parser IA original, base técnica de este plan.
- `plan-conciliacion-contable.md` — patrón de arquitectura (decisiones numeradas, registry/servicios, catálogo de motivos, fases con checklist, plan de pruebas, riesgos) usado como plantilla estructural.
