from datetime import datetime, timedelta from fastapi import APIRouter, Request, Form, Depends from fastapi.responses import JSONResponse from app.auth import get_current_user from app.database import get_connection from app.services.firebird_service import get_firebird_from_config from app.services.whatsapp_sync import sync_todos, guardar_sync_log router = APIRouter(prefix="/pacientes", tags=["pacientes"]) # Trae todos los pacientes distintos en un rango de fechas de recepción. # Reutiliza la misma query de automation para no duplicar lógica. _SQL_TODOS = """ SELECT DISTINCT p.CODIGO, p.TIPOIDENT, p.DOCIDENT, p.NOMBRES, p.APELLIDOS, p.DIRECCION, p.CIUDAD AS COD_CIUDAD, c.NOMBRE AS NOM_CIUDAD, p.TELEFONOS, p.EMAIL, p.F_NACIMIENTO, p.SEXO, p.TIPORES, p.CODETNIA FROM PACIENTE p LEFT JOIN CIUDAD c ON c.CODIGO = p.CIUDAD LEFT JOIN RECEPCION r ON r.COD_PACIENTE = p.CODIGO WHERE (:fecha_ini IS NULL OR r.FECHA_RECEPCION BETWEEN :fecha_ini AND :fecha_fin) AND r.NUM_FACTURA > 0 """ _SQL_EXAMENES_CEDULA = """ SELECT r.IDRECEPCION, r.HORAINICIORECEPCION, TRIM(rel.COD_EXAMEN) AS COD_EXAMEN, TRIM(ex.NOMBRE) AS NOM_EXAMEN, COALESCE(NULLIF(TRIM(ex.NUM_ISS), ''), TRIM(rel.COD_EXAMEN)) AS CUPS, rel.PRECIO FROM RECEPCION r JOIN RELACION rel ON rel.IDRECEPCION = r.IDRECEPCION LEFT JOIN EXAMEN ex ON TRIM(ex.CODIGO) = TRIM(rel.COD_EXAMEN) JOIN PACIENTE p ON p.CODIGO = r.COD_PACIENTE WHERE TRIM(p.DOCIDENT) = :cedula AND r.FECHA_RECEPCION = CURRENT_DATE ORDER BY r.IDRECEPCION DESC """ _SQL_SIN_FILTRO = """ SELECT DISTINCT p.CODIGO, p.TIPOIDENT, p.DOCIDENT, p.NOMBRES, p.APELLIDOS, p.DIRECCION, p.CIUDAD AS COD_CIUDAD, c.NOMBRE AS NOM_CIUDAD, p.TELEFONOS, p.EMAIL, p.F_NACIMIENTO, p.SEXO, p.TIPORES, p.CODETNIA FROM PACIENTE p LEFT JOIN CIUDAD c ON c.CODIGO = p.CIUDAD WHERE p.DOCIDENT IS NOT NULL AND p.NOMBRES IS NOT NULL """ @router.get("/examenes") async def examenes_paciente(request: Request, cedula: str = ""): """Server-to-server: exámenes registrados hoy (últimos 5 min) para una cédula.""" conn = get_connection() configs = {row["key"]: row["value"] for row in conn.execute("SELECT * FROM config").fetchall()} conn.close() api_key = request.headers.get("X-Lab-Key", "") if not api_key or api_key != configs.get("whatsapp_api_key", ""): return JSONResponse({"ok": False, "error": "No autorizado"}, status_code=401) cedula = cedula.strip() if not cedula: return JSONResponse({"ok": False, "error": "cedula requerida"}, status_code=400) fb, ok, msg = get_firebird_from_config(configs) if not ok: return JSONResponse({"ok": False, "error": f"Error Firebird: {msg}"}, status_code=503) ok_q, err_q, rows = fb.execute_query(_SQL_EXAMENES_CEDULA, {"cedula": cedula}) fb.disconnect() if not ok_q: return JSONResponse({"ok": False, "error": f"Error consulta: {err_q}"}, status_code=500) # Filtrar últimos 5 minutos por HORAINICIORECEPCION ahora = datetime.now() limite = ahora - timedelta(minutes=5) def parse_hora(raw) -> datetime | None: if not raw: return None s = str(raw) try: if "T" in s: dt = datetime.fromisoformat(s) return ahora.replace(hour=dt.hour, minute=dt.minute, second=dt.second, microsecond=0) partes = s.split(":") return ahora.replace(hour=int(partes[0]), minute=int(partes[1]), second=int(partes[2].split(".")[0]), microsecond=0) except Exception: return None examenes = [] for row in rows: hora_dt = parse_hora(row.get("HORAINICIORECEPCION")) if hora_dt and hora_dt < limite: continue examenes.append({ "recepcion_id": row.get("IDRECEPCION"), "hora": row.get("HORAINICIORECEPCION"), "cod_examen": (row.get("COD_EXAMEN") or "").strip(), "nombre": (row.get("NOM_EXAMEN") or "").strip(), "cups": (row.get("CUPS") or "").strip(), "precio": row.get("PRECIO"), }) return JSONResponse({"ok": True, "examenes": examenes}) @router.get("") async def pacientes_page(request: Request, user: dict = Depends(get_current_user)): conn = get_connection() configs = {row["key"]: row["value"] for row in conn.execute("SELECT * FROM config").fetchall()} conn.close() wa_url = configs.get("whatsapp_url", "") wa_key = configs.get("whatsapp_api_key", "") return request.app.state.templates.TemplateResponse("pacientes.html", { "request": request, "user": user, "wa_configurado": bool(wa_url and wa_key), "wa_url": wa_url, }) @router.post("/sync-all") async def sync_all( request: Request, user: dict = Depends(get_current_user), fecha_ini: str = Form(""), fecha_fin: str = Form(""), todos: str = Form(""), ): conn = get_connection() configs = {row["key"]: row["value"] for row in conn.execute("SELECT * FROM config").fetchall()} conn.close() wa_url = configs.get("whatsapp_url", "").rstrip("/") wa_key = configs.get("whatsapp_api_key", "") if not wa_url or not wa_key: return JSONResponse({ "success": False, "message": "Configura la URL y API Key de WhatsApp Lab antes de sincronizar.", }) ingest_url = f"{wa_url}/api/lab/ingest_paciente.php" fb, ok, msg = get_firebird_from_config(configs) if not ok: return JSONResponse({"success": False, "message": f"Error Firebird: {msg}"}) if todos == "1" or (not fecha_ini and not fecha_fin): ok_q, err_q, rows = fb.execute_query(_SQL_SIN_FILTRO, None) else: if not fecha_ini or not fecha_fin: fb.disconnect() return JSONResponse({"success": False, "message": "Indica fecha inicio y fecha fin."}) params = { "fecha_ini": f"{fecha_ini} 00:00:00", "fecha_fin": f"{fecha_fin} 23:59:59", } ok_q, err_q, rows = fb.execute_query(_SQL_TODOS, params) fb.disconnect() if not ok_q: return JSONResponse({"success": False, "message": f"Error al consultar Firebird: {err_q}"}) if not rows: return JSONResponse({"success": False, "message": "No se encontraron pacientes con esos criterios."}) timeout = int(configs.get("api_timeout", 30)) resultado = await sync_todos(rows, ingest_url, wa_key, timeout, modo="insertar") guardar_sync_log(resultado, user["user_id"], origen="manual", modo="insertar") resultado["success"] = True resultado["message"] = ( f"{resultado['total']} procesados — " f"{resultado['created']} nuevos, " f"{resultado['skipped']} ya existían, " f"{resultado['errores']} errores." ) return JSONResponse(resultado) @router.get("/historial") async def historial(request: Request, user: dict = Depends(get_current_user)): conn = get_connection() rows = conn.execute(""" SELECT l.*, u.username FROM sync_wa_log l LEFT JOIN users u ON u.id = l.user_id ORDER BY l.created_at DESC LIMIT 100 """).fetchall() conn.close() return JSONResponse([dict(r) for r in rows])