# Implementación: Tabla boletas_detalle

**Fecha:** 2026-01-23  
**Estado:** Implementado

---

## Resumen

Se implementó una tabla hija `boletas_detalle` para la tabla `boletas` que permite agregar cargos dinámicos sin modificar la estructura de la tabla principal.

## Archivos Creados/Modificados

### Nuevos Archivos
- `migrations/007_add_boletas_detalle.sql` - Migración SQL
- `src/app/api/mantenedores/tipos-cargo/route.ts` - API para gestionar tipos de cargo
- `src/app/api/facturacion/detalle/route.ts` - API para gestionar detalle de boletas

### Archivos Modificados
- `src/lib/queries.ts` - Nuevas queries para tipos_cargo y boletas_detalle
- `src/lib/boleta-builder.ts` - Funciones para construir datos usando detalle
- `src/lib/procedures.ts` - Funciones para insertar detalles

---

## Estructura de Base de Datos

### Tabla `tipos_cargo`
Catálogo de tipos de cargo disponibles.

```sql
CREATE TABLE tipos_cargo (
    id_tipo_cargo INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    codigo VARCHAR(30) NOT NULL UNIQUE,
    nombre VARCHAR(100) NOT NULL,
    descripcion VARCHAR(255),
    es_descuento TINYINT(1) DEFAULT 0,  -- 0=suma, 1=resta
    activo TINYINT(1) DEFAULT 1,
    orden_impresion INT DEFAULT 0
);
```

### Tabla `boletas_detalle`
Detalle de cargos por boleta.

```sql
CREATE TABLE boletas_detalle (
    id_detalle INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    id_boleta INT UNSIGNED NOT NULL,
    id_tipo_cargo INT UNSIGNED NOT NULL,
    descripcion VARCHAR(100),
    cantidad DECIMAL(10,2) DEFAULT 1.00,
    valor_unitario INT DEFAULT 0,
    monto INT NOT NULL,
    FOREIGN KEY (id_boleta) REFERENCES boletas(id_boleta) ON DELETE CASCADE
);
```

### Tipos de Cargo Predefinidos

| Código | Nombre | Es Descuento |
|--------|--------|--------------|
| CONSUMO_BASE | Consumo Base | No |
| CONSUMO_TRAMO1 | Consumo Tramo 1 | No |
| CARGO_FIJO | Cargo Fijo | No |
| ALCANTARILLADO | Alcantarillado | No |
| CUOTA_MORTUORIA | Cuota Mortuoria | No |
| MULTA_ATRASO | Multa por Atraso | No |
| MULTA_CORTE | Multa por Corte | No |
| MULTA_MATRIZ | Multa Matriz | No |
| REPACTACION | Cuota Repactación | No |
| SUBSIDIO | Subsidio Estatal | **Sí** |
| SALDO_ANTERIOR | Saldo Anterior | No |

---

## Uso

### Ejecutar Migración

```bash
# Conectar a MySQL y ejecutar:
docker exec -i aprsolo-mysql56 mysql -u root -paprsolo 071_bsaires < migrations/007_add_boletas_detalle.sql
```

### Migrar Datos Históricos (Opcional)

```sql
CALL migrar_boletas_a_detalle();
```

### Agregar Nuevo Tipo de Cargo

**Opción 1: Vía SQL**
```sql
INSERT INTO tipos_cargo (codigo, nombre, es_descuento, orden_impresion) 
VALUES ('MULTA_RECONEXION', 'Multa Reconexión Urgente', 0, 12);
```

**Opción 2: Vía API**
```bash
POST /api/mantenedores/tipos-cargo
{
  "codigo": "MULTA_RECONEXION",
  "nombre": "Multa Reconexión Urgente",
  "es_descuento": false,
  "orden_impresion": 12
}
```

### Agregar Cargo a una Boleta

**Vía API**
```bash
POST /api/facturacion/detalle
{
  "id_boleta": 12345,
  "codigo_cargo": "MULTA_RECONEXION",
  "monto": 25000,
  "descripcion": "Reconexión fuera de horario"
}
```

**Vía Código**
```typescript
import { agregarCargoABoleta } from '@/lib/procedures';

await agregarCargoABoleta(12345, 'MULTA_RECONEXION', 25000, 'Reconexión fuera de horario');
```

### Consultar Detalle de Boleta

```bash
GET /api/facturacion/detalle?id_boleta=12345
```

---

## APIs Disponibles

### GET /api/mantenedores/tipos-cargo
Obtiene todos los tipos de cargo.

### POST /api/mantenedores/tipos-cargo
Crea un nuevo tipo de cargo.

### PUT /api/mantenedores/tipos-cargo
Actualiza un tipo de cargo existente.

### GET /api/facturacion/detalle?id_boleta={id}
Obtiene el detalle de cargos de una boleta.

### POST /api/facturacion/detalle
Agrega un cargo a una boleta existente.

---

## Retrocompatibilidad

La implementación es **100% retrocompatible**:

1. Las boletas existentes siguen funcionando con las columnas actuales
2. Las nuevas funciones `buildBoletaDataConDetalle` y `buildMultipleBoletaDataConDetalle` detectan automáticamente si hay detalles en la nueva tabla
3. Si no hay detalles, se usan los valores de las columnas legacy
4. No es necesario migrar datos históricos inmediatamente

---

## Flujo Recomendado para Nuevas Boletas

1. Crear boleta con stored procedure `calulo_boleta` (mantiene compatibilidad)
2. Llamar `insertarDetallesBoleta()` para guardar detalles en nueva tabla
3. Para cargos adicionales, usar `agregarCargoABoleta()`

```typescript
// Después de crear la boleta
import { insertarDetallesBoleta, agregarCargoABoleta } from '@/lib/procedures';

// Insertar detalles estándar
await insertarDetallesBoleta(idBoleta, {
  consumo_m3: 25,
  valor_base: 12000,
  valor_tramo1: 3750,
  cargo_fijo: 2650,
  cuota_mortuoria: 200,
  subsidio: 4800
});

// Agregar cargo adicional (ej: multa especial)
await agregarCargoABoleta(idBoleta, 'MULTA_RECONEXION', 15000);
```

---

## Stored Procedures Modificados

### `calulo_boleta` (migración 008)
- Ahora inserta automáticamente en `boletas_detalle` después de crear la boleta
- Inserta todos los cargos: consumo, cargo fijo, alcantarillado, multas, subsidio, etc.

### `cancel_fact` (migración 008)  
- Ahora elimina los registros de `boletas_detalle` al anular una boleta

---

## Análisis de Impacto en Módulos del Sistema

| Módulo | Estado | Descripción |
|--------|--------|-------------|
| **Facturación** | ✅ Actualizado | `calulo_boleta` inserta en `boletas_detalle` |
| **Anulación** | ✅ Actualizado | `cancel_fact` elimina de `boletas_detalle` |
| **Condonaciones** | ✅ Actualizado | Registra descuento en `boletas_detalle` |
| **Pagos** | ✅ Sin cambios | Solo cambia `estado_pago`, no agrega cargos |
| **Repactaciones** | ✅ Sin cambios | Cuotas se agregan vía `calulo_boleta` |
| **Cortes** | ✅ Sin cambios | Multas se aplican en próxima boleta |
| **Cierre Mensual** | ✅ Sin cambios | Solo valida y cierra período |
| **Subsidios** | ✅ Sin cambios | Se aplican vía `calulo_boleta` |

### Detalle por Módulo

**Pagos** (`/api/pagos`)
- Los stored procedures `mod_pagos_update` y `mod_abonos_update` solo actualizan el estado de pago
- No agregan cargos nuevos, por lo que no necesitan modificar `boletas_detalle`

**Repactaciones** (`/api/repactaciones`)
- Las cuotas de repactación se agregan cuando se genera la boleta mensual
- El stored procedure `calulo_boleta` ya maneja esto automáticamente

**Cortes** (`/api/cortes`)
- Las multas por corte/reposición se registran en `multas_socio`
- Se aplican en la siguiente boleta vía `calulo_boleta`

**Condonaciones** (`/api/condonaciones`)
- **Actualizado**: Ahora registra el descuento en `boletas_detalle` con tipo `CONDONACION`

---

## Próximos Pasos (Opcionales)

1. **Actualizar BoletaPDF** para renderizar cargos adicionales dinámicamente
2. **Crear UI de mantenedor** para tipos de cargo en `/mantenedores/tipos-cargo`
3. **Deprecar columnas legacy** de la tabla `boletas` una vez estable
