feat: add Resumen Diario TNS page as submodule

Groups envios by factura+tipo per day and shows estado_final
(exitoso if any send succeeded, error persistente if all failed).
Supports inline reenvío and JSON detail modal. Added to sidebar
under Historial TNS and as TNS submodule link.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Lizandro Guarnizo
2026-07-26 17:59:42 -05:00
co-authored by Claude Sonnet 4.6
parent 3859095f17
commit ab2ef167f9
3 changed files with 336 additions and 2 deletions
+55 -1
View File
@@ -1,5 +1,5 @@
import json as json_lib
from datetime import datetime
from datetime import datetime, date as date_cls
import httpx
from fastapi import APIRouter, Request, Depends
from fastapi.responses import JSONResponse
@@ -199,6 +199,60 @@ async def reenviar_envio(envio_id: int, request: Request, user: dict = Depends(g
return JSONResponse({"success": new_status != "error", "message": msg})
@router.get("/resumen")
async def resumen_page(
request: Request,
user: dict = Depends(get_current_user),
fecha: str = "",
tipo: str = "",
):
if not fecha:
fecha = date_cls.today().isoformat()
conn = get_connection()
where_extra = ""
params_q: list = [fecha]
if tipo:
where_extra = "AND tipo = ?"
params_q.append(tipo)
rows = conn.execute(f"""
SELECT
factura, tipo, contrato, cedula, idrecepcion,
COUNT(*) AS intentos,
SUM(CASE WHEN status != 'error' THEN 1 ELSE 0 END) AS exitos,
MIN(created_at) AS primer_envio,
MAX(created_at) AS ultimo_envio,
MAX(CASE WHEN status = 'error' THEN id END) AS ultimo_error_id,
MAX(CASE WHEN status != 'error' THEN id END) AS exitoso_id,
CASE WHEN SUM(CASE WHEN status != 'error' THEN 1 ELSE 0 END) > 0
THEN MAX(CASE WHEN status != 'error' THEN status END)
ELSE 'error'
END AS estado_final
FROM envios
WHERE DATE(created_at) = ? {where_extra}
GROUP BY factura, tipo, contrato, cedula, idrecepcion
ORDER BY estado_final, tipo, factura
""", params_q).fetchall()
conn.close()
total = len(rows)
exitosos = sum(1 for r in rows if r["estado_final"] != "error")
errores = sum(1 for r in rows if r["estado_final"] == "error")
return request.app.state.templates.TemplateResponse("resumen.html", {
"request": request, "user": user,
"fecha": fecha,
"filtro_tipo": tipo,
"rows": rows,
"total": total,
"exitosos": exitosos,
"errores": errores,
})
@router.get("/detalle/{envio_id}")
async def detalle_envio(envio_id: int, request: Request, user: dict = Depends(get_current_user)):
conn = get_connection()