import io import pytest fitz = pytest.importorskip("fitz") def _account(admin): r = admin.post("/api/accounts", json={"name": "Beleg", "type": "girokonto", "currency": "EUR"}) assert r.status_code == 201 return r.json() def _make_pdf() -> bytes: doc = fitz.open() page = doc.new_page() page.insert_text((50, 72), "15.03.2026 REWE Supermarkt Zuerich -50.00") page.insert_text((50, 96), "25.03.2026 Gehalt Firma AG 3000.00") page.insert_text((50, 120), "Kein Datum hier, nur Text 12.34") return doc.tobytes() def test_parse_transactions_heuristic(): from app.services import ocr text = ( "Kontoauszug März 2026\n" "15.03.2026 REWE Supermarkt -50,00\n" "2026-03-25 Gehalt 3'000.00\n" "Zwischensumme\n" ) rows = ocr.parse_transactions(text) assert len(rows) == 2 assert rows[0]["date"] == "2026-03-15" assert rows[0]["amount_cents"] == -5000 assert "REWE" in rows[0]["payee"] assert rows[1]["date"] == "2026-03-25" assert rows[1]["amount_cents"] == 300000 # Schweizer Tausender-Apostroph N26_TEXT = "\n".join([ "GUIDO OLIVIER SCHMIT", "Riedstrasse 18, 8908 Hedingen", "IBAN: DE54100110012138281295 • BIC: NTSBDEB1XXX", "Issued on", "20.08.2026", "1 / 2", "Description", "Booking Date", "Amount", "La Flamme", "Mastercard • Bars & Restaurants", "Value Date 31.01.2026", "01.02.2026", "-97,00€", "Guido Schmit", "Income", "IBAN: LT293250031382885526 • BIC: REVOLT21XXX", "Gesendet von Revolut", "Value Date 01.02.2026", "01.02.2026", "+43,00€", "Noemi Konig", "Outgoing Transfers", "IBAN: DE65120300001207628981 • BIC: BYLADEM1001", "WG Miete Guido Schmit", "Value Date 02.02.2026", "02.02.2026", "-288,00€", ]) def test_parse_transactions_n26_blocks(): from app.services import ocr rows = ocr.parse_transactions(N26_TEXT) assert len(rows) == 3 assert rows[0]["date"] == "2026-02-01" assert rows[0]["amount_cents"] == -9700 assert rows[0]["payee"] == "La Flamme" assert rows[1]["amount_cents"] == 4300 # Eingang (+) assert rows[1]["payee"] == "Guido Schmit" assert rows[1]["counterparty_iban"] == "LT293250031382885526" assert rows[2]["amount_cents"] == -28800 assert rows[2]["payee"] == "Noemi Konig" # Gegen-IBAN der Miete – NICHT die eigene Kopf-IBAN (DE54…). assert rows[2]["counterparty_iban"] == "DE65120300001207628981" def test_render_pages_pdf(): from app.services import ocr doc = fitz.open() doc.new_page() pages = ocr.render_pages(doc.tobytes(), "beleg.pdf", "application/pdf") assert len(pages) == 1 assert pages[0].startswith("data:image/png;base64,") def test_pdf_document_preview(admin): acc = _account(admin) pdf = _make_pdf() r = admin.post( "/api/documents/preview", files={"file": ("beleg.pdf", io.BytesIO(pdf), "application/pdf")}, data={"account_id": str(acc["id"])}, ) assert r.status_code == 200, r.text body = r.json() assert body["count"] == 2 rows = body["rows"] kinds = {(row["type"], row["amount_cents"]) for row in rows} assert ("expense", -5000) in kinds assert ("income", 300000) in kinds