feat: Schlagwort per Doppelklick oben in der Zeile bearbeiten

Bisher oeffnete der Doppelklick ein Eingabefeld im Chip selbst. Dort war nur
Platz fuer das Wort - der Betrag liess sich gar nicht aendern, weil die
Inline-Bearbeitung bewusst nur { word } geschickt hat.

Jetzt laedt der Doppelklick Wort und Betrag in dieselbe Zeile, in der auch
neue Schlagwoerter entstehen. Der Knopf wechselt auf ein Haekchen, daneben
steht Abbrechen (auch per Escape), und der bearbeitete Chip ist markiert.
Gespeichert wird per PATCH mit ausdruecklichem amount_cents, damit ein
geleertes Betragsfeld den Betrag auch wirklich loescht; ein geparstes 0 wird
zu null, weil das Schema gt=0 verlangt. Ueber POST ginge es nicht: das
antwortet bei vorhandenem Wort mit geaendertem Betrag mit 409.

Tests decken jetzt ab, dass Betrag mitgeaendert wird, beim Weglassen stehen
bleibt und bei ausdruecklichem null verschwindet.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Scarriffle
2026-08-20 13:49:43 +02:00
co-authored by Claude Opus 5
parent e503baa8a6
commit cdf21474cf
6 changed files with 127 additions and 81 deletions
+35
View File
@@ -135,6 +135,41 @@ def test_keyword_update_and_conflict(admin):
assert admin.patch(f"/api/categories/keywords/{kw['id']}", json={"word": "coop"}).status_code == 409
def test_keyword_update_amount(admin):
"""Wort und Betrag gemeinsam ändern – das Popup lädt beides in die Zeile."""
(a,) = _expense_cats(admin, 1)
kw = admin.post(
f"/api/categories/{a['id']}/keywords", json={"word": "sbb", "amount_cents": 500}
).json()
assert kw["amount_cents"] == 500
r = admin.patch(
f"/api/categories/keywords/{kw['id']}", json={"word": "sbb", "amount_cents": 750}
)
assert r.status_code == 200, r.text
assert r.json()["amount_cents"] == 750
# Nur das Wort schicken lässt den Betrag stehen.
r = admin.patch(f"/api/categories/keywords/{kw['id']}", json={"word": "sbb cff"})
assert r.status_code == 200, r.text
assert r.json()["amount_cents"] == 750
# Ausdrücklich null löscht ihn (geleertes Betragsfeld im Popup).
r = admin.patch(
f"/api/categories/keywords/{kw['id']}", json={"word": "sbb cff", "amount_cents": None}
)
assert r.status_code == 200, r.text
assert r.json()["amount_cents"] is None
gespeichert = admin.get(f"/api/categories/{a['id']}/keywords").json()
assert next(k for k in gespeichert if k["id"] == kw["id"])["amount_cents"] is None
# Null ist erlaubt, null-als-Betrag nicht.
r = admin.patch(
f"/api/categories/keywords/{kw['id']}", json={"word": "sbb cff", "amount_cents": 0}
)
assert r.status_code == 422
def test_below_threshold_not_flagged(admin):
giro = _account(admin, name="Giro NoFlag")
a, b = _expense_cats(admin, 2)