# Sprint 1.5a · Schema Necesidad Inmediata (NI)

> **Para Ricci:** schema completo del flujo NI con fidelidad al sistema legacy chileno.

## Filosofía

Replicamos el flujo de venta NI del sistema legacy `systemserp_sgc` pero **modernizado**, **multi-tenant** y **legible**. Cada tabla vive en `innovium_<tenant>`.

Lo que viene del legacy:
- Estructura del contrato (datos del contratante + fallecido + servicio + valores)
- Catálogos chilenos (entidades previsionales, parentesco, estado civil, comunas, etc.)
- Concepto de aporte previsional (HABITAT, IPS, PROVIDA, etc.)
- Tramitación Registro Civil
- Capilla, Carroza, Auto, Van como detalles del servicio

Lo que **modernizamos** vs legacy:
- ❌ NO replicamos el desglose detallado de pagos (cheques, tarjetas, transferencias) → eso es Sprint 2.x cobranzas
- ✅ SÍ guardamos abono total + aporte previsional (suficiente para el PDF del contrato)
- ✅ Snapshot de precios (legacy lo hace mal, los precios se editan)
- ✅ Soft delete real (legacy borra físicamente)
- ✅ FK con integridad real (legacy tiene MyISAM sin FKs)

---

## Las 14 tablas nuevas

### CATÁLOGOS MASTER (8 tablas que se siembran al hacer migrate:tenant)

> Estos catálogos son comunes a todas las funerarias chilenas. Los seedeamos automáticamente al crear un tenant nuevo. Después el admin puede activar/desactivar items según le convenga.

#### 1. `entidades_previsionales`

> AFPs, compañías de seguros, IPS, mutuales, etc. De aquí sale el aporte previsional.

| Columna | Tipo | Para qué |
|---|---|---|
| `id` | BIGINT auto | |
| `nombre` | VARCHAR(80) | "HABITAT", "PROVIDA", "IPS", "BICE VIDA" |
| `tipo` | ENUM | `afp`, `seguro`, `ips`, `mutual`, `otro` |
| `activo` | TINYINT(1) | |
| `orden_visual` | INT | |
| `creado_en`, `actualizado_en` | DATETIME | |

**Seed inicial (~30 entidades chilenas):**
HABITAT, PROVIDA, CUPRUM, PLAN VITAL, MODELO, CAPITAL (AFPs)
PENTA VIDA, BICE VIDA, EUROAMÉRICA, CHILENA CONSOLIDADA, VIDA SECURITY, RENTA NACIONAL, CONSORCIO, METLIFE (Seguros)
IPS, CAPREDENA, DIPRECA, MUTUAL DE CARABINEROS, PGU (Sociales)

#### 2. `parentescos`

| Columna | Tipo | Para qué |
|---|---|---|
| `id` | BIGINT auto | |
| `nombre` | VARCHAR(50) | "Hijo(a)", "Cónyuge", "Padre" |
| `activo` | TINYINT(1) | |
| `orden_visual` | INT | |

**Seed:** Padre, Madre, Hijo(a), Hermano(a), Abuelo(a), Nieto(a), Tío(a), Sobrino(a), Primo(a), Padrastro, Madrastra, Hijastro(a), Hermanastro(a), Esposo(a)/Cónyuge, Cuñado(a), Suegro(a), Yerno, Nuera, Otro

#### 3. `estados_civiles`

| Columna | Tipo |
|---|---|
| `id` | INT |
| `nombre` | VARCHAR(50) |

**Seed:** Soltero(a), Casado(a), Viudo(a), Divorciado(a), Conviviente Civil

#### 4. `nacionalidades`

| Columna | Tipo |
|---|---|
| `id` | BIGINT auto |
| `nacionalidad` | VARCHAR(50) (ej: "CHILENA") |
| `pais` | VARCHAR(50) (ej: "CHILE") |
| `activo` | TINYINT(1) |

**Seed:** ~160 nacionalidades del legacy.

#### 5. `regiones`, `provincias`, `comunas`

> Geografía chilena. Datos públicos del SUBDERE.

`regiones` → 16 regiones de Chile
`provincias` → 56 provincias
`comunas` → ~346 comunas

#### 6. `capillas`

| Columna | Tipo |
|---|---|
| `id` | INT |
| `nombre` | VARCHAR(50) |

**Seed:** No, Cirios, Eléctrica

#### 7. `tipos_carroza`

| Columna | Tipo |
|---|---|
| `id` | INT |
| `nombre` | VARCHAR(50) |
| `color` | VARCHAR(20) |

**Seed:** Blanca, Negra, Plata, etc.

#### 8. `convenios` (descuentos institucionales)

| Columna | Tipo | Para qué |
|---|---|---|
| `id` | BIGINT auto | |
| `nombre` | VARCHAR(150) | "Empresa XX", "Sindicato YY" |
| `descuento_porcentaje` | DECIMAL(5,2) | 0-100 |
| `activo` | TINYINT(1) | |
| `notas` | TEXT NULL | |

**Sin seed.** El admin de cada funeraria carga los suyos en /admin/convenios (pantalla pequeña que agregamos a admin).

---

### TABLAS OPERATIVAS (6 tablas que el wizard llena)

#### 9. `clientes`

| Columna | Tipo | Para qué |
|---|---|---|
| `id` | BIGINT auto | |
| `rut` | VARCHAR(15) UNIQUE | Formato chileno |
| `nombres` | VARCHAR(150) | "Juan Carlos" |
| `apellido_paterno` | VARCHAR(100) | "Carrasco" |
| `apellido_materno` | VARCHAR(100) NULL | "Jhonson" |
| `email` | VARCHAR(180) NULL | |
| `telefono_1` | VARCHAR(15) NULL | |
| `telefono_2` | VARCHAR(15) NULL | |
| `direccion` | VARCHAR(500) NULL | |
| `region_id` | BIGINT FK NULL | |
| `provincia_id` | BIGINT FK NULL | |
| `comuna_id` | BIGINT FK NULL | |
| `fecha_nacimiento` | DATE NULL | |
| `parentesco_id` | BIGINT FK NULL | con quien tiene la relación |
| `notas` | TEXT NULL | |
| `creado_en`, `actualizado_en`, `eliminado_en` | DATETIME | |

#### 10. `fallecidos`

> En NI hay un fallecido siempre. En NF NO se usa esta tabla.

| Columna | Tipo | Para qué |
|---|---|---|
| `id` | BIGINT auto | |
| `nombres` | VARCHAR(150) | |
| `apellido_paterno` | VARCHAR(100) | |
| `apellido_materno` | VARCHAR(100) NULL | |
| `rut` | VARCHAR(15) NULL | A veces no lo tienen |
| `fecha_nacimiento` | DATE NULL | |
| `fecha_defuncion` | DATE NOT NULL | |
| `lugar_defuncion` | VARCHAR(200) NULL | "Hospital del Trabajador" |
| `comuna_defuncion_id` | BIGINT FK | |
| `causa_muerte` | VARCHAR(300) NULL | |
| `estado_civil_id` | INT FK | |
| `nacionalidad_id` | BIGINT FK | |
| `profesion` | VARCHAR(100) NULL | |
| `creado_en`, `actualizado_en` | DATETIME | |

#### 11. `contratos`

> El corazón del módulo NI. Replica los **conceptos clave** del legacy `contrato`.

| Columna | Tipo | Para qué |
|---|---|---|
| `id` | BIGINT auto | |
| `numero` | VARCHAR(20) UNIQUE | "1149", "1150" — secuencial |
| `tipo` | ENUM | `NI`, `NF` (en este sprint solo NI) |
| `estado` | ENUM | `firmado`, `anulado`, `completado` |
| `fecha_contrato` | DATE | |
| `hora_contrato` | TIME | |
| `cliente_id` | BIGINT FK | titular pagador |
| `fallecido_id` | BIGINT FK NULL | solo NI |
| `vendedor_id` | BIGINT FK | usuario que vendió |
| `sucursal_id` | BIGINT FK | dónde se vendió |
| `velatorio_id` | BIGINT FK NULL | dónde se vela |
| `convenio_id` | BIGINT FK NULL | si tiene descuento institucional |
| `convenio_descuento_pct` | DECIMAL(5,2) DEFAULT 0 | % aplicado |
| `plan_id` | BIGINT FK NULL | si compró un plan |
| `plan_nombre_snapshot` | VARCHAR(150) NULL | snapshot |
| `cofre_codigo` | VARCHAR(50) NULL | "1014", "URN-OLM-001" |
| `cofre_descripcion` | VARCHAR(200) NULL | "TERCIADO LISO" |
| `cofre_color` | VARCHAR(50) NULL | "CAFÉ" |
| `cofre_valor_clp` | INT | snapshot precio cofre |
| `cofre_alto_cm` | INT NULL | medida del cofre |
| `cofre_ancho_cm` | INT NULL | |
| `cofre_largo_cm` | INT NULL | |
| **Servicio funerario** | | |
| `capilla_id` | INT FK NULL | |
| `tipo_carroza_id` | INT FK NULL | |
| `cantidad_auto` | INT DEFAULT 0 | |
| `cantidad_van` | INT DEFAULT 0 | |
| `cruz` | TINYINT(1) DEFAULT 0 | |
| `tarjetero` | TINYINT(1) DEFAULT 0 | |
| `libro_condolencias` | TINYINT(1) DEFAULT 0 | |
| `tarjeta_condolencias` | TINYINT(1) DEFAULT 0 | |
| `arreglo_floral` | TINYINT(1) DEFAULT 0 | |
| `cafeteria` | TINYINT(1) DEFAULT 0 | |
| `tramitacion_registro_civil` | TINYINT(1) DEFAULT 0 | |
| `certificacion_medica` | TINYINT(1) DEFAULT 0 | |
| **Complemento** | | |
| `lugar_velacion` | VARCHAR(200) NULL | |
| `lugar_sepultacion` | VARCHAR(200) NULL | |
| `fecha_funeral` | DATE NULL | NULL si "POR CONFIRMAR" |
| `hora_funeral` | TIME NULL | |
| `fecha_funeral_por_confirmar` | TINYINT(1) DEFAULT 1 | |
| **Valores** | | |
| `valor_lista_clp` | INT | suma de todo a precio lista |
| `total_servicios_clp` | INT | con descuentos aplicados |
| `aporte_previsional_total_clp` | INT DEFAULT 0 | suma de los aportes |
| `abono_cliente_clp` | INT DEFAULT 0 | lo que paga cash el cliente |
| `descuento_clp` | INT DEFAULT 0 | descuento extra |
| `pendiente_pago_clp` | INT | calculado: total - aportes - abono |
| **Firma y PDF** | | |
| `firma_r2_path` | VARCHAR(500) NULL | |
| `pdf_r2_path` | VARCHAR(500) NULL | |
| `fecha_firma` | DATETIME | |
| `firmado_desde_ip` | VARCHAR(45) | |
| `observaciones` | TEXT NULL | |
| **Auditoría** | | |
| `creado_en`, `actualizado_en`, `anulado_en` | DATETIME | |
| `anulado_por_user_id` | BIGINT FK NULL | |
| `razon_anulacion` | TEXT NULL | |

⚠️ **Decisión de diseño:** muchas columnas pero está bien. Es un contrato real con muchos detalles. Lo que NO tiene sentido es normalizar todo en N tablas separadas para datos que siempre vienen juntos (ej: medidas del cofre).

#### 12. `contrato_aportes_previsionales`

> Hasta 3 entidades pueden aportar a un mismo contrato (ej: AFP + Seguro + IPS).

| Columna | Tipo | Para qué |
|---|---|---|
| `id` | BIGINT auto | |
| `contrato_id` | BIGINT FK ON DELETE CASCADE | |
| `entidad_previsional_id` | BIGINT FK | HABITAT, IPS, etc. |
| `nombre_snapshot` | VARCHAR(80) | snapshot por si se borra entidad |
| `monto_clp` | INT | $ 595.000 |
| `fecha_verificada` | DATE NULL | cuando se confirmó el pago |
| `orden` | INT | 1, 2, 3 |
| `creado_en`, `actualizado_en` | DATETIME | |

#### 13. `contrato_servicios_extra`

> Servicios adicionales con precio (TRASLADO, etc.)

| Columna | Tipo | Para qué |
|---|---|---|
| `id` | BIGINT auto | |
| `contrato_id` | BIGINT FK ON DELETE CASCADE | |
| `nombre` | VARCHAR(150) | "TRASLADO", "EXHUMACIÓN" |
| `monto_clp` | INT | |
| `orden` | INT | |
| `creado_en` | DATETIME | |

#### 14. `contratos_secuencias`

> Para numeración correlativa por tenant.

| Columna | Tipo |
|---|---|
| `tipo_contrato` | ENUM `NI`/`NF` (PK) |
| `ultimo_numero` | INT |
| `actualizado_en` | DATETIME |

**Seed inicial:** demo arranca en `1149` (siguiendo numeración legacy de Infinia para realismo). Cada tenant nuevo arranca en `1` para NI y `1` para NF.

---

## SUCURSALES (tabla extra)

### 15. `sucursales`

> Las sucursales/oficinas de la funeraria. El legacy las usa, las replicamos.

| Columna | Tipo | Para qué |
|---|---|---|
| `id` | BIGINT auto | |
| `nombre` | VARCHAR(100) | "Casa Matriz", "Sucursal Providencia" |
| `direccion` | VARCHAR(200) NULL | |
| `telefono` | VARCHAR(15) NULL | |
| `comuna_id` | BIGINT FK NULL | |
| `activo` | TINYINT(1) | |
| `creado_en`, `actualizado_en` | DATETIME | |

**Seed por tenant:** crear "Casa Matriz" automáticamente al hacer `tenant:create`.

---

## VELATORIOS (tabla extra)

### 16. `velatorios`

| Columna | Tipo |
|---|---|
| `id` | BIGINT auto |
| `nombre` | VARCHAR(150) |
| `direccion` | VARCHAR(200) NULL |
| `comuna_id` | BIGINT FK NULL |
| `capacidad_personas` | INT NULL |
| `activo` | TINYINT(1) |

---

## Foreign Keys importantes

```sql
clientes.parentesco_id → parentescos.id ON DELETE SET NULL
clientes.region_id → regiones.id ON DELETE SET NULL
clientes.provincia_id → provincias.id ON DELETE SET NULL
clientes.comuna_id → comunas.id ON DELETE SET NULL

fallecidos.estado_civil_id → estados_civiles.id ON DELETE SET NULL
fallecidos.nacionalidad_id → nacionalidades.id ON DELETE SET NULL
fallecidos.comuna_defuncion_id → comunas.id ON DELETE SET NULL

contratos.cliente_id → clientes.id ON DELETE RESTRICT
contratos.fallecido_id → fallecidos.id ON DELETE RESTRICT
contratos.vendedor_id → users.id ON DELETE RESTRICT
contratos.sucursal_id → sucursales.id ON DELETE RESTRICT
contratos.velatorio_id → velatorios.id ON DELETE SET NULL
contratos.convenio_id → convenios.id ON DELETE SET NULL
contratos.plan_id → productos.id ON DELETE SET NULL
contratos.capilla_id → capillas.id ON DELETE SET NULL
contratos.tipo_carroza_id → tipos_carroza.id ON DELETE SET NULL

contrato_aportes_previsionales.contrato_id → contratos.id ON DELETE CASCADE
contrato_aportes_previsionales.entidad_previsional_id → entidades_previsionales.id ON DELETE RESTRICT

contrato_servicios_extra.contrato_id → contratos.id ON DELETE CASCADE
```

**Decisión clave:** los contratos firmados NUNCA se eliminan físicamente. Solo se anulan (`estado='anulado'` + `anulado_en`).

---

## Lo que NO entra en este sprint

- 🚫 Médico certificador con monto y honorarios → Sprint 1.5c o 2.x
- 🚫 Datero (intermediario que trae clientes) → Sprint 2.x
- 🚫 Detalle de cheques con bancos y números → Sprint 2.x cobranzas
- 🚫 Tarjetas TDB/TDC con números → Sprint 2.x
- 🚫 Transferencias detalladas → Sprint 2.x
- 🚫 Devoluciones, notas crédito → Sprint 2.x
- 🚫 Egresos de contrato (gastos reales) → Sprint 2.x
- 🚫 Inscripciones a doctor → Sprint 2.x
- 🚫 Licitaciones municipales → Sprint 2.x
- 🚫 Pago al datero / vendedor (comisiones) → Sprint 2.x
