Skip to content

Flujo Reporte semanal

Base URL: /api/v1. Backend: camaroneras_backend (módulo reportes) ✅. Admin: camaroneras_admin (feature reportes) ✅. Mobile: no aplica (el reporte es principalmente web, ver referencia/produccion-flow.md). Octavo módulo de negocio; depende de piscinas, ciclos, muestreos, alimentacion (registro + guía referencial) y raleos. La sábana digital: no se llena, se genera a partir de los demás módulos, agrupada por sector con una fila por piscina. Fórmulas en referencia/sabana-calculos.md; la desviación cruza contra referencia/guia-campo-ab.md.

Requests y responses 2xx: el shape de la respuesta exitosa está en la API Reference, generada desde el spec OpenAPI. Acá quedan solo las respuestas de error (4xx/5xx) y las reglas de negocio/flujo.

Ver ADR-0044 por la semántica de la "semana" (ventana móvil de 7 días al corte, no pestañas de fecha fija como el Excel) y por qué el export queda fuera de v1.

Modelo

El reporte no tiene tablas propias: agrega en memoria, por piscina, el ciclo activa (si tiene) con su Siembra, Sampling[], Population[], Feeding[], Harvest[] (raleos ejecutados) y PoolEquipment[], más la curva de alimentación (propia del ciclo o la isDefault de la organización) para la desviación.

Semántica de la fecha de corte y la ventana semanal

  • date (query, opcional, default hoy) es la fecha de corte del reporte — equivalente a la pestaña de fecha del Excel del socio, pero calculada a demanda para cualquier fecha, no solo hoy.
  • La "semana" es la ventana móvil (corte − 7 días, corte], no una semana de calendario. weekStart/weekEnd en la respuesta marcan esa ventana.
  • Peso ant / peso act: el muestreo vigente al corte (pesoActG) es el más reciente con fecha ≤ corte; el de la semana previa (pesoAntG) es el más reciente con fecha ≤ weekStart. Si no hubo un muestreo nuevo dentro de la ventana, ambos coinciden (incremento 0) — igual que en la sábana real cuando no hay biometría esa semana.
  • Últimos 4 incrementos (promedioIncrementosG): se leen en los cortes corte, corte−7, corte−14, corte−21, corte−28 (hasta 4 diferencias consecutivas); no hay tabla de snapshots semanales, se deriva del historial real de Sampling.
  • Alimento: feedAccumPrevKg = suma de Feeding.kg con fecha ≤ weekStart; feedWeekKg = suma con fecha en la ventana; feedAccumTotalKg = la suma de ambos (kg acumulado total, el que entra al FCR).
  • Raleo (raleoLb): suma de Harvest type=raleo ejecutados con fecha ≤ corte (sin incluir cosecha_final, igual que el summary de raleos).

Derivados (ver referencia/sabana-calculos.md para las fórmulas exactas)

densidadHa, densidadActualHa, diasEngorde, diasVacio, incrementoG, crecimientoDiaG, crecimientoSemanalG, promedioIncrementosG, animalesVivos, biomasaLb, biomasaAcumuladaLb, lbPorHaActual, lbPorHaTotal, kgHaDia, fcr. Todos null si falta el dato de entrada correspondiente (igual que una celda en blanco del Excel) — una piscina sin ciclo activo devuelve una fila con todos estos campos en null (o 0 para los acumulados de alimento) y cycleId: null.

  • densidadActualHa = animales vivos / ha (vs. densidadHa, que es la densidad de siembra).
  • biomasaAcumuladaLb = biomasaLb (biomasa en pie) + raleoLb.
  • lbPorHaActual = biomasaLb / ha (sin raleo) — biomasa en pie por hectárea.
  • lbPorHaTotal = biomasaAcumuladaLb / ha (con raleo) — es el que alimenta el semáforo de carga (estadoCarga, ver Columnas KPI): mide presión acumulada de producción por ha, no la biomasa en pie. Antes de esta tarea era el único campo, llamado lbPorHa.

Sobrevivencia: real vs. estimada

Cada fila trae dos fuentes de sobrevivencia, independientes entre sí:

  • survivalPct (real): el % del muestreo de campo / aguaje (Population). Es la única que alimenta animalesVivos, biomasaLb, lbPorHaActual/Total, fcr y los semáforos KPI (estadoSupervivencia, índice de salud, prioridad). No cambia con esta tarea.
  • survivalEstimadaPct / animalesVivosEstimados (estimada, informativa): censo por consumo — invierte la guía de alimentación teórica usando el alimento real de la semana en vez de la densidad declarada (cM2Est = (feedWeekKg/7) ÷ ha ÷ factor, con factor buscado por pesoActG en la curva vigente del ciclo; ver referencia/guia-campo-ab.md → "C/m² a cosecha"). null si la piscina no tiene curva asignada, el peso está fuera de rango, feedWeekKg es 0 o no hay larvaeCount/ha. Puede superar 100% si la piscina está sobrealimentada respecto a su densidad real — no se recorta, es información válida (señal de desperdicio de alimento), no un error de cálculo.

No confundir con kgReferencialSemana/desviacionKg (sección siguiente): esos comparan alimento real vs. sugerido a partir de la densidad real declarada; la estimada hace el camino inverso, infiriendo densidad a partir del alimento.

diasVacio = fecha de siembra del ciclo activo (o el corte, si la piscina está vacía) menos la fecha de la cosecha final ejecutada más reciente de esa piscina (entre todos sus ciclos, no solo el activo). null si la piscina nunca tuvo una cosecha final.

Desviación (referencial vs. real)

Reutiliza el cálculo de la guía de alimentación (alimentacion/feeding-guide/feeding-guide.calc.tscomputeGuide().kgSugeridos, kg/día sugeridos a partir de factor(pesoActG) × c/m² × ha, ver referencia/guia-campo-ab.md), no lo reimplementa:

  • kgReferencialSemana = kgSugeridos/día × 7. null si la piscina no tiene curva asignada o el peso actual está fuera del rango de la curva.
  • desviacionKg = feedWeekKg − kgReferencialSemana (positivo = se alimentó de más).
  • desviacionPct = desviacionKg / kgReferencialSemana × 100.

Columnas KPI (scoring, WL Aqua Intelligence v4)

Cada fila trae además estadoFca, estadoSupervivencia, estadoCrecimientoDiario, estadoCrecimiento3Sem, estadoCarga, indiceSalud, prioridad y recomendacion — salen del motor de scoring configurable por organización. Ver 10 · Parámetros KPI para las fórmulas, el modelo de umbrales y el submódulo de edición.

RBAC

  • Módulo reportes (label "Reporte semanal") en el catálogo, clients ["web"].
  • Defaults: Administrador ver + exportar; Técnico y Bodeguero ver. La acción exportar ya está sembrada en el catálogo aunque v1 no expone ningún endpoint de export (queda en el backlog).

Endpoints (protegidos: AccessJwtGuard + PermissionGuard; tenant del JWT)

GET /reports/weekly — (reportes:ver)

Sábana semanal a la fecha de corte, agrupada por sector.

Query: date? (ISO 8601; default hoy).

json
// response 400 (fecha de corte inválida)
{ "error": "...", "message": "Fecha de corte inválida", "statusCode": 400 }

Flujo admin (camaroneras_admin, feature reportes)

  • Ruta: /reportes — protegida (ProtectedRoute module="reportes" action="ver"). Sin sesión → /login; sin permiso reportes:ver → bloqueada y sin ítem de nav.
  • Selector de fecha de corte (FormField type="date", default hoy): cambia la query key de React Query (['reports', 'weekly', date]) y recalcula toda la sábana a esa fecha.
  • Tabla por sector: una sección por sector (SECTOR NORTE, …) con una tabla ancha (overflow-x-auto, patrón de GuiaAlimentacionPage) — piscina, ciclo/estado, Año/Ciclo (seasonYear/seasonNumber del ciclo activo, fila del Excel — ver ADR-0058), días de cultivo/vacío, biometría, biomasa, alimentación (semana/acumulado/kg-ha-día), FCR, kg referencial, desviación (color: text-destructive si se alimentó de más, text-emerald-600 si de menos, mismo criterio semántico que la desviación de GuiaAlimentacionPage), raleo y las columnas KPI (semáforos/índice/prioridad/recomendación, ver 10 · Parámetros KPI). Piscinas sin ciclo muestran "Vacía" y guiones en los derivados (incluida Año/Ciclo) (y 5× "Sin dato" en los semáforos).
  • Sobrevivencia real vs. estimada: dos columnas contiguas, "Sobrev % (real)" y "Sobrev % (estimada)" — la estimada en text-muted-foreground con title aclarando que es censo por consumo, informativa (no alimenta biomasa ni semáforos). Puede mostrar más de 100%, sin recortar (ver "Sobrevivencia: real vs. estimada" arriba).
  • Estados límite: cargando (Cargando…), semana sin piscinas (empty state), token expirado (flujo de refresh existente del api client).

Backlog / a futuro

  • Export de la sábana (xlsx/csv) — la acción reportes:exportar ya está en el catálogo RBAC, sin endpoint todavía. Ver backlog del proyecto.
  • Mobile: fuera de alcance (reporte principalmente web).