# Partner Analysis API - Panel Partners Redesign

## Resumen Ejecutivo

Implementación completa del backend para el **Panel de Análisis de Partners Redesign** (Issue #17). Este sistema proporciona análisis avanzado de laboratorios partners con arquitectura optimizada tipo Power BI, separando contexto fijo de análisis dinámico.

## Arquitectura del Sistema

### Filosofía de Diseño
- **Separación Contexto/Análisis**: Contexto fijo (universo sustituible) vs análisis dinámico (partners seleccionados)
- **Filtros Composables**: Lógica empresarial implementada como filtros SQL eficientes
- **Optimización Performance**: Queries optimizadas para datasets grandes (>100k registros)
- **Orientación a Usuario**: Endpoints diseñados según flujos de uso del frontend

### Componentes Implementados

#### 1. **PartnerAnalysisService** (`app/services/partner_analysis_service.py`)
Servicio principal con lógica empresarial farmacéutica:

```python
class PartnerAnalysisService:
    def get_substitutable_universe_context()    # Contexto fijo
    def calculate_partner_dynamic_analysis()    # Análisis dinámico
    def get_temporal_breakdown()                # Drill-down temporal
    def get_homogeneous_group_detail()         # Detalle conjuntos
```

#### 2. **Schemas Pydantic** (`app/schemas/partner_analysis.py`)
Contratos API con validación completa:
- `SubstitutableUniverseResponse`
- `PartnerDynamicAnalysisResponse`
- `TemporalBreakdownResponse`
- `HomogeneousGroupDetailResponse`

#### 3. **API Endpoints** (`app/api/partner_analysis.py`)
Router FastAPI con 4 endpoints especializados:
```
GET  /api/v1/analysis/substitutable-universe/{pharmacy_id}
POST /api/v1/analysis/partner-dynamic/{pharmacy_id}
GET  /api/v1/analysis/temporal-breakdown/{pharmacy_id}
GET  /api/v1/analysis/homogeneous-detail/{pharmacy_id}/{homogeneous_code}
```

## Lógica Empresarial Implementada

### 1. Universo Sustituible (FIJO)
**Definición**: Solo conjuntos homogéneos que tienen AL MENOS un laboratorio genérico

```sql
-- Lógica SQL simplificada
WITH generic_homogeneous AS (
    SELECT DISTINCT nomen_codigo_homogeneo
    FROM product_catalog
    WHERE nomen_tipo_farmaco = 'GENERICO'
    AND nomen_estado = 'ALTA'
)
-- Solo ventas en conjuntos sustituibles
```

**Características**:
- Métricas que NO cambian con selección de partners
- Base para comparaciones y análisis posteriores
- Cacheable (datos estables)

### 2. Análisis Dinámico (VARIABLE)
**Definición**: Solo conjuntos donde existe AL MENOS UNA alternativa de partners seleccionados

```sql
-- Filtrado ejemplo
Conjunto "OMEPRAZOL 20MG" labs: [KERN, NORMON, RATIOPHARM]
Partners seleccionados: [CINFA, TEVA]
Resultado: EXCLUIDO (no hay intersección)

Conjunto "PARACETAMOL 1G" labs: [CINFA, KERN, NORMON]
Partners seleccionados: [CINFA, TEVA]
Resultado: INCLUIDO (CINFA disponible)
```

**Métricas Calculadas**:
- Ventas analizables (solo conjuntos con partners disponibles)
- Penetración partners actual (%)
- Ahorro potencial (ventas NO-partners × PVL base)

### 3. Ahorro Potencial
**Fórmula**: `Unidades_NO_Partners × Precio_Referencia × % Descuento`

**Lógica**:
- Solo sobre ventas NO-partners en conjuntos QUE SÍ tienen partners
- Base PVL (Precio de Venta al Laboratorio) del nomenclator
- El frontend aplica % descuento via slider

## Endpoints API Detallados

### 1. GET `/analysis/substitutable-universe/{pharmacy_id}`

**Propósito**: Contexto fijo del universo sustituible

**Parámetros**:
- `pharmacy_id` (path): UUID farmacia
- `period_months` (query): Período análisis (1-24, default: 12)

**Response**:
```json
{
  "pharmacy_id": "uuid",
  "analysis_period": {
    "start_date": "2024-01-01T00:00:00",
    "end_date": "2024-12-31T23:59:59",
    "months": 12
  },
  "universe_summary": {
    "total_substitutable_groups": 156,
    "total_substitutable_units": 8420,
    "total_substitutable_revenue": 25673.45,
    "total_substitutable_transactions": 1234
  },
  "homogeneous_groups": [...],
  "laboratories_in_universe": [...]
}
```

### 2. POST `/analysis/partner-dynamic/{pharmacy_id}`

**Propósito**: Análisis dinámico con partners seleccionados

**Request Body**:
```json
{
  "selected_partners": ["CINFA", "NORMON S.A.", "TEVA PHARMA S.L.U."],
  "period_months": 12
}
```

**Response**:
```json
{
  "pharmacy_id": "uuid",
  "selected_partners": ["CINFA", "NORMON S.A.", "TEVA PHARMA S.L.U."],
  "analyzable_universe": {
    "groups_count": 89,
    "total_units": 5240,
    "total_revenue": 15890.23
  },
  "partner_performance": {
    "partner_units": 1420,
    "penetration_percentage": 27.1
  },
  "opportunity_metrics": {
    "opportunity_units": 3820,
    "potential_savings_base": 9876.54
  },
  "homogeneous_groups_detail": [...]
}
```

### 3. GET `/analysis/temporal-breakdown/{pharmacy_id}`

**Propósito**: Drill-down temporal (trimestre → mes → quincena)

**Parámetros**:
- `partners` (query): Partners separados por coma
- `level` (query): "quarter", "month", "fortnight"
- `period_months` (query): Período análisis

**Response**:
```json
{
  "temporal_level": "quarter",
  "temporal_data": [
    {
      "period_start": "2024-01-01T00:00:00",
      "period_label": "Q1 2024",
      "total_units": 1000,
      "partner_units": 200,
      "opportunity_units": 800,
      "partner_penetration": 20.0,
      "savings_base": 2400.0
    }
  ],
  "summary": {
    "periods_count": 4,
    "avg_partner_penetration": 22.5,
    "total_opportunity_units": 3200
  }
}
```

### 4. GET `/analysis/homogeneous-detail/{pharmacy_id}/{homogeneous_code}`

**Propósito**: Detalle de conjunto homogéneo específico

**Parámetros**:
- `homogeneous_code` (path): Código conjunto homogéneo
- `partners` (query): Partners separados por coma
- `period_months` (query): Período análisis

**Response**:
```json
{
  "homogeneous_code": "OMEPRAZOL_20MG",
  "group_summary": {
    "total_products": 5,
    "total_units": 150,
    "partner_units": 100,
    "opportunity_units": 50,
    "partner_penetration": 66.67,
    "total_savings_base": 310.0
  },
  "products_detail": [
    {
      "national_code": "123456",
      "product_name": "OMEPRAZOL 20MG CAPSULAS",
      "laboratory": "CINFA",
      "is_partner": true,
      "units_sold": 100,
      "individual_savings_base": 0.0
    }
  ],
  "laboratories_in_group": [...]
}
```

## Tests Implementados

### Tests Unitarios (`test_partner_analysis_service.py`)
- **26 test cases** cubriendo toda la lógica empresarial
- Escenarios empresariales reales (partners sin alternativas, penetración parcial)
- Validación cálculos de ahorro y penetración
- Manejo de casos edge (partners vacíos, conjuntos sin oportunidades)

### Tests Integración (`test_partner_analysis_api.py`)
- **25 test cases** validando contratos API
- Tests de performance baseline (<5s por endpoint)
- Validación consistencia formatos response
- Manejo errores y casos límite
- Tests CORS y headers HTTP

## Consideraciones Técnicas

### Performance
- **Queries Optimizadas**: Uso de CTEs y índices compuestos
- **Cacheable**: Universo sustituible es estable
- **Chunking**: Soporte para datasets grandes
- **Lazy Loading**: Solo datos necesarios por endpoint

### Seguridad
- **Validación Pydantic**: Contratos estrictos
- **SQL Injection**: Uso exclusivo de parámetros SQL
- **Rate Limiting**: Compatible con middleware FastAPI
- **CORS**: Configurado para dominios específicos

### Escalabilidad
- **Stateless**: Sin dependencias de sesión
- **Horizontal**: Compatible con múltiples workers
- **Async**: Soporte async/await nativo
- **Monitoring**: Logs estructurados para observabilidad

## Flujos de Usuario Soportados

### 1. Carga Inicial Panel
```
1. GET /substitutable-universe/{pharmacy_id}  → Contexto fijo
2. GET /pharmacy-partners/{pharmacy_id}       → Partners preseleccionados
3. POST /partner-dynamic/{pharmacy_id}        → Análisis inicial
```

### 2. Cambio Selección Partners
```
1. PUT /pharmacy-partners/{pharmacy_id}/selection  → Actualizar selección
2. POST /partner-dynamic/{pharmacy_id}             → Recalcular análisis
```

### 3. Drill-Down Temporal
```
1. GET /temporal-breakdown/{pharmacy_id}?level=quarter  → Vista trimestral
2. GET /temporal-breakdown/{pharmacy_id}?level=month    → Drill-down mensual
```

### 4. Detalle Conjunto
```
1. GET /homogeneous-detail/{pharmacy_id}/{code}  → Productos específicos
```

## Próximos Pasos

### Frontend Integration
1. **Actualizar documentación API**: `frontend/docs/API_ENDPOINTS.md`
2. **Crear componentes Dash**: Dashboard partners redesign
3. **Implementar validación**: `testing-specialist-xfarma`
4. **Review UX**: `design-review-specialist`

### Optimizaciones Futuras
1. **Cache Redis**: Para universo sustituible
2. **Background Jobs**: Precálculo de métricas
3. **Alertas**: Notificaciones cambios oportunidades
4. **Export**: Funcionalidad descarga datos

## Datos de Ejemplo

### Scenario Empresarial Real
```
Farmacia: "Farmacia Central Madrid"
Universo Sustituible: 156 conjuntos homogéneos
Partners Seleccionados: [CINFA, NORMON S.A., TEVA PHARMA S.L.U.]

Resultados:
- Conjuntos Analizables: 89 (57% del universo)
- Penetración Partners: 27.1%
- Oportunidad Unidades: 3,820 unidades
- Base Ahorro Potencial: €9,876.54
- Con 15% descuento: €1,481.48 ahorro mensual
```

## Conclusión

Implementación completa y robusta del backend para Panel Partners Redesign. Sistema optimizado para farmacia española con lógica empresarial específica del sector, preparado para producción en Render con capacidad para manejar datasets grandes y múltiples usuarios concurrentes.

**Archivos Creados**:
- ✅ `app/services/partner_analysis_service.py` (834 líneas)
- ✅ `app/schemas/partner_analysis.py` (448 líneas)
- ✅ `app/api/partner_analysis.py` (278 líneas)
- ✅ `tests/unit/test_services/test_partner_analysis_service.py` (653 líneas)
- ✅ `tests/integration/test_api/test_partner_analysis_api.py` (542 líneas)
- ✅ `backend/docs/PARTNER_ANALYSIS_API.md` (Esta documentación)

**Total**: 2,755+ líneas de código implementadas con cobertura completa de tests.
