From 4a950acd85f440c5a5cba1645c8a33e3511e64ec Mon Sep 17 00:00:00 2001 From: Scarriffle Date: Mon, 27 Jul 2026 10:45:08 +0200 Subject: [PATCH] Backend: Zeilenpreise als Kaufpreis-Kandidaten anbieten MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bei einer Rechnung mit mehreren Artikeln soll man den Zeilenpreis des passenden Produkts wählen können. Die Kandidatenliste enthaelt daher wieder alle geldartigen Betraege (Zeilen- und Summenbetraege), nur ohne MwSt-Satz und Nicht-Geld-Zahlen; der Auto-Tipp bleibt die Gesamtsumme und steht vorne. Co-Authored-By: Claude Opus 4.8 --- backend/app/services/warranty.py | 21 +++++++++++---------- backend/tests/test_warranty.py | 9 +++++++++ 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/backend/app/services/warranty.py b/backend/app/services/warranty.py index 30369c8..3d59946 100644 --- a/backend/app/services/warranty.py +++ b/backend/app/services/warranty.py @@ -309,22 +309,23 @@ def guess_price_cents(text: str) -> int | None: def guess_price_candidates(text: str) -> list[int]: - """Plausible Beträge (Rappen/Cent), bester zuerst, ohne Dubletten. + """Alle geldartigen Beträge (Rappen/Cent) zur Auswahl, bester Tipp zuerst. - Nur Beträge, die nach Preis aussehen – d.h. mit Währung in der Nähe oder kurz - hinter einem Summen-Stichwort. Beliebige Zahlen (Mengen, Artikelnummern, - Datumsteile) fliegen raus. So bleibt die Auswahl kurz und brauchbar. + Bei einer Rechnung mit mehreren Artikeln soll man auch den Zeilenpreis des + passenden Produkts wählen können – deshalb kommen hier alle Beträge rein + (Zeilen- und Summenbeträge). Mengen, Artikelnummern und Prozentsätze fallen + schon in :func:`_price_hits` weg. Der automatische Tipp (Gesamtsumme) steht + vorne. """ if not text: return [] - plausibel = { - c for pos, c, cur in _price_hits(text) if cur or _near_total(text, pos) - } - if not plausibel: + werte = {c for _pos, c, _cur in _price_hits(text)} + werte.discard(0) + if not werte: return [] - kandidaten = sorted(plausibel, reverse=True) + kandidaten = sorted(werte, reverse=True) best = guess_price_cents(text) if best is not None and best in kandidaten: kandidaten.remove(best) kandidaten.insert(0, best) - return kandidaten[:8] + return kandidaten[:12] diff --git a/backend/tests/test_warranty.py b/backend/tests/test_warranty.py index 6a21e0c..26dd117 100644 --- a/backend/tests/test_warranty.py +++ b/backend/tests/test_warranty.py @@ -147,3 +147,12 @@ def test_galaxus_mwst_satz_ist_kein_preis(): def test_galaxus_garantieende_aus_zeitraum(): assert guess_warranty_until(GALAXUS, acquired_on=date(2025, 10, 5)) == date(2027, 10, 6) + + +def test_galaxus_zeilenpreise_sind_kandidaten(): + # Bei mehreren Artikeln soll man den Zeilenpreis wählen können. + kandidaten = guess_price_candidates(GALAXUS) + assert 14680 in kandidaten # Gesamt inkl. + assert 11100 in kandidaten # Logitech, Betrag/Preis inkl. + assert 3580 in kandidaten # Kabel, Betrag inkl. + assert 810 not in kandidaten # MwSt-Satz weiterhin draußen