from __future__ import annotations import csv import io from fastapi import APIRouter, Request from fastapi.responses import RedirectResponse, StreamingResponse from app.core.db.common import CommonSessionLocal from app.core.http_responses import ui_access_denied from app.core.security.csrf import get_or_create_csrf_token from app.core.security.session_auth import get_current_user from app.core.templating import templates from app.modules.aqmm_dashboard.service import build_aqmm_dashboard_payload, can_view_aqmm_dashboard from app.modules.core.rbac.deps import get_user_permissions, get_user_roles router = APIRouter(prefix="/aqmm", tags=["aqmm-dashboard-ui"]) def _ctx(request: Request, db, user, **extra): base = { "request": request, "current_user": user, "current_user_roles": get_user_roles(db, user.id), "current_user_permissions": get_user_permissions(db, user.id), "csrf_token": get_or_create_csrf_token(request), "title": "AQMM Dashboard", } base.update(extra) return base @router.get("/dashboard") def dashboard(request: Request, financial_year: str = "", q: str = ""): db = CommonSessionLocal() try: user = get_current_user(request, db=db) if not user: return RedirectResponse(url="/login", status_code=303) if not can_view_aqmm_dashboard(db, user): return ui_access_denied() payload = build_aqmm_dashboard_payload(db, request, user, financial_year=financial_year, q=q) return templates.TemplateResponse( "modules/aqmm_dashboard/templates/aqmm_dashboard/dashboard.html", _ctx(request, db, user, **payload), ) finally: db.close() @router.get("/dashboard/export.csv") def dashboard_export_csv(request: Request, financial_year: str = "", q: str = ""): db = CommonSessionLocal() try: user = get_current_user(request, db=db) if not user: return RedirectResponse(url="/login", status_code=303) if not can_view_aqmm_dashboard(db, user): return ui_access_denied() payload = build_aqmm_dashboard_payload(db, request, user, financial_year=financial_year, q=q) buf = io.StringIO() writer = csv.writer(buf) writer.writerow([ "Client", "Service", "FY", "Status", "AQMM Status", "KYC", "Independence", "Conflict", "Engagement Letter", "AQMM Tasks", "Evidence Pending", "Manager Review Pending", "Partner Review Pending", "Review Partner Pending", "Closure Status", "Blockers", ]) for item in payload["engagements"]: row = item["row"] closure = item.get("closure") counts = item["counts"] writer.writerow([ row.client.client_name if row.client else "", row.catalogue.service_name if row.catalogue else "", row.financial_year or "", row.status or "", row.quality_workflow_status or "", row.quality_kyc_status or "", row.quality_independence_status or "", row.quality_conflict_status or "", row.quality_engagement_letter_status or "", counts.get("total", 0), counts.get("evidence_pending", 0), counts.get("manager_pending", 0), counts.get("partner_pending", 0), counts.get("review_partner_pending", 0), closure.closure_status if closure else "not_started", "; ".join(item.get("blockers") or []), ]) data = buf.getvalue().encode("utf-8-sig") filename = f"aqmm_dashboard_{financial_year or 'all'}.csv" return StreamingResponse( iter([data]), media_type="text/csv", headers={"Content-Disposition": f'attachment; filename="{filename}"'}, ) finally: db.close()