Magento und die reservierte Bestellnummer

Immer wieder beliebt, vielen bekannt und eine immer wiederkehrende Serviceanfrage des Kunden: „Der Kunde kann nicht mehr bestellen“, „Der Kunde hängt im Einkaufsprozess fest“ oder für die Geübten auch „Bitte Kunde ABC freischalten“. Diese sind meist Folge von folgender Fehlermeldung, die die Kunden dann an den Shopbetreiber weiterleiten:

Was ist passiert?

Wenn Magento eine neue Bestellnummer generiert, dann passiert das nicht erst dann, wenn die Bestellung erfolgt ist, sondern schon früher. Sie werd als reservierte Bestellnummer (Feld reserved_order_id) an den Warenkorb des Kunden gehängt und beim Erzeugen der Bestellung dann in Letztere mit übertragen (in Mage_Sales_Model_Convert_Quote). Warum das so gemacht wird, konnte ich noch nicht herausfinden. Wer es weiß, möge mich bitte aufklären.

Nun kann es ja immer mal sein, dass der Bestellvorgang aufgrund eines Fehlers nicht abgeschlossen werden kann. Das tritt verhäuft bei der Anbindung externer Bezahldienstleister auf, wie z.B. bei PayPal oder einem der hundert Kreditkartenanbieter. Hier wird nämlich erst die Bestellung schon mal gespeichert (Status Neu bzw. Ausstehend XY), dann folgt das – zumeist externe – Prozedere, und erst dann wird per Statusänderung die Bestellung abgeschlossen. Schlägt dazwischen etwas fehl, wird der Vorgang abgebrochen und der Benutzer verbleibt im Checkout.

Was bei einem direkten Fehler, wenn noch keine Bestellung gespeichert wird, kein Problem ist, da der Benutzer jederzeit die Bestellung erneut abfeuern kann, wird zu einem Problem, wenn dadurch die halbfertige Bestellung, die dem externen Zahlungsprozess vorgezogen wurde, bestehen bleibt. Das passiert auch dann, wenn gar kein Fehler vorliegt, aber der Benutzer den externen Bezahlvorgang einfach verlässt. Dann nämlich wird beim erneuten Kauf versucht, eine Bestellung anzulegen, deren Bestellnummer bereits vergeben wurde. Der geübte Shopbetreiber erkennt dies schnell am exception.log, wenn dort steht:

PDOException with message 'SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '[BESTELLNUMMER]' for key 'UNQ_SALES_FLAT_ORDER_INCREMENT_ID'

Das Problem verschärft sich, umso frequentierter der Shop genutzt wird, da dann sogar mehrere Benutzer um eine Bestellnummer konkurrieren können. Ausnahmslos alle Projekte, in die ich involviert bin, und die über recht ansehnlichen Traffic verfügen, klagen über dieses Problem. Es ist damit kein Einzelfall.

Was kann man dagegen tun?

Der gezielte Eingriff

Nun, der schnellste Eingriff im Akutfall, ist das Zurücksetzen der reservierten Bestellnummer im Warenkorb. Wenn die Bestellnummer bekannt ist (siehe exception.log), geht das recht schnell, mit folgendem SQL:

UPDATE sales_flat_quote sfq
SET sfq.reserved_order_id = NULL
WHERE sfq.reserved_order_id = 'BESTELLNUMMER'

Für BESTELLNUMMER ist natürlich die jeweilige Bestellnummer einzusetzen. Ebenso einen eventuell vergebenen Tabellenpräfix nicht vergessen! Ist die Bestellnummer nicht bekannt, muss natürlich auf anderweitigem Weg versucht werden, den blockierten Warenkorb zu finden. Mögliche Hilfsmittel sind hier die Kunden- oder Sitzungsdaten oder auch Inhalte des Warenkorbs (Produkte).

Der pauschale Eingriff

Wenn sich die Anfragen zu blockierten Warenkörben häufen ist das natürlich wenig zielführend, ganz zu schweigen von den genervten Kunden und den dadurch ausbleibenden Bestellungen. Um den Vorgang zu vereinfachen, deshalb hier ein SQL, um alle aktuell blockierten Warenkörbe auf einen Schlag zu ermitteln:

SELECT sfq.entity_id, sfq.reserved_order_id
FROM sales_flat_quote sfq
WHERE sfq.reserved_order_id IN (
    SELECT sfo.increment_id
    FROM sales_flat_order sfo
    WHERE sfo.quote_id != sfq.entity_id
)

Ein etwas abgewandeltes SQL setzt sogleich dann alle blockierten Warenkörbe zurück, in dem es die reservierten Bestellnummern löscht, was Magento veranlasst, eben bei Bedarf eine neue zu generieren:

UPDATE sales_flat_quote sfq
SET sfq.reserved_order_id = NULL
WHERE sfq.reserved_order_id IN (
    SELECT sfo.increment_id
    FROM sales_flat_order sfo
    WHERE sfo.quote_id != sfq.entity_id
)

Natürlich Bedarf auch dies immer noch dem manuellen Eingriff in ein Live-System(!) mit vorgeschalteter Kundenunzufriedenheit etc. Und den Kunden damit zu tracktieren, dass er bitte alle Cookies löschen möge, um einen neuen Warenkorb ohne reservierte Bestellnummer zu erhalten, was ohnehin nicht bei eingeloggten Nutzern funktioniert, ist nur was für ganz Umsatzscheue.

Ausblick

Die elegantere Lösung muss also automatisch greifen und möglichst den Benutzer niemals in diese Sackgasse führen. Denkbar wäre, das Bereinigungs-SQL als CRON mit einzubinden, aber auch das ist immer noch reaktionär und beseitigt das Problem nicht präventiv. Noch besser wäre es daher, das Szenario der reservierten Bestellnummer ganz zu überdenken oder eben das Convert-Model mit etwas mehr Toleranz auszustatten, sodaß im Konfliktfall einfach versucht wird, eine neue Bestellnummer (d.h. die nächst Freie) zu erzeugen.

Es gibt auch einige Zahlungsmodule, die im Fehlerfall die reservierte Bestellnummer zurücksetzen. Das ist sicher auch ein guter Workaround, hilft aber nicht in allen Fällen. Die Lösung muss daher schon in Magento selbst stattfinden.

Leider ist mir auch bei den jetzt aktuell erschienen und noch erscheinden Versionen EE 1.13 bzw. CE 1.8 nicht bekannt, dass an dem grundlegenden Prozedere etwas verändert wurde.

Feedback

Wer sich ähnlich im Alltag mit diesem Problem konfrontiert sieht kann mir gerne mal seine Erfahrungen schildern. Vielleicht existiert auch eine schon mir unbekannte Lösung oder es findet sich die Möglichkeit, zusammen an einer zu arbeiten. Insbesondere würde mich interessieren, warum es das Verfahren der reservierten Bestellnummer überhaupt gibt.

Es grüßt Euch für heute,
Euer Christian

Haftungsausschluss

Bei den in diesem Artikel genannten Tipps und aufgeführten Programmschnipseln handelt es sich ausschließlich um unverbindliche Ratschläge. Für entstandene Schäden, die auf die Anwendung dieser Ratschläge zurückzuführen sind, übernehme ich keinerlei Haftung. Wenden Sie diese Ratschläge nicht an, wenn Sie damit nicht einverstanden sind.

Creative Commons Lizenzvertrag
Dieser Artikel Inhalt steht unter einer Creative Commons Namensnennung – Weitergabe unter gleichen Bedingungen 3.0 Unported Lizenz.

4 Gedanken zu „Magento und die reservierte Bestellnummer

  1. Kevin Hennen

    Gleiches Problem hatte ich auch im Webshop, allerdings mit SOFORT Überweisung als Payment. Bei allen anderen PayPal & Co. ging es ohne Probleme, scheint das SOFORT beim Check-Out automatisch ein Problem mit der reservierten Bestellnummer hat. Wie folgt haben wir das Problem gelöst:

    1. im FTP-Server Datei suchen: app/code/core/Mage/Sales/Model/Resource/Quote.php
    2. in der Datei suchen nach der Code-Zeile: isOrderIncrementIdUsed method
    3. in der Code-Zeile folgendes ersetzen:

    $bind = array(‚:increment_id‘ => (int)$orderIncrementId);
    $bind = array(‚:increment_id‘ => $orderIncrementId);

    Im Prinzip wird nur (int) entfernt. Anschließend die Datei aktualisieren und das Problem ist weg.

    ————————————————————

  2. Michele

    Hallo

    Ich habe Magento 1.9.0.1 installiert und erfolgreich live geschaltet.
    Die allererste Bestellung ging problemlos durch meinen Shop modelcarshop.ch und hat die Bestellnummer 100000001.
    Eine zweite Bestellung funktioniert leider nicht mehr.
    Beim Abschliessen des Bestellvorganges erscheint o.g. Fehlermeldung „Bei der Verarbeitung Ihrer Bestellung ist ein Fehler aufgetreten…“

    Das Log-File bringt folgende Fehlermeldung:
    exception ‚PDOException‘ with message ‚SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry ‚100000001‘ for key ‚UNQ_SALES_FLAT_ORDER_INCREMENT_ID“ in /home/www/web81/html/lib/Zend/Db/Statement/Pdo.php:228

    Beim Ausführen o.g. SELECT-Befehls (Ermittlung blockierte Warenkörbe) erhalte ich ein Resultat mit reserved_order_id 100000001, d.h. mit derselben Bestellnummer wie die erste erfolgreich abgeschlossene Bestellung.
    Auch die Durchführung des zweiten o.g. UPDATE-Befehlt hat leider nicht geholfen, d.h. bei einer neuen Bestellung wird wieder reseved_order_id 100000001 ausgegeben.

    Woran kann dies liegen?
    Wird die reserved_order_id nicht erhöht?

    Vielen Dank für deine Hilfe, da ich langsam am Verzweifeln bin 🙁

    Beste Grüsse
    Michele Cioffi

    1. Christian Beitragsautor

      Das Problem ist das Gleiche, vielleicht hat sich in dieser Version nur etwas am Workaround geändert.
      Wenn Sie möchten geben Sie mir mal Zugriff auf die Datenbank (z.B. per phpMyAdmin) dann schaue ich mir das unverbindlich an.
      VG

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.