Files
paperlessmanager/docs/superpowers/specs/2026-11-02-duplikat-neue-version-design.md
T

12 KiB
Raw Blame History

Duplikat → neue Version (Design)

Stand: 02.11.2026

Worum es geht

Wird ein Beleg ein zweites Mal mit derselben internen Belegnummer nach Paperless gebracht, soll er nicht als zweites, eigenständiges Dokument landen. Stattdessen sieht der Benutzer beide Belege nebeneinander und entscheidet:

  • Als neue Version hinzufügen – die Datei wird über die Versionsfunktion von Paperless-NGX an das vorhandene Dokument gehängt.
  • Verwerfen – der Beleg wird nicht importiert.

Typische Fälle:

  1. Korrigierte Rechnung: Lieferant schickt eine fehlerbereinigte Fassung mit derselben Rechnungsnummer.
  2. Nachträglich geteilt: Ein Dokument enthielt zwei Belege. Der Benutzer teilt das PDF von Hand und sendet es neu; der Teil mit der bereits vergebenen Belegnummer wird zur neuen Version.

Ziele

  • Gleicher Vergleichsdialog im E-Mail-Import und im Posteingang (Scanner).
  • Oben im Dialog eine Leiste mit Auffälligkeiten: abweichende Seitenzahl und abweichende Wortzahl. Darunter beide PDFs nebeneinander.
  • Maßgeblich für „Belegnummer existiert schon“ ist Paperless (Custom Field 7 = interne Belegnummer). Das ist die wichtige Prüfung.

Nicht-Ziele

  • Umbau der Task-Bearbeitung – läuft unverändert weiter.
  • Checksummen-Duplikate umgehen (gleiche Datei erneut importieren) – bleibt wie heute, wird in docs/todos.md notiert.
  • Inhaltliche Analyse (Beträge, Datum, Positionen) für die Auffälligkeiten – dafür gibt es noch keine Auswertung.
  • Metadaten des vorhandenen Dokuments ändern (Titel, Tags, Custom Fields, Korrespondent bleiben unverändert; nur die Datei kommt als Version dazu).
  • Nachgelagerte Automatik für die Version (Postprocessing-Regeln, Mail, WebDAV-Export, Agrarmonitor-Austausch/Storno) – wird vorerst unterdrückt, die fachliche Logik kommt später (siehe Todos).

Anti-Ziele (wäre ein Fehlschlag, auch wenn es „funktioniert“)

  • Ein Beleg mit vorhandener Belegnummer landet doch als zweites Dokument in Paperless, ohne dass der Benutzer es so entschieden hat.
  • Eine Version wird an das falsche Dokument gehängt.
  • „Verwerfen“ lässt eine reservierte Belegnummer oder einen halb angelegten Task zurück.

Paperless-API (am Live-System geprüft, API v10)

  • POST /api/documents/{id}/update_version/ – multipart, Feld document (Datei, Pflicht), version_label (optional, max. 64 Zeichen). Antwort: String (vermutlich die Consume-Task-ID; Verarbeitung asynchron).
  • PATCH|DELETE /api/documents/{id}/versions/{version_id}/ – Label ändern/löschen.
  • DocumentVersionInfo: id, added, version_label, checksum, is_root.

Ablauf E-Mail-Import (MailImportWizard.tsx)

Schritte: 0 Zuordnung → 1 Bearbeitung → 2 Abschluss.

  1. In Schritt 1 („Bearbeitung“) hat ein Beleg den Modus Manuell und eine Belegnummer (Jahr + 6-stellige Nummer → JJJJ-NNNNNN).
  2. Beim Klick auf Weiter (Schritt 1 → 2) prüft das Backend für jeden manuellen Beleg in Paperless, ob die Belegnummer schon vergeben ist (CF7 und ASN, siehe „Eindeutigkeit des Treffers“).
  3. Gibt es Treffer, öffnet sich vor dem Schrittwechsel der Vergleichsdialog – nacheinander für jeden betroffenen Beleg.
    • Links: vorhandenes Dokument aus Paperless. Rechts: der neue Beleg (bei geteilten Anhängen nur die gewählten Seiten).
    • Als neue Version hinzufügen → Beleg wird für den Import als „Version zu Dokument X“ markiert.
    • Verwerfen → Beleg wird auf IGNORE gestellt. Stehen danach alle Belege der Mail auf IGNORE, greift die bestehende Logik (Mail als ignoriert markieren).
    • Dialog schließen (X) ohne Entscheidung → kein Schrittwechsel, der Benutzer bleibt in Schritt 1.
  4. Beim Import ausführen werden Version-Belege nicht per post_document hochgeladen, sondern per update_version an Dokument X gehängt.
    • Die ASN-Sperre (validateAsnNotExists) und der Belegnummer-Duplikatcheck entfallen für diese Belege – sonst würde der Import abbrechen.
    • Hochgeladen wird wie beim normalen Import das Original-PDF bzw. die gewählten Seiten, ohne eingebrannten Stempel.
    • Kein neuer Enrichment-Task in der tasks-Tabelle nötig (Metadaten bleiben).
    • Im Attachment-Datensatz wird die Dokument-ID X unter dem jeweiligen Bereich eingetragen, damit der Anhang als importiert gilt.
  5. Die Checksummen-Prüfung (recheckDuplicates) bleibt unverändert.

Ablauf Posteingang (InboxDetailPage.tsx, inbox-postprocessor)

Heute: runPaperless meldet ein Duplikat mit duplicateOfDocumentId; der Wizard bietet „Neue Version erstellen“ (= Duplikatprüfung überspringen und als zweites Dokument hochladen), „Vergleichen“ und „Überspringen“. Im Vergleichsdialog ist „Neue Version anlegen“ noch ein TODO.

Neu:

  • Liefert der Duplikat-Treffer eine Paperless-Dokument-ID, öffnet sich der Vergleichsdialog automatisch.
  • Als neue Version hinzufügen → Backend verarbeitet den Abschnitt erneut, lädt die fertige PDF (nach allen Bearbeitungen/Stempeln) aber per update_version an Dokument X hoch statt per post_document. Danach ist der Abschnitt „erfolgreich“.
  • Verwerfen → entspricht dem heutigen „Überspringen“ (Text wird umbenannt).
  • Der bisherige Weg „Duplikatprüfung überspringen und als eigenes Dokument hochladen“ entfällt in der Oberfläche.
  • Duplikate ohne Dokument-ID (Checksumme, lokaler Task ohne PaperlessDocumentID) behalten den heutigen Weg: nur Verwerfen/Überspringen.
  • Rechts im Dialog wird der betroffene Abschnitt gezeigt, nicht das ganze Inbox-Dokument (heute zeigt der Dialog das ganze Dokument).

Nachgelagerte Automatik unterdrücken

Entscheidung des Nutzers: Nach dem Hinzufügen einer Version bekommt das (Stamm-)Dokument den Tag „neue Version hochgeladen“ (ID 21). Der Nutzer konfiguriert die Postprocessing-Regeln so, dass Belege mit Tag 21 ignoriert werden. Im Code gibt es keine eigene Unterdrückung (keine Markierung, keine Änderung an der Webhook-Warteschlange).

  • Reihenfolge: erst Tag 21 setzen (Tags lesen, 21 ergänzen, vorhandene behalten), dann update_version. Schlägt der Versions-Upload fehl, wird Tag 21 wieder entfernt – aber nur, wenn er vorher nicht schon gesetzt war.
  • Entfernen von Tag 21 ist Sache des Nutzers.
  • Die Anreicherung in processDocumentById (Tag 17, bereit/nicht bereit, Titel-Template) läuft beim Webhook weiterhin – nur die Regeln greifen nicht.

Im Posteingang betrifft die Abfrage nur die Aktion „An Paperless senden“. Die übrigen Aktionen des Barcode-Templates (MAIL, EXPORT) davor und danach laufen normal: Die Aktionen davor sind beim Erkennen des Duplikats bereits gelaufen und werden nicht wiederholt; die Aktionen danach werden nach der Entscheidung (Version oder Verwerfen) ganz normal ausgeführt.

Vergleichsdialog (gemeinsame Komponente)

  • Eine Komponente für beide Stellen (aus CompareModal herauslösen).
  • Titel z. B. „Belegnummer 2026-000123 existiert bereits“.
  • Auffälligkeiten-Leiste oben (Ant Design Alert/Tags):
    • Seitenzahl: „Seiten: 2 (vorhanden) → 3 (neu)“ – hervorgehoben bei Abweichung.
    • Wortzahl: „Wörter: 412 → 398“ – hervorgehoben bei Abweichung.
    • Ist eine Zahl nicht ermittelbar (z. B. PDF ohne Textebene), steht dort „nicht ermittelbar“ statt einer Abweichung.
    • Keine Abweichung → kurzer neutraler Hinweis „Seiten- und Wortzahl gleich“.
  • Darunter beide PDFs nebeneinander (mobil untereinander), wie heute.
  • Knöpfe: Verwerfen / Als neue Version hinzufügen (primär).

Kennzahlen ermitteln (Backend-Endpunkt)

  • Vorhanden (Paperless): Seitenzahl aus page_count des Dokuments, Wortzahl aus dessen content (OCR-Text von Paperless). Verglichen wird mit der aktuellen (neuesten) Fassung des Dokuments.
  • Neu: Seitenzahl per pdf-lib, Wortzahl aus der Textebene per pdf-parse (beides bereits Abhängigkeiten im Backend). Keine Textebene → „nicht ermittelbar“.
  • Wortzählung: Text an Leerraum trennen, nur Tokens mit mindestens einem Buchstaben oder einer Ziffer zählen.

Versionsbezeichnung

version_label = „Korrektur vom TT.MM.JJJJ“ (Datum des Hinzufügens). Max. 64 Zeichen.

Eindeutigkeit des Treffers

Geprüft wird immer gegen Paperless, und zwar über beide Merkmale, die aus der internen Belegnummer folgen:

  • CF7 = interne Belegnummer (z. B. 2026-000123)
  • ASN = interne Belegnummer ohne Bindestrich (z. B. 2026000123) – auch im Posteingang, unabhängig von einem im Template separat hinterlegten ASN-Feld.

„Als neue Version hinzufügen“ wird nur angeboten, wenn alle Treffer auf genau ein Dokument zeigen. Zeigen CF7- und ASN-Treffer auf verschiedene Dokumente oder gibt es mehrere CF7-Treffer, zeigt der Dialog einen Hinweis und bietet nur Verwerfen an. Dafür muss die Suche alle Treffer liefern, nicht nur den ersten.

Am Live-System zu prüfen (vor/bei der Umsetzung)

  • Antwort von update_version (Task-ID?) und wie der Abschluss erkennbar ist.
  • Liefern CF7-Suche, GET /documents/{id}/ (content, page_count) und /download/ bei einem versionierten Dokument die Stamm-ID bzw. die neueste Fassung? update_version muss immer auf die Stamm-ID zielen.

Todos-Einträge

In docs/todos.md ergänzen:

  1. „Duplikatprüfung per Checksumme gezielt umgehen können, wenn ein bereits importiertes Dokument bewusst erneut importiert (z. B. geteilt) werden soll.“
  2. „Neue Version eines Belegs in Agrarmonitor nachziehen (derzeit unterdrückt):
    • Beleg noch im AM-Posteingang → dort löschen und neue Fassung senden.
    • Beleg verarbeitet, aber nicht gebucht → im jeweiligen Einkauf das vorhandene Dokument löschen und die neue Fassung hochladen.
    • Beleg bereits gebucht → Storno-Beleg zum gebuchten Beleg erstellen und die neue Fassung über die jeweilige E-Mail-Adresse neu in den AM-Posteingang senden. Außerdem klären, ob Postprocessing-Regeln (Mail an Buchhaltung, Export) für Versionen laufen sollen.“
  3. „Task-Bearbeitung (PaperlessTaskProcessorService, 30-s-Cron) auf den Paperless-Webhook umstellen. Beim Upload werden die Metadaten schon gesetzt; übrig bleiben Owner entfernen, Notizen, Anlage-Verknüpfung (Feld 8) und die lokale Buchführung (Task/Attachment/documents) – die brauchen die Dokument-ID nach dem Consume.“

Dem Umsetzer überlassen

  • Schnitt der Backend-Endpunkte (eigener Endpunkt für „Belegnummern prüfen“ und „Kennzahlen“, oder zusammengefasst).
  • Wie das Ergebnis von update_version verfolgt wird (Task-Polling wie beim normalen Upload, sofern die Antwort eine Task-ID ist).
  • Tests: mindestens Unit-Tests für Wortzählung/Auffälligkeiten und für die Entscheidung Upload vs. Version im Backend.

Eigene Entscheidungen (nicht ausdrücklich vom Nutzer)

  • Versionsbezeichnung „Korrektur vom …“.

  • Version nur bei eindeutigem Treffer (CF7 und ASN zeigen auf dasselbe Dokument); sonst nur Verwerfen.

  • E-Mail-Import: Version wird wie normale Importe ohne eingebrannten Stempel hochgeladen; keine erneute Barcode-Notiz (die hat das Stammdokument schon).

  • Automatisches Öffnen des Dialogs im Posteingang; Wegfall von „als eigenes Dokument hochladen“.

  • Dialog schließen ohne Entscheidung = im Schritt bleiben.

  • Rechts nur der betroffene Abschnitt statt des ganzen Inbox-Dokuments.

Ergebnisse Live-Prüfung (02.11.2026, nur lesend)

  • GET /api/documents/ liefert je Dokument root_document (bei Stammdokumenten null) und versions (Liste inkl. des Stamms selbst mit is_root: true). Normalisierung root_document ?? id ist damit tragfähig.
  • Im System gibt es derzeit kein Dokument mit mehr als einer Version; ob Versionen in Listen-/Suchergebnissen als eigene Einträge auftauchen, ist daher offen – die Normalisierung deckt beide Fälle ab.
  • Der schreibende Teil (Test-Upload einer Version, Antwortformat, Webhook) wird bei der Abnahme in Task 7 mit Freigabe des Nutzers nachgeholt.