# Plan — Recibos Multi-Factura + Retenciones (REC-MULTI-01)

## Estado general: Fases 1–4 completadas ✅ | Fase 5 pendiente

## Actualización 2026-05-27

- ✅ **Fix saldo_pendiente fantasma**: `facturasPendientesCliente()` ya no aplica `NULLIF(..., 0)` sobre `saldo_pendiente`. Antes, una factura totalmente cobrada (saldo=0) caía al fallback `total_factura` por COALESCE y resurgía como pendiente en el wizard. Ahora: `COALESCE(cuotas.saldo_cuotas, fc.saldo_pendiente, fc.total_factura)` respeta el 0 explícito.
- ✅ **Marcar NC como consumida** (`PATCH /recibos-multi/nc/:ncId/marcar-consumida`): pone `rec_saldo_disponible = 0` sin generar recibo ni asiento. Pensado para NC migradas / aplicadas fuera del sistema. UI en *Tesorería → Revisión CxC* (botón por NC del cliente seleccionado + confirmación).
- ✅ **NC importadas desde Marangatu** (módulo `marangatu`) llegan con `rec_modo_aplicacion`:
  - `ESTRICTO` si se resolvió la factura asociada por CDC (`gCAsoc`).
  - `FLEXIBLE` si quedaron libres (sin factura match) → aplicables a cualquier factura del cliente desde el wizard multi.
  - Se considera NC venta cuando la empresa figura como emisor (`gDatGralOpe.gEmis.dRucEm === empresas.ruc`); se consultan al SET con `tipoRegistro=COMPRA` (así las publica Marangatu para el receptor-emisor) y luego se filtran por `tipoComprobante=NOTA DE CRÉDITO` (normalizado NFD para tolerar acentos).
- ✅ **Deduplicación al consultar Marangatu**: `consultarDocumentos` ahora cruza también contra `nota_credito_cab.cdc` para marcar `yaImportado` (antes solo miraba `factura_cab` / `compra_cab` y las NC siempre aparecían como nuevas).

## Consideraciones — Cheques al día vs diferidos en Recibos Multi

El medio de pago `CHEQUE` en un recibo multi se persiste en `tes_cheques` con la siguiente lógica (`recibos.service.ts` ~L705):

| Condición | Estado inicial cheque | Movimiento tesorería | Saldo cuenta |
|---|---|---|---|
| `fecha_vencimiento <= hoy` (o sin fecha) | `EN_CARTERA` | `CONFIRMADO` | Incrementa al instante |
| `fecha_vencimiento > hoy` (diferido) | `DIFERIDO` | `CONFIRMADO` | Incrementa al instante |

**Implicancias:**

1. **CxC se cierra inmediatamente en ambos casos.** El recibo imputa la factura y reduce `saldo_pendiente` apenas se confirma — el cliente queda "pagado" aunque el cheque sea posfechado. Es la convención contable usual en PY (se reconoce el pago al recibir el documento), pero hay que tenerlo presente al analizar morosidad: un cliente con cheques diferidos largos aparece sin deuda aun antes de que el banco debite.
2. **El saldo de la cuenta de tesorería sube de inmediato incluso con cheque DIFERIDO.** No es un saldo "en tránsito" — es saldo disponible. Esto puede inflar la posición de caja real. Para la posición proyectada/realista usar el reporte *Cartera de cheques* + filtrar por estado `DIFERIDO`.
3. **El cheque diferido sigue su ciclo en Tesorería → Cheques**: pasa de `DIFERIDO` → `EN_CARTERA` (al llegar la fecha) → `DEPOSITADO` → `ACREDITADO` o `RECHAZADO`. Si **rechaza**, la reversión de CxC del recibo no es automática hoy (ver pendiente en `plan-tesoreria-bancos.md` Fase 2). Workaround: anular el recibo multi desde *Cobros → Recibos Multi*, lo que revierte la imputación de facturas + saldo de tesorería + asiento; luego registrar el cheque rechazado como movimiento de gasto si aplica.
4. **Anular recibo con cheques fuera de cartera está bloqueado.** El service detecta cheques en estado `DEPOSITADO/ACREDITADO/RECHAZADO/DEBITADO` y exige reversarlos primero desde Tesorería (mensaje claro al usuario). Esto evita asientos huérfanos.
5. **Diferimiento "al día" no detectado por flag**: la decisión la toma `fecha_vencimiento > hoy`. Si el usuario omite `fecha_vencimiento`, el cheque entra como `EN_CARTERA` aunque la intención sea diferida. El wizard de recibo multi debería marcar `fecha_vencimiento` como obligatoria cuando `medio=CHEQUE` (validación pendiente — hoy es solo `fecha_emision` la obligatoria).

---

## Decisiones de diseño confirmadas

| # | Decisión |
|---|---|
| 1 | Retenciones en ambas direcciones (recibidas y emitidas) |
| 2 | NC mode configurable por empresa: ESTRICTO / FLEXIBLE (override por permiso) |
| 3 | Diferencias: saldo a favor, pago parcial, ajuste manual — todos soportados |
| 4 | Pagos parciales por cuota permitidos |
| 5 | FIFO automático con override manual (permiso COB_REC_OVERRIDE_FIFO) |
| 6 | Una retención por factura (correcto fiscalmente) |
| 7 | Intereses como línea separada en el mismo recibo |
| 8 | Comisión calculada por recibo total |
| 9 | Un recibo = un cliente |
| 10 | Reversión automática total al anular |
| 11 | Comprobante interno (sin timbrado SET) |
| 12 | Integración con módulo Tesorería existente |
| 13 | Retenciones recibidas: entrada manual + libro mensual |
| 14 | Retenciones emitidas: solo preparación DB en v1, endpoints diferidos |
| 15 | UI nueva en Finanzas > Recibos Multi (no migrar históricos) |
| 16 | 8 permisos nuevos bajo módulo COBRANZAS |

---

## Fase 1 — Base de datos ✅

**Archivo:** `prisma/migrations/20260519_recibos_multi_retenciones/migration.sql`

10 tablas nuevas:
- `rec_config_empresa` — config NC mode, ajuste máximo, formato numeración
- `rec_regimenes_retencion` — catálogo SET PY (5 regímenes seed)
- `rec_saldos_cliente` — saldos a favor generados
- `rec_saldos_cliente_mov` — movimientos de saldos
- `rec_multi` — header del recibo
- `rec_multi_facturas` — facturas imputadas
- `rec_multi_nc` — NC aplicadas
- `rec_multi_retenciones` — retenciones recibidas por factura
- `rec_multi_medios_pago` — medios de pago
- `rec_retenciones_emitidas` — preparación DB solo

ALTER `nota_credito_cab`: +`rec_modo_aplicacion`, +`rec_saldo_disponible`

**Prisma schema:** 9 modelos añadidos (líneas 6988–7182). Sin `@relation` a tablas externas (solo rec_* ↔ rec_*).

**Seed inserts embebidos en migration.sql** (idempotentes con NOT EXISTS):
- 8 privilegios en tabla `privilegios`
- 6 cuentas contables nuevas en `cont_plan_cuentas`

---

## Fase 2 — Backend NestJS ✅

### Archivos creados/modificados:

**`src/recibos/recibos.service.ts`**
- `listar()` — paginado con filtros
- `detalle()` — detalle completo con includes
- `facturasPendientesCliente()` — SQL raw con `total_factura` (campo real en factura_cab, NO `total`)
- `ncDisponiblesCliente()` — NC con saldo disponible
- `saldosFavorCliente()` — saldos a favor del cliente
- `preview()` — cálculo FIFO sin persistir
- `crear()` — transacción atómica completa
- `anular()` — reversión automática completa
- `libroRetenciones()` — libro mensual con join
- `marcarDeclarada()` — marcar declarada al SET

**`src/recibos/dto/create-recibo.dto.ts`** — DTOs completos

**`src/recibos/recibos.controller.ts`** — 9 endpoints bajo `/recibos-multi`

**`src/recibos/recibos.module.ts`** — módulo con PrismaModule + ContabilidadModule

**`src/app.module.ts`** — RecibosModule registrado

**`src/contabilidad/services/integracion.service.ts`** — método `integrarReciboMulti()` añadido

**`src/contabilidad/seeds/plan-cuentas-paraguay.seed.ts`** — 6 cuentas nuevas + 7 mapeos en MAPEO_DEFAULT

**`prisma/seed.ts`** — 8 privilegios nuevos en `privilegiosData`

### Bug corregido post-deploy:
`fc.total` → `fc.total_factura` en las 5 queries SQL raw de `recibos.service.ts`

---

## Fase 3 — Contabilidad ✅

Asiento al crear recibo:
- **DEBE:** medios de pago (por cuenta tesorería), retenciones IVA/Renta, NC puente, anticipo consumido
- **HABER:** clientes (total), intereses, anticipo generado (si saldo a favor)
- Idempotente via `cont_documentos` con `origen_tipo='recibos_multi'`
- Reversión via `revertirDocumento('recibos_multi', reciboId, usuarioId)`

---

## Fase 4 — Frontend React ✅

**Archivos creados:**

`src/api/recibos-multi.service.js` — 10 funciones API

`src/tanstack/RecibosMultiStack.js` — 10 hooks TanStack Query

`src/components/organismos/RecibosMulti/RetencionFormModal.jsx`
- Dialog para agregar retención por factura
- Campos: tipo (IVA/RENTA), monto (MonedaInput), %, nro_comprobante, timbrado, fecha

`src/components/organismos/RecibosMulti/RecibosMultiPanel.jsx`
- Panel principal: tabla con filtros de fecha, búsqueda, paginación
- Dialog detalle inline (facturas, medios de pago, NC, retenciones)
- Dialog anulación con motivo

`src/components/organismos/RecibosMulti/NuevoReciboMultiWizard.jsx`
- Wizard 4 pasos: Cliente+Facturas → NC+Retenciones → Medios de pago → Confirmación
- Paso 1: Autocomplete de clientes (campo real: `personas.razon_social`), tabla facturas con importe parcial
- Paso 2: NC disponibles (modo flexible), retenciones por factura
- Paso 3: medios de pago con cálculo de diferencia en tiempo real
- Paso 4: preview FIFO antes de confirmar

`src/components/organismos/RecibosMulti/LibroRetencionesPanel.jsx`
- Selector de período (últimos 24 meses)
- Resumen totales IVA/Renta
- Tabla con marcar declarada + export XLSX

`src/pages/Tesoreria.jsx`
- 2 tabs nuevos: "Recibos Multi" (`COBRANZAS/COB_REC_VER`) y "Libro Retenciones" (`COBRANZAS/COB_REC_LIBRO_RETENCIONES`)

### Bugs corregidos:
- `MonedaInput` usa export nombrado (no default) → `import { MonedaInput }`
- `bgcolor: "grey.50"` en table headers → `bgcolor: "action.hover"` (compatible tema oscuro)
- `getOptionLabel` usaba `o.razon_social` → corregido a `o.personas?.razon_social` (estructura real del endpoint)

---

## Fase 5 — Pendiente

- [ ] **Retenciones emitidas:** endpoints completos (controller + service + DTO). Las tablas ya existen en DB.
- [ ] **Config por empresa:** UI para cambiar modo NC (ESTRICTO/FLEXIBLE) desde panel de configuración
- [ ] **QA end-to-end:** recorrido completo con empresa real (crear recibo → verificar asiento contable → anular → verificar reversión)
- [x] **Export PDF:** comprobante interno del recibo multi (sin timbrado) — `GET /recibos-multi/:id/pdf?tipo=view|base64`
- [ ] **Validar `fecha_vencimiento` obligatoria** al elegir medio=CHEQUE en el wizard (hoy solo `fecha_emision` es required en DTO).
- [ ] **Reversa automática de CxC al rechazar cheque de tercero** (ver `plan-tesoreria-bancos.md` Fase 2 — actualmente manual).

---

## Archivos clave de referencia

```
Backend:
  src/recibos/recibos.service.ts
  src/recibos/recibos.controller.ts
  src/recibos/dto/create-recibo.dto.ts
  src/contabilidad/services/integracion.service.ts
  prisma/migrations/20260519_recibos_multi_retenciones/migration.sql

Frontend:
  src/components/organismos/RecibosMulti/
  src/tanstack/RecibosMultiStack.js
  src/api/recibos-multi.service.js
  src/pages/Tesoreria.jsx

Docs:
  /var/www/html/proyectos/smartfactvoice-backend/docs/plan-recibos-multifactura-retenciones.md
```
