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:
@@ -392,7 +392,7 @@ def _parse_monat(value: str | None, today: date) -> date | None:
|
|||||||
if not value:
|
if not value:
|
||||||
return today.replace(day=1)
|
return today.replace(day=1)
|
||||||
m = re.fullmatch(r"(\d{4})-(\d{2})", value.strip())
|
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 None
|
||||||
return date(int(m.group(1)), int(m.group(2)), 1)
|
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")
|
ctx["monat_anzeige"] = month.strftime("%m.%Y")
|
||||||
scenario = None
|
scenario = None
|
||||||
if szenario:
|
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
|
scenario = session.get(Scenario, int(szenario)) if valid_id else None
|
||||||
if scenario is None:
|
if scenario is None:
|
||||||
ctx["error"] = "Unbekanntes Szenario – bitte neu wählen."
|
ctx["error"] = "Unbekanntes Szenario – bitte neu wählen."
|
||||||
|
|||||||
@@ -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 { display: flex; flex-wrap: wrap; gap: 1.5rem; margin-bottom: 1rem; }
|
||||||
.kennzahlen div { display: flex; flex-direction: column; }
|
.kennzahlen div { display: flex; flex-direction: column; }
|
||||||
.kennzahlen strong { font-size: 1.25rem; }
|
.kennzahlen strong { font-size: 1.25rem; }
|
||||||
.aufteilung-grid {
|
.tabelle-scroll { overflow-x: auto; }
|
||||||
display: grid; grid-template-columns: minmax(0, 3fr) minmax(0, 2fr);
|
/* Torte: schmal untereinander, breit SVG neben Legende */
|
||||||
gap: 1.5rem; align-items: start;
|
.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 figcaption { font-weight: bold; margin-bottom: 0.5rem; }
|
||||||
.torte-svg { width: 100%; max-width: 280px; display: block; margin: 0 auto; }
|
.torte-svg { width: 100%; max-width: 280px; display: block; margin: 0 auto; }
|
||||||
.torte-svg .seg { stroke: #fff; stroke-width: 0.02; }
|
.torte-svg .seg { stroke: #fff; stroke-width: 0.02; }
|
||||||
|
|||||||
@@ -38,8 +38,7 @@
|
|||||||
{% if s.deficit %}
|
{% 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>
|
<div class="warning">Kosten übersteigen die Einkünfte um {{ (s.costs - s.income)|eur }} € — das Diagramm zeigt die Aufteilung der Gesamtkosten.</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<div class="aufteilung-grid">
|
<div class="tabelle-scroll">
|
||||||
<div>
|
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr><th>Posten</th><th>Kategorie</th><th>Art</th><th>Monatsbetrag</th><th>% der Einkünfte</th></tr>
|
<tr><th>Posten</th><th>Kategorie</th><th>Art</th><th>Monatsbetrag</th><th>% der Einkünfte</th></tr>
|
||||||
@@ -63,12 +62,11 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</tfoot>
|
</tfoot>
|
||||||
</table>
|
</table>
|
||||||
<p>Gesamte Einkünfte: <strong>{{ s.income|eur }} €</strong></p>
|
</div>
|
||||||
</div>
|
<p>Gesamte Einkünfte: <strong>{{ s.income|eur }} €</strong></p>
|
||||||
<div>
|
<div>
|
||||||
{% include "_aufteilung_torte.html" %}
|
{% include "_aufteilung_torte.html" %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -129,6 +129,8 @@ def test_ungueltiger_monat_und_unbekanntes_szenario(client):
|
|||||||
_login(client)
|
_login(client)
|
||||||
for params, text in (({"monat": "2030-13"}, "Ungültiger Monat"),
|
for params, text in (({"monat": "2030-13"}, "Ungültiger Monat"),
|
||||||
({"monat": "abc"}, "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": "999"}, "Unbekanntes Szenario"),
|
||||||
({"monat": MONAT, "szenario": "x"}, "Unbekanntes Szenario"),
|
({"monat": MONAT, "szenario": "x"}, "Unbekanntes Szenario"),
|
||||||
({"monat": MONAT, "szenario": "9" * 30}, "Unbekanntes Szenario")):
|
({"monat": MONAT, "szenario": "9" * 30}, "Unbekanntes Szenario")):
|
||||||
@@ -148,3 +150,11 @@ def test_doppelzaehlungs_hinweis(client, db):
|
|||||||
db.commit()
|
db.commit()
|
||||||
assert "⚠ Fixposten „Autorate“ zählt evtl. doppelt mit Kredit „Autokredit“" in _get(client, monat=MONAT).text
|
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
|
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>")
|
||||||
|
|||||||
Reference in New Issue
Block a user