Skip to main navigation Skip to main content Skip to page footer

Bestell-Zustandsautomat (order state machine)

Seit Version 5.11.0 hat die Shop-Erweiterung einen Bestell-Zustandsautomaten („state-machine“). Damit definierst Du pro Payment-Type / Order-Type:

  • welche States es gibt,
  • welche State-Wechsel erlaubt sind,
  • welche Wechsel/States im Backend sichtbar sind,
  • unter welchen Bedingungen ein Wechsel angeboten wird (Conditions).

Gemeinsamkeit aller Flows: Sie starten mit prepared und enden mit processed.

stateDiagram-v2
    [*] --> prepared : Order is being prepared (FE customer / BE operator)
    prepared --> customSteps : Order placed (order + invoice no. assigned)
    customSteps --> processed : Order is finished
    processed --> [*]

Bezahlart × Bestell-Status Matrix

Payment-Type prepared ordered paid shipped requested answered credited refunded canceled canceled_unpaid processed
request (Produkt-Anfrage)
onInvoice (Rechnung)
prePayment (Vorkasse)
sepa (SEPA-Lastschrift)
payPal (PayPal-Wallet)
payPalCheckout
stripe (Kreditkarte etc.)
klarna
manual (manuelle Bestellung)
Return (Retoure)
Storno

Hinweis: Die Matrix beschreibt typische Flüsse. Die tatsächlich erlaubten States werden über die State-Machine-Konfiguration bestimmt (siehe unten).

Hinweise zu den Zuständen

  • prepared → Bestellung ist in einem Erstellungsstatus. Es wurde noch keine Bestell- oder Rechnungsnummer vergeben. Einziger Status, in dem eine Bestellung im TYPO3-Backend gelöscht werden kann (es sei denn, es handelt sich um eine Warenkorbbestellung vom Typ request).
  • ordered → Bestellung wurde platziert; Bestell- und Rechnungsnummer wurden vergeben.
  • paid → Zahlung wurde verbucht/markiert.
  • shipped → Versand wurde erfasst (z. B. Versanddatum gesetzt).
  • requested → Anfrage wurde gestellt (Anfrage-Workflow).
  • answered → Anfrage wurde beantwortet/abgeschlossen (Anfrage-Workflow).
  • credited → Retoure-/Gutschrift-Bestellung wurde erstellt (negative Positionen) und dokumentiert.
  • refunded → Erstattung/Storno-Dokument wurde erstellt bzw. Erstattung wurde dokumentiert (je nach Typ).
  • canceled → Bestellung ist nicht bezahlt und nicht versandt und soll storniert werden. Daraus resultiert typischerweise eine neue Bestellung vom Typ storno (Gegendarstellungs-/Storno-Dokument).
  • canceled_unpaid → Abbruch einer Bestellung (je nach Zahlungsart möglich; oft mit Geldfluss/Refund gekoppelt).
  • processed → Bestellvorgang ist abgeschlossen (Endzustand für den jeweiligen Flow).

Grundprinzip

Ein State definiert die möglichen Folgestates (Transitions). Eine Transition kann optional eine Condition haben. Zusätzlich kann ein State per hidden-condition im Backend ausgeblendet werden.

  • allowed: Welche Ziel-States sind aus diesem State heraus erreichbar?
  • condition: Wann ist ein allowed-Übergang verfügbar?
  • hidden: Wann ist ein State (oder optional auch ein Übergang) im Backend ausgeblendet?

Wichtig:

  • Wenn ein State erreicht wurde, gelten ausschließlich dessen allowed-Transitions.
  • Der State processed ist ein Endzustand – trotzdem muss allowed definiert sein (leer).

Konfigurationsstruktur (TypoScript)

Die Konfiguration erfolgt in TypoScript unter:

plugin.tx_shop.settings.basketOrder.orderOptions.<orderType>.status.<state> {
    allowed { ... }
    hidden { ... }
}
  • <orderType> ist z. B. prePayment, onInvoice, payPal, request, return, storno, …
  • <state> ist z. B. prepared, ordered, paid, shipped, processed, …

Beispiel: prePayment (Vorkasse)

plugin.tx_shop.settings.basketOrder.orderOptions.prePayment {
    status {
        prepared {
            # Im status "prepared" kann die Bestellung nur zu "ordered" wechseln.
            allowed {
                ordered =
            }
        }
        ordered {
            # Im status "ordered" kann die Bestellung zu "paid" oder "canceled" wechseln.
            allowed {
                paid =
                canceled =
            }
        }
        paid {
            # Im status "paid" kann die Bestellung zu "shipped" oder "processed" wechseln.
            # Die möglichen States sind mit einer Condition belegt.
            # Wenn mehrere Conditions enthalten sind, müssen diese alle zutreffen (AND).
            allowed {
                shipped {
                    # Show marked-as-shipped when not "only digital products" are in basket-order
                    condition {
                        basket = NotContainsDigitalProductsOnly
                    }
                }
                processed {
                    # Skip shipping step for digital-only orders
                    condition {
                        basket = ContainsDigitalProductsOnly
                    }
                }
            }
        }
        shipped {
            # Hide whole shipped state when "only digital products" are in basket-order
            hidden {
                condition {
                    basket = ContainsDigitalProductsOnly
                }
            }
            # Im status "shipped" kann die Bestellung nur zu "processed" wechseln.
            allowed {
                processed =
            }
        }
        canceled {
            # Im status "canceled" kann die Bestellung nur zu "processed" wechseln.
            allowed {
                processed =
            }
        }
        processed {
            # Endzustand – allowed muss existieren, bleibt aber leer
            allowed =
        }
    }
}

Leseregel (aus dem Beispiel):

prepared → ordered → paid → shipped → processed

Oder (bei digitalen Produkten): paid → processed (ohne Versand)

Conditions

Conditions steuern, ob eine Transition (oder ein kompletter State) im Backend angeboten wird.

Konvention:

  • Conditions sind als „Condition-Key → Condition-Klasse“ (oder Resolver) aufgebaut.
  • Eine Condition wird erfüllt, wenn die Klasse/Logik für die aktuelle Bestellung true ergibt.
  • Mehrere Conditions in einem Block werden als AND interpretiert.

Conditions:

  • ContainsDigitalProductsOnly
  • NotContainsDigitalProductsOnly
  • NotEmpty
  • Empty

Typische Conditions:

  • basket = ContainsDigitalProductsOnly: Warenkorb enthält nur digitale Produkte
  • basket = NotContainsDigitalProductsOnly: Warenkorb enthält nicht nur digitale Produkte
  • basket = NotEmpty: Warenkorb muss nicht leer sein
  • paid_date = Empty: Bezahlungsdatum muss leer sein
  • ordered_date = NotEmpty: Bestelldatum muss gesetzt sein

States ausblenden (hidden)

Ein State kann komplett im Backend ausgeblendet werden – z. B. wenn ein Schritt im Flow für bestimmte Bestellungen irrelevant ist.

shipped {
    hidden {
        condition {
            basket = ContainsDigitalProductsOnly
        }
    }
    allowed {
        processed =
    }
}

Ergebnis:

  • Der State shipped taucht für digitale-only Bestellungen nicht auf.
  • Der Flow kann trotzdem direkt nach processed führen (über Transition aus paid).

Best-Practice: Endzustand immer definieren

Auch wenn processed keine Folgestates hat, muss es im Statusbaum existieren:

processed {
    allowed =
}

So ist der Flow „geschlossen“ und die State-Machine kann eindeutig validieren, dass keine weiteren Übergänge vorgesehen sind.

Beispiel-Flows als Diagramm

Vorauskasse Bestellung

stateDiagram-v2
    [*] --> prepared
    prepared --> ordered
    ordered --> paid
    paid --> shipped : physical goods
    paid --> processed : digital-only
    shipped --> processed
    processed --> [*]

Anfrage Bestellung

stateDiagram-v2
    [*] --> prepared
    prepared --> requested
    requested --> answered
    answered --> processed
    processed --> [*]

Konfiguration erweitern

Du kannst die State-Machine pro orderOptions.<type> beliebig erweitern:

  • Neue States hinzufügen: State-Block unter status { ... } anlegen.
  • Übergänge hinzufügen/entfernen: allowed { ... } anpassen.
  • Business-Regeln erzwingen: Transitions mit condition { ... } schützen.
  • UI vereinfachen: irrelevante States per hidden.condition ausblenden.

Wichtig ist, dass:

  1. prepared als Start-Status existiert,
  2. processed als End-Status existiert,
  3. jeder State einen allowed-Block besitzt (auch wenn leer),
  4. keine „toten“ States existieren (States, die nie erreicht werden können), sofern das nicht bewusst so gewollt ist.

Typische Stolperfallen

  • Rabatte/Versand/Steuern* beeinflussen nicht die State-Machine direkt – aber Deine Conditions können darauf reagieren (z. B. Warenkorb enthält nur digitale Produkte).
  • State-Wechsel ohne Condition bedeutet: Der Wechsel ist immer verfügbar (sofern der aktuelle State passt).
  • hidden blendet aus, verhindert aber nicht zwingend die Existenz eines States im System – es ist primär UI/Backend-Steuerung.
  • Neue Order-Types benötigen immer eine vollständige status-Definition, sonst ist der Flow unklar.
Dokumentation

TYPO3 Shop by coding.ms

Ein umfangreicher Shop für TYPO3 zur Realisierung von Webshops, Online-Shops oder Payment-Subscriptions, vergleichbar mit tt_products, Cart oder Aimeos. Enthalten sind PayPal, PayPal-Checkout, Klarna, Stripe, Bookmarks, UPS-API, Rechnungs­erstellung, Backend-Modul, Vergleichsfunktion, Staffelpreise sowie Produktvarianten, Filter, Steuer- und Versandlogik für den praktischen Einsatz.

Menü
Warenkorb 0 Produkte

Dieses Demo wurde gebaut mit*

EXT:bootstrap_package für das Site-Package aka Theme basierend auf Bootstrap 5.

EXT:modules für Benutzer-Plugins wie Benutzerprofile, Registrierung, Benutzeradressen und mehr.

EXT:shop für die gesamte Shop-Funktionalität.

EXT:questions für die FAQ-Seite und die in den Produktdetailseiten verlinkten FAQs.

EXT:glossaries für die Glossare und Definitionen.

EXT:fluid_fpdf zur Erstellung von Rechnungen, Lieferscheinen, Produktblättern und mehr.

EXT:parsedown_extra zum Rendern der Erweiterungsdokumentation von Markdown in HTML.

* Es wurden ausschließlich integrierte Einstellungen mit site-settings & TypoScript vorgenommen – keine Templates oder andere Dateien wurden geändert oder überschrieben!