"""Metrologist blueprint - SPC statistics dashboard and API proxies.""" import requests as http_requests from flask import Blueprint, jsonify, render_template, request, session from flask_babel import gettext as _ from blueprints.auth import login_required, role_required from config import Config from services.api_client import api_client statistics_bp = Blueprint("statistics", __name__) # ============================================================================ # PAGINE # ============================================================================ @statistics_bp.route("/dashboard") @login_required @role_required("Metrologist") def dashboard(): """SPC dashboard overview — loads recipes for filter dropdown.""" resp = api_client.get("/api/recipes", params={"per_page": 100}) if isinstance(resp, dict) and resp.get("error"): recipes = [] else: recipes = resp.get("items", []) if isinstance(resp, dict) else [] return render_template("statistics/dashboard.html", recipes=recipes) # ============================================================================ # PROXY API AJAX → FastAPI # ============================================================================ def _proxy_statistics(endpoint: str): """Forward query params to a FastAPI statistics endpoint.""" params = {} for key in [ "recipe_id", "version_id", "subtask_id", "date_from", "date_to", "operator_id", "lot_number", "serial_number", "n_bins", ]: val = request.args.get(key) if val is not None and val != "": params[key] = val resp = api_client.get(f"/api/statistics/{endpoint}", params=params) if isinstance(resp, dict) and resp.get("error"): return jsonify({"error": True, "detail": resp.get("detail", "")}), resp.get("status_code", 500) return jsonify(resp) @statistics_bp.route("/api/summary") @login_required @role_required("Metrologist") def api_summary(): """Proxy: summary pass/fail/warning.""" return _proxy_statistics("summary") @statistics_bp.route("/api/capability") @login_required @role_required("Metrologist") def api_capability(): """Proxy: capability indices.""" return _proxy_statistics("capability") @statistics_bp.route("/api/control-chart") @login_required @role_required("Metrologist") def api_control_chart(): """Proxy: control chart data.""" return _proxy_statistics("control-chart") @statistics_bp.route("/api/histogram") @login_required @role_required("Metrologist") def api_histogram(): """Proxy: histogram data.""" return _proxy_statistics("histogram") @statistics_bp.route("/api/subtasks") @login_required @role_required("Metrologist") def api_subtasks(): """Proxy: get subtasks for recipe filter.""" params = {} recipe_id = request.args.get("recipe_id") if recipe_id: params["recipe_id"] = recipe_id version_id = request.args.get("version_id") if version_id: params["version_id"] = version_id resp = api_client.get("/api/statistics/subtasks", params=params) if isinstance(resp, dict) and resp.get("error"): return jsonify({"error": True, "detail": resp.get("detail", "")}), resp.get("status_code", 500) # Response is a list if isinstance(resp, list): return jsonify(resp) return jsonify(resp) # ============================================================================ # PROXY REPORT PDF → FastAPI # ============================================================================ def _proxy_report(endpoint: str): """Forward query params to a FastAPI reports endpoint and return PDF.""" params = {} for key in [ "recipe_id", "version_id", "subtask_id", "date_from", "date_to", "operator_id", "lot_number", "serial_number", ]: val = request.args.get(key) if val is not None and val != "": params[key] = val base_url = Config.API_SERVER_URL.rstrip("/") headers = {} api_key = session.get("api_key") if api_key: headers["X-API-Key"] = api_key try: resp = http_requests.get( f"{base_url}/api/reports/{endpoint}", headers=headers, params=params, timeout=120, ) except (http_requests.ConnectionError, http_requests.Timeout) as e: return jsonify({"error": True, "detail": str(e)}), 502 if not resp.ok: try: err = resp.json() detail = err.get("detail", f"HTTP {resp.status_code}") except Exception: detail = f"HTTP {resp.status_code}" return jsonify({"error": True, "detail": detail}), resp.status_code from flask import Response as FlaskResponse return FlaskResponse( resp.content, mimetype="application/pdf", headers={ "Content-Disposition": resp.headers.get( "Content-Disposition", f'attachment; filename="report.pdf"' ) }, ) @statistics_bp.route("/api/report-spc") @login_required @role_required("Metrologist") def api_report_spc(): """Proxy: download SPC PDF report.""" return _proxy_report("spc") @statistics_bp.route("/api/report-measurements") @login_required @role_required("Metrologist") def api_report_measurements(): """Proxy: download measurements PDF report.""" return _proxy_report("measurements")