fix: Aufteilung – Tabelle volle Breite, Torte darunter; ungültige Eingaben inline (A13-T5)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-29 16:29:24 +02:00
co-authored by Claude Opus 5.5
parent 2a62bdca6c
commit 4b6144d812
4 changed files with 21 additions and 12 deletions
+2 -2
View File
@@ -392,7 +392,7 @@ def _parse_monat(value: str | None, today: date) -> date | None:
if not value:
return today.replace(day=1)
m = re.fullmatch(r"(\d{4})-(\d{2})", value.strip())
if not m or not 1 <= int(m.group(2)) <= 12:
if not m or not 1 <= int(m.group(2)) <= 12 or int(m.group(1)) < 1:
return None
return date(int(m.group(1)), int(m.group(2)), 1)
@@ -429,7 +429,7 @@ def _aufteilung_context(session: Session, today: date, monat: str | None,
ctx["monat_anzeige"] = month.strftime("%m.%Y")
scenario = None
if szenario:
valid_id = szenario.isdigit() and len(szenario) <= 9 # kein Integer-Überlauf in der DB
valid_id = re.fullmatch(r"[0-9]{1,9}", szenario) # ASCII, kein Integer-Überlauf
scenario = session.get(Scenario, int(szenario)) if valid_id else None
if scenario is None:
ctx["error"] = "Unbekanntes Szenario – bitte neu wählen."
+6 -5
View File
@@ -248,12 +248,13 @@ label:has(input:disabled), label:has(select:disabled) {
.kennzahlen { display: flex; flex-wrap: wrap; gap: 1.5rem; margin-bottom: 1rem; }
.kennzahlen div { display: flex; flex-direction: column; }
.kennzahlen strong { font-size: 1.25rem; }
.aufteilung-grid {
display: grid; grid-template-columns: minmax(0, 3fr) minmax(0, 2fr);
gap: 1.5rem; align-items: start;
.tabelle-scroll { overflow-x: auto; }
/* Torte: schmal untereinander, breit SVG neben Legende */
.torte { margin: 0; display: grid; grid-template-columns: minmax(0, 1fr); gap: 1rem; align-items: start; }
@media (min-width: 700px) {
.torte { grid-template-columns: 280px minmax(0, 1fr); }
.torte figcaption { grid-column: 1 / -1; }
}
@media (max-width: 800px) { .aufteilung-grid { grid-template-columns: minmax(0, 1fr); } }
.torte { margin: 0; }
.torte figcaption { font-weight: bold; margin-bottom: 0.5rem; }
.torte-svg { width: 100%; max-width: 280px; display: block; margin: 0 auto; }
.torte-svg .seg { stroke: #fff; stroke-width: 0.02; }
+3 -5
View File
@@ -38,8 +38,7 @@
{% if s.deficit %}
<div class="warning">Kosten übersteigen die Einkünfte um {{ (s.costs - s.income)|eur }} € — das Diagramm zeigt die Aufteilung der Gesamtkosten.</div>
{% endif %}
<div class="aufteilung-grid">
<div>
<div class="tabelle-scroll">
<table>
<thead>
<tr><th>Posten</th><th>Kategorie</th><th>Art</th><th>Monatsbetrag</th><th>% der Einkünfte</th></tr>
@@ -63,12 +62,11 @@
</tr>
</tfoot>
</table>
<p>Gesamte Einkünfte: <strong>{{ s.income|eur }} €</strong></p>
</div>
</div>
<p>Gesamte Einkünfte: <strong>{{ s.income|eur }} €</strong></p>
<div>
{% include "_aufteilung_torte.html" %}
</div>
</div>
{% endif %}
{% endif %}
</div>
+10
View File
@@ -129,6 +129,8 @@ def test_ungueltiger_monat_und_unbekanntes_szenario(client):
_login(client)
for params, text in (({"monat": "2030-13"}, "Ungültiger Monat"),
({"monat": "abc"}, "Ungültiger Monat"),
({"monat": "0000-01"}, "Ungültiger Monat"),
({"monat": MONAT, "szenario": "²"}, "Unbekanntes Szenario"),
({"monat": MONAT, "szenario": "999"}, "Unbekanntes Szenario"),
({"monat": MONAT, "szenario": "x"}, "Unbekanntes Szenario"),
({"monat": MONAT, "szenario": "9" * 30}, "Unbekanntes Szenario")):
@@ -148,3 +150,11 @@ def test_doppelzaehlungs_hinweis(client, db):
db.commit()
assert "⚠ Fixposten „Autorate“ zählt evtl. doppelt mit Kredit „Autokredit“" in _get(client, monat=MONAT).text
assert "⚠" not in _get(client, monat=MONAT, gesendet="1", fixposten="1", einmal="1").text
def test_tabelle_scrollbar_torte_darunter(client, db):
_login(client)
_daten(db)
t = _get(client, monat=MONAT).text
assert re.search(r'<div class="tabelle-scroll">\s*<table', t)
assert t.index('id="aufteilung-torte"') > t.index("</table>")