# Plan: Acreedores Varios y Proveedores del Exterior

**Fecha**: Julio 2026
**Estado**: Definición completada — pendiente implementación
**Módulos afectados**: Compras & Gastos, Contabilidad, Tesorería (indirecto), Importaciones (alineación)
**Doc relacionados**: `plan-compras-gastos.md`, `plan-contabilidad.md`, `plan-importaciones.md`

---

## Problema

Hoy los acreedores varios (alquileres, servicios profesionales, entes públicos, financieras, etc.) se cargan como proveedores comunes, y los proveedores del exterior no se diferencian de los locales. Ambos casos deben imputar a **cuentas contables distintas** de `2.1.1.01 Proveedores`:

- Acreedores varios → cuenta pasivo tipo `2.1.1.03 Acreedores Varios`.
- Proveedores del exterior → cuenta pasivo tipo `2.1.1.02 Proveedores del Exterior`.

## Decisiones de diseño (cerradas con Marcelo, 06/07/2026)

| # | Decisión | Resolución |
|---|---|---|
| 1 | Modelado | **Campo `tipo_entidad` en `proveedores`** (`PROVEEDOR_LOCAL` \| `PROVEEDOR_EXTERIOR` \| `ACREEDOR_VARIO`). Sin tabla nueva. Coherente con `es_extranjero` del plan de importaciones. |
| 2 | Cuentas contables | **Conceptos nuevos en `cont_mapeo_cuentas`** (`ACREEDORES_VARIOS`, `PROVEEDORES_EXTERIOR`) como default por empresa, **+ override opcional por tercero** (`proveedores.cuenta_contable_id`). |
| 3 | Datos existentes | **Reclasificación asistida**: migración marca todo como `PROVEEDOR_LOCAL`; UI permite reclasificar. Saldos CxP abiertos y asientos históricos no se tocan; solo documentos nuevos usan la cuenta nueva. |
| 4 | Fiscal exterior | **Solo diferenciación contable** en esta fase. Retención INR a no residentes queda para fase posterior (diseñar campos sin implementar cálculo). |
| 5 | Flujo operativo | Acreedores varios operan por el flujo existente de **Gastos → CxP → OP** (sin OC/recepción/matching). Proveedores del exterior operan por Compras o Importaciones según el caso. |
| 6 | Compatibilidad | `es_extranjero` (importaciones) se mantiene y se **deriva** de `tipo_entidad`: trigger/servicio lo sincroniza (`tipo_entidad='PROVEEDOR_EXTERIOR'` ⇔ `es_extranjero=true`). Sin breaking changes en contratos. |

---

## Modelo de datos

### Extensión a `proveedores` (migración idempotente)

```sql
ALTER TABLE proveedores
  ADD COLUMN IF NOT EXISTS tipo_entidad VARCHAR(30) NOT NULL DEFAULT 'PROVEEDOR_LOCAL',
  -- PROVEEDOR_LOCAL | PROVEEDOR_EXTERIOR | ACREEDOR_VARIO
  ADD COLUMN IF NOT EXISTS cuenta_contable_id UUID REFERENCES cont_plan_cuentas(id),
  -- override opcional; NULL = usar cont_mapeo_cuentas
  ADD COLUMN IF NOT EXISTS pais VARCHAR(3),               -- ya previsto por importaciones
  ADD COLUMN IF NOT EXISTS swift VARCHAR(20),             -- idem
  ADD COLUMN IF NOT EXISTS banco_corresponsal VARCHAR(200),-- idem
  ADD COLUMN IF NOT EXISTS es_extranjero BOOLEAN DEFAULT false; -- idem, se mantiene sincronizado

CREATE INDEX IF NOT EXISTS idx_proveedores_tipo_entidad
  ON proveedores(empresa_id, tipo_entidad);
```

Backfill de coherencia (idempotente):

```sql
UPDATE proveedores SET tipo_entidad = 'PROVEEDOR_EXTERIOR'
WHERE es_extranjero = true AND tipo_entidad = 'PROVEEDOR_LOCAL';
```

### Conceptos nuevos en `cont_mapeo_cuentas` (seed)

```
PROVEEDORES            → 2.1.1.01  (existente, sin cambios)
PROVEEDORES_EXTERIOR   → 2.1.1.02  (nuevo — agregar cuenta al seed Paraguay si no existe)
ACREEDORES_VARIOS      → 2.1.1.03  (nuevo — idem)
```

- Agregar las 2 cuentas al seed `plan-cuentas-paraguay.seed.ts` (`is_sistema=true`, nivel hoja, `acepta_movimientos=true`, naturaleza ACREEDORA) y los 2 conceptos a `MAPEO_DEFAULT`.
- Seed idempotente (`ON CONFLICT DO NOTHING` / verificación por código de cuenta).
- El contador puede reasignar desde UI `Contabilidad → Mapeo de Cuentas` sin tocar código (mecanismo existente).

### Resolución de cuenta pasivo del tercero (regla central)

```
resolverCuentaPasivo(proveedor, empresaId):
  1. proveedor.cuenta_contable_id            → si existe y acepta_movimientos, usarla
  2. cont_mapeo_cuentas[concepto según tipo_entidad]:
       ACREEDOR_VARIO      → ACREEDORES_VARIOS
       PROVEEDOR_EXTERIOR  → PROVEEDORES_EXTERIOR
       PROVEEDOR_LOCAL     → PROVEEDORES
  3. fallback: PROVEEDORES (comportamiento actual, garantiza no-regresión)
```

Esta función vive en `ContabilidadIntegracionService` (o helper compartido) y es el **único** punto donde se decide la cuenta. Compras, gastos, OP, NC/ND de compra y reversiones la consumen.

---

## Reglas de negocio

### Validaciones por tipo de entidad

| Regla | PROVEEDOR_LOCAL | PROVEEDOR_EXTERIOR | ACREEDOR_VARIO |
|---|---|---|---|
| RUC válido PY | Obligatorio | **No exigir** (usar tax ID libre / documento del país) | Obligatorio (u opción CI) |
| Timbrado en documento de compra/gasto | Según reglas actuales | **No exigir** (invoice exterior sin timbrado) | Según reglas actuales |
| IVA crédito fiscal | Según reglas actuales | **No genera IVA crédito local** (invoice exterior) | Según reglas actuales |
| Moneda de CxP | Cualquiera | Típicamente USD/otra; multimoneda existente aplica | Típicamente PYG |
| País/SWIFT/banco corresponsal | Opcional | Recomendado (warning en UI, no bloqueo) | N/A |
| Puede usarse en OC/recepción/matching | Sí | Sí | **No** (solo gastos) |
| Puede usarse en Importaciones | No | Sí | No |

### Asientos afectados (cambia solo la cuenta pasivo, no la estructura)

| Operación | Hoy (HABER/DEBE pasivo) | Con este plan |
|---|---|---|
| Factura compra crédito | HABER `PROVEEDORES` | HABER `resolverCuentaPasivo(tercero)` |
| Gasto crédito | HABER `PROVEEDORES` | idem |
| OP / pago proveedor | DEBE `PROVEEDORES` | DEBE `resolverCuentaPasivo(tercero)` |
| NC de compra / reversiones | espejo sobre `PROVEEDORES` | espejo sobre la cuenta resuelta |

**Regla de consistencia crítica**: la OP debe debitar la **misma cuenta** que acreditó el documento origen. Para garantizarlo, persistir `cuenta_pasivo_id` en `cuentas_pagar` al generar la CxP y usarla en la OP (no re-resolver, porque el tercero pudo reclasificarse entre medio).

```sql
ALTER TABLE cuentas_pagar
  ADD COLUMN IF NOT EXISTS cuenta_pasivo_id UUID REFERENCES cont_plan_cuentas(id);
-- NULL = legacy → comportamiento actual (PROVEEDORES)
```

- Reversiones/anulaciones ya usan asiento espejo del original → heredan la cuenta correcta sin cambios.
- Multimoneda: sin cambios, aplica mecanismo existente (`cont_tipo_cambio`, monto original + PYG).
- Integración contable sigue siendo **no bloqueante** (BORRADOR + reintento) y opcional por empresa (`tieneModuloContabilidad()`).

### Reclasificación asistida

- Endpoint `PATCH /proveedores/:id/tipo-entidad` con permiso dedicado.
- Reglas:
  - Reclasificar **no** modifica CxP abiertas ni asientos existentes (mantienen `cuenta_pasivo_id` congelada).
  - Warning en UI si el tercero tiene CxP abiertas: "los saldos existentes permanecen en la cuenta original; solo documentos nuevos usan la cuenta nueva".
  - No permitir `ACREEDOR_VARIO` si el tercero tiene OC o embarques de importación activos.
  - Auditoría automática vía `AuditInterceptor` (sin trabajo extra).
- Reporte de apoyo: listado de terceros con tipo, cuenta efectiva y saldo CxP abierto, para que el contador decida reclasificaciones (y si quiere hacer asiento manual de reclasificación de saldos, lo hace con el módulo de asientos manuales existente — fuera de alcance automatizarlo).

### Preparación fiscal exterior (sin implementar cálculo)

- Dejar en `proveedores`: `pais`, `swift`, `banco_corresponsal` (ya previstos).
- Documentar hook futuro en OP: punto de extensión para retención INR a no residentes (fase posterior, validar alícuotas con contador).

---

## Cambios por capa

### Backend (`smartfactvoice-backend/`)

1. **Migración** `prisma/migrations/` idempotente: columnas en `proveedores` y `cuentas_pagar`, índice, backfill. Luego `npx prisma generate`.
2. **Seed**: 2 cuentas nuevas en `plan-cuentas-paraguay.seed.ts` + 2 conceptos en `MAPEO_DEFAULT` + permiso nuevo en `seed.service.ts` (idempotente):
   - `COMPRAS_RECLASIFICAR_TERCERO` (o dentro de `COMPRAS + EDITAR` si se prefiere no crear permiso; decidir en implementación — default: permiso nuevo).
3. **DTOs proveedores**: `tipo_entidad`, `cuenta_contable_id`, `pais`, `swift`, `banco_corresponsal` en create/update (class-validator: enum, UUID opcional).
4. **Servicio proveedores**:
   - sincronía `tipo_entidad` ⇔ `es_extranjero`;
   - validación de `cuenta_contable_id` (existe, empresa, `acepta_movimientos=true`, naturaleza acreedora);
   - `GET /compras/proveedores/search` acepta filtro `tipo_entidad` (sin breaking: opcional).
5. **ContabilidadIntegracionService**: implementar `resolverCuentaPasivo()` y usarla en integración de compras, gastos, OP y reversiones. Persistir `cuenta_pasivo_id` en CxP al crearla.
6. **Validaciones fiscales condicionales** en compras/gastos: relajar RUC/timbrado/IVA para `PROVEEDOR_EXTERIOR` según tabla de reglas.
7. **Bloqueo operativo**: `ACREEDOR_VARIO` rechazado en OC, recepciones, requisiciones e importaciones con mensaje funcional claro.
8. **Endpoint reclasificación** `PATCH /proveedores/:id/tipo-entidad` + reporte `GET /pagos-proveedor/terceros-clasificacion` (tipo, cuenta efectiva, saldo abierto).

### Frontend (`pos-ventas/`)

1. Formulario de proveedor: selector `Tipo de entidad`, campos exterior (país, SWIFT, banco corresponsal) visibles solo si `PROVEEDOR_EXTERIOR`, selector de cuenta contable override (autocomplete de cuentas hoja pasivo).
2. Listado de proveedores: columna/chip de tipo + filtro.
3. Selector de proveedor en Gastos: incluye acreedores varios; en OC/Compras con OC: excluye `ACREEDOR_VARIO`.
4. Pantalla/acción de reclasificación con warning de saldos abiertos.
5. Mapeo de Cuentas (Contabilidad): los 2 conceptos nuevos aparecen automáticamente (mecanismo existente).

### Contratos y compatibilidad

- Sin breaking changes: campos nuevos opcionales en requests, siempre presentes en responses.
- `es_extranjero` se mantiene para importaciones (derivado).
- CxP legacy con `cuenta_pasivo_id=NULL` → comportamiento actual.

---

## Fases de implementación

### Fase 1 — Base de datos + clasificación (sin impacto contable) — ✅ COMPLETADA
Migración, seed de cuentas/conceptos, DTOs, CRUD proveedores con tipo, sincronía `es_extranjero`, filtros y UI de formulario/listado. **Entregable**: se pueden clasificar terceros; contabilidad sigue igual.

Aplicado:
- Migración `20260707_fase1_acreedores_exterior` (columnas `proveedores.tipo_entidad`, `proveedores.cuenta_contable_id`, `cuentas_pagar.cuenta_pasivo_id` + FKs + índices + backfill).
- Seed: cuentas `2.1.1.06 Proveedores del Exterior` y `2.1.1.07 Acreedores Varios` + conceptos `PROVEEDORES_EXTERIOR` y `ACREEDORES_VARIOS` en `MAPEO_DEFAULT`. El contador puede reasignar códigos desde `Contabilidad → Mapeo de Cuentas`.
- Backend: DTOs, `resolverFaseAcreedoresPayload` en `proveedores.service.ts` (sync `tipo_entidad ⇔ es_extranjero` + validación de `cuenta_contable_id` como cuenta hoja PASIVO ACREEDORA), filtro `tipo_entidad` en el search.
- Frontend: enum `tiposEntidadProveedor` en `_standards`, sección "Clasificación contable" en `ProveedorFormDialog` (con campos SWIFT/banco corresponsal visibles solo para exterior + autocomplete de cuenta contable override), chips de filtro y badges en el listado.

### Fase 2 — Integración contable diferenciada — ✅ COMPLETADA
`resolverCuentaPasivo()`, `cuenta_pasivo_id` en CxP, integración en compras/gastos/OP, bloqueo de `ACREEDOR_VARIO` en OC/importaciones/compras. **Entregable**: documentos nuevos imputan a la cuenta correcta end-to-end.

Aplicado:
- `ContabilidadIntegracionService.resolverCuentaPasivo(proveedorId, empresaId)`: override → concepto según `tipo_entidad` → fallback `PROVEEDORES` (no-regresión garantizada si un concepto nuevo no está mapeado en la empresa).
- Aplicado en `integrarFacturaCompra`, `integrarCierreDespacho` (importaciones), `integrarGasto` (solo cuando la contraparte es un proveedor a crédito), `integrarPago` y `integrarOrdenPago`.
- **`cuenta_pasivo_id` congelada** al crear la CxP en `ComprasService.persistCuentasPagar` y `GastosService.createCuentaPorPagarDesdeGasto`. La OP lee la cuenta congelada; si no existe (CxP legacy), resuelve en vivo.
- `integrarOrdenPago` agrupa el DEBE por `cuenta_pasivo_id` de cada CxP asociada (soporta multi-pago con cuentas distintas).
- Bloqueo de `ACREEDOR_VARIO` en: `OrdenesCompraService.validateCabeceraRefs`, `ComprasService.validateCabeceraRefs`, `ImportacionesService.validateEmbarqueRefs`. Recepciones hereda del bloqueo de OC.
- **No hay reintento automático**: `resolverCuentaPasivo` cae a `PROVEEDORES` legacy si el concepto nuevo no está mapeado; nunca lanza para no interrumpir el flujo.

Pendiente para Fase 2 (opcional, cuando sea prioridad):
- Validaciones fiscales condicionales (RUC/timbrado/IVA relajados para `PROVEEDOR_EXTERIOR`).

### Fase 3 — Reclasificación asistida + reportes ✅ COMPLETADA
Endpoint y UI de reclasificación, reporte de clasificación con saldos, warnings. **Entregable**: el contador puede ordenar la cartera existente.

Aplicado backend:
- `PATCH /proveedores/:id/tipo-entidad` — reclasifica tipo + cuenta_contable_id override + motivo (auditado).
  - Bloquea destino `ACREEDOR_VARIO` si el tercero tiene OC (`estado ∉ completada,cancelada`) o embarques activos (`estado ∉ CERRADO,CANCELADO`).
  - Devuelve `warning`: los saldos y asientos existentes NO migran (cuenta_pasivo_id ya congelada en CxP); solo documentos nuevos usan la cuenta destino.
- `GET /proveedores/reporte-clasificacion?tipo_entidad=&activo=` — lista con tipo, cuenta override, cuenta_efectiva_origen (OVERRIDE | CONCEPTO_*) y saldo CxP abierto agrupado.

Aplicado frontend (`pos-ventas`):
- `reclasificarProveedor()` + `getReporteClasificacionProveedores()` en `src/api/proveedores.service.js`.
- `useReclasificarProveedorMutation` + `useReporteClasificacionProveedoresQuery` en `src/tanstack/ProveedoresStack.jsx`.
- `ProveedorReclasificarDialog.jsx`: tipo destino + override de cuenta + motivo, con `Alert` de "saldos no migran" y bloqueo si destino=ACREEDOR_VARIO y hay OC/embarques activos.
- Botón "Reclasificar" en el listado de proveedores.
- Página `ReporteClasificacionTerceros` (ruta `/reportes/compras/clasificacion-terceros`, entrada en Reportes → Administrativos), con filtros por tipo/estado, búsqueda, chips de resumen (locales/exterior/acreedores), tabla con cuenta efectiva + origen (OVERRIDE | CONCEPTO_*) + saldo CxP y acceso directo a reclasificar por fila.

Aplicado backend — validaciones fiscales relajadas para `PROVEEDOR_EXTERIOR`:
- `compras.service.ts::validateCreateOrUpdatePayload` ahora es async y pre-fetch `tipo_entidad`. Para exterior salta los regex `/^\d{8}$/` y `/^\d{3}$/` de timbrado/establecimiento/punto_expedicion; sólo controla largo máximo. Locales/legacy mantienen validaciones idénticas.
- `gastos.service.ts::normalizeDocumentoFiscal` acepta `opts.esExterior`; helper `isProveedorExterior` pre-fetch. Exterior: acepta texto libre y fuerza `deducible=false` (no genera IVA crédito local).

Aplicado frontend (`pos-ventas/ComprasTemplate.jsx`):
- Detecta `esProveedorExterior` desde `selectedProveedor.tipo_entidad === 'PROVEEDOR_EXTERIOR'` o `es_extranjero`.
- `updateCabecera`: bypass del `numericOnly` + `zeroPad` para campos fiscales cuando exterior.
- Validación en submit: skip de `CABECERA_REQUIRED_FIELDS` y `exactLength`; sólo obliga `numero_factura` (para trazabilidad interna).
- Labels dinámicos: "Invoice / Nº documento", "Serie/prefijo", "Timbrado (opcional)", "Sub-serie".

Fase 3 completa. Queda como mejora futura opcional:
- Reporte SET Marangatu diferenciado para importaciones (dato ya persistido, sólo falta layout).

Gate entre fases: tests en verde + build backend/frontend OK (patrón de gates de `plan-compras-gastos.md`).

---

## Plan de pruebas

1. **Unit/smoke backend** (Jest, patrón `test:smoke:*`):
   - `resolverCuentaPasivo`: override → mapeo → fallback, por cada `tipo_entidad`.
   - Gasto crédito de acreedor vario → asiento HABER `ACREEDORES_VARIOS`; OP posterior → DEBE la misma cuenta (`cuenta_pasivo_id`).
   - Compra crédito exterior en USD → HABER `PROVEEDORES_EXTERIOR`, conversión PYG por `cont_tipo_cambio`, sin IVA crédito.
   - Reclasificar tercero con CxP abierta → OP de esa CxP sigue debitando la cuenta original.
   - Empresa sin módulo contabilidad → todo persiste sin asientos (guard).
   - Empresa sin mapeo de conceptos nuevos → documento persiste, `cont_documentos` BORRADOR, reintento OK (no bloqueante).
2. **Regresión**: suites existentes de compras, gastos, pagos-proveedor, ordenes, recepciones (35+) sin regresiones; proveedor legacy sin `tipo_entidad` explícito opera idéntico a hoy.
3. **QA manual UI** (checklist estilo F2/F3):
   - Alta de acreedor vario, gasto a crédito, OP y verificación del asiento en Libro Mayor de `2.1.1.03`.
   - Alta proveedor exterior sin RUC PY ni timbrado → guarda sin error; mismo flujo verificando `2.1.1.02`.
   - `ACREEDOR_VARIO` no seleccionable en OC/requisición/importaciones.
   - Balance de Comprobación cuadra tras operaciones mixtas (local + exterior + acreedor).
4. **Verificación contable con el contador**: revisar códigos de cuenta definitivos (2.1.1.02/2.1.1.03 son propuestos) antes del seed final.

---

## Riesgos y mitigaciones

| Riesgo | Mitigación |
|---|---|
| OP debita cuenta distinta a la del documento (tercero reclasificado) | `cuenta_pasivo_id` congelada en CxP (regla central del plan) |
| Empresas existentes sin los conceptos nuevos mapeados | Seed idempotente re-ejecutable + integración no bloqueante con reintento |
| Relajar validación fiscal exterior abre hueco en compras locales | Validaciones condicionales **solo** por `tipo_entidad='PROVEEDOR_EXTERIOR'`, con tests de regresión sobre local |
| Divergencia `es_extranjero` vs `tipo_entidad` | Sincronía en servicio + backfill en migración; importaciones sigue leyendo `es_extranjero` |
| Códigos de cuenta del seed no coinciden con plan real del cliente | Conceptos re-mapeables por UI (mecanismo existente); confirmar con contador antes de cerrar seed |

---

## Supuestos y defaults

- Sin retención INR ni tratamiento de IVA no residente en esta fase (decisión #4).
- Sin asiento automático de reclasificación de saldos (el contador usa asientos manuales si lo necesita).
- `ACREEDOR_VARIO` solo opera vía Gastos; si a futuro se necesita "compra" a acreedor, se revisa.
- Multiempresa, RBAC por decorador, auditoría global, migraciones idempotentes y transaccionalidad CxP/OP según `CLAUDE.md` raíz — obligatorios en toda la implementación.
