20 KiB
Bedienung und technische Dokumentation
Stand: 16.10.2026 · Version 1.0
Einrichtung und persönliche Vorlagen
Die README enthält den sofort nutzbaren Ein-Aufruf-Ablauf mit einvoice --create. Installation aus dem Repository
mit pip install -e '.[pdf]'; Java wird für Mustang benötigt. setup-mustang
installiert die geprüfte Referenzversion 2.26.0 aus Maven Central mit SHA1-Abgleich.
Der Abgleich prüft die Downloadintegrität; er ist keine Signaturprüfung.
mustang-update zeigt neuere Versionen, mustang-update --apply installiert sie.
Danach eine Testrechnung erneut prüfen. JR_EINVOICE_MUSTANG_JAR überschreibt den
Standardpfad. Downloads erfolgen nur bei Setup/Update; Generierung und Validierung
laufen lokal ohne Upload der Rechnungsdaten.
Vorlagen werden in dieser Reihenfolge zusammengeführt:
examples/invoice.init.yaml.- Versionierte
presets/seller.default.yamlmit Beispieldaten. - Lokale
private/presets/seller.default.yaml. - Lokale
private/presets/customers/<kunde>.yaml, sonst die versionierte Kunden-Datei, sonstpresets/customers.yaml. - Rechnungsnummer, Datum, Zahlungsziel und Monats-/Stundenangaben des Befehls.
JR_EINVOICE_HOME=/absoluter/pfad setzt das private Datenverzeichnis.
JR_EINVOICE_PRESETS=/absoluter/pfad setzt ein anderes Verzeichnis für die lokalen
Vorlagen (gleiche Unterstruktur). Persönliche Daten nicht in die versionierten
Beispieldateien eintragen. private/, invoices/, die virtuelle Umgebung und
Ausgabeordner sind gitignoriert. Externe Rechnungsordner separat gegen versehentliches
Committen sichern. Die lokale IDV-Vorlage ist nur historischer Bestand; keine Empfängeradresse ist dafür erforderlich.
Durchgängiges Praxisbeispiel
Halian GmbH: C# Entwicklung Bank Projekt, Oktober 2026
zeigt die Rechnungserstellung, das Anhängen der PDF-Datei und den manuellen Versand
an invoice@halian.com, einschließlich Betreff, Textvorlage und optionalem EML-Entwurf.
Die Beispielannahmen (120 Stunden und 85 EUR netto „all in“ zuzüglich Umsatzsteuer)
sind dort ausdrücklich gekennzeichnet. Halian ist hier kein bestätigter Kunde.
Befehle
jr-einvoice --help und <befehl> --help zeigen alle Parameter.
# Vollständig erzeugen und validieren (normaler Ablauf):
einvoice --create --Customer "Kundenfirma GmbH" \
--Entry "Geleistete Stunden Oktober 2026" --Volume 120 --Price "85,00 €"
# Expertenablauf für mehrere Positionen / manuell bearbeitete YAML-Dateien:
jr-einvoice init private/invoices --auto-folder --open
jr-einvoice generate /pfad/zum/rechnungsordner --json
jr-einvoice email /pfad/zum/rechnungsordner --to rechnung@empfaenger.example
Ein-Aufruf-Erstellung
einvoice ist ein eigener Konsolenbefehl. Die Optionen --Customer, --Entry,
--Volume und --Price sind erforderlich. Der Kunde wird über den Namen oder einen
angezeigten Schlüssel aus einvoice --customers gefunden. Für neue Kunden erfasst
der Befehl einmalig eine vollständige Rechnungsanschrift. Alternativ können diese
Daten mit --Street, --PostalCode, --City und optional --Country, --Email,
--VatId übergeben werden. In Skripten führen fehlende Daten zu einer konkreten
Fehlermeldung; es gibt keine erfundenen Adressen oder hängenden Eingabeaufforderungen.
Adressoptionen überschreiben keine bereits gespeicherten Kunden. Deren Stammdaten
gezielt in der lokalen Kundendatei bearbeiten. Der Kunde IDV ist ein ehemaliger
Kunde und hat keine besondere Rolle im Ablauf.
--Price ist der Nettopreis pro Einheit. Deutsche Schreibweise (85,00 €,
1.234,56 EUR) und ungegliederte Dezimalpunkt-Schreibweise (85.00) sind zulässig.
--Volume und --Tax verstehen dieselben Dezimalzahlen. Ohne Dezimalkomma gilt ein
Punkt als Dezimalpunkt; 1.234 bedeutet daher 1,234 und nicht 1234. Gemischte oder
ungültige Angaben werden abgewiesen. Standardwerte: --Unit HUR, --Tax 19,
--DueDays 30, Rechnungsdatum heute. Preis, Menge und Steuer werden ausdrücklich
angegeben bzw. verwenden diese dokumentierten Standardwerte; ein alter
kundenspezifischer Stundensatz wird nicht unbemerkt übernommen.
Ein deutscher Monatsname plus Jahr in --Entry, z. B. „Oktober 2026“, ergibt den
vollständigen Leistungsmonat. --Month YYYY-MM setzt ihn ausdrücklich;
--ServiceDate YYYY-MM-DD überschreibt die automatische Erkennung durch ein
Einzeldatum. Beide expliziten Optionen zusammen sind nicht zulässig. Ohne Monat
oder Leistungsdatum gilt das Rechnungsdatum als Leistungsdatum. Die Konsole zeigt
den verwendeten Zeitraum; tatsächliche Leistungsdaten vor Versand prüfen.
Nummern werden unter Dateisperre im gewählten --root automatisch als
JR-JJJJ-NNNN vergeben. Alle gespeicherten YAML-Rechnungen auf der ersten Ebene
werden auf bereits verwendete Nummern geprüft; --Number kann eine eigene freie
Nummer setzen. Bei fehlgeschlagenem PDF-Build bleibt der Entwurf erhalten und
reserviert seine Nummer. Der Befehl meldet einen Fehler und veröffentlicht kein
fertiges Anhang-PDF. In out/logs/run.log stehen Details. Zum Korrigieren und
Wiederholen den betreffenden Entwurf mit jr-einvoice generate aufbauen; keinen
bereits versandten Datensatz verändern.
Nach erfolgreicher PDF/A- und XML-Validierung wird das vollständige hybride PDF
zusätzlich als Rechnung_<Nummer>.pdf im Rechnungsordner bereitgestellt. Diese
Datei direkt an eine E-Mail anhängen. out/invoice.pdf ist lediglich die Sichtkopie.
out/manifest.json hält SHA-256-Prüfsummen einschließlich des Anhang-PDFs fest.
--json schreibt nur ein JSON-Ergebnis mit Nummer, Ordner, PDF, Prüfbericht, Log
und technical_validation: valid nach stdout. Keine automatische Mailübertragung.
Die Konsole bestätigt „PDF/A und EN16931-XML technisch gültig“. Sie behauptet keine vollständige rechtliche oder steuerliche Prüfung der Geschäftsdaten; siehe BMF-FAQ zur Validierung.
Älterer Monatsentwurf
Der ergänzende jr-einvoice monthly-Befehl bleibt für gespeicherte
Stundenvorlagen verfügbar; der neue Standard ist einvoice --create.
monthly übernimmt genau eine Stundenposition (HUR) aus der Kundenvorlage,
setzt deren Menge und deutschen Monatsnamen sowie Anfang/Ende des Monats. --date
setzt ein abweichendes Rechnungsdatum, ansonsten gilt heute. --rate überschreibt
den Nettostundensatz. Ungültige Monatsentwürfe hinterlassen keinen Rechnungsordner.
Explizite Nummern dürfen noch nicht vergeben sein. monthly prüft YAML-Rechnungen
auf der ersten Ordnerebene desselben Stamms, auch bei anderen Kunden, und verhindert
Überschreiben. Das optionale Nummernvorschlagen von init --auto-folder verwendet
weiter das Schema YYYY-NNNN aus Ordnernamen. Es kennt die bisherigen YYYY-MM-PDFs
nicht. Für den Wechsel daher eine freie Nummer ausdrücklich setzen; keine
bereits versandte Rechnung unter gleicher Nummer neu ausstellen. Die lokale
Ordneranlage ist per Dateisperre serialisiert; kein verteiltes Rechnungsregister.
init --print-path-only, generate --print-artifacts-only und generate --json
schreiben maschinenlesbare Ergebnisse nach stdout; Logs laufen nach stderr.
--open verwendet $EDITOR, danach verfügbare Editoren. Ein unbekannter Kunde
führt zu einem Fehler statt zu einer Rechnung mit generischem Empfänger.
YAML und Beträge
Die vollständige Ausgangsvorlage steht in examples/invoice.sample.yaml.
Zusätzlich werden folgende optionale Meta-Felder unterstützt:
meta:
# ... invoice_number, invoice_date, service_date, currency ...
service_period_start: '2026-10-01'
service_period_end: '2026-10-31'
buyer_reference: 'Kundenreferenz'
order_reference: 'Bestellnummer'
Alle Pflichtangaben einschließlich Leistungsbeschreibung und Zeitraum gelangen
in PDF und XML. Für Monatsrechnungen steht service_date auf dem Monatsende.
Bei Teilmonaten den tatsächlichen Zeitraum setzen. payment.reference ist der
Verwendungszweck, keine Bestellnummer. Kunden- und Bestellreferenzen stehen in den
eigenen Meta-Feldern. Ein B2B-Empfänger benötigt keine erfundene Leitweg-ID.
Geld, Mengen und Steuersätze verwenden Decimal. Jede Nettoposition wird kaufmännisch
auf Cent gerundet; je Steuersatz wird die Steuer aus der Summe der gerundeten
Nettopositionen berechnet und auf Cent gerundet. PDF und XML verwenden dieselbe
Berechnung. Dezimalpunkt verwenden; besonders genaue Mengen/Preise in YAML als
Zeichenkette angeben (quantity: '72.5'). Leere Positionen, nicht endliche Zahlen,
negative Preise, Nullsteuersätze, unbekannte YAML-Felder und ungültige IBAN-Prüfsummen
werden abgewiesen. Der Validator prüft zusätzlich Format und Geschäftsregeln.
PDF/A, XML und Validierung
WeasyPrint erzeugt PDF/A-3b. Mustang kombiniert diese Sichtkopie mit dem CII-D16B-XML,
Profil EN16931 (--format fx --version 1 --profile E). Die konkrete Kombination
wurde mit Mustang 2.26.0 einschließlich PDF/A und eingebettetem XML erfolgreich
geprüft. Die CLI-Formatversion 1 bezeichnet Factur-X, nicht ZUGFeRD 1.
Es wird keine Behauptung einer Zertifizierung oder vollständigen Unterstützung
aller neuen ZUGFeRD-2.5.2-Funktionen abgeleitet.
Der frühere wkhtmltopdf-Fallback bleibt für eine Sichtkopie verfügbar, garantiert aber kein PDF/A. Ohne gültiges PDF/A darf die abschließende Prüfung nicht bestehen. Für den produktiven Weg WeasyPrint verwenden.
generate kombiniert und validiert immer. Die Python-Pipeline kann für interne
Anwendungsfälle auch nur Sichtkopie und XML erzeugen. Ein Erfolg erfordert einen
parsebaren Mustang-Bericht mit XML-Prüfabschnitt und ausschließlich gültigen
Zusammenfassungen einschließlich Gesamtergebnis. Ein Exitcode 0 allein genügt nicht.
Bei fehlgeschlagener Validierung bleibt der Bericht erhalten und das nicht freigegebene
hybride PDF wird entfernt. Alte Mailentwürfe werden bei einem neuen Build verworfen.
Pro Lauf stehen Details und Mustang-Ausgaben in out/logs/run.log.
Für Eingänge kann validate XML und hybride PDF prüfen. Eine normale PDF-Datei
wird nicht als strukturierte E-Rechnung akzeptiert. Quellen bleiben unverändert;
Berichte an einem eigenen Pfad aufbewahren. Inhaltliche Prüfung (Leistung, Parteien,
Betrag, Steuersatz, Doppelrechnung) bleibt zusätzlich erforderlich.
Versand und Aufbewahrung
email erzeugt die Standardausgabe erneut aus invoice.yaml und legt erst nach
erfolgreicher Prüfung invoice.eml an. Absender kommt aus seller.email, Empfänger
aus buyer.email oder --to. Die Mail enthält nur das hybride PDF als Rechnungsanhang;
XML ist darin eingebettet. X-Unsent: 1 kennzeichnet den Entwurf. Kein SMTP-Zugang,
kein Passwort und kein automatischer Versand sind nötig. Das konkrete Öffnen als
Entwurf hängt vom Mailprogramm ab. Versand und Zustellnachweis erfolgen dort.
manifest.json enthält SHA-256-Prüfsummen von YAML, XML, hybridem PDF, Bericht und
EML. Es unterstützt die Integritätskontrolle, schafft aber allein kein unveränderbares
Archiv. Nach Versand den vollständigen Rechnungsordner und die gesendete Originalmail
samt Versandnachweis in die bestehende gesicherte Ablage übernehmen. Versandte
Rechnungen nicht durch erneutes generate überschreiben. Für Berichtigungen einen
fachlich abgestimmten Prozess verwenden. Das Tool verwaltet keine Stornos.
Prüfung der Überarbeitung
python -m unittest discover -s tests -v
# Einschließlich echter PDF-/XML-/Mail-Prüfung durch Mustang:
JR_EINVOICE_INTEGRATION=1 python -m unittest discover -s tests -v
Die Tests decken deutschen Preisparser, neue/wiederverwendete Kunden, Ein-Aufruf-Nummernvergabe, Abbruch ohne fertigen PDF-Anhang sowie dezimale Rundung, mehrere Steuersätze, Pflichtdaten und ungültige Zahlen/IBAN, XML-Inhalte, HTML-Escaping, Monatsgrenzen einschließlich Schaltjahr, Nummernkollisionen, unbrauchbare oder widersprüchliche Validierungsberichte sowie veraltete Mailentwürfe ab. Der echte Mustang-Lauf ist ein zusätzlicher Integrationstest und erfordert Java und das lokale Jar.
Lokal wurde eine Testrechnung mit den Juli-Beispielwerten erstellt: 75 Stunden zu
85 EUR → 6.375,00 EUR netto + 1.211,25 EUR USt = 7.586,25 EUR. Nummer TEST-2026-07,
keine neue echte Rechnung. Der Mailtest verwendet die nicht zustellbare Adresse
rechnung@example.invalid. Die alten PDF-Rechnungen wurden nicht verändert.
Bewusster Funktionsumfang
Normale positive Dienstleistungsrechnungen in EUR mit positiver Umsatzsteuer und mehreren Steuersätzen sind unterstützt. Nicht implementiert sind steuerfreie Positionen, Kleinunternehmer, Reverse Charge, Abschläge/Anzahlungen, Skonto/Zuschläge/Rabatte, Gutschriften/Storno, Fremdwährungs-Steuerumrechnung, XRechnung-CIUS-Ausgabe, Peppol, DATEV-API und automatischer Postfacheingang. Diese Fälle nicht durch bloße Freitexthinweise nachbilden. Das vorhandene CII-XML ist keine XRechnung, auch wenn beide Formate EN16931 verwenden. Aufbewahrung/Backups und fachliche Freigabe müssen in den betrieblichen Ablauf eingebunden werden.
Updates und Rollback
Der empfohlene Update-Einstieg für diesen Linux-Checkout ist
python3 scripts/update.py (nur Standardbibliothek, unabhängig von der venv).
Alternativ: ./bin/einvoice --update. Mit --apply aktivieren, mit --status
den aktiven/vorherigen Stand anzeigen, mit --rollback zurückwechseln.
--mustang-version 2.26.0 erlaubt eine gezielte stabile Mustang-Version.
Ohne Versionsvorgabe wird Maven release bevorzugt; Vorabversionen werden abgewiesen.
- Exklusive Dateisperre verhindert gleichzeitige Wartungsläufe.
- Neue venv unter
.runtime/releases/<Zeit-ID>/venverstellen und Projekt als Wheel installieren, einschließlich PDF-Extra und transitiver Abhängigkeiten.pyproject.tomlist die maßgebliche Abhängigkeitsdefinition. pip wählt die neuesten zum Interpreter und zu diesen Vorgaben passenden Versionen. - Mustang von Maven herunterladen und veröffentlichte SHA1-Prüfsumme vergleichen. Das prüft Übertragungsfehler, ist keine unabhängige Signaturprüfung.
- Versionen vergleichen und Installationsbericht, vollständigen Paketstand
(
requirements.freeze.txt) sowie Manifest mit Quell-Commit und JAR-SHA256 speichern. pip check, WeasyPrint-PDF, beide CLI-Hilfen und alle Unittests einschließlich echter Integrationstests ausführen. Dazu gehören PDF/A, eingebettetes XML, EML-Anhang, neuer/bekannter Kunde sowie Ablehnung falscher Summen, Einheiten und PDFs ohne Rechnungs-XML. Tests nutzen temporäre Muster-/Kundendaten.-Iund ein fremdes Arbeitsverzeichnis verhindern, dass der Checkout die tatsächlich installierte Anwendung bei den Tests verdeckt.- Nur bei
--apply: bisherigen Stand sichern und.runtime/currentatomar auf den Kandidaten setzen. Dieselben Healthchecks nach der Aktivierung wiederholen; bei Fehler/KeyboardInterrupt sofort den bisherigen Zeiger wiederherstellen.
bin/einvoice und bin/jr-einvoice lösen den Zeiger pro Aufruf einmal auf und
verwenden Python und Mustang aus demselben Release. Nutzerablage bleibt standardmäßig
private/ im Checkout, auch bei Wheel-Installation; JR_EINVOICE_HOME und
JR_EINVOICE_PRESETS werden respektiert. Vor dem ersten verwalteten Update nutzen
die Starter .venv; beim ersten Aktivieren wird diese unverändert verlinkt und die
bisherige Mustang-JAR kopiert. Diese erste Baseline ist noch die ursprüngliche
Entwicklerumgebung: nicht löschen/verändern, wenn sie als Rückfall benötigt wird.
Spätere Releases sind eigenständige, fest installierte Wheel-Umgebungen.
Fehlende Downloads, defekte Prüfsummen, Resolverfehler, Timeouts und fehlgeschlagene
Tests führen zu Exitcode 1. Erfolgreiche Wartung liefert 0. Kandidaten, vorherige
Releases und Logs bleiben zur Diagnose erhalten; es gibt kein automatisches Löschen.
Nach Abbruch durch SIGKILL/Stromausfall zeigt current auf einen vollständigen
vorherigen oder neuen Stand; eine noch ausstehende Nachprüfung wird nicht automatisch
nachgeholt. Bei Bedarf --rollback ausführen. Rollback prüft den Zielstand vorab;
ist er wegen externer Änderungen defekt, bleibt der aktuelle Zeiger erhalten.
Updates ändern keine Rechnungen, Kunden oder Rechnungsnummern. Rollback umfasst
Python-Pakete, den installierten Anwendungscode und Mustang; keine Git-Änderungen,
privaten Daten, Python-Systemversion, Java oder nativen Bibliotheken. Nach Systemupdates
muss eine bisherige venv ggf. neu aufgebaut werden. Systemupdates auf Arch als
vollständiges Update über sudo pacman -Syu durchführen und danach den Prüflauf
starten. Der Updater führt weder sudo noch Systempaketänderungen aus.
Es gibt bewusst keinen Hintergrundtimer: neue Stände werden explizit geprüft und
übernommen. Zum Beispiel vor dem nächsten Rechnungslauf oder monatlich prüfen.
Neue Projektversionen zunächst separat über Git holen, danach den Updater starten;
der Updater führt kein git pull aus. Uncommittete Quellen werden mit eingebaut,
der Manifest-Commit allein beschreibt diese daher nicht vollständig. Die bisherigen
setup-mustang/mustang-update --apply sind einfache Direktinstallationen ohne
Transaktionsschutz und verwalten die neue Laufzeit nicht; für Updates den gemeinsamen
Ablauf verwenden. Eine Wheel-Installation außerhalb des Checkouts besitzt diesen
Checkout-Updater nicht.
Technische Grundlagen: pip Versionsauflösung und Installationsbericht, Python venv und feste Umgebungspfade. Umgebungen bleiben deshalb an ihrem Erstellungsort; nur der Zeiger wird gewechselt.
Konsolenbefehle installieren
Einmal im Checkout python3 scripts/install_commands.py ausführen. Der Installer
benötigt kein sudo und verlinkt einvoice sowie jr-einvoice nach ~/.local/bin.
Die verlinkten Starter finden den Checkout auch beim Aufruf aus einem anderen
Verzeichnis und verwenden den aktiven Update-/Rollback-Stand. Beide Befehle werden
mit --help geprüft. Bei Fehlern setzt der Installer seine Änderungen zurück.
Vorhandene andere Dateien/Symlinks werden unter *.before-einvoice-<Zeit-ID>
gesichert; bereits korrekt eingerichtete Links bleiben erhalten.
# Einmalig:
cd /home/johannes/localdev/einvoice
python3 scripts/install_commands.py
# Danach auch außerhalb des Checkouts:
einvoice --help
einvoice --customers
einvoice --update --status
einvoice --update --apply
einvoice --update --rollback
jr-einvoice --help
Abweichender Zielordner: --bin-dir /absoluter/pfad. Falls dieser Ordner nicht im
PATH steht, zeigt der Installer die passende Export-Zeile an; dauerhaft in die eigene
Shell-Konfiguration übernehmen. Auf Johannes' Rechner ist ~/.local/bin bereits im
PATH, daher ist keine Änderung der Shell-Konfiguration nötig. Bei einem alten
Shell-Cache rehash (zsh) oder hash -r (bash) verwenden. Eine aktivierte .venv
kann den alten Einstieg vorziehen; mit deactivate die verwalteten Befehle nutzen.
Der Checkout muss am Installationsort erhalten bleiben. Nach Verschieben den
Installer am neuen Ort erneut ausführen. Die Starter benötigen bash, readlink und
Python 3; diese sind auf dem vorgesehenen Linux-System vorhanden.
Office-Unabhängigkeit und LibreOffice
Die Quell-, Vorlagen- und Datenformate der Anwendung sind YAML, HTML/Jinja2, SVG und Markdown. Erzeugt werden PDF/A-3, strukturiertes XML, Prüfberichte, JSON-Manifeste und optional EML. Weder DOC/DOCX, XLS/XLSX, PPT/PPTX noch COM-/Microsoft-Office-APIs werden verwendet. Es gibt keine Abhängigkeit von Word, Excel, Outlook oder einer Microsoft-365-Lizenz. Die Python-Abhängigkeiten und die externen Werkzeuge WeasyPrint/Mustang/Java benötigen keine Office-Installation.
Für diese Rechnungslösung muss deshalb beim Wechsel zu LibreOffice nichts nach ODT/ODS konvertiert werden. ODF-Import/-Export ist keine Funktion des Tools; Dokumentvorlagen werden weiterhin als HTML/Jinja2 bearbeitet, Daten als YAML. Die versandfertige E-Rechnung ist das validierte PDF mit eingebettetem XML. Dieses Original nicht in Office/LibreOffice bearbeiten oder als neues PDF exportieren, da XML-Einbettung und PDF/A-Eigenschaften dabei verloren gehen können.
Der optionale EML-Entwurf ist eine Datei ohne Outlook-Automation. Mailprogramm, Mailkonto, Zugang und tatsächlicher Versand liegen außerhalb der Toolchain. Die Prüfung betrifft dieses eInvoice-Projekt; andere persönliche oder betriebliche Office-Dateien und Microsoft-365-Dienste wurden damit nicht geprüft oder migriert.