feat: Buchungen serverseitig nach Spalte sortierbar (A11-T5)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
from datetime import date, timedelta
|
||||
from decimal import Decimal
|
||||
|
||||
import pytest
|
||||
|
||||
from app.models.tables import Account, Category, Transaction
|
||||
|
||||
H = {"Authorization": "Bearer test-key"}
|
||||
|
||||
|
||||
def _tx(db, acc, day, amount, purpose="Zweck", counterparty="X", category=None, n=[0]):
|
||||
n[0] += 1
|
||||
db.add(Transaction(account_id=acc.id, booking_date=day, amount=Decimal(amount),
|
||||
purpose=purpose, counterparty=counterparty, status="confirmed",
|
||||
category_id=category.id if category else None,
|
||||
dedup_hash=f"sort-{n[0]}"))
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def small(db):
|
||||
zeta = Account(bank="t", iban="DE-SO-1", name="Zeta", type="giro")
|
||||
alpha = Account(bank="t", iban="DE-SO-2", name="alpha", type="giro")
|
||||
kat = Category(name="Miete")
|
||||
db.add_all([zeta, alpha, kat])
|
||||
db.flush()
|
||||
_tx(db, zeta, date(2026, 1, 3), "-5.00", "b-Zweck", "Bert", kat)
|
||||
_tx(db, alpha, date(2026, 1, 1), "20.00", "A-Zweck", "anna", None)
|
||||
_tx(db, zeta, date(2026, 1, 2), "-30.00", "c-Zweck", "Carl", kat)
|
||||
db.commit()
|
||||
|
||||
|
||||
def _amounts(client, qs):
|
||||
r = client.get(f"/api/transactions?{qs}", headers=H)
|
||||
assert r.status_code == 200
|
||||
return [Decimal(t["amount"]) for t in r.json()]
|
||||
|
||||
|
||||
def test_standard_bleibt_datum_aufsteigend(client, small):
|
||||
assert _amounts(client, "") == [Decimal("20.00"), Decimal("-30.00"), Decimal("-5.00")]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("sort,dir,expected", [
|
||||
("betrag", "asc", ["-30.00", "-5.00", "20.00"]),
|
||||
("betrag", "desc", ["20.00", "-5.00", "-30.00"]),
|
||||
("datum", "desc", ["-5.00", "-30.00", "20.00"]),
|
||||
("konto", "asc", ["20.00", "-5.00", "-30.00"]), # alpha vor Zeta (case-insensitiv), Gleichstand -> id
|
||||
("zweck", "asc", ["20.00", "-5.00", "-30.00"]), # A-, b-, c-Zweck
|
||||
("empfaenger", "desc", ["-30.00", "-5.00", "20.00"]), # Carl, Bert, anna
|
||||
("kategorie", "asc", ["-5.00", "-30.00", "20.00"]), # Miete (id-Reihenfolge), unkategorisiert zuletzt
|
||||
("kategorie", "desc", ["-30.00", "-5.00", "20.00"]), # unkategorisiert auch absteigend zuletzt
|
||||
])
|
||||
def test_sortierung_je_spalte(client, small, sort, dir, expected):
|
||||
assert _amounts(client, f"sort={sort}&dir={dir}") == [Decimal(e) for e in expected]
|
||||
|
||||
|
||||
def test_ungueltige_werte_fallen_auf_standard(client, small):
|
||||
assert _amounts(client, "sort=foo;drop&dir=hoch") == _amounts(client, "")
|
||||
client.post("/login", data={"username": "admin", "password": "geheim"})
|
||||
assert client.get("/buchungen?sort=foo&dir=bar").status_code == 200
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def many(db):
|
||||
acc = Account(bank="t", iban="DE-SO-3", name="Viel", type="giro")
|
||||
db.add(acc)
|
||||
db.flush()
|
||||
for i in range(1, 61): # Beträge i,37; Datum verwürfelt
|
||||
_tx(db, acc, date(2026, 1, 1) + timedelta(days=(i * 7) % 60), f"{i}.37", f"Miete {i}")
|
||||
db.commit()
|
||||
|
||||
|
||||
def test_sortierung_gilt_ueber_alle_seiten(client, many):
|
||||
client.post("/login", data={"username": "admin", "password": "geheim"})
|
||||
p1 = client.get("/buchungen?sort=betrag&dir=desc").text
|
||||
p2 = client.get("/buchungen?sort=betrag&dir=desc&page=2").text
|
||||
assert ">60,37</td>" in p1 and ">1,37</td>" not in p1
|
||||
assert ">1,37</td>" in p2 and ">60,37</td>" not in p2
|
||||
|
||||
|
||||
def test_links_erhalten_filter_und_sortierung(client, many):
|
||||
client.post("/login", data={"username": "admin", "password": "geheim"})
|
||||
html = client.get("/buchungen?q=Miete&sort=betrag&dir=asc").text
|
||||
# Aktiver Spaltenkopf kehrt die Richtung um, übernimmt den Filter, ohne page.
|
||||
assert 'href="/buchungen?q=Miete&status=confirmed&sort=betrag&dir=desc"' in html
|
||||
# Inaktive Spalte startet aufsteigend.
|
||||
assert 'href="/buchungen?q=Miete&status=confirmed&sort=datum&dir=asc"' in html
|
||||
# Pager behält Filter + Sortierung.
|
||||
assert "q=Miete&status=confirmed&sort=betrag&dir=asc&page=2" in html
|
||||
assert "▲" in html
|
||||
Reference in New Issue
Block a user