Nachdem ich meine grundlegende Arbeitsweise mit Paperless-ngx nun detailliert vorgestellt habe, möchte ich noch etwas Content für die richtigen Nerds unter uns abliefern. Auf der Seite über Klassifizierungen habe ich ein paar Mal von einer Middleware gesprochen. Eigentlich trifft es das Wort gar nicht richtig, da es in Paperless-ngx derzeit keine Möglichkeiten gibt, eigene Programmabläufe während der Laufzeit des Systems einzubringen. Und komm mir jetzt nicht mit den neuen Workflows… das Feature hätte Potenzial, wenn… ach… lassen wir das fürs Erste.
Dunkelverarbeitung#
Na, kennst du das Wort? Gerade im Büro einer größeren Firma werden wir häufig mit diesem Begriff konfrontiert. Es bezeichnet die automatisierte Erledigung wiederkehrender Aufgaben, ohne dass ein Mensch darauf Einfluss nehmen muss. In deinem papierlosen Büro wirst du dich sicher auch immer wieder selbst dabei ertappen, die immer und immer selben Tätigkeiten zu erledigen. Haha, habe ich dich ertappt 😎?
Eigentlich bringt Paperless-ngx schon viele tolle Möglichkeiten mit, wie zum Beispiel die Auto-Klassifizierung. Wenn es jedoch an die Details geht, müssen wir immer wieder selbst nacharbeiten.
Ein Beispiel#
Wenn ich meine allmonatlichen Kontoauszüge an Paperless-ngx übergebe, sollen sie immer eine Kombination aus Jahr und Monat im Titel tragen: 2024/03
. Und zwar nicht des Monats, in dem das Dokument erstellt oder vom Document Consumer konsumiert wurde, sondern für den Monat, für den der Kontoauszug schlichtweg ist. Ganz einfach.
Das System generiert keine passenden Titel für meine Kontoauszüge, und manuelle Anpassungen sind oft umständlich, besonders wenn Dokumente über das Share Sheet vom iPhone hochgeladen werden. Und mal im Ernst: möchtest du bei jedem Dokument wirklich noch darüber nachdenken, den Titel anzupassen? Versuch es ruhig. Das klappt sicher anfangs noch gut 😁. Auf der Zeitachse führt es zu Inkonsistenzen in der Benennung deiner Dokumente.
Paperless Secretary#
Aus diesem und anderen Gründen erstellte ich für Paperless-ngx ein Python Modul namens pypaperless, welches die API anspricht und einem Entwickler die Möglichkeit gibt, Einfluss auf sein DMS zu nehmen.
Little api client for paperless(-ngx).
Dieses Modul bildet die Grundlage für mein Projekt Paperless Secretary, also einen virtuellen Sekretär, der wiederkehrende Aufgaben für mich erledigt. Meine Aufgabe besteht darin, diese wiederkehrenden Aufgaben zu identifizieren und entsprechende Bearbeitungsregeln zu erstellen.
Regel für Kontoauszüge#
Kommen wir auf mein oben genanntes Beispiel zurück, welches ich wie folgt gelöst habe:
"""N26; Kontoauszüge; Titel bearbeiten."""
import re
from pypaperless.models import Document
from .base import Rule
from .const import CORRESPONDENT_N26, DOCUMENT_TYPE_KONTOAUSZUG
# 1)
_rule = Rule("N26; Kontoauszüge; Titel => yyyy/MM (Sparkonto)")
# 2)
@_rule.condition(name="correspondent == N26")
async def check_correspondent(item: Document) -> bool:
return item.correspondent == CORRESPONDENT_N26
# 3)
@_rule.condition(name="document_type == Kontoauszug")
async def check_document_type(item: Document) -> bool:
return item.document_type == DOCUMENT_TYPE_KONTOAUSZUG
# 4)
@_rule.condition(name="title !~ yyyy/MM")
async def check_document(item: Document) -> bool:
content = item.content or ""
if "Sparkonto" in content:
pattern = r"^\d{4}/(0[1-9]|1[0-2])\sSparkonto*$"
else:
pattern = r"^\d{4}/(0[1-9]|1[0-2])*$"
return not bool(re.match(pattern, item.title))
# 5)
@_rule.action(name="Apply new document title.")
async def apply_title(*, rule: Rule, item: Document) -> bool:
match = re.search(r"\d{2}\.(\d{2})\.(\d{4}) bis \d{2}\.\1\.\2", content)
if match:
year = match.group(2)
month = match.group(1)
content = item.content or ""
item.title = f"{year}/{month}"
if "Sparkonto" in content:
item.title += " Sparkonto"
# 6)
if not rule.dry_run:
return await item.update()
return False
Keine Sorge, sieht schlimmer aus, als es wirklich ist 😄. Ich habe ein paar Stellen im Code nummeriert und gehe nun einmal kurz darauf ein.
- Es wird eine neue
Rule
erstellt. Hierbei handelt es sich um eine Klasse, die zum Core des Secretary gehört. Der Secretary verarbeitet solche Regeln dann, indem er sie auf Dokumente in Paperless-ngx anwendet. - Der Regel wird eine
Condition
angeheftet. Das bedeutet, dass die Regel nur ausgeführt wird, wenn die Bedingung erfüllt wird. Konkret prüft sie also, ob das Dokument von meiner Bank ist. - Wieder eine
Condition
. Diesmal wird überprüft, ob das Dokument ein Kontoauszug ist. - Die letzte
Condition
überprüft, ob der Kontoauszug einen Titel in dem Formatyyyy/MM
oderyyyy/MM Sparkonto
hat, so wie ich mir das wünsche. Besser gesagt: ob genau dieser Fall hier nicht zutrifft. - Jetzt wird die
Action
implementiert. Das ist die Aktion, die ausgeführt wird, wenn alle Bedingungen zutreffen. Im Dokument-Inhalt ist bei meiner Bank ein Hinweis enthalten, ob der Kontoauszug für mein Girokonto oder Tagesgeldkonto ist. Deswegen überprüft die Aktion das kurz und bildet dann aus dem Inhalt des Dokuments den korrekten Titel. - Wenn der Secretary gerade nicht im Testmodus ausgeführt wird, wird der neue Titel dann letztendlich in Paperless-ngx festgelegt.
Bei der Klasse Document
handelt es sich um ein Objekt von pypaperless. Dieses Objekt stellt nicht nur sämtliche Daten aus Paperless-ngx bereit, sondern auch Funktionen zum ändern und löschen von eben solchen Daten.
Weitere Use-Cases#
Es gibt zahlreiche Anwendungsmöglichkeiten für diese Regeln. In meinem Fall haben sich folgende Use-Cases herauskristallisiert:
- Titel von Dokumenten anpassen
- Custom Fields von Dokumenten automatisch befüllen
- Reminder für Wiedervorlagen/Todos
- Verschiedene Validierungen
Ich bin gespannt, welche Herausforderungen du mit diesen Regeln angehen würdest. Teile mir gerne deine Ideen mit!
Feature-Foto von Chris Ried auf Unsplash