fix: use same KW range for year-over-year KPI comparison

The previous implementation compared a partial current year against a
full previous year, producing misleading percentages. Now determines the
max KW with data in the selected year and filters the previous year to
the same KW range for a fair comparison.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
CCS Admin 2026-02-28 13:23:03 +00:00
parent 73b0d6761c
commit 2f0a556371
2 changed files with 32 additions and 12 deletions

View file

@ -19,6 +19,7 @@ from app.schemas.report import (
ReportListResponse, ReportListResponse,
ReportMeta, ReportMeta,
) )
from app.config import get_settings
from app.services.audit_service import log_action from app.services.audit_service import log_action
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -43,13 +44,27 @@ def dashboard(
jahr = date_to_jahr(date.today()) jahr = date_to_jahr(date.today())
try: try:
from sqlalchemy import func as sa_func
from app.models.case import Case
from app.services.report_service import ( from app.services.report_service import (
calculate_dashboard_kpis, calculate_dashboard_kpis,
calculate_sheet1_data, calculate_sheet1_data,
) )
# Determine the highest KW with data in the selected year so
# the previous-year comparison covers the same calendar-week range.
max_kw = (
db.query(sa_func.max(Case.kw))
.filter(
Case.versicherung == get_settings().VERSICHERUNG_FILTER,
Case.jahr == jahr,
)
.scalar()
)
kpis = calculate_dashboard_kpis(db, jahr) kpis = calculate_dashboard_kpis(db, jahr)
prev_kpis = calculate_dashboard_kpis(db, jahr - 1) prev_kpis = calculate_dashboard_kpis(db, jahr - 1, max_kw=max_kw)
sheet1 = calculate_sheet1_data(db, jahr) sheet1 = calculate_sheet1_data(db, jahr)
return DashboardResponse(kpis=kpis, prev_kpis=prev_kpis, weekly=sheet1.get("weekly", [])) return DashboardResponse(kpis=kpis, prev_kpis=prev_kpis, weekly=sheet1.get("weekly", []))
except ImportError: except ImportError:

View file

@ -497,9 +497,12 @@ def calculate_sheet5_data(db: Session, jahr: int, max_kw: int | None = None, fal
# Dashboard KPIs # Dashboard KPIs
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
def calculate_dashboard_kpis(db: Session, jahr: int) -> dict: def calculate_dashboard_kpis(db: Session, jahr: int, max_kw: int | None = None) -> dict:
"""Calculate live KPIs for the dashboard. """Calculate live KPIs for the dashboard.
If *max_kw* is given, only cases up to and including that calendar week
are counted. This is used for fair year-over-year comparisons.
Returns:: Returns::
{ {
@ -513,18 +516,21 @@ def calculate_dashboard_kpis(db: Session, jahr: int) -> dict:
"gutachten_typen": {"alternative": X, "bestaetigung": X, "uncodiert": X}, "gutachten_typen": {"alternative": X, "bestaetigung": X, "uncodiert": X},
} }
""" """
# Base filter for this portal's insurance # Base filters for this portal's insurance + year (+ optional KW cutoff)
v_filter = Case.versicherung == settings.VERSICHERUNG_FILTER v_filter = Case.versicherung == settings.VERSICHERUNG_FILTER
base_filters = [v_filter, Case.jahr == jahr]
if max_kw is not None:
base_filters.append(Case.kw <= max_kw)
# Total cases for the year # Total cases for the year
total_cases = ( total_cases = (
db.query(func.count(Case.id)).filter(v_filter, Case.jahr == jahr).scalar() or 0 db.query(func.count(Case.id)).filter(*base_filters).scalar() or 0
) )
# Cases without ICD codes entered # Cases without ICD codes entered
pending_icd = ( pending_icd = (
db.query(func.count(Case.id)) db.query(func.count(Case.id))
.filter(v_filter, Case.jahr == jahr, Case.icd == None) # noqa: E711 .filter(*base_filters, Case.icd == None) # noqa: E711
.scalar() .scalar()
or 0 or 0
) )
@ -533,8 +539,7 @@ def calculate_dashboard_kpis(db: Session, jahr: int) -> dict:
pending_coding = ( pending_coding = (
db.query(func.count(Case.id)) db.query(func.count(Case.id))
.filter( .filter(
v_filter, *base_filters,
Case.jahr == jahr,
Case.gutachten == True, # noqa: E712 Case.gutachten == True, # noqa: E712
Case.gutachten_typ == None, # noqa: E711 Case.gutachten_typ == None, # noqa: E711
) )
@ -545,7 +550,7 @@ def calculate_dashboard_kpis(db: Session, jahr: int) -> dict:
# Gutachten totals # Gutachten totals
total_gutachten = ( total_gutachten = (
db.query(func.count(Case.id)) db.query(func.count(Case.id))
.filter(v_filter, Case.jahr == jahr, Case.gutachten == True) # noqa: E712 .filter(*base_filters, Case.gutachten == True) # noqa: E712
.scalar() .scalar()
or 0 or 0
) )
@ -553,7 +558,7 @@ def calculate_dashboard_kpis(db: Session, jahr: int) -> dict:
# Ablehnungen # Ablehnungen
total_ablehnungen = ( total_ablehnungen = (
db.query(func.count(Case.id)) db.query(func.count(Case.id))
.filter(v_filter, Case.jahr == jahr, Case.ablehnung == True) # noqa: E712 .filter(*base_filters, Case.ablehnung == True) # noqa: E712
.scalar() .scalar()
or 0 or 0
) )
@ -561,7 +566,7 @@ def calculate_dashboard_kpis(db: Session, jahr: int) -> dict:
# Unterlagen # Unterlagen
total_unterlagen = ( total_unterlagen = (
db.query(func.count(Case.id)) db.query(func.count(Case.id))
.filter(v_filter, Case.jahr == jahr, Case.unterlagen == True) # noqa: E712 .filter(*base_filters, Case.unterlagen == True) # noqa: E712
.scalar() .scalar()
or 0 or 0
) )
@ -569,7 +574,7 @@ def calculate_dashboard_kpis(db: Session, jahr: int) -> dict:
# Per-Fallgruppe counts # Per-Fallgruppe counts
fg_rows = ( fg_rows = (
db.query(Case.fallgruppe, func.count(Case.id).label("cnt")) db.query(Case.fallgruppe, func.count(Case.id).label("cnt"))
.filter(v_filter, Case.jahr == jahr) .filter(*base_filters)
.group_by(Case.fallgruppe) .group_by(Case.fallgruppe)
.all() .all()
) )
@ -581,7 +586,7 @@ def calculate_dashboard_kpis(db: Session, jahr: int) -> dict:
# Gutachten type breakdown # Gutachten type breakdown
typ_rows = ( typ_rows = (
db.query(Case.gutachten_typ, func.count(Case.id).label("cnt")) db.query(Case.gutachten_typ, func.count(Case.id).label("cnt"))
.filter(v_filter, Case.jahr == jahr, Case.gutachten == True) # noqa: E712 .filter(*base_filters, Case.gutachten == True) # noqa: E712
.group_by(Case.gutachten_typ) .group_by(Case.gutachten_typ)
.all() .all()
) )