Live Demo: Teste dieses und weitere Plugins live — ohne Installation, ohne Risiko: demo.markus-michalski.net
Diese Dokumentation bezieht sich immer auf die aktuellste veröffentlichte Version.
Die Rechnung wird nicht von einem Bestell-Event ausgelöst. Sie entsteht entweder beim Versand der Bestellmail oder manuell im Admin. Beide Wege rufen denselben Service auf (InvoiceService.createForOrder).
Die Reihenfolge in createForOrder ist: vorhandene Rechnung prüfen, Nummer vergeben, Snapshot erzeugen, PDF erzeugen, Datei ablegen, Hashwert berechnen, Datensatz speichern. Die Nummer steht also vor dem PDF fest.
Der Admin-Weg endet mit dem gespeicherten PDF. Er hängt nichts an eine Bestellmail an und setzt keinen Versandstatus. Das Anhängen und das Setzen des Versandstatus gehören nur zum Mail-Weg in ExtendedEmail.send:
| Klasse | Aufgabe |
|---|---|
ExtendedEmail |
Erweitert Email, merkt sich Bestellmails und hängt in send() das PDF an |
ExtendedOrder |
Erweitert Order, liefert Rechnung und erzeugt den Snapshot |
InvoiceService |
Orchestriert Erstellung, Laden, Hash-Prüfung und Neugenerierung |
InvoiceNumberGenerator |
Vergibt Rechnungsnummern über die Tabelle mmd_pdfinvoice_seq |
PdfGenerator |
Bereitet die Template-Variablen vor, rendert das Twig-Template und erzeugt das PDF mit Dompdf |
InvoiceStorage |
Schreibt, liest und löscht die PDF-Dateien |
InvoiceRepository |
Liest und schreibt die Tabelle mmd_pdfinvoice |
InvoiceConfiguration |
Liest die Moduleinstellungen |
DebugLogger |
Schreibt Debug-Meldungen nur bei aktivem Debug-Logging |
InvoiceController |
Admin-Controller mmd_pdfinvoice_admin mit den Aktionen createInvoice, downloadPdf, sendInvoiceEmail, regeneratePdf |
ModuleEvents |
Legt bei der Aktivierung Tabellen und Verzeichnis an |
| Eigenschaft | Wert |
|---|---|
| Modul-ID | mmd_pdfinvoice |
| Composer-Paket | mmd/oxid7-pdf-invoice |
| Installationsverzeichnis | source/modules/mmd/pdf-invoice |
| Admin-Controller | mmd_pdfinvoice_admin |
| Admin-Tab | tbclorder_pdfinvoice (Bestellungen > Bestellung) |
| Templates | @mmd_pdfinvoice/pdf/invoice, @mmd_pdfinvoice/admin/invoice_main |
| Events | onActivate (Tabellen und Verzeichnis anlegen), onDeactivate (löscht nichts) |
Format: {Präfix}{Jahr}-{Nummer} mit fünfstelliger Nummer und führenden Nullen, zum Beispiel RE-2026-00001.
mmd_pdfinvoice_seq.UPDATE über LAST_INSERT_ID(), damit parallele Anfragen keine Nummer doppelt bekommen. Das Verfahren ist MySQL-spezifisch.Im Admin erscheint die Einstellung "Nummerierung jährlich zurücksetzen" (
mmdPdfInvoiceResetYearly). Sie hat im Code keine Wirkung. Die Nummerierung läuft immer je Shop und Jahr, unabhängig davon, ob die Option an- oder ausgeschaltet ist.
Pfad: {Speicherpfad}/{Shop-ID}/{Jahr}/{Monat}/{Rechnungsnummer}.pdf, relativ zum Shop-Verzeichnis. Aus der Rechnungsnummer werden alle Zeichen außer Buchstaben, Ziffern, - und _ durch _ ersetzt. Jahr und Monat stammen vom Rechnungsdatum.
Beim Lesen vergleicht das Modul den SHA-256-Hashwert der Datei mit dem in PDF_HASH gespeicherten Wert. Weicht er ab, wird die Datei nicht ausgeliefert, bis das PDF neu generiert wurde.
Dompdf legt seinen Schrift-Cache in source/tmp/dompdf ab. Das PDF wird im Format A4 hochkant mit der Standardschrift DejaVu Sans erzeugt.
| Spalte | Beschreibung |
|---|---|
OXID |
Primärschlüssel |
OXORDERID |
Bestell-ID |
OXSHOPID |
Shop-ID |
INVOICE_NUMBER |
Formatierte Rechnungsnummer |
INVOICE_DATE |
Rechnungsdatum |
PDF_PATH |
Relativer Pfad der PDF-Datei |
PDF_HASH |
SHA-256-Hashwert der PDF-Datei |
SENT_TO_CUSTOMER |
Kennzeichen: an Kunden gesendet |
SENT_AT_CUSTOMER |
Zeitpunkt des Versands an den Kunden |
SENT_TO_OWNER |
Kennzeichen: an Shopbetreiber gesendet |
SENT_AT_OWNER |
Zeitpunkt des Versands an den Shopbetreiber |
SNAPSHOT_DATA |
JSON-Snapshot der Bestelldaten |
CREATED_AT |
Zeitpunkt der Erstellung |
OXTIMESTAMP |
Zeitstempel der letzten Änderung (automatisch) |
Eindeutige Schlüssel: OXORDERID + OXSHOPID (eine Rechnung je Bestellung und Shop) und INVOICE_NUMBER + OXSHOPID (eine Rechnungsnummer je Shop).
| Spalte | Beschreibung |
|---|---|
OXSHOPID |
Shop-ID (Teil des Primärschlüssels) |
YEAR |
Jahr (Teil des Primärschlüssels) |
CURRENT_NUMBER |
Zuletzt vergebene Nummer |
PREFIX |
Präfix zum Zeitpunkt der Anlage der Zeile |
Die Spalte PREFIX wird beim Anlegen der Zeile befüllt. Für die Nummernbildung wird immer die aktuelle Einstellung verwendet.
Beim Erstellen der Rechnung speichert das Modul den Snapshot in SNAPSHOT_DATA. Er wird aus der Bestellung erzeugt und enthält:
| Schlüssel | Inhalt |
|---|---|
version |
Format-Version des Snapshots, aktuell der Wert 1.0 |
created_at |
Zeitpunkt der Erstellung |
order |
Bestellnummer, Bestelldatum, Versanddatum, Trackingcode, Währung, Kurs, Bestellnotiz |
billing |
Rechnungsadresse inklusive Telefon, Fax, E-Mail und USt-IdNr. |
delivery |
Lieferadresse, wenn in der Bestellung ein Liefernachname hinterlegt ist, sonst null (kein Vergleich mit der Rechnungsadresse) |
items |
Positionen mit Artikelnummer, Titel, Menge, Preisen, MwSt. und Gewicht |
totals |
Netto-, Brutto- und Gesamtsumme, Versand-, Zahlungs-, Verpackungs- und Geschenkkartenkosten, Rabatt, MwSt.-Aufschlüsselung |
payment |
Zahlungsart-ID, Bezeichnung und bei Lastschrift die Bankdaten |
Nicht im Snapshot enthalten sind die Shop-Stammdaten und das Logo. Beim Neugenerieren eines PDFs werden sie aktuell gelesen.