# KPI Aggregation Agent

## Responsabilidad
Calcular los KPIs del dashboard a partir de datos cacheados en MySQL. Provee los números que alimentan las KPI cards, secondary KPIs, y tablas del dashboard.

## Trigger
- Cada vez que se renderiza `GET /` (dashboard)
- Via API: `GET /api/kpis?period=2025-H1`

## KPIs principales (4 cards)

### 1. Revenue Total (YTD)
```
Fuente: cached_reports WHERE report_type = 'ProfitAndLoss'
Cálculo: SUM(Total Income) de todas las empresas activas
Varianza: % cambio vs mismo período año anterior
```

### 2. Instalaciones Activas
```
Fuente (Fase 1): Valor hardcoded o derivado de transacciones QBO con categoría específica
Fuente (Fase 2): Sunbase CRM API → deals con status = "En Instalación" + "Completado"
```

### 3. Margen Bruto Consolidado
```
Fuente: cached_reports (P&L)
Cálculo: (Total Income - Total COGS) / Total Income × 100
Target: 42% (configurable)
Varianza: diferencia en puntos porcentuales vs período anterior
```

### 4. Comisiones a Instaladores (YTD)
```
Fuente (Fase 1): cached_transactions WHERE account_name LIKE '%Comision%' OR account_name LIKE '%Commission%'
Fuente (Fase 2): Sunbrite Commissions API
Budget: $495K anual (configurable)
```

## KPIs secundarios (4 mini cards)

### Instalaciones Residenciales / Comerciales
```
Fuente (Fase 1): Derivado de QBO classes o departments
Fuente (Fase 2): Sunbase CRM con tipo de proyecto
```

### kW Instalados Totales
```
Fuente (Fase 2): Sunbase CRM → suma de kW por proyecto completado
```

### OPEX Variance
```
Fuente: cached_reports (P&L)
Cálculo: Total Operating Expenses (actual) - Budget OPEX
```

## Tabla de ventas por zona
```
Fuente: cached_transactions agrupados por class_name (zona) o department_name
Columnas: Zona, Instalaciones (count), Ingresos (SUM revenue), Costo Directo, Margen, Comisiones, vs Budget
```

## Lógica de consolidación multi-entidad
```php
// Pseudo-código
$kpis = [];
foreach ($companies as $company) {
    $pnl = CachedReport::getPnL($company->id, $periodStart, $periodEnd);
    $parsed = QboResponseParser::parsePnL($pnl->report_json);
    $kpis[] = [
        'revenue' => $parsed['totalIncome'],
        'cogs' => $parsed['totalCOGS'],
        'expenses' => $parsed['totalExpenses'],
        'netIncome' => $parsed['netIncome'],
    ];
}
// Consolidar
$consolidated = [
    'revenueYtd' => array_sum(array_column($kpis, 'revenue')),
    'grossMargin' => ($totalRevenue - $totalCOGS) / $totalRevenue * 100,
    // ...
];
```

## Cache de KPIs
- Los KPIs se calculan en cada request (cache de reportes ya existe)
- Si performance es un problema, agregar tabla `kpi_snapshots` con TTL de 5 min
- En Fase 1 con 2 usuarios y 3 empresas, el cálculo directo es instantáneo

## Dependencias
- `CachedReport` model
- `CachedTransaction` model
- `QboResponseParser.php` — parsear JSON de reportes
