Tablero — captura y actividad por hora (entrega 3, Q3)¶
Dos endpoints nuevos para la pantalla de promociones del Tablero: el embudo ofrecido→aplicado
por beneficio, y la actividad de hoy desglosada por hora. Complementan al
Tablero de entrega 2
(GET /api/admin/tablero) y al Panel de resultados
(GET /api/admin/tablero/resultados) — los tres viven bajo /api/admin/tablero/**, leídos por
ambos roles (INV-S04), pero cada uno tiene su propio controller/service/DTO, deliberadamente
separados para no tocar las piezas ya probadas de entregas anteriores. Fuente: ACCEPTANCE.md
§Entrega 3 y el código en backend/src/main/java/com/tipre/beneficioscenter/auditoria/ del
repositorio del sistema.
Embudo de captura por beneficio¶
Cruza consulta_beneficio (lo ofrecido) con resultado_pago (lo aplicado) para el
embudo completo y un ranking por beneficio.
Parámetros¶
| Parámetro | Tipo | Obligatorio | Descripción |
|---|---|---|---|
desde |
fecha ISO (YYYY-MM-DD) |
no | Si se omite junto con hasta, el rango es hoy. Si solo se pasa uno de los dos, el otro toma el mismo valor. |
hasta |
fecha ISO (YYYY-MM-DD) |
no | Igual que desde. |
Rango máximo: 90 días (hasta - desde <= 90, límite inclusive). Igual convención que
GET /api/admin/tablero y GET /api/admin/tablero/resultados.
Response 200¶
{
"desde": "2026-09-13",
"hasta": "2026-09-13",
"embudo": {
"consultas": 120,
"conBeneficioOfrecido": 45,
"pagosAprobados": 38,
"beneficiosAplicados": 30
},
"porBeneficio": [
{
"benefitId": 3,
"description": "Aniversario DINO 15%",
"ofrecido": 20,
"aplicado": 18,
"efectividadPct": 90.00,
"descuentoEntregado": 270000.00
}
]
}
| Campo | Descripción |
|---|---|
embudo.consultas |
Total de POST /resolver en el rango. |
embudo.conBeneficioOfrecido |
Consultas distintas con al menos una fila en consulta_beneficio — la tabla autoritativa de lo ofrecido, no el CSV denormalizado de consulta.beneficios_aplicados. |
embudo.pagosAprobados |
Filas de resultado_pago con estado=APROBADO en el rango. |
embudo.beneficiosAplicados |
De esos pagos aprobados, cuántos tienen un benefitId asociado. |
porBeneficio[].benefitId / .description |
Identificación del beneficio; description cae a "(unknown)" si el beneficio ya no existe en el catálogo. |
porBeneficio[].ofrecido |
Veces que consulta_beneficio registró este beneficio en el rango. |
porBeneficio[].aplicado |
Veces que un resultado_pago APROBADO trae este benefitId. |
porBeneficio[].efectividadPct |
aplicado / ofrecido × 100, escala 2, HALF_UP; 0.00 si ofrecido es cero (nunca divide por cero). |
porBeneficio[].descuentoEntregado |
Suma de descuentoAplicado de los pagos aprobados de ese beneficio. |
porBeneficio es la unión de los beneficios ofrecidos y aplicados en el rango — un beneficio
ofrecido pero nunca aplicado igual aparece, con aplicado: 0; ordenado por aplicado
descendente y luego ofrecido descendente.
Errores¶
| Status | Cuándo | field |
|---|---|---|
400 |
Rango mayor a 90 días | hasta |
Sin datos en el rango: 200 con el embudo en cero y porBeneficio vacío (nunca un error).
Actividad por hora¶
Sin parámetros — siempre devuelve el día de hoy, zona America/Argentina/Cordoba. No sigue
el selector de rango de fechas del resto del Tablero.
Response 200¶
{
"fecha": "2026-09-13",
"horas": [
{ "hora": 0, "consultas": 0, "aplicados": 0 },
{ "hora": 14, "consultas": 12, "aplicados": 9 }
]
}
| Campo | Descripción |
|---|---|
fecha |
Fecha de hoy en Córdoba. |
horas[] |
Siempre 24 entradas, hora de 0 a 23 ascendente, sin huecos aunque no haya datos. |
horas[].consultas |
POST /resolver recibidos en esa hora local. |
horas[].aplicados |
Filas de resultado_pago con estado=APROBADO recibidas en esa hora local. |
Por qué el bucketing es en Java, no en SQL
recibida_en/recibido_en se guardan como Instant (UTC). La hora del bucket es la hora
local en Córdoba (UTC-3 fijo, sin horario de verano) — agrupar por hora en SQL no sería
portable ni correcto entre H2 y SQL Server para un corte en hora local. El servicio trae los
Instant del día (una consulta por repositorio, no una por hora) y los agrupa convirtiendo
cada uno a America/Argentina/Cordoba y leyendo la hora. Esto también resuelve bien el
límite del día: un registro a las 01:00 Córdoba es 04:00 UTC (un día calendario distinto en
UTC), pero cae en el bucket hora: 1, no hora: 4.
No hay parámetro de rango que pueda fallar validación — esta ruta no tiene respuesta 400.
Dónde sigue¶
- El resto del Tablero (consultas totales, p99, sucursales desconocidas) y el rediseño de la pantalla completa, en Consola web — Tablero.
- Lo que pasó con cada pago después de la resolución, en Pipeline de resultado de pago.
- Todos los criterios que fijan este contrato, en la Matriz de aceptación.