# Contract: Herramienta `listar_contratos_unicliente` (agent_database)

**Feature**: `005-contratos-unicliente-detalle`
**Consumer**: `AgentDatabaseQueryCapabilityHandler` → `AgentCommercialQueryService`
**Connection**: `agent_db_secondary`

## Protocol (sin cambios respecto a la 002)

LLM turno 1 devuelve JSON:

```json
{ "query_name": "listar_contratos_unicliente", "parameters": { "tipo": "ambos", "vista": "listado" } }
```

Turno 2: el LLM interpreta las filas devueltas en lenguaje natural (español, Markdown).

## Tool: `listar_contratos_unicliente`

| Property | Value |
|----------|-------|
| Description | Lista/detalla contratos Unicliente UniPunto (`TipProCom=1`) y UniCliente MultiPuntos (`TipProCom=2`) con datos de cliente y suministro (CUPS, tarifas, potencias, consumos). Excluye MultiCliente MultiPunto (`TipProCom=3`). Ordena por fecha de contrato desc. |
| Eloquent path | `PropuestaComercialCups` → `whereHas(propuestaComercialCliente.propuestaComercial, TipProCom IN [1,2])` + `with(cliente.localidadSocial, puntoSuministro.localidad, cupsElectrico, cupsGas, tarifaElectrica, tarifaGas)` + `whereHas(producto)` |
| FR | FR-001, FR-003, FR-004, FR-005, FR-006, FR-007, FR-008 |

### Parameters

| Param | Tipo | Default | Descripción |
|-------|------|---------|-------------|
| `tipo` | string | `ambos` | `unicliente_unipunto` (TipProCom=1) \| `unicliente_multipuntos` (TipProCom=2) \| `ambos` |
| `vista` | string | `listado` | `listado` (agrupado por contrato, CUPS anidados) \| `detalle` (una fila por CUPS) |
| `termino` | string | — | Filtro libre por cliente: nombre comercial, NIF/CIF, correo, teléfono o dirección del cliente. Comodines `%`. |
| `direccion_suministro` | string | — | Filtro por dirección del punto de suministro (`NomViaPunSum`). |
| `cups` | string | — | Filtro por código CUPS (eléctrico `CUPsEle` o gas `CupsGas`). |
| `tarifa` | string | — | Filtro por nombre de tarifa (`NomTarEle` o `NomTarGas`). |
| `tipo_energia` | string | — | `electrico` (TipCups=1) \| `gas` (TipCups=2). |
| `localidad` | string | — | Filtro por localidad del punto de suministro o del cliente (`DesLoc`). |
| `fec_desde` | string (YYYY-MM-DD) | — | `FecProCom >=`. |
| `fec_hasta` | string (YYYY-MM-DD) | — | `FecProCom <=`. |
| `orden` | string | `fecha_desc` | `fecha_desc` \| `fecha_asc` (por `FecProCom`). |
| `limite` | int | — | Opcional; acotado por `contratos_unicliente.max_rows`. |

### Output columns (per row / per CUPS)

`CodProCom`, `fechaContrato`, `tipoContrato`, `NumCifCli`, `NomComCli`, `EmaCli`, `TelFijCli`,
`direccionCliente`, `localidadCliente`, `direccionPuntoSuministro`, `LocalidadPuntoSuministro`,
`FechaInicioContratoCup`, `FechaVencimientoContratoCup`, `codigoCupsElectrico`, `codigoCupsGas`,
`NombreTarifaElectrica`, `NombreTarifaGas`, `consumoGas`, `consumoElectrico`,
`PotEleConP1`, `PotEleConP2`, `PotEleConP3`, `PotEleConP4`, `PotEleConP5`, `PotEleConP6`.

> Campos no aplicables a la energía de la línea quedan vacíos/`null` (eléctrico vs gas según `TipCups`).

### Response shape (internal, hacia el LLM)

**vista = detalle** (una fila por CUPS):

```json
{
  "rows": [ { "CodProCom": 123, "fechaContrato": "2026-05-20", "tipoContrato": "UniCliente MultiPuntos", "NomComCli": "...", "codigoCupsElectrico": "ES00...", "PotEleConP1": 4.6, "...": "..." } ],
  "truncated": false,
  "count": 1
}
```

**vista = listado** (agrupado por contrato, CUPS anidados):

```json
{
  "rows": [
    {
      "CodProCom": 123,
      "fechaContrato": "2026-05-20",
      "tipoContrato": "UniCliente MultiPuntos",
      "NumCifCli": "B12345678",
      "NomComCli": "Empresa S.L.",
      "EmaCli": "...", "TelFijCli": "...",
      "direccionCliente": "...", "localidadCliente": "Madrid",
      "puntos_suministro": [
        { "direccionPuntoSuministro": "...", "LocalidadPuntoSuministro": "Madrid", "codigoCupsElectrico": "ES00...", "NombreTarifaElectrica": "2.0TD", "PotEleConP1": 4.6, "consumoElectrico": 3500 }
      ]
    }
  ],
  "truncated": false,
  "count": 1
}
```

### Límite de filas (FR-008 / FR-009)

- **NO** aplica `agent.agent_database.max_results` (50).
- Usa `agent.agent_database.contratos_unicliente.max_rows` (propuesta default **500**, vía env).
- En `vista=listado` se agrupa por `CodProCom` antes de aplicar el límite de contratos.
- Si se supera el límite, `truncated: true` y el asistente debe indicarlo.

## Error codes (runtime)

| Code | Meaning |
|------|---------|
| `agent_db_unreachable` | Fallo de conexión a la BD secundaria |
| `agent_query_unknown` | `query_name` inválido |
| `agent_query_invalid_params` | Parámetros faltantes o inválidos |
| `agent_query_no_results` | Resultado vacío (el LLM lo explica al usuario) |

## Routing hints (IntentClassifier)

Palabras clave que MUST enrutar a `agent_database` y, dentro del handler, a esta herramienta:
"contrato/contratos unicliente", "unipunto", "multipuntos", "punto de suministro", "CUPS", "tarifa eléctrica/gas", "potencia contratada", "consumo eléctrico/gas".
