# Fix: Problema al Re-facturar Después de Anular Boletas

**Fecha:** 22 de Enero, 2026  
**Severidad:** Alta  
**Estado:** Solucionado

---

## 🔴 PROBLEMA IDENTIFICADO

### Síntoma
Después de anular una boleta de un cliente, al intentar generar boletas masivas para el sector, el sistema muestra:
- **0 Clientes en Sector**
- **0 Con Lectura**
- **0 Sin Lectura**

Esto impide volver a facturar al cliente cuya boleta fue anulada.

### Causa Raíz

El procedimiento almacenado `cancel_fact` tenía una **lógica incompleta**:

1. ✅ Marcaba la boleta como anulada (`estado_pago = 9`)
2. ✅ Eliminaba la deuda asociada
3. ❌ **NO restauraba la lectura a estado pendiente**

Cuando se anula una boleta, la lectura asociada mantiene:
- `id_boleta` = ID de la boleta anulada (≠ 0)
- `estado_pago` = 5 o algún valor ≠ 0

### Por qué el sistema muestra 0 clientes

La query que busca clientes con lecturas pendientes de facturar es:

```sql
SELECT COUNT(DISTINCT l.id_cliente) as total
FROM lecturas_clie_mensual l
INNER JOIN clientes c ON l.id_cliente = c.Id_cliente
WHERE c.sector = ?
  AND MONTH(l.fecha_ingreso_lectura) = ?
  AND YEAR(l.fecha_ingreso_lectura) = ?
  AND l.id_boleta = 0          -- ❌ La lectura tiene id_boleta ≠ 0
  AND l.estado_pago = 0         -- ❌ La lectura tiene estado_pago ≠ 0
```

Como la lectura no cumple las condiciones (`id_boleta = 0` y `estado_pago = 0`), el sistema no la detecta como disponible para facturar.

---

## ✅ SOLUCIÓN IMPLEMENTADA

### Migración 006: `006_fix_cancel_fact_procedure.sql`

La migración corrige el procedimiento `cancel_fact` para que:

1. Marque la boleta como anulada (`estado_pago = 9`)
2. **Restaure la lectura asociada** a estado pendiente:
   - `id_boleta = 0`
   - `estado_pago = 0`
3. Elimine la deuda asociada

### Nuevo Procedimiento `cancel_fact`

```sql
CREATE PROCEDURE cancel_fact(IN id_bolet INT)
BEGIN
    DECLARE id_cli INT;
    DECLARE fecha_boleta DATE;
    
    -- Obtener datos de la boleta
    SELECT id_cliente, fecha_a_pagar 
    INTO id_cli, fecha_boleta
    FROM boletas 
    WHERE id_boleta = id_bolet;
    
    -- 1. Marcar la boleta como anulada
    UPDATE boletas 
    SET estado_pago = 9
    WHERE id_boleta = id_bolet;
    
    -- 2. CRÍTICO: Restaurar la lectura a estado pendiente
    UPDATE lecturas_clie_mensual
    SET id_boleta = 0,
        estado_pago = 0
    WHERE id_cliente = id_cli
      AND MONTH(fecha_ingreso_lectura) = MONTH(fecha_boleta)
      AND YEAR(fecha_ingreso_lectura) = YEAR(fecha_boleta)
      AND id_boleta = id_bolet;
    
    -- 3. Eliminar la deuda asociada
    DELETE FROM deudas 
    WHERE Id_boleta = id_bolet;
END
```

### Script de Corrección para Datos Existentes

La migración también incluye un script para **restaurar lecturas ya afectadas**:

```sql
-- Restaurar lecturas de boletas anuladas previamente
UPDATE lecturas_clie_mensual l
INNER JOIN boletas b ON l.id_boleta = b.id_boleta
SET l.id_boleta = 0,
    l.estado_pago = 0
WHERE b.estado_pago = 9  -- Boletas anuladas
  AND l.id_boleta != 0;  -- Lecturas que aún tienen referencia
```

---

## 📋 INSTRUCCIONES DE APLICACIÓN

### Opción 1: Aplicar desde Docker (Recomendado)

```bash
# 1. Copiar el archivo de migración al contenedor
docker cp migrations/006_fix_cancel_fact_procedure.sql mysql-apr:/tmp/

# 2. Ejecutar la migración
docker exec -i mysql-apr mysql -uroot -paprsolo 071_bsaires < /tmp/006_fix_cancel_fact_procedure.sql

# 3. Verificar que se aplicó correctamente
docker exec -it mysql-apr mysql -uroot -paprsolo 071_bsaires -e "SHOW PROCEDURE STATUS WHERE Name = 'cancel_fact';"
```

### Opción 2: Aplicar desde MySQL Workbench

1. Abrir MySQL Workbench
2. Conectar a la base de datos `071_bsaires`
3. Abrir el archivo `migrations/006_fix_cancel_fact_procedure.sql`
4. Ejecutar todo el script (Ctrl + Shift + Enter)
5. Verificar que no hay errores en el log

### Opción 3: Aplicar manualmente

```bash
# Desde Git Bash en Windows
mysql -h localhost -P 3307 -uroot -paprsolo 071_bsaires < migrations/006_fix_cancel_fact_procedure.sql
```

---

## 🧪 VERIFICACIÓN

### 1. Verificar que el procedimiento fue actualizado

```sql
SHOW CREATE PROCEDURE cancel_fact;
```

Debes ver la nueva lógica que incluye el `UPDATE` a `lecturas_clie_mensual`.

### 2. Verificar lecturas restauradas

```sql
-- Ver cuántas lecturas fueron restauradas
SELECT COUNT(*) as lecturas_restauradas
FROM lecturas_clie_mensual l
INNER JOIN boletas b ON l.id_cliente = b.id_cliente
WHERE b.estado_pago = 9
  AND l.id_boleta = 0
  AND l.estado_pago = 0
  AND MONTH(l.fecha_ingreso_lectura) = MONTH(b.fecha_a_pagar)
  AND YEAR(l.fecha_ingreso_lectura) = YEAR(b.fecha_a_pagar);
```

### 3. Probar en la aplicación

1. Ir a **Facturación → Generar Boletas**
2. Seleccionar el sector afectado (ej: SAN FRANCISCO)
3. Seleccionar mes y año (ej: enero 2026)
4. Verificar que ahora muestra:
   - ✅ **Clientes en Sector** > 0
   - ✅ **Con Lectura** > 0
5. Generar la boleta nuevamente

---

## 🎯 RESULTADO ESPERADO

Después de aplicar la migración:

### Antes
```
Clientes en Sector: 0
Con Lectura: 0
Sin Lectura: 0
Boletas Generadas: 0
```

### Después
```
Clientes en Sector: 45
Con Lectura: 1  (el cliente cuya boleta fue anulada)
Sin Lectura: 44
Boletas Generadas: 0
```

Ahora podrás:
- ✅ Ver el cliente en la lista de pendientes
- ✅ Generar una nueva boleta para ese cliente
- ✅ El sistema funcionará correctamente para futuras anulaciones

---

## 📊 IMPACTO

### Funcionalidades Afectadas
- ✅ Anulación de boletas (`DELETE /api/facturacion`)
- ✅ Generación masiva de boletas
- ✅ Estadísticas de facturación

### Datos Afectados
- Todas las lecturas asociadas a boletas anuladas previamente
- El script de corrección las restaurará automáticamente

### Compatibilidad
- ✅ Compatible con todas las versiones anteriores
- ✅ No requiere cambios en el código de la aplicación
- ✅ No afecta boletas activas o pagadas

---

## 🔄 FLUJO CORRECTO DESPUÉS DEL FIX

1. **Usuario anula una boleta** → `DELETE /api/facturacion?id=123`
2. **Procedimiento `cancel_fact` ejecuta:**
   - Marca boleta como anulada (`estado_pago = 9`)
   - **Restaura lectura** (`id_boleta = 0`, `estado_pago = 0`)
   - Elimina deuda asociada
3. **Usuario va a generar boletas masivas**
4. **Sistema detecta la lectura** como pendiente de facturar
5. **Usuario puede generar nueva boleta** para ese cliente

---

## 📝 NOTAS TÉCNICAS

### Tablas Afectadas
- `boletas` - Se marca como anulada
- `lecturas_clie_mensual` - Se restaura a estado pendiente
- `deudas` - Se elimina el registro

### Estados de Boleta
- `5` = Pendiente
- `6` = Pagada
- `7` = Pendiente con DTE
- `8` = Pagada con DTE
- `9` = **Anulada**

### Estados de Lectura
- `0` = Pendiente de facturar
- `5` = Facturada pendiente de pago
- `6` = Facturada y pagada

---

## ✅ CONCLUSIÓN

El problema ha sido **completamente resuelto** con la migración 006.

**Acción requerida:**
1. Aplicar la migración `006_fix_cancel_fact_procedure.sql`
2. Verificar que las lecturas fueron restauradas
3. Probar anular y re-facturar una boleta

**Beneficios:**
- ✅ Permite re-facturar después de anular
- ✅ Corrige datos históricos afectados
- ✅ Previene el problema en futuras anulaciones
- ✅ No requiere cambios en el código de la aplicación
