- Anmeldung über Argon2id und JWT in httpOnly-Cookies, Refresh mit echter Rotation über die neue Tabelle refresh_token - AuthProvider-Protokoll als Vorbereitung für OIDC, Administrator-Anlage beim Erststart mit erzwungenem Passwortwechsel - CRUD für Konten, Kategorien (zweistufiger Baum), Firmen, Recurrences, Preisversionen, Buchungen, Budgets, Vorlagen und Sparziele - Fälligkeiten mit Overlay-Logik: abrufen, bestätigen, auslassen, zurücksetzen - Kontosalden zum Stichtag, Monatsübersicht mit Plan-Ist-Vergleich - SECRET_KEY jetzt mindestens 32 Zeichen; Platzhalter in Produktion abgelehnt - 61 neue Integrationstests, insgesamt 148 grün Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014e7t8UpmoVNMtWivY5LiSH
52 lines
1.7 KiB
Python
52 lines
1.7 KiB
Python
"""Auswertungen."""
|
|
|
|
from datetime import date
|
|
|
|
from fastapi import APIRouter, Query
|
|
|
|
from app.api.deps import DbSession
|
|
from app.core.clock import today
|
|
from app.schemas.report import MonthComparisonOut, MonthReportOut, TotalsOut
|
|
from app.services.reports import Totals, month_report
|
|
|
|
router = APIRouter(prefix="/reports", tags=["reports"])
|
|
|
|
|
|
def _totals(value: Totals) -> TotalsOut:
|
|
return TotalsOut(income=value.income, expenses=value.expenses, balance=value.balance)
|
|
|
|
|
|
@router.get(
|
|
"/month",
|
|
response_model=MonthReportOut,
|
|
summary="Monatsübersicht",
|
|
description="Einnahmen, Ausgaben, Saldo, Plan-Ist-Vergleich, Aufteilung in fixe "
|
|
"und variable Kosten sowie die Veränderung gegenüber dem Vormonat.",
|
|
)
|
|
async def read_month_report(
|
|
session: DbSession,
|
|
month: date | None = Query(
|
|
default=None, description="Beliebiger Tag im gewünschten Monat; Vorgabe ist heute."
|
|
),
|
|
) -> MonthReportOut:
|
|
report = await month_report(session, month or today())
|
|
return MonthReportOut(
|
|
month=report.month,
|
|
planned=_totals(report.planned),
|
|
actual=_totals(report.actual),
|
|
previous_planned=_totals(report.previous_planned),
|
|
previous_actual=_totals(report.previous_actual),
|
|
delta_to_previous=MonthComparisonOut(
|
|
income=report.income_delta,
|
|
expenses=report.expenses_delta,
|
|
balance=report.balance_delta,
|
|
),
|
|
fixed_costs=report.fixed_costs,
|
|
variable_costs=report.variable_costs,
|
|
reserves=report.reserves,
|
|
available_after_fixed=report.available_after_fixed,
|
|
confirmed_count=report.confirmed_count,
|
|
open_count=report.open_count,
|
|
skipped_count=report.skipped_count,
|
|
)
|