Files
rdmsandClaude Opus 5.5 4458300f43 feat: Tabellen per Spaltenkopf sortierbar (A11-T4)
Neues static/sort.js sortiert Tabellen clientseitig per Klick auf den
Spaltenkopf (⇅/▲/▼): Datum TT.MM.JJJJ, deutsche Zahlen/Beträge, sonst
Text (Intl.Collator 'de'). Sortierwert optional per td[data-sort]
(Punkt-Dezimal/ISO) überschreibbar, th[data-nosort] bekommt keinen
Button, table[data-sort-mode="server"] wird übersprungen (Buchungen
sortiert serverseitig, folgt in Task 5). Bearbeiten-/Tilgungsplan-
Zeilen (tr[data-sort-follow]) wandern mit ihrer Vorzeile mit.
Initialisierung über htmx.onLoad, greift auch bei nachgeladenen
Fragmenten.

Templates entsprechend annotiert (Planung, Szenarien, Admin, Index,
Salden, Import-Liste, Buchungen); Salden-Gesamtzeile dafür in ein
tfoot verschoben. test_gui.py::test_gui_zeigt_deutsche_betragsformate
angepasst, da das neue machinenlesbare data-sort-Attribut bewusst
Punkt-Dezimal führt (Interface-Konvention) - die Prüfung auf deutsches
Format im sichtbaren Text bleibt bestehen.

JS-Unit-/DOM-Tests unter tests/js (node --test, DOM-Teil optional via
jsdom), pytest-Wrapper skip ohne node (Fable-Gate führt sie per
Podman aus). Suite: 248 passed, 3 skipped (vorher 242/2).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-28 19:22:34 +02:00

70 lines
2.2 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{% extends "base.html" %}
{% block title %}Salden – Finanzberatung{% endblock %}
{% block content %}
<h1>Salden</h1>
<h2>Salden am {{ stichtag.strftime('%d.%m.%Y') }}</h2>
<form method="get" action="/salden" class="inline-form">
<input type="date" name="stichtag" value="{{ stichtag.isoformat() }}">
<button type="submit">Anzeigen</button>
</form>
<table>
<thead>
<tr><th>Konto</th><th>Saldo</th></tr>
</thead>
<tbody>
{% for account, balance in balances %}
<tr>
<td class="account">{{ account.name }}</td>
<td class="amount {{ 'neg' if balance < 0 else '' }}">{{ balance|eur }} €</td>
</tr>
{% else %}
<tr><td colspan="2">Keine Konten angelegt.</td></tr>
{% endfor %}
</tbody>
<tfoot>
<tr class="total-row">
<td><strong>Gesamt</strong></td>
<td class="amount {{ 'neg' if total < 0 else '' }}"><strong>{{ total|eur }} €</strong></td>
</tr>
</tfoot>
</table>
<h2>Monatsanfangs-Übersicht</h2>
<p class="hint">
Stand: Ende des Vortags (letzter Tag des Vormonats) — Buchungen am 1. eines
Monats zählen bewusst noch nicht zum "Anfangs"-Saldo, sonst würde der
Monatsanfang durch Buchungen des laufenden Monats verzerrt.
</p>
<table>
<thead>
<tr>
<th>Monat</th>
{% for account in accounts %}<th>{{ account.name }}</th>{% endfor %}
<th>Gesamt</th>
</tr>
</thead>
<tbody>
{% for row in months %}
<tr data-month="{{ row['month'].isoformat() }}">
<td data-sort="{{ row['month'].isoformat() }}">{{ row['month'].strftime('%m.%Y') }}</td>
{% for account, value in row['values'] %}
<td class="amount {{ 'neg' if value < 0 else '' }}">{{ value|eur }} €</td>
{% endfor %}
<td class="amount {{ 'neg' if row['total'] < 0 else '' }}">{{ row['total']|eur }} €</td>
</tr>
{% else %}
<tr><td colspan="{{ accounts|length + 2 }}">Keine bestätigten Buchungen vorhanden.</td></tr>
{% endfor %}
</tbody>
</table>
{% if accounts_without_anchor %}
<p class="hint">
Fußnote „ohne Anker — relative Werte" (Basis 0 statt Datei-Kontostand) gilt für:
{{ accounts_without_anchor|map(attribute='name')|join(', ') }}.
</p>
{% endif %}
{% endblock %}