Die primäre Transaktion einer Bestellung
Shopware 6.7 legt zwei Verweise an, die endlich sagen, welche Lieferung und welche Zahlung die maßgebliche ist. Gefüllt werden sie in 6.7 noch nicht.
Eine Shopware-Bestellung kann mehrere Zahlungstransaktionen und mehrere Lieferungen haben. Welche davon die maßgebliche ist, stand bisher nirgends — jede Integration hat sich ihre eigene Regel gebaut, und die Regeln wichen voneinander ab.
6.7 schafft dafür zwei Felder. Wer sie heute benutzt, sollte wissen, in welchem Zustand sie sind.
Was neu ist
Am Bestelldatensatz gibt es zwei Fremdschlüssel und die zugehörigen Verknüpfungen:
| Feld | Bedeutung |
|---|---|
primary_order_delivery_id | die maßgebliche Lieferung |
primary_order_transaction_id | die maßgebliche Zahlungstransaktion |
Beide tragen das Merkmal ApiAware — sie sind also über die Admin-API lesbar —
und NoConstraint, es gibt also keine Fremdschlüsselbeschränkung in der
Datenbank. Dazu kommen zwei Eins-zu-eins-Verknüpfungen primaryOrderDelivery
und primaryOrderTransaction, ebenfalls API-sichtbar.
Fachlich ist das eine gute Sache: Die Frage „welche Zahlung zählt" wird vom Datenmodell beantwortet statt von jedem Konsumenten einzeln.
Der Haken: die Spalten sind leer
Hier wird es interessant, und hier liegt der Grund für diesen Text.
Die 6.7-Migration legt nur die Spalten an. Sie enthält genau eine
strukturverändernde Anweisung — ein ALTER TABLE auf order — und kein
einziges UPDATE. Für Bestellungen, die vor dem Update entstanden sind,
bleiben beide Felder damit leer.
Das Nachfüllen steckt in einer anderen Migration, und zwar im Verzeichnis
V6_8. Sie arbeitet sich in Blöcken zu 1.000 Bestellungen vor und setzt den
Verweis auf die jeweils passende Transaktion.
In der von uns gemessenen 6.7.13.1 war keine einzige 6.8-Migration eingetragen. Das ist kein Fehler, sondern die Reihenfolge: Eine 6.7 führt keine 6.8-Migrationen aus.
Daraus folgt für heute: Auf einer 6.7 sind die Felder für Altbestellungen NULL.
Wie der Kern selbst damit umgeht
Er verlässt sich nicht darauf. An den Stellen, die die Verweise brauchen, steht ein Muster wie dieses:
$deliveryDate = $order->getPrimaryOrderDelivery()?->getShippingDateLatest();
$transaction = $order->getPrimaryOrderTransaction();
if (!Feature::isActive('v6.8.0.0')) {
$deliveryDate = $order->getDeliveries()?->first()?->getShippingDateLatest();
$transaction = $order->getTransactions()?->last();
}
Ohne den Funktionsschalter greift der Kern also weiter auf die erste Lieferung und die letzte Transaktion zu — die bisherige Faustregel. Insgesamt finden sich im Kern von 6.7.13.1 32 Stellen, die auf die neuen Zugriffsmethoden verweisen.
Das ist die Vorlage für jede Integration: neuen Verweis lesen, bei NULL auf die alte Logik zurückfallen. Nicht umstellen, sondern ergänzen.
Was das praktisch bedeutet
| Lage | was zu tun ist |
|---|---|
Integration liest heute transactions und nimmt die letzte | so lassen, ergänzen um den neuen Verweis mit Rückfall |
| Integration soll neu gebaut werden, Ziel ist 6.7 | neuen Verweis benutzen, Rückfall einplanen, NULL erwarten |
| Reporting greift direkt auf die Datenbank zu | primary_order_transaction_id ist unter 6.7 kein verlässliches Kriterium |
| Shop steht vor dem Update auf 6.7 | nichts zu tun — das Feld kommt, stört aber niemanden |
Warum die Unterscheidung zählt
Bei einer Bestellung mit einem einzigen Zahlungsversuch ist die letzte Transaktion auch die richtige, und die ganze Frage ist akademisch.
Sie wird konkret, wenn ein Kunde eine Zahlung abbricht und eine zweite startet, wenn eine Zahlung fehlschlägt und wiederholt wird, oder wenn nachträglich eine Rückerstattung angelegt wird. Dann gibt es mehrere Transaktionen mit unterschiedlichen Zuständen, und „die letzte" ist eine Konvention, keine Aussage.
Dieselbe Frage stellt sich bei der E-Rechnung: Welche Transaktion liefert die Zahlart, die im Dokument steht? Der Erzeuger im Kern nutzt genau das oben gezeigte Muster — E-Rechnung im Shopware-Kern.
Was wir nicht gemessen haben
Der Abschnitt gehört dazu, weil die Versionsgrenze hier scharf ist:
- Nichts über das Verhalten von 6.8. Wir haben eine 6.7.13.1 gemessen. Dass
eine Nachfüll-Migration im Verzeichnis
V6_8liegt und der Kern einen Funktionsschalterv6.8.0.0kennt, ist im Quelltext dieser 6.7 sichtbar — wie sich eine laufende 6.8 tatsächlich verhält, ist damit nicht gezeigt. - Kein Test mit echten Bestellungen. Die gemessene Installation enthielt keine. Die Aussagen folgen aus den Migrationen und aus der Definition, nicht aus einem Datenbestand.
- Keine Aussage über den Zeitpunkt. Wann 6.8 erscheint und ob die Migration in dieser Form bleibt, ist nicht Gegenstand der Messung.
Die kurze Fassung
Die Felder sind da, sie sind über die API lesbar, und sie sind auf einer 6.7 für Altbestellungen leer. Wer heute darauf baut, baut auf etwas, das erst mit der nächsten Hauptversion trägt — und sollte den Rückfallpfad einplanen, den der Kern selbst benutzt.
Wie sich das Schema zwischen den beiden Linien insgesamt verändert, steht in Was ein Versionssprung an der Datenbank wirklich tut. Wenn eine Integration daran angepasst werden muss, gehört das zu App- und Plugin-Entwicklung.
Häufige Fragen
- Was ist die primäre Transaktion?
- Ein Verweis am Bestelldatensatz auf die Zahlungstransaktion, die als die maßgebliche gilt. Vorher musste sich jeder Konsument selbst eine Regel dafür bauen — üblicherweise die zuletzt angelegte.
- Kann ich mich in 6.7 darauf verlassen?
- Nein. Die Spalten sind da, das Nachfüllen für bestehende Bestellungen steckt in einer 6.8-Migration. In der von uns gemessenen 6.7.13.1 war keine 6.8-Migration eingetragen.
- Warum hat Shopware das eingeführt?
- Weil bei mehreren Zahlungsversuchen oder Teillieferungen bisher jede Integration ihre eigene Antwort auf die Frage hatte, welcher Datensatz zählt. Die Antworten wichen voneinander ab.
- Was mache ich bis dahin?
- Die bisherige Logik behalten und den neuen Verweis nur benutzen, wenn er gefüllt ist. Der Kern macht es unter dem Funktionsschalter genauso.
