- Neuer Parser erkennt mehrzeilige Auszüge (N26 & Co.): Beschreibung → Value Date → Buchungsdatum → Betrag stehen auf eigenen Zeilen; Betrags-Zeile schließt eine Buchung ab, Kopf-/Fußzeilen (Name/Adresse/eigene IBAN/Seitenzahl/ Spaltenköpfe) werden gefiltert, Gegen-IBAN und Zweck werden übernommen - Alter Ein-Zeilen-Heuristik-Parser bleibt als Fallback - /documents/preview liefert zusätzlich die Seiten als PNG-Data-URLs (PyMuPDF get_pixmap, kein poppler nötig) - Tests: N26-artige mehrzeilige Fixture + Seiten-Rendering (74 grün); am echten 34-Seiten-Auszug 207 Buchungen erkannt Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
37 lines
1.2 KiB
Python
37 lines
1.2 KiB
Python
"""PDF-/Bild-Beleg-Import (Phase 5, lokal). Nutzt die Prüf-/Buchungslogik des CSV-Imports."""
|
|
|
|
from fastapi import APIRouter, Depends, File, Form, HTTPException, UploadFile
|
|
from sqlalchemy.orm import Session
|
|
|
|
from ..database import get_db
|
|
from ..deps import get_current_user, get_owned
|
|
from ..models import Account, User
|
|
from ..services import csv_import, ocr
|
|
|
|
router = APIRouter(prefix="/documents", tags=["documents"])
|
|
|
|
|
|
@router.post("/preview")
|
|
async def preview(
|
|
file: UploadFile = File(...),
|
|
account_id: int = Form(...),
|
|
db: Session = Depends(get_db),
|
|
user: User = Depends(get_current_user),
|
|
) -> dict:
|
|
account = get_owned(db, Account, account_id, user)
|
|
data = await file.read()
|
|
try:
|
|
text = ocr.extract_text(data, file.filename or "", file.content_type or "")
|
|
except ocr.ExtractionError as exc:
|
|
raise HTTPException(status_code=400, detail=str(exc))
|
|
candidates = ocr.parse_transactions(text)
|
|
rows = csv_import.detect_rows(db, user, account, candidates)
|
|
pages = ocr.render_pages(data, file.filename or "", file.content_type or "")
|
|
return {
|
|
"rows": rows,
|
|
"text": text[:8000],
|
|
"count": len(rows),
|
|
"filename": file.filename or "",
|
|
"pages": pages,
|
|
}
|