Anfängerfehler
Danke dir!
Viele grüße!
Speicherpfad für Rechnungen
Dieser Code legt fest, wie Rechnungen in Paperless-ngx gespeichert werden. Der Pfad organisiert die Dokumente automatisch nach Benutzername, Jahr und einem eindeutigen Dateinamen.
Code:
{{ owner_username }}/Rechnungen/{{ created_year }}/{{ created_year }}-{{ created_month }}-{{ created_day }}_{{ correspondent.replace(" ", "_") }}{% if "Belegnummer" in custom_fields and custom_fields.Belegnummer.value %}_{{ custom_fields.Belegnummer.value | replace(" ", "_") }}{% endif %}
Erklärung:
{{ owner_username }}
) und unter „Rechnungen“ nach Jahr ({{ created_year }}
) abgelegt.correspondent
) und, falls vorhanden, die Belegnummer. Alle Leerzeichen werden durch Unterstriche (_
) ersetzt, um Probleme zu vermeiden.Für eine Rechnung vom 15.08.2023 von Lieferant XY mit Belegnummer 12345 wird der Pfad:
maxmustermann/Rechnungen/2023/2023-08-15_Lieferant_XY_12345
Dieser Code hilft, Dokumente klar und einheitlich zu speichern.
Kleiner Tipp: es muss jetzt nicht mehr alles in einer Zeile stehen, mehrere Zeilen sind durchaus erlaubt und auch leichter lesbar. Vielleicht magst deinen Code ja nochmal umbrechen?
Hier ist der Code mit Kommentaren:
# Hauptverzeichnis des Nutzers
{{ owner_username }}/Rechnungen/
# Jahr des Erstellungsdatums
{{ created_year }}/
# Dateiname: Jahr-Monat-Tag_Gesprächspartner
{{ created_year }}-{{ created_month }}-{{ created_day }}_{{ correspondent.replace(" ", "_") }}
# Wenn das Feld "Belegnummer" vorhanden ist und einen Wert hat, wird dieser zum Dateinamen hinzugefügt
{% if "Belegnummer" in custom_fields and custom_fields.Belegnummer.value %}
# Belegnummer (Leerzeichen werden durch Unterstriche ersetzt)
_{{ custom_fields.Belegnummer.value | replace(" ", "_") }}
{% endif %}
Hier ist der Code besser lesbar formatiert:
{{ owner_username }}/Rechnungen/{{ created_year }}/
{{ created_year }}-{{ created_month }}-{{ created_day }}_{{ correspondent.replace(" ", "_") }}
{% if "Belegnummer" in custom_fields and custom_fields.Belegnummer.value %}
_{{ custom_fields.Belegnummer.value | replace(" ", "_") }}
{% endif %}
Dynamische Speicherpfade basierend auf Dokumenttyp
Dieser Code erstellt einen Speicherpfad für Dokumente in Paperless-ngx, basierend auf bestimmten Merkmalen des Dokuments wie Dokumenttyp, Erstellungsdatum, Korrespondenten und benutzerdefinierte Felder.
{{ owner_username }}/
{% if document_type == "Angebot" %}Angebote
{% elif document_type == "Rechnung" %}Rechnungen
{% else %}Andere{% endif %}/
{{ created_year }}/{{ created_year }}-{{ created_month }}-{{ created_day }}_{{ correspondent.replace(" ", "_") }}
{% if "Belegnummer" in custom_fields and custom_fields.Belegnummer.value %}_{{ custom_fields.Belegnummer.value | replace(" ", "_") }}{% endif %}
Hier ist eine Erklärung, wie der Pfad aufgebaut wird:
Benutzername des Dokumentbesitzers: Der Pfad beginnt mit dem Benutzernamen des Besitzers des Dokuments, der mit {{ owner_username }}
eingefügt wird. So wird der Pfad je nach Benutzer in einem eigenen Ordner abgelegt.
Dokumenttyp: Anschließend prüft der Code den Dokumenttyp:
Dadurch werden Dokumente je nach Art in verschiedenen Ordnern organisiert: Dokumente vom Typ „Rechnung“ werden im Ordner „Rechnungen“ abgelegt, Dokumente vom Typ „Angebot“ im Ordner „Angebote“, und alle anderen Dokumenttypen landen im Ordner „Andere“.
Der Code lässt sich außerdem flexibel erweitern, um zusätzliche Dokumenttypen hinzuzufügen. So kann man für jeden neuen Dokumenttyp (wie z. B. „Vertrag“ oder „Bericht“) einen eigenen Ordner erstellen, indem der passende Dokumenttyp im Code ergänzt wird. Alternativ könnte man den Code auch so gestalten, dass alle Dokumente automatisch in einem Ordner abgelegt werden, dessen Name dem jeweiligen Dokumenttyp entspricht.
Jahresordner: Innerhalb des Dokumenttyps wird das Dokument in einem Jahresordner gespeichert, z. B. 2023
.
Datum im Dateinamen: Der Dateiname beginnt mit dem Erstellungsdatum des Dokuments im Format Jahr-Monat-Tag
, zum Beispiel 2023-11-01
. Dadurch sind die Dateien chronologisch geordnet und leicht auffindbar.
Absender/Empfänger: Nach dem Datum wird der Name des Korrespondenten (Absender oder Empfänger) eingefügt. Um den Namen einheitlich und ohne Leerzeichen darzustellen, werden eventuelle Leerzeichen durch Unterstriche ersetzt.
Benutzerdefinierte Belegnummer: Falls das Dokument ein benutzerdefiniertes Feld namens „Belegnummer“ hat, wird diese Nummer ebenfalls im Dateinamen ergänzt. Auch hier werden Leerzeichen durch Unterstriche ersetzt, um Einheitlichkeit zu gewährleisten.
Beispiel-Pfad: Angenommen, ein Benutzer MaxMuster
hat ein Dokument vom Typ „Rechnung“, das am 1. November 2023 erstellt wurde und dessen Korrespondent „Firma Beispiel GmbH“ ist. Das Dokument hat die Belegnummer „12345“. Der Pfad würde dann wie folgt aussehen:
MaxMuster/Rechnungen/2023/2023-11-01_Firma_Beispiel_GmbH_12345
Dieser Aufbau sorgt für eine klare Struktur, in der Dokumente nach Benutzern, Dokumenttypen und Datum organisiert sind und durch die Zusatzinformationen leicht identifizierbar bleiben.
Wer Umlaute zwar im Titel oder anderen Metadaten haben möchte aber nicht im Dateinamen wird sie mit
{{ title
|replace(" ","_")
|replace(".","-")
|replace("ß","ss")
|replace("ä","ae")
|replace("ö","oe")
|replace("ü","ue")
|replace("Ä","Ae")
|replace("Ö","Oe")
|replace("Ü","Ue")
}}
wieder los. Und ja, das kann man so mehrzeilig eingeben. Wenns zu lang wird kann man das Eingabefenster unten rechts vergrößerten. Hier einzeilig:
{{ title|replace(" ","_")|replace(".","-")|replace("ß","ss")|replace("ä","ae")|replace("ö","oe")|replace("ü","ue")|replace("Ä","Ae")|replace("Ö","Oe")|replace("Ü","Ue")}}
Wenn man viele tags hat und die Variable {{ tag list }} verwendet so wie hier
{{ title }}/{{ tag_list }}
dann kommt sowas dabei heraus:
test_tag/1,2,3,4,5,6,7,8,9
Ich habe also ein Dokument mit dem Titel test_tag
und den Tags der Reihe nach 1 bis 9.
Die Variable {{ tag_list }}
ist allerdings ein String, der durch Kommata getrennt ist. Es gibt auch die Variable {{ tag_name_list }}
die intern durch eine Liste repräsentiert wird. Das macht es etwas einfacher die einzelnen Werte abzugreifen.
Das kann jetzt eine ziemlich lange Liste werden, evtl möchte man aber nur bestimmte tags in seinem Dateinamen haben. Das kann man dann lösen, indem man durch die Liste iteriert und nur die ausgibt, die man möchte.
{{ title }}/
{% for tag in tag_name_list %}
{% if tag == "2" or tag == "3" or tag == "7" %}
{% print(tag) %}
{% endif %}
{% endfor %}
Das Ergebnis ist dann
test_tag/237
Unschön ist natürlich, dass die Tags jetzt alle aneinander kleben. Also noch einen Unterstrich dazwischen
{{ title }}/
{% for tag in tag_name_list %}
{% if tag == "2" or tag == "3" or tag == "7" %}
{% print(tag + "_") %}
{% endif %}
{% endfor %}
Ergebnis:
test_tag/2_3_7_
Schon besser, aber der letzte Unterstrich ist noch störend. Das war ein bisschen knifflig, weil so manchen weas in python geht in den Jinja Templates nicht geht. Aber die Liste der Tags ist alphabetisch sortiert, siehe Dokumentation:
{{ tag_name_list }}
: A list of tag names applied to the document, ordered by the tag name. Note this is a list, not a single string
Wir wissen also dass das Tag 7 der letzte auszugebende Tag ist und können darauf reagieren:
{{ title }}/
{% for tag in tag_name_list %}
{% if tag == "2" or tag == "3" or tag == "7" %}
{% if tag == "7" %}
{% print(tag) %}
{% else %}
{% print(tag + "_") %}
{% endif %}
{% endif %}
{% endfor %}
Wir gehen also durch die liste durch, schauen ob es eines der Tags ist die wir ausgeben wollen, müssen dann schauen ob es der letzte alphabetisch gesehen ist und geben dann entweder den Tag mit einem Unterstrich aus oder sofern es der letze Eintrag ist nur den Tag. Ergebnis:
test_tag/2_3_7
La Voilá
Erkauft wird das allerdings mit dem Preis, dass man nun auch die Speicherpfade anpassen muss, wenn ein neues auszugebendes Tag erstellt wird.
Nagelprobe: ich habe das Tag „2“ von Dokument entfernt.
test_tag/3_7
Wen man jetzt aber auch noch die "7"vom Dokument entfernt, ist der letzte Tag die 3.
test_tag/3_
Da ist dann wieder der unschöne abschließende Unterstrich.
Wenn man aber dafür sorgt dass die TagList nicht das Ende des Dateinamens ist sondern noch etwas kommt, sei es der Korrespondent, Dokumenttyp oder schlicht fester Text, dann kann man sich das ganze Gehampel mit dem Unterstrich sparen:
{{ title }}/
{% for tag in tag_name_list %}
{% if tag == "2" or tag == "3" or tag == "7" %}
{% print(tag + "_") %}
{% endif %}
{% endfor %}
ENDE
test_tag/3_ENDE
Ein bischen Dokumentation lesen hilft doch immer Hier jetzt eine Lösung, die die Taglist immer schön mit Unterstrich zwischen den Elementen daher, aber nicht am Anfang und nicht am Ende, dafür muss man jetzt sekbst sorgen und danit die Kontrolle. Allerdings geht das jetzt schon etwas in die Jinja Feinheiten rein und detailliert gehe ich jetzt hier nicht drauf ein. Lediglich soviel, ich speicher mir, ob ich am ANfang der Liste bin, geben dannm nur das Tag aus, und alle folgenden Tags werden dann mit einem führendem Unterstrich ausgegeben. Allerdings muss man hier aufpassen, das scoping der Variablen in Blöcken ist gewöhnungsbedürftig. Daher auch das Gefiesel mt dem namepace.
{% set ns = namespace(first=true) %}
{{ title }}/
{% for tag in tag_name_list %}
{% if tag == "2" or tag == "3" or tag == "7" %}
{% if ns.first == true %}
{% print(tag) %}
{% else %}
{% print("_" + tag) %}
{% endif %}
{% set ns.first = false %}
{% endif %}
{% endfor %}
Hallo Zusammen,
ich bin gerade beim Testen des neuen features und komme nicht weiter.
Aktuell verwende ich folgenden Code
{{ owner_username }}/{% if custom_fields.Land.value == 'Deutschland' %}Deutschland{% else %}Andere{% endif %}/
In der Vorschau wird der richtige Speicherpfad angegeben:
User1/Deutschland
Sobald ich jedoch den Speicherpfad abspeichern möchte, bekomme ich die Fehlermeldung:
Ungültige Variable erkannt.
Kennt jemand diese Fehlermeldung und kann mir bitte weiterhelfen .
Vielen Dank und Gruß,
Michael
Moin,
als erstes fällt aufm dass du dein Beispiel mit einem / abschließt. Entgegen seinem Namen storage_path
sollte hier jedoch ein vollständiger Pfad mit Dateiname stehen. Die Extension hängt PLNGX selbst dazu.
Dann übherprüfst du nicht, ob das benutzerdefinierte Feld Land
überhaupt dem Dokument zugefügt wurde. Und nein, „das ist der immer der Fall“ ist kein Grund, das nicht zu überprüfen. Es kann immer mal wieder Fälle geben, wo das eben dann doch nicht der Fall ist, und das „Programm“ sollte angemessen auf einen solchen Fall reagieren.
Das sieht dann so aus wie in einigen Beispielen oben drüber:
{{ owner_username }}/
{% if "Land" in custom_fields and custom_fields.Land.value == 'Deutschland' %}
Deutschland/
{% else %}
Andere/
{% endif %}
{{ title }}
Den title
habe ich jetzt mal hinzugefügt damit ein vollständiger Pfad entsteht,
Ich hatte allerdings auch schon mal den Fall, dass es beim Abspeichern dann immer noch „Unbekannte Variable“ hieß. Leider konnte ich das nicht reproduzieren, also habe ich auch noch keinen Issue angelegt, und hab auch noch keinen dsbzgl gesehen. Man kann sich dann aber mit dem Filter get_cf_value
behelfen.
{{ owner_username }}/
{% if "Land" in custom_fields and custom_fields|get_cf_value( "Land" ) == 'Deutschland' %}
Deutschland/
{% else %}
Andere/
{% endif %}
{{ title }}
So langsam komme ich weiter
Vielen Dank für`s Teilen der Infos!
Ich habe es bei mir aktuell so eingestellt, dass ich
{created_year}{created_month}{created_day}-{correspondent}-{document_type}-{owner_username}
, womit ich auch ohne PLNGX mit den Dokumenten anhand der Namen schon etwas anfangen kann.docker-compose.env
unter PAPERLESS_FILENAME_FORMAT=
hinfällig, oder wird der noch andersweitig benötigt?{% if correspondent in ["Bank1", "Bank2", "Geldgeber"] %}
FINANZEN/{{ correspondent }}/
{% endif %}
{{ owner_username }}/
{% if correspondent in ["Bank1", "Bank1", "Geldgeber"] %}
FINANZEN/{{ correspondent }}/
{% endif %}
{% if correspondent in ["Sichermann", "Sicherfrau", "GanzSicher"] %}
VERSICHERUNGEN/{{ correspondent }}/
{% endif %}
{{ created_year }}/{{ title }}
Das ist dann der Fallback, wenn irgendetwas schiefläuft und Speicherpfade nicht zugewiesen werden oder Arbeitsabläufe abbrechen etc. Ich habe
PAPERLESS_FILENAME_FORMAT: '99_Neu/{{ created_year }}-{{ created_month }}-{{ created_day }}_{{ correspondent }}_{{ document_type }}_{{ original_name }}'
bei mir stehen. Idealerweise ist das dann immer leer respektive gar nicht erst vorhanden. Die 99 dient bei mir lediglich zur Sortierung.
Sehr gut. Der Fallback ist sicherlich sinnvoll. Das werde ich auch so machen .
Viele Grüße!
Oh man Jetzt habe ich in der docker-compose.env
PAPERLESS_FILENAME_FORMAT=99/{created_year}{created_month}{created_day}-{correspondent}-{document_type}-{owner_username}
eingetragen und docker compose up -d
ausgeführt und bekomme diesen Fehler:
⠼ Container paperless-webserver-1 Starting 2.5s
Error response from daemon: error while creating mount source path '/home/bdream/paperless/consume': mkdir /home/bdream/paperless/consume: file exists
Jetzt sehe ich, dass du in deiner Angabe alle { und } durch {{ und }} ersetzt hast.
Muss dies jetzt in allen Konfigurationsfiles (.env und .yml) erfolgen?
Ich dachte das bezieht sich lediglich auf die Speicherpfade.
PAPERLESS_FILE_FORMAT ist ein Speicherpfad.
Deshalb ja die Frage. Muss das jetzt überall, wo {} stehen {{}} eingetragen werden?
Hallo huebi,
vielen Dank für deine schnelle Hilfe und deine Erklärung .
Dein erstes Beispiel funktioniert bereits ohne eine Fehlermeldung.
Gruß Michael
Hallo huebi, vielen Dank für die Beispiele und die Erklärung. Gibt es eine Dokumentation für die benutzerdefinierten Speicherpfade?
Gruß Michael
Ja ist auch hier im Thread verlinkt.
Hallo huebi,
vielen Dank. Ich habe die Dokumentation gefunden.
Gruß Michael