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>
70 lines
2.2 KiB
HTML
70 lines
2.2 KiB
HTML
{% 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 %}
|