Häufige Fehler bei eigenen Zahlungs- und Versandarten
Häufige Fehler bei eigenen Zahlungs- und Versandarten
~7 Min. Lesezeit Zuletzt aktualisiert am 9. August 2026
Block 8 endet wie Block 6 mit Kapitel 54 (Barrierefreiheit) und wie es Block 7 mit Kapitel 61 (Widget vs. Content Type) getan hat: eine gesammelte Rückschau, diesmal auf die Fehlerquellen, die beim Bau eigener Zahlungs- und Versandarten am häufigsten wirklich passieren.
Stillschweigend fehlende Zahlungsart im Checkout
Achtung: Der häufigste Fehler überhaupt, schon in Kapitel 65 angesprochen: Der Schlüssel im renders-Array der Layout-XML stimmt nicht exakt mit PointsRedemptionConfigProvider::METHOD_CODE überein - keine JavaScript-Fehlermeldung, keine PHP-Exception, die Methode fehlt einfach in der Liste. Immer zuerst per Browser-Devtools window.checkoutConfig.payment.methods prüfen, ob der Methodencode dort überhaupt als verfügbar auftaucht, bevor an der Renderer-Registrierung gesucht wird.
Buchung an der falschen Stelle
Achtung: collectRates() und die AvailabilityHandler-Prüfung laufen potenziell mehrfach pro Request - jede Buchungslogik dort (Ledger-Eintrag, Punktestand-Reduktion) würde bei jedem erneuten Aufruf erneut abziehen. Derselbe Fehler wie bei ApplyPointsRedemptionToTotalsPlugin (Kapitel 39) und die Lösung, für die sich Kapitel 63/67 bewusst entschieden haben: ausschließlich in sales_order_place_after buchen, garantiert genau einmal pro Bestellung.
Ungefangene Exceptions in der Verfügbarkeitsprüfung
Achtung: Wirft AvailabilityHandler::handle() (Kapitel 64) eine unbehandelte Exception - etwa weil CustomerRepositoryInterface::getById() bei einem inzwischen gelöschten Kunden fehlschlägt -, bricht der GESAMTE Payment-Step ab, nicht nur diese eine Zahlungsart. Der ValueHandlerPool fängt hier nichts automatisch ab. Defensive Typprüfungen (instanceof) und frühe return false-Pfade statt tief verschachtelter Zugriffe sind hier kein Stil, sondern Robustheit.
config-Cache vs. setup:upgrade verwechseln
Achtung: Eine neue system.xml-Gruppe (Kapitel 64/67) braucht nur bin/cache-clean config. Eine neue Datenbankspalte (Kapitel 63s quote.loyalty_points_to_redeem) oder ein neuer Data Patch (Kapitel 63s InstallSalesLoyaltyRedeemedAttribute) braucht dagegen zwingend bin/magento setup:upgrade. Wird nur der Cache geleert, bleibt die Spalte unsichtbar, und $quote->setData('loyalty_points_to_redeem', ...) schlägt fehl oder wird beim Speichern stillschweigend verworfen.
allow_multiple_address vergessen
Achtung: payment.xmls allow_multiple_address (Kapitel 62) steht bei mironsoft_loyalty_points bewusst auf 0: Eine Mehrfachadress-Bestellung (mehrere Lieferadressen, mehrere Teil-Bestellungen aus einem Warenkorb) hat kein einzelnes, eindeutiges grand_total, gegen das AvailabilityHandler (Kapitel 64) den eingelösten Punktebetrag prüfen könnte. Bleibt der Wert auf dem Standard 1 stehen, taucht die Zahlungsart dort auf, ohne dass die Verfügbarkeitslogik dafür je getestet wurde.
Länderfilter bei Versandarten vergessen
Achtung: Fehlen sallowspecific/specificcountry in der system.xml (Kapitel 66/67), lässt sich "Kostenloser Versand durch Punkte" im Admin nicht auf bestimmte Länder einschränken, selbst wenn checkAvailableShipCountries() im Code korrekt aufgerufen wird - die Prüfung liest schlicht immer denselben, nicht editierbaren Standardwert.
Router und rohe AJAX-Route vermischen
Achtung: Der eigene Router aus Kapitel 46 fängt gezielt die hübschen URLs unter /treuepraemien/... ab. Controller\Ajax\ApplyPoints (Kapitel 63) nutzt bewusst die technische Standard-Route mironsoft_loyalty/ajax/applypoints und braucht dafür keine Router-Änderung. Wird versehentlich versucht, auch diese Route über den Router "hübsch" umzuschreiben, bricht der AJAX-Aufruf aus Kapitel 65 - Formular-/AJAX-Ziele sind nicht SEO-relevant, dieselbe Begründung wie schon beim Redeem-Formular in Kapitel 53.
Tipp: Damit ist Block 8 abgeschlossen: eine Zahlungsart über die moderne Adapter-Facade, eine bewusst rabattbasierte Lösung für Teilzahlung statt echtem Split-Payment, eine explizit begründete, eng begrenzte Knockout.js-Ausnahme im Checkout-Frontend, und eine Versandart über den klassischen AbstractCarrier-Weg - beide gebucht über denselben, um Idempotenz bemühten sales_order_place_after-Observer. Block 9 wendet sich als Nächstes einem eigenen Produkttyp zu.