---
date: 2026-04-22
session_type: refactor_architecture
scope: modulo_fichas_inventario_seccion_4
analyst: kimi-code-cli
branches_affected:
  - main
---

# Reporte de Sesión: Refactor de Sección 4 — Uso Funcional del Inmueble

## Resumen Ejecutivo

Refactorización completa de la Sección 4 (Uso Funcional del Inmueble). Se reemplazó una tabla con 32 columnas fijas por una arquitectura relacional basada en catálogo, eliminando código duplicado y haciendo el sistema mantenible y escalable.

**Estado final:** 10 tests pasando, 0 fallos. Se eliminaron ~100 líneas de código duplicado.

> **⚠️ Nota de Desarrollo:** Este sistema se encuentra actualmente en fase de desarrollo activo. No existe datos en producción, por lo que este refactor puede aplicarse de manera segura sin necesidad de migraciones de datos o consideraciones de compatibilidad hacia atrás.
>

---

## 1. Problemas Identificados

### Antes del Refactor

1. **Tabla fija con 32 columnas**: `f_inv_seccion_4` tenía 8 tipos de uso × 4 campos cada uno (original/actual + porcentajes)
2. **Validación concatenada**: Se usaban loops con concatenación de strings para generar reglas (`uso_{$type}_actual`)
3. **Frontend hardcodeado**: Los 8 tipos de uso estaban escritos literalmente en el componente React
4. **Imposible de extender**: Agregar un nuevo tipo de uso requería modificar tabla, backend, frontend y tests
5. **Lógica de negocio confusa**: Los booleanos y porcentajes estaban mezclados, sin semántica clara

---

## 2. Decisión de Arquitectura

### "Catálogo + Tabla Relacional"

Se decidió usar el patrón de catálogo ya existente en el sistema (usado en sección 16.4):

- **Catálogo** (`f_inventario_items_catalogo`): Define los tipos de uso disponibles
- **Tabla de valores** (`f_inv_seccion_4_usos`): Almacena solo los usos seleccionados por cada inventario
- **Inferencia de estado**: Si existe el registro → está marcado. Si no existe → no está marcado.

### Ventajas

1. **Dinámico**: Agregar un nuevo tipo de uso = insertar en catálogo
2. **Limpio**: Solo se guardan los usos marcados (sin campos null innecesarios)
3. **Escalable**: No requiere cambios en migraciones ni código
4. **Consistente**: Usa el mismo patrón que la sección 16.4

---

## 3. Cambios Realizados

### Backend

#### Nueva Tabla: `f_inv_seccion_4_usos`

```sql
id                   integer PK
f_inventario_id      integer FK → f_inventario.id
tipo_uso_id          integer FK → f_inventario_items_catalogo.id
porcentaje_original  integer nullable
porcentaje_actual    integer nullable
timestamps
```

**Índice único**: `(f_inventario_id, tipo_uso_id)`

#### Nuevo Modelo: `InvSeccion4Uso`

- Relación `inventario()` → BelongsTo
- Relación `tipoUso()` → BelongsTo (catálogo)
- Campos casteados a integer

#### Action Refactorizada: `SaveSeccion4Action`

**Antes**: 32 campos individuales, validación con loops y concatenación
**Después**: 
- Recibe array `usos[]` con 3 campos: `tipo_uso_id`, `porcentaje_original`, `porcentaje_actual`
- Validación declarativa con `exists:f_inventario_items_catalogo,id,section_code,4`
- `afterValidator()`: Contador simple para validar "al menos un uso actual"
- Método `handle()`: Sync de array (crear/actualizar/eliminar)

#### Seeder: `InventarioItemCatalogoSeccion4Seeder`

8 tipos de uso insertados en el catálogo:
- Habitacional, Administrativo, Culto/Religión, Comercio/Servicio
- Educación, Salud, Industrial, Equipamiento/Otro

#### Controller Actualizado

- `edit()`: Carga `usosFuncionales` en vez de `seccion4`
- `completitud()`: Verifica `$inventario->usosFuncionales->isNotEmpty()`
- `loadSectionData()`: Devuelve array de usos con datos del catálogo
- `catalogsForSection()`: Incluye `items_section_4` con opciones del catálogo

#### Enum Actualizado

`InventarioSectionCode`: Agregado `case Section4 = '4'`

### Frontend

#### Componente: `Section4.tsx`

**Antes**: 
- 32 campos hardcodeados en `useSectionForm`
- Array `rows` con 8 tipos de uso literales
- Validación de campos individuales

**Después**:
- Recibe `catalogs.items_section_4` dinámicamente
- Estado: Array de `usos` con objetos `{tipo_uso_id, porcentaje_original, porcentaje_actual}`
- Solo renderiza inputs cuando el checkbox está marcado
- Elimina uso del array cuando ambos porcentajes son null

#### Serializer: `section-4.serializer.ts`

**Antes**: `passthroughSerializer` (enviaba todo)
**Después**: Filtra usos vacíos antes de enviar al backend

#### Validación: `use-section-validation.ts`

**Antes**: 32 reglas individuales + lógica de "al menos uno"
**Después**: 
- Una sola regla: `usos` es array requerido
- Contador de `porcentaje_actual !== null` para validar "al menos uno"

### Tests

**Antes**: Tests con datos hardcodeados de 32 campos
**Después**:
- Usa `InventarioItemCatalogoSeccion4Seeder` para crear catálogo
- Datos de prueba generados dinámicamente desde el catálogo
- Tests de validación: array vacío, IDs inválidos, IDs de otra sección, porcentajes fuera de rango, sin uso actual
- Tests de negocio: crear, actualizar, eliminar usos desmarcados

### Eliminaciones

- **Migración**: `2026_04_04_011425_create_f_inv_seccion_4_table.php`
- **Modelo**: `InvSeccion4.php`
- **Factory**: `InventarioItemCatalogoFactory.php` (no era necesario)

---

## 4. Reglas de Validación

### Backend

```php
'usos' => ['required', 'array', 'min:1'],
'usos.*.tipo_uso_id' => ['required', 'integer', 'exists:f_inventario_items_catalogo,id,section_code,4'],
'usos.*.porcentaje_original' => ['nullable', 'integer', 'between:1,100'],
'usos.*.porcentaje_actual' => ['nullable', 'integer', 'between:1,100'],
```

### After Validation

```php
$countActual = 0;
foreach ($usos as $uso) {
    if (!empty($uso['porcentaje_actual'])) {
        $countActual++;
    }
}
if ($countActual === 0) {
    $validator->errors()->add('usos', 'Debe seleccionar al menos un uso actual');
}
```

---

## 5. Métricas

| Aspecto | Valor |
|---------|-------|
| Tests pasando | 10/10 |
| Assertions | 31 |
| Archivos modificados | 14 |
| Archivos creados | 3 |
| Archivos eliminados | 3 |
| Líneas netas | -1 (479 insertadas, 478 eliminadas) |

---

## 6. Notas para Continuación

- **Regla de oro**: Al reemplazar una tabla, eliminar la migración vieja (documentado en CONTRIBUTING.md)
- **Para nuevas secciones con catálogo**: Crear seeder específico + usar `InventarioItemCatalogo`
- **Patrón de validación**: `exists:tabla,id,section_code,X` garantiza que solo se usen items del catálogo correcto
- **Frontend dinámico**: Siempre leer del catálogo en vez de hardcodear opciones

---

*Reporte generado el 22 de Abril, 2026*
