feat: Betragseingabe mit Komma (data-type=amount in json-form)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -50,6 +50,14 @@
|
|||||||
out[k] = null;
|
out[k] = null;
|
||||||
} else if (kind === 'int') {
|
} else if (kind === 'int') {
|
||||||
out[k] = parseInt(v, 10);
|
out[k] = parseInt(v, 10);
|
||||||
|
} else if (kind === 'amount') {
|
||||||
|
// Deutsche Betragseingabe: "1.234,56" -> "1234.56". Ohne Komma
|
||||||
|
// bleibt der Wert unveraendert (Punkt-Eingaben funktionieren weiter).
|
||||||
|
var s = String(v).replace(/[\s€]/g, '');
|
||||||
|
if (s.indexOf(',') !== -1) {
|
||||||
|
s = s.replace(/\./g, '').replace(',', '.');
|
||||||
|
}
|
||||||
|
out[k] = s;
|
||||||
} else {
|
} else {
|
||||||
out[k] = v;
|
out[k] = v;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,7 @@
|
|||||||
hx-swap="none" hx-on::after-request="if(event.detail.successful){window.location.reload()}">
|
hx-swap="none" hx-on::after-request="if(event.detail.successful){window.location.reload()}">
|
||||||
<input type="date" name="anchor_date"
|
<input type="date" name="anchor_date"
|
||||||
value="{{ account.anchor_date.isoformat() if account.anchor_date is not none else '' }}" required>
|
value="{{ account.anchor_date.isoformat() if account.anchor_date is not none else '' }}" required>
|
||||||
<input type="text" name="anchor_balance" placeholder="500.00"
|
<input type="text" name="anchor_balance" data-type="amount" placeholder="500,00"
|
||||||
value="{{ account.anchor_balance|eur if account.anchor_balance is not none else '' }}" required>
|
value="{{ account.anchor_balance|eur if account.anchor_balance is not none else '' }}" required>
|
||||||
<button type="submit">Anker setzen</button>
|
<button type="submit">Anker setzen</button>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -36,7 +36,7 @@
|
|||||||
<form hx-ext="json-form" hx-post="/api/recurring" hx-swap="none"
|
<form hx-ext="json-form" hx-post="/api/recurring" hx-swap="none"
|
||||||
hx-on::after-request="if(event.detail.successful){window.location.reload()}">
|
hx-on::after-request="if(event.detail.successful){window.location.reload()}">
|
||||||
<label>Name <input type="text" name="name" required></label>
|
<label>Name <input type="text" name="name" required></label>
|
||||||
<label>Betrag <input type="text" name="amount" placeholder="-49.99" required></label>
|
<label>Betrag <input type="text" name="amount" data-type="amount" placeholder="-49,99" required></label>
|
||||||
<label>Rhythmus
|
<label>Rhythmus
|
||||||
<select name="rhythm" data-type="str">
|
<select name="rhythm" data-type="str">
|
||||||
{% for rh in rhythms %}<option value="{{ rh }}">{{ rh|de_label }}</option>{% endfor %}
|
{% for rh in rhythms %}<option value="{{ rh }}">{{ rh|de_label }}</option>{% endfor %}
|
||||||
@@ -120,7 +120,7 @@
|
|||||||
<form hx-ext="json-form" hx-post="/api/planned" hx-swap="none"
|
<form hx-ext="json-form" hx-post="/api/planned" hx-swap="none"
|
||||||
hx-on::after-request="if(event.detail.successful){window.location.reload()}">
|
hx-on::after-request="if(event.detail.successful){window.location.reload()}">
|
||||||
<label>Name <input type="text" name="name" required></label>
|
<label>Name <input type="text" name="name" required></label>
|
||||||
<label>Betrag <input type="text" name="amount" placeholder="-2000.00" required></label>
|
<label>Betrag <input type="text" name="amount" data-type="amount" placeholder="-2000,00" required></label>
|
||||||
<label>Fällig am <input type="date" name="due" required></label>
|
<label>Fällig am <input type="date" name="due" required></label>
|
||||||
<label>Kategorie
|
<label>Kategorie
|
||||||
<select name="category_id" data-type="int">
|
<select name="category_id" data-type="int">
|
||||||
@@ -175,8 +175,8 @@
|
|||||||
<form hx-ext="json-form" hx-post="/api/loans" hx-swap="none"
|
<form hx-ext="json-form" hx-post="/api/loans" hx-swap="none"
|
||||||
hx-on::after-request="if(event.detail.successful){window.location.reload()}">
|
hx-on::after-request="if(event.detail.successful){window.location.reload()}">
|
||||||
<label>Name <input type="text" name="name" required></label>
|
<label>Name <input type="text" name="name" required></label>
|
||||||
<label>Darlehenssumme <input type="text" name="principal" placeholder="10000.00" required></label>
|
<label>Darlehenssumme <input type="text" name="principal" data-type="amount" placeholder="10000,00" required></label>
|
||||||
<label>Zins p.a. (%) <input type="text" name="annual_rate_pct" placeholder="4.5" required></label>
|
<label>Zins p.a. (%) <input type="text" name="annual_rate_pct" data-type="amount" placeholder="4,5" required></label>
|
||||||
<label>Laufzeit (Monate) <input type="number" name="term_months" data-type="int" min="1" required></label>
|
<label>Laufzeit (Monate) <input type="number" name="term_months" data-type="int" min="1" required></label>
|
||||||
<label>Auszahlungsdatum <input type="date" name="payout_date" required></label>
|
<label>Auszahlungsdatum <input type="date" name="payout_date" required></label>
|
||||||
<label>Tilgungsart
|
<label>Tilgungsart
|
||||||
@@ -269,7 +269,7 @@
|
|||||||
{% for k in modifier_kinds %}<option value="{{ k }}">{{ k|de_label }}</option>{% endfor %}
|
{% for k in modifier_kinds %}<option value="{{ k }}">{{ k|de_label }}</option>{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
</label>
|
</label>
|
||||||
<label>Wert <input type="text" name="value" value="0"></label>
|
<label>Wert <input type="text" name="value" data-type="amount" value="0"></label>
|
||||||
<button type="submit">Modifikator hinzufügen</button>
|
<button type="submit">Modifikator hinzufügen</button>
|
||||||
</form>
|
</form>
|
||||||
</details>
|
</details>
|
||||||
|
|||||||
@@ -66,6 +66,22 @@ def test_planung_zeigt_deutsche_labels(client, db):
|
|||||||
assert "-600,00" in r.text
|
assert "-600,00" in r.text
|
||||||
|
|
||||||
|
|
||||||
|
def test_betragsfelder_haben_amount_typ_und_deutsche_platzhalter(client, db):
|
||||||
|
client.post("/login", data={"username": "admin", "password": "geheim"})
|
||||||
|
planung = client.get("/planung").text
|
||||||
|
# Fixposten-, Einmalposten-, Kredit-Formulare senden deutsche Eingaben:
|
||||||
|
assert planung.count('data-type="amount"') >= 4
|
||||||
|
assert '-49,99' in planung and '-2000,00' in planung
|
||||||
|
assert '-49.99' not in planung and '-2000.00' not in planung
|
||||||
|
# Anker-Formular wird nur je Konto gerendert - ohne Konto in der DB gaebe
|
||||||
|
# es keine Zeile mit dem Anker-Input (Template-Zweig "Keine Konten
|
||||||
|
# angelegt"), daher hier ein Konto anlegen wie in den Nachbartests.
|
||||||
|
db.add(Account(bank="dkb", iban="DE-AMT-1", name="Amount-Test", type="giro"))
|
||||||
|
db.commit()
|
||||||
|
index = client.get("/").text
|
||||||
|
assert 'placeholder="500,00"' in index
|
||||||
|
|
||||||
|
|
||||||
def test_import_page_has_dropzone_and_list(client):
|
def test_import_page_has_dropzone_and_list(client):
|
||||||
client.post("/login", data={"username": "admin", "password": "geheim"})
|
client.post("/login", data={"username": "admin", "password": "geheim"})
|
||||||
r = client.get("/import")
|
r = client.get("/import")
|
||||||
|
|||||||
Reference in New Issue
Block a user