# Data Model: Contratos Unicliente (UniPunto y MultiPuntos)

**Feature**: `005-contratos-unicliente-detalle` | **Connection**: `agent_db_secondary`

## Dominio

`contrato = PropuestaComercial`. Esta feature cubre `TipProCom ∈ {1, 2}`:

- `TipProCom = 1` → Unicliente UniPunto
- `TipProCom = 2` → UniCliente MultiPuntos
- `TipProCom = 3` → MultiCliente MultiPunto (**fuera de alcance**)

El nodo central de la consulta es **`PropuestaComercialCups`** (una fila por punto de suministro/CUPS).

## Entity Relationship (logical)

```mermaid
erDiagram
    PropuestaComercial ||--o{ PropuestaComercialCliente : has
    PropuestaComercialCliente }o--|| Cliente : "titular (TipProCom 1/2)"
    PropuestaComercialCliente ||--o{ PropuestaComercialCups : has
    PropuestaComercialCups }o--|| PuntoSuministro : "CodPunSum"
    PropuestaComercialCups }o--o| CupsElectrico : "CodCup (TipCups=1)"
    PropuestaComercialCups }o--o| CupsGas : "CodCup (TipCups=2)"
    PropuestaComercialCups }o--o| TarifaElectrica : "CodTar (TipCups=1)"
    PropuestaComercialCups }o--o| TarifaGas : "CodTar (TipCups=2)"
    PropuestaComercialCups }o--|| Producto : "CodPro (inner)"
    PropuestaComercialCups }o--o| AnexoProducto : "CodAnePro (left)"
    Cliente }o--|| Localidad : "CodLocSoc"
    PuntoSuministro }o--|| Localidad : "CodLoc"
```

## Cadena de la consulta

```text
PropuestaComercial (TipProCom IN 1,2)
  → PropuestaComercialCliente (CodProCom)
     → Cliente (CodCli)  → Localidad (CodLocSoc)
     → PropuestaComercialCups (CodProComCli)   [nodo central, 1 fila por CUPS]
        → PuntoSuministro (CodPunSum) → Localidad (CodLoc)
        → CupsElectrico  (CodCup, TipCups=1)   / CupsGas (CodCup, TipCups=2)
        → TarifaElectrica (CodTar, TipCups=1)  / TarifaGas (CodTar, TipCups=2)
        → Producto (CodPro, inner)             / AnexoProducto (CodAnePro, left)
```

## Entidades nuevas (a modelar)

> Todas: `protected $connection = 'agent_db_secondary'; public $timestamps = false;`

### PuntoSuministro (`T_PuntoSuministro`)

| Field | Role |
|-------|------|
| `CodPunSum` | PK |
| `NomViaPunSum` | Dirección del punto de suministro (`direccionPuntoSuministro`) |
| `CodLoc` | FK → `T_Localidad` (localidad del suministro) |

**Relations**: `belongsTo(Localidad, 'CodLoc', 'CodLoc')`.

### CupsElectrico (`T_CUPsElectrico`)

| Field | Role |
|-------|------|
| `CodCupsEle` | PK |
| `CUPsEle` | Código CUPS eléctrico (`codigoCupsElectrico`) |

### CupsGas (`T_CUPsGas`)

| Field | Role |
|-------|------|
| `CodCupGas` | PK |
| `CupsGas` | Código CUPS de gas (`codigoCupsGas`) |

### TarifaElectrica (`T_TarifaElectrica`)

| Field | Role |
|-------|------|
| `CodTarEle` | PK |
| `NomTarEle` | Nombre de tarifa eléctrica (`NombreTarifaElectrica`) |

### TarifaGas (`T_TarifaGas`)

| Field | Role |
|-------|------|
| `CodTarGas` | PK |
| `NomTarGas` | Nombre de tarifa de gas (`NombreTarifaGas`) |

### Producto (`T_Producto`)

| Field | Role |
|-------|------|
| `CodPro` | PK |

Sin columnas de salida; el `join` es **inner** (restringe a CUPS con producto válido).

### AnexoProducto (`T_AnexoProducto`)

| Field | Role |
|-------|------|
| `CodAnePro` | PK |

Sin columnas de salida; `left join` (opcional).

## Cambios en entidades existentes

### PropuestaComercialCups (`T_Propuesta_Comercial_CUPs`) — añadir relaciones

Campos relevantes ya presentes: `CodProComCup` (PK), `CodProComCli` (FK), `CodCup`, `TipCups`, `CodTar`, `CodPunSum`, `CodPro`, `CodAnePro`, `FecActCUPs`, `FecVenCUPs`, `CauDiaGas`, `ConCup`, `PotEleConP1..P6`.

Nuevas relaciones:

| Relation | Tipo | Claves | Condición |
|----------|------|--------|-----------|
| `puntoSuministro()` | belongsTo `PuntoSuministro` | `CodPunSum` → `CodPunSum` | — |
| `cupsElectrico()` | belongsTo `CupsElectrico` | `CodCup` → `CodCupsEle` | `TipCups = 1` |
| `cupsGas()` | belongsTo `CupsGas` | `CodCup` → `CodCupGas` | `TipCups = 2` |
| `tarifaElectrica()` | belongsTo `TarifaElectrica` | `CodTar` → `CodTarEle` | `TipCups = 1` |
| `tarifaGas()` | belongsTo `TarifaGas` | `CodTar` → `CodTarGas` | `TipCups = 2` |
| `producto()` | belongsTo `Producto` | `CodPro` → `CodPro` | inner (whereHas) |
| `anexoProducto()` | belongsTo `AnexoProducto` | `CodAnePro` → `CodAnePro` | opcional |

> Casts de fecha ya existentes: `FecActCUPs`, `FecVenCUPs` → `date`.

### Cliente (`T_Cliente`) — añadir relación de domicilio social

Campos usados: `NumCifCli`, `NomComCli`, `EmaCli`, `TelFijCli`, `NomViaDomSoc` (`direccionCliente`), `CodLocSoc`.

| Relation | Tipo | Claves |
|----------|------|--------|
| `localidadSocial()` | belongsTo `Localidad` | `CodLocSoc` → `CodLoc` |

> La relación `localidad()` existente usa `CodLocFis` (domicilio físico); no se modifica.

## Mapa columnas de salida ↔ origen (FR-006)

| Columna de salida (negocio) | Origen |
|-----------------------------|--------|
| `CodProCom` | `T_PropuestaComercial.CodProCom` |
| `fechaContrato` | `T_PropuestaComercial.FecProCom` |
| `tipoContrato` | derivado de `TipProCom` (1=Unicliente UniPunto, 2=UniCliente MultiPuntos) |
| `NumCifCli` | `T_Cliente.NumCifCli` |
| `NomComCli` | `T_Cliente.NomComCli` |
| `EmaCli` | `T_Cliente.EmaCli` |
| `TelFijCli` | `T_Cliente.TelFijCli` |
| `direccionCliente` | `T_Cliente.NomViaDomSoc` |
| `localidadCliente` | `T_Localidad.DesLoc` (vía `CodLocSoc`) |
| `direccionPuntoSuministro` | `T_PuntoSuministro.NomViaPunSum` |
| `LocalidadPuntoSuministro` | `T_Localidad.DesLoc` (vía `PuntoSuministro.CodLoc`) |
| `FechaInicioContratoCup` | `T_Propuesta_Comercial_CUPs.FecActCUPs` |
| `FechaVencimientoContratoCup` | `T_Propuesta_Comercial_CUPs.FecVenCUPs` |
| `codigoCupsElectrico` | `T_CUPsElectrico.CUPsEle` (TipCups=1) |
| `codigoCupsGas` | `T_CUPsGas.CupsGas` (TipCups=2) |
| `NombreTarifaElectrica` | `T_TarifaElectrica.NomTarEle` (TipCups=1) |
| `NombreTarifaGas` | `T_TarifaGas.NomTarGas` (TipCups=2) |
| `consumoGas` | `T_Propuesta_Comercial_CUPs.CauDiaGas` |
| `consumoElectrico` | `T_Propuesta_Comercial_CUPs.ConCup` |
| `PotEleConP1`…`PotEleConP6` | `T_Propuesta_Comercial_CUPs.PotEleConP1..P6` |

## Laravel model location (planned)

```text
app/Models/Commercial/
├── PuntoSuministro.php      # NUEVO
├── CupsElectrico.php        # NUEVO
├── CupsGas.php              # NUEVO
├── TarifaElectrica.php      # NUEVO
├── TarifaGas.php            # NUEVO
├── Producto.php             # NUEVO
├── AnexoProducto.php        # NUEVO
├── PropuestaComercialCups.php  # EDITAR (relaciones)
└── Cliente.php                 # EDITAR (localidadSocial)
```

## Validation / read-only rules

- Todas las consultas: **SELECT only** (FR-012). Sin escritura desde la ruta del agente.
- `TipProCom` restringido a `{1, 2}` (FR-001); `3` excluido explícitamente.
- Términos de búsqueda: trim, longitud máxima razonable, comodines `%` permitidos para LIKE.
- Límite de filas: clave dedicada `agent.agent_database.contratos_unicliente.max_rows` (NO el tope de 50; FR-008).
