# Próximo ajuste — Saldo a favor de proveedor (NC de compra/gasto sobre documentos ya pagados)

Estado: **pendiente** (propuesta). Fecha de registro: 2026-08-19.
Alcance: módulo Compras / Notas de crédito de compra + Gastos + Tesorería + Contabilidad.

## Contexto

La **nota de crédito de compra** (`nota_credito_compras`) puede asociarse a un documento origen:

- una **compra** (`compra_id`), o
- una **factura de gasto** deducible (`gasto_id`) — agregado el 2026-08-19, migración `20260819_ncc_gasto_origen`.

Al registrarse, la NC reduce el saldo por pagar del proveedor vía `reducirCuentasPagar()`,
consumiendo cuotas abiertas de `cuentas_pagar` (FIFO por vencimiento) acotadas al origen
(`compra_id` o `origen_tipo='gasto' + origen_id`).

### Comportamiento actual (MVP) — el gap

Si el documento origen **ya está pagado** (o es de **contado**, sin cuenta por pagar), la NC
se registra igual (documento + asiento contable inverso) pero `reducirCuentasPagar()` aplica **0**:
no hay saldo pendiente que reducir. El excedente queda como **saldo a favor _implícito_**:

```ts
// nota-credito-compras.service.ts → reducirCuentasPagar()
// "...el resto queda como saldo a favor implícito — no se genera CxN negativa en este MVP"
```

Es decir: **el crédito a favor de la empresa NO se registra en ningún lado**. No se puede
aplicar a una compra/gasto futuro ni gestionar un reembolso. Esto aplica **igual a compras y a
gastos** (paridad intencional).

## Objetivo del ajuste

Registrar y poder **utilizar** el saldo a favor que genera una NC sobre un documento pagado,
de forma **unificada para compras y gastos** (un solo modelo de crédito de proveedor).

## Diseño propuesto

### 1. Modelo de datos

Opción recomendada: una tabla de **crédito/saldo a favor de proveedor** (CxP negativa explícita),
en vez de meter montos negativos en `cuentas_pagar`.

```prisma
model proveedor_saldo_favor {
  id            String   @id @default(dbgenerated("uuid_generate_v4()")) @db.Uuid
  empresa_id    String   @db.Uuid
  proveedor_id  String   @db.Uuid
  // Origen del crédito: la NC que lo generó
  origen_tipo   String   @db.VarChar(30) // 'nota_credito_compra'
  origen_id     String   @db.Uuid
  moneda_id     String?  @db.Uuid
  monto_original Decimal @db.Decimal(18, 2)
  monto_aplicado Decimal @default(0) @db.Decimal(18, 2)
  saldo          Decimal @db.Decimal(18, 2) // monto_original - monto_aplicado
  estado         String  @default("disponible") @db.VarChar(20) // disponible | aplicado_parcial | aplicado | anulado
  created_at     DateTime @default(now()) @db.Timestamp(6)
  updated_at     DateTime @default(now()) @db.Timestamp(6)

  @@index([empresa_id, proveedor_id, estado])
  @@index([origen_tipo, origen_id])
}

// Aplicaciones del crédito contra un documento por pagar (trazabilidad)
model proveedor_saldo_favor_aplicacion {
  id                 String   @id @default(dbgenerated("uuid_generate_v4()")) @db.Uuid
  saldo_favor_id     String   @db.Uuid
  cuenta_pagar_id    String?  @db.Uuid // cuota de cuentas_pagar a la que se aplicó
  monto              Decimal  @db.Decimal(18, 2)
  created_at         DateTime @default(now()) @db.Timestamp(6)
}
```

### 2. Backend — al crear la NC (`nota-credito-compras.service.ts`)

`reducirCuentasPagar()` ya devuelve el **monto efectivamente aplicado** (`aplicadoCxp`).
La diferencia `total - aplicadoCxp` es el excedente:

```ts
const aplicadoCxp = await this.reducirCuentasPagar(tx, empresaId, proveedorId, origen, total);
const excedente = this.round(total - aplicadoCxp, 2);
if (excedente > 0) {
  await tx.proveedor_saldo_favor.create({
    data: {
      empresa_id: empresaId, proveedor_id, moneda_id: dto.moneda_id ?? null,
      origen_tipo: 'nota_credito_compra', origen_id: cab.id,
      monto_original: excedente, monto_aplicado: 0, saldo: excedente, estado: 'disponible',
    },
  });
}
```

### 3. Backend — aplicar el crédito

Al **pagar** una compra/gasto (orden de pago / recibo de pago a proveedor), ofrecer aplicar el
saldo a favor disponible del proveedor antes/junto con el medio de pago:

- descontar de `proveedor_saldo_favor.saldo` (FIFO por antigüedad),
- registrar `proveedor_saldo_favor_aplicacion`,
- reducir la cuota de `cuentas_pagar` correspondiente,
- actualizar estados.

### 4. Backend — al **anular** la NC

`restaurarCuentasPagar()` ya revierte lo aplicado a CxP. Además hay que:

- si el crédito **no** se usó → marcar `proveedor_saldo_favor.estado='anulado'`;
- si **ya se aplicó** (parcial/total) → decidir política: bloquear la anulación de la NC, o
  revertir las aplicaciones (reponer las cuotas de `cuentas_pagar` que había saldado el crédito).
  **Recomendado:** bloquear la anulación de la NC si su crédito ya fue aplicado, con mensaje claro.

### 5. Contabilidad

El asiento inverso de la NC ya se genera hoy (`integrarNotaCreditoCompra`). El saldo a favor es un
**activo/menor pasivo** con el proveedor; validar con el plan de cuentas si requiere una cuenta
puente ("Anticipos / Créditos con proveedores") al generarse y al aplicarse.

### 6. Frontend / UX

- En el buscador de origen de la NC (`BuscadorComprasNCC`) ya se listan documentos **pagados**;
  al elegir uno pagado, mostrar un aviso: _"Este documento está pagado; la NC generará un saldo a
  favor con el proveedor"_.
- En el pago a proveedor (OP / recibo), mostrar y permitir aplicar el **saldo a favor disponible**.
- En la ficha del proveedor / cuentas por pagar, mostrar el saldo a favor vigente.

## Consideraciones

- **Multi-moneda:** el crédito guarda `moneda_id`; aplicar solo contra documentos de la misma
  moneda (o convertir a la cotización de la aplicación, según política contable).
- **Hacerlo para compras y gastos a la vez:** el modelo es agnóstico al origen (la NC es la misma
  entidad), así que no duplicar lógica por tipo.
- **Migración prod:** requiere `prisma migrate deploy` de las nuevas tablas.

## Punteros de código

- `src/nota-credito-compras/nota-credito-compras.service.ts` → `create()`, `reducirCuentasPagar()`,
  `restaurarCuentasPagar()`, `anular()`, `gastosOrigen()`.
- `src/gastos/gastos.service.ts` → generación de `cuentas_pagar` (`origen_tipo='gasto'`).
- Pagos a proveedor: `src/pagos-proveedor/*`, `src/ordenes-compra/*` (punto de aplicación del crédito).
- Contabilidad: `src/contabilidad/services/integracion.service.ts` → `integrarNotaCreditoCompra`.
