Türchen 05: Magento und seine Bestellstatus - ein Überblick

Magento bietet seit Version 1.5 (CE) die Möglichkeit, benutzerdefinierte Bestellstatus komfortabel über das Backend anzulegen und zu verwalten. Dennoch sehe ich in meiner täglichen Freelancer-Tätigkeit, dass diese Funktionalität insbesondere bei kleineren Magento-Shops in vielen Fällen noch völlig vernachlässigt wird. Daher möchte ich in diesem Adventskalender-Türchen dieses Feature etwas näher betrachten und einige Tipps für den Umgang mit den Bestell-Status geben. Sofern nicht explizit angegeben, beziehe ich mich im Folgenden immer auf die Magento Community-Edition ohne zusätzlich installierte Extensions.

Die Status-Theorie - oder: wieso wird meine Bestellung nicht als vollständig markiert?

Die Status Pending, Processing und Complete (bzw. deren lokalisierte Pendants) sind sicherlich jedem geläufig - sei es als Magento Shop-Betreiber oder -Entwickler. Daneben existieren in einer unmodifizierten Magento 1.8 Installation noch weitere eher unbekannte Status wie PayPal Canceled Reversal oder Suspected Fraud. Die Status in Magento im Allgemeinen repräsentieren den aktuellen Zustand einer Bestellung im System und können beispielsweise, wie die beiden zuletztgenannten, auf mögliche Fehler (in diesem Fall der PayPal-Zahlungsabwicklung) hinweisen.

Magento unterscheidet zwischen Status, die dem Backend-Anwender sowie Kunden im Benutzerkonto im Frontend angezeigt werden und sog. States (Zuständen). State und Status sind über eine 1:n-Beziehung miteinander verknüpft, wobei jeder State einen Standard-Status definiert. Ein Status ist über den Statuscode eindeutig identifizierbar und kann unterschiedliche Bezeichnungen pro StoreView erhalten.

Die verschiedenen Status und deren Zuordnung sind in der Datenbank-Tabelle sales_order_status_state festgelegt und können über das Magento-Backend unter dem Menüpunkt System->Order Statuses geändert und zugeordnet werden:

State-Wechsel erfolgen code-seitig oder durch verschiedene Backend-Aktionen, wie beispielsweise die Rechnung oder den Lieferschein erstellen.
Status-Wechsel sind im Magento Backend über die Kommentar-Funktion auf Bestell-Ebene möglich - allerdings limitiert auf den aktuellen State.

Das folgende Schaubild zeigt den zugrunde liegenden, vereinfachten Zustandsautomaten ohne Berücksichtigung der von der Zahlungsart abhängigen Status und ohne Schleifen:

Die Transition des States new in processing erfolgt über das Flag

$order->setIsInProcess(true)

Der spezielle Status holded kann sowohl aus dem Status pending als auch aus dem Status processing heraus gesetzt werden und speichert über die Magic Setter

$order->setHoldBeforeState()

bzw.
$order->setHoldBeforeStatus()

den vorherigen Zustand.

Welche Möglichkeiten habe ich im Code, um den Status bzw. State der Bestellung zu ändern?

  1. Analog zur Handhabung über das Backend, kann auch im Code durch das Hinzufügen eines Kommentars der Bestellstatus geändert werden:
    Mage_Sales_Model_Order::addStatusHistoryComment()
    ändert mit dem Statuscode als zweitem Parameter den Status der Bestellung bzw. setzt den Default Status, sofern
    true
    übergeben wird.
  2. Die Funktion
    addStatusHistoryComment()
    ruft intern den Magic Setter
    $order->setStatus()
    auf, der natürlich auch direkt verwendet werden kann.
  3. Status- und State-Wechsel können zudem über die Methode
    Mage_Sales_Model_Order::setState()
    erreicht werden. Eine Ausnahme bilden hierbei die States complete und closed, diese können nicht explizit über die genannten Methoden gesetzt werden, da sie per Intention nur über den oben gezeigten Workflow erreicht werden sollen. Vorausgesetzt, man weiß was man tut (!), kann dieser Schutzmechanismus allerdings über einen Aufruf der internen Methode
    $order->_setState()
    mit dem fünften Parameterwert
    $shouldProtectState = false
    nach entsprechendem Rewrite umgangen werden.

Was kann schief gehen?

Der State wird automatisch über die Methode

Mage_Sales_Model_Order::_checkState()

bei jedem Speichern des Order-Objekts gesetzt. Unglücklicherweise prüft Magento beim Setzen der Status über die oben genannten Methoden nicht, ob die Status/State-Zuordnung eingehalten wurde.
D.h. es ist zum Beispiel möglich - und wird leider in manchen Extensions auch so gehandhabt - über den Aufruf
$order->setStatus('pending')->save();

im State complete den (nicht zugeordneten) Status pending zu setzen, was natürlich nicht im Sinne des Erfinders sein dürfte:

Dies führt unter anderem dazu, dass im Backend das Status-Dropdown über dem Kommentarfeld nicht mehr mit dem aktuellen Bestellstatus übereinstimmt und ein Shop-Mitarbeiter, der lediglich einen Kommentar einstellen möchte, ungewollt den Bestellstatus ändert:

Abhilfe schafft hier ein kleines Modul, das die Status/State-Integrität über einen Observer auf das Event sales_order_save_before sicher stellt:
Befindet sich der gewünschte Status nicht im zugeordneten State, verhindert eine Exception das Speichern des Order-Objekts.
Somit entstehen keine inkonsistenten Status/State-Zuordnungen in der Datenbank und das oben angesprochene Setzen des Status pending wäre nicht möglich gewesen.

Durch die Tatsache, dass der

_checkState()
-Aufruf in der Reihenfolge nach dem Observer aufgerufen wird, ist es in der Implementierung leider notwendig, die Logik zu replizieren, wenn man nicht die Alternative über einen Rewrite gehen möchte.

Wie kann ich Prozesse auf Basis dieser Status definieren?

Wir haben in den vorangegangenen Abschnitten gesehen, wie das Status-Handling in Magento implementiert ist und welche Fallstricke es bieten kann. Im Folgenden soll die Frage beantwortet werden, wie bestimmte Aktionen ausgeführt werden können, wenn eine Bestellstatus-Transformation erfolgt ist.
Hierzu eignet sich das Event sales_order_save_after, in dem über

$order->getOrigData('status')

an den Bestellstatus vor der Speicherung zugegriffen werden kann. Für den Fall, dass ein Unterschied zum aktuellen Status besteht, liegt ein Statuswechsel vor und die gewünschte Aktion kann ausgeführt werden.
Denkbar wäre hier zum Beispiel die Implementierung eigener
dispatchEvent()
Aufrufe für jeden Status-Übergang, eine eigene, flexible Konfiguration im Backend, etc.

Und was ist mit Magento 2?

Abschließend werfen wir einen kurzen Blick in das offizielle Magento 2 Github-Repository
(2.0.0.0-dev54):
Abgesehen von der neuen Namenskonvention hat sich an der Order Status/State-Thematik bis dato nichts verändert; die Status- und Statecodes sind identisch, so dass der oben gezeigte Zustandsautomat (zumindest momentan) auch weiterhin anwendbar ist.

Ich hoffe, ich konnte mit diesem Artikel etwas zu diesem sehr informativen Adventskalender beitragen, der immer wieder klasse Tipps rund um das Thema Magento bietet.

In diesem Sinne eine frohe und besinnliche Weihnachtszeit mit Euren Magento-Shops;-)


Quellen:
http://www.duden.de/rechtschreibung/Status ;-)



Ein Beitrag von Christoph Massmann
Christoph's avatar

With multiple years in Magento freelance consulting Christoph Maßmann and Michael Stork as former CTO combine their knowledge and founded BESUGRE in 2013, a company that focuses on providing a Recommendation Engine for personalized product experiences in Magento shops of any size.

Alle Beiträge von Christoph

Kommentare
Türchen 14: A possible solution for Dropshipping in Magento - Magento Blog für Entwickler und eCommerce-Shops - webguys.de Magento Blog für Entwickler und eCommerce-Shops – webguys.de am

[…] the Magento order stack. For managing and tracking the partner an additional workflow with its own status handling is required. This sub-process has to be integrated between a successful payment and the creation of […]

Tobias Vogt am

Danke Chris, sehr guter Beitrag. So intensiv und detailiert hatte ich mich damit auch noch nicht beschäftigt :-)

Andrej am

Danke für diesen hilfreichen Beitrag, der Licht auf ein vernachlässigtes und bislang etwas im Dunkeln liegendes Thema wirft.

Dein Kommentar