from __future__ import annotations """API routes for Fraktions-Dashboard.""" from typing import Optional, List from fastapi import APIRouter, Depends, HTTPException, Query from tracker.core.kategorien import BEWERTUNGSKATEGORIEN from tracker.db.session import get_connection router = APIRouter(prefix="/fraktionen", tags=["Fraktionen"]) def _db(): conn = get_connection() try: yield conn finally: conn.close() @router.get("/kategorien") def get_kategorien(): """Return category definitions for frontend tooltips.""" return { key: { "label": val["label"], "farbe": val["farbe"], "icon": val["icon"], "beschreibung": val["beschreibung"], "beispiel": val["beispiel"], "score_range": val["score_range"], } for key, val in BEWERTUNGSKATEGORIEN.items() } @router.get("") def list_fraktionen(conn=Depends(_db)): """List all parties with Antrag counts.""" rows = conn.execute(""" SELECT p.id, p.kuerzel, p.name, p.farbe, COUNT(a.vorlage_id) as anzahl FROM parteien p LEFT JOIN antragsteller a ON p.id = a.partei_id GROUP BY p.id HAVING anzahl > 0 ORDER BY anzahl DESC """).fetchall() return [dict(r) for r in rows] @router.get("/{kuerzel}/dashboard") def fraktion_dashboard( kuerzel: str, jahr: Optional[int] = None, conn=Depends(_db), ): """Dashboard for a single Fraktion with Umsetzungsanalyse.""" # Find party partei = conn.execute( "SELECT id, kuerzel, name, farbe FROM parteien WHERE kuerzel = ?", (kuerzel,) ).fetchone() if not partei: raise HTTPException(404, f"Fraktion '{kuerzel}' nicht gefunden") # Base query: all Vorlagen by this party jahr_filter = "" params = [partei["id"]] if jahr: jahr_filter = "AND strftime('%Y', v.datum_eingang) = ?" params.append(str(jahr)) # Total Anträge total = conn.execute(f""" SELECT COUNT(DISTINCT v.id) as c FROM vorlagen v JOIN antragsteller a ON a.vorlage_id = v.id WHERE a.partei_id = ? {jahr_filter} """, params).fetchone()["c"] # With Ketten-Match results umsetzung_rows = conn.execute(f""" SELECT json_extract(kb.anmerkungen, '$.bewertung') as bewertung, COUNT(*) as anzahl, ROUND(AVG(kb.score), 2) as avg_score FROM vorlagen v JOIN antragsteller a ON a.vorlage_id = v.id JOIN ki_bewertungen kb ON kb.vorlage_id = v.id AND kb.typ = 'umsetzung_match' WHERE a.partei_id = ? {jahr_filter} GROUP BY bewertung ORDER BY anzahl DESC """, params).fetchall() umsetzung = [dict(r) for r in umsetzung_rows] bewertet = sum(r["anzahl"] for r in umsetzung_rows) # Top Anträge with scores antraege = conn.execute(f""" SELECT v.id, v.aktenzeichen, v.betreff, v.typ, v.datum_eingang, kb.score as umsetzung_score, json_extract(kb.anmerkungen, '$.bewertung') as umsetzung_bewertung, kb.begruendung as umsetzung_begruendung FROM vorlagen v JOIN antragsteller a ON a.vorlage_id = v.id LEFT JOIN ki_bewertungen kb ON kb.vorlage_id = v.id AND kb.typ = 'umsetzung_match' WHERE a.partei_id = ? {jahr_filter} ORDER BY v.datum_eingang DESC LIMIT 200 """, params).fetchall() # Jahre für Filter jahre = conn.execute(""" SELECT DISTINCT strftime('%Y', v.datum_eingang) as j FROM vorlagen v JOIN antragsteller a ON a.vorlage_id = v.id WHERE a.partei_id = ? AND v.datum_eingang IS NOT NULL ORDER BY j DESC """, [partei["id"]]).fetchall() return { "partei": dict(partei), "total_antraege": total, "bewertet": bewertet, "umsetzung": umsetzung, "antraege": [dict(r) for r in antraege], "jahre": [r["j"] for r in jahre], }