fix(v3): Seiten-Möblierung aus BT-22-Freitext strippen (mehrseitige Rechnungen)

Bei mehrseitigen Rechnungen steht die erste 'Pos.'-Zeile auf Seite 1, die erste
echte Position aber erst nach einem Seitenumbruch. Dadurch rutschte die dazwischen
liegende Seiten-Möblierung (Seitenkopf RECHNUNG..Betrag €, Bank-/Registerzeilen)
in den globalen Freitext BT-22. extract_pre_position_freetext strippt jetzt diese
Möblierung (via _strip_bundle_furniture), bevor die Referenzzeilen entfernt werden.

Verifiziert: R26-252 hat nun leeren BT-22; die 7 bekannten Rechnungen behalten
ihren Freitext unverändert.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
dfuhrmann3 2026-07-14 16:06:36 +02:00
parent cd187585dd
commit 555272bcf6
1 changed files with 10 additions and 6 deletions

View File

@ -202,8 +202,11 @@ def extract_pre_position_freetext(text):
Position deterministisch aus dem PDF-Text - unabhaengig vom (oft unvollstaendigen) LLM. Alles
zwischen der ersten 'Pos.'-Zeile und der ersten Positionsnummer wird uebernommen, ausser den
Referenzzeilen (Auftragsbestaetigung/Angebot/Vergabeangebot/Lieferschein/Vertrag), die eigene
Felder haben. Gibt den Freitext zurueck ("" wenn keiner vorhanden) oder None, wenn die
Tabellenstruktur nicht erkennbar ist (dann bleibt ein evtl. LLM-Freitext unveraendert)."""
Felder haben, und der zwischen Seiten wiederholten Moeblierung (Seitenkopf, Bank-/Register-
zeilen, Uebertrag/Vortrag) - relevant bei mehrseitigen Rechnungen, deren erste 'Pos.'-Zeile auf
Seite 1 steht, die erste echte Position aber erst nach einem Seitenumbruch. Gibt den Freitext
zurueck ("" wenn keiner vorhanden) oder None, wenn die Tabellenstruktur nicht erkennbar ist
(dann bleibt ein evtl. LLM-Freitext unveraendert)."""
lines = [ln.strip() for ln in text.split("\n")]
header_idx = next((i for i, ln in enumerate(lines) if ln == "Pos."), None)
@ -217,10 +220,11 @@ def extract_pre_position_freetext(text):
if first_pos_idx is None:
return None
freetext_lines = [
ln for ln in lines[header_idx + 1:first_pos_idx]
if ln and not _REFERENCE_LINE_PATTERN.match(ln)
]
# Leere Zeilen raus, dann die Seiten-Moeblierung strippen (Seitenkopf 'RECHNUNG'..'Betrag €',
# Bank-/Registerzeilen, Uebertrag/Vortrag), zuletzt die Referenzzeilen mit eigenem Feld.
region = [ln for ln in lines[header_idx + 1:first_pos_idx] if ln]
region = _strip_bundle_furniture(region)
freetext_lines = [ln for ln in region if not _REFERENCE_LINE_PATTERN.match(ln)]
return "\n".join(freetext_lines)