Hooking in PreDispatch funktioniert für Nachmahme (Zahlungsart), aber nicht für Paypal/Sofort

Hallo Zusammen,

Ich habe so eine Eregnis-Anmeldung:

 

public static function getSubscribedEvents()
    {
        return [
              'Enlight_Controller_Action_PreDispatch_Frontend_Checkout' => 'onPreDispatchCheckout',

...

In onPreDispatchChckout() erledige ich einige Sachen. Unter anderem übermittle ich eine Anfrage an einen Server von einem Lieferanten und wenn die Anfrage scheitert oder ein Fehlercode zurückkommt, breche ich den Checkout-Prozess ab:

/**
     * @param \Enlight_Event_EventArgs $args
     */
    public function onPreDispatchCheckout(\Enlight_Event_EventArgs $args)
    {
        /** @var \Shopware_Controllers_Frontend_Checkout $controller */
        $controller = $args->get('subject');
       
        // DAS IST HIER NOCH NICHT SEHR RELEVANT
        // as we only want to change the finishAction, check for it here
        // but if it is confirmAction and we've been forwarded here from finishAction
        // and during finishAction a session variable orderIsFulfillable == false was set,
        // we should assign a template variable orderIsFulfillable to display error to user
        // saying that we cannot take the order, because it is unfulfillable.
        if ($controller->Request()->getActionName() === 'confirm') {
            $sessionNamespace = $this->container->get('session');
            $orderIsFulfillable = $sessionNamespace->get('orderIsFulfillable');
            if(isset($orderIsFulfillable) && $orderIsFulfillable === false){
                $controller->View()->assign('orderIsFulfillable', false);
                $sessionNamespace->offsetSet('orderIsFulfillable', null); // reset this variable for not showing the error next time to user
            }
            return;
        }
        if ($controller->Request()->getActionName() !== 'finish') {
            return;
        }

        // DAS WICHTIGSTE IST AB HIER
        // $this->prepareOrderData() (unter anderem) kommuniziert mit dem externen Server
        // und zuweist $orderVariables['orderIsFulfillable'] true/false 
        $orderVariables = $this->prepareOrderData();
        if ($orderVariables['orderIsFulfillable'] !== true) {
            return $controller->forward('confirm');
        }

        // AUCH UNRELEVANT
        // reset this session variable to not show the error to the user on the next confirmAction
        // I think this is only needed during development, because in production we don't get false
        // for this session AND true for $orderVariables['orderIsFulfillable'].
        // Anyway this won't harm here, I guess.
        $this->container->get('session')->offsetSet('orderIsFulfillable', null);


        // WEITER SOLL DIE ZAHLUNG ABGEWICKELT WERDEN UND DIE BESTELLUNG GESPEICHERT
        // everything is ok, let
        // Shopware do its order stuff       
    }

Nach meinem Plan (und so funktioniert das bei Nachmahme als Zahlungsart) soll wenn $orderVariables[‘orderIsFulfillable’] !== true weder Zahlungsvorgang noch die Speicherung der Bestellung stattfinden. Leider wenn ich PayPal oder Sofort als Zahlungsart auswähle, startet der Zahlungsvorgang und die Bestellung wird auch gespeichert. Am Ende des Zahlungsvorgangs befinde ich mich auf /checkout/finish/sUniqueID/[hier folgt eine Zeichenkette] und sehe einen Fehler “Sie haben keine Artikel im Warenkorb” und kann in Backend die Bestellung finden.

Es erfolgt also kein $controller->forward(‘confirm’), was bedeutet auch, dass $orderVariables[‘orderIsFulfillable’] == true, aber das ist nicht möglich, weil ich hardcoded habe, dass $orderVariables[‘orderIsFulfillable’] == false. Auch ist es merkwurdig, dass wenn Zahlungsvorgang erfolgreich abgeschlossen wäre und $orderVariables[‘orderIsFulfillable’] == true wäre, dann müsste ich auf die Nachricht weitergeleitet werden, dass die Bestellung stattgefunden ist und nicht dass “keine Artikel im Warenkorb”.

Ich denke, dass  die Zahlungsplugins irgendwie mit meinem Plugin schlecht zusammen spielen im Sinne, dass sie sich vllt. für dieselben Ereignisse anmelden und nach Erfolg irgendwas tun, was dann die Funktion von meinem Plugin irgendwie beinträchtigt (eine Weiter/Umleitung?). Was könnte es sein bzw. wie könnte ich es beseitigen?

Ich vermute, die Zahlungs-Plugine agieren früher als mein. Wie könnte ich die Priorität von meinem Plugin erhöhen?

Moin,

evtl. hilft das:

https://forum.shopware.com/discussion/31135/event-hook-nach-bestellabschluss-aber-vor-bezahlplugins

1 „Gefällt mir“

Danke, kanuma, das gibt zumindest ein Richtung. Da geht es darum nicht in Enlight_Controller_Action_PreDispatch_Frontend_Checkout, sondern in Enlight_Controller_Action_PreDispatch_Frontend (also, ohne Checkout, generell in Frontend). Dadurch wird nicht in Checkout-Controller eingehooked und mehrere Controllers möglich sind und einige davon sind Zahlung-Controllers. Dann wird vorgeschlagen die Plugin-Hanldungen dann auszuführen, wenn es um ein von Zahlungs-Plugins-Controllers geht. 

Die Lösung scheint logisch zu sein und sobald Zahlungsplugins eigene Controllers haben wirken natürlich meine Plugin-Hooks nicht unbedingt vor der Zahlung.

Aber gibt es noch einen besseren/einfacheren Weg?

Hallo @rreimche‍,

um ehrlich zu sein, habe ich nicht genau verstanden was du probiere zu machen.

aber ich habe die follogende Antwort:

1- die ‚Enlight_Controller_Action_PreDispatch_Frontend_Checkout‘ ist richtig wie ich sehe und du kannst es benutzen

2- um ein Priorität zu deine Subscrib geben du kannst deine Action wie ein Array schreiben [‚ActionName‘, Priorität] also Z.B:

'Enlight_Controller_Action_PreDispatch_Frontend_Checkout' => ['onPreDispatchCheckout', 200],

3- ob du möchtest ‚Enlight_Controller_Action_PreDispatch_Frontend‘ zu benutzen du kannst das Funktion getControllerName, um die aktuelle controller zu überprüfen:

$controller->Request()->getControllerName() == 'Checkout'

4- wie ich sehe du möchtest nur finish und confirm subscriben. also warum beuntzest du nicht die events :

Enlight_Controller_Action_Frontend_Checkout_Finish

Enlight_Controller_Action_Frontend_Checkout_Confirm

VG,

Tel.: +49 755 - 183 990 00 | Web: http://enbit.de/

1 „Gefällt mir“

Danke, @ahmadsaad‍, die Events, die du nennst passen mir besser, wirklich.

Im Bezug darauf, was ich zu machen versuche: Ich versuch die Aktionen von meinem Plugin VOR der Aktionen von Zahlungs-Plugins auszuführen.

Hallo @rreimche‍,

zuerst du darfst wiesen , welche Event das Zahlungs-Plugins benutzen, um diese zu machen.

VG,

Tel.: +49 755 - 183 990 00 | Web: http://enbit.de/

Ich denke, ich habe die Lösung gefunden. Anstatt …Checkout_Finish sollte ich …Checkout_Payment benuzten. Die Taste „Kostenpflichtig Bestellen“ POSTet auf /checkout/payment und nicht auf /checkout/finish. Ja, so simple :slight_smile:

Soweit sieht das funktionierend aus, aber ich möchte noch ein paar Tests machen.

Bezahlung per Nachnahme POSTet auf /checkout/finish, aber Sofort und Paypal auf /checkout/payment. Somit ist es anscheinend wichtig beide Actions zu berücksichtigen.

Ich habe versucht so mein Plugin anzumelden (wie @ahmadsaad‍ empfehlt):

 public static function getSubscribedEvents()
    {
        return [
            
            'Enlight_Controller_Action_Frontend_Checkout_Confirm' => 'onPreConfirmAction',
            'Enlight_Controller_Action_Frontend_Checkout_Payment' => 'onPrePaymentAction',
            'Enlight_Controller_Action_Frontend_Checkout_Finish' => 'onPreFinishAction',
            'Enlight_Controller_Action_PostDispatchSecure_Frontend_Checkout' => 'onPostDispatchCheckout',
        ];
    }

Aber ich habe einige merkwurdige Effekte bekommen und deshalb bin ich am Ende mit der Lösung geblieben:

 public static function getSubscribedEvents()
    {
        return [
            
            'Enlight_Controller_Action_PreDispatch_Frontend_Checkout' => 'onPreDispatchCheckout',
            'Enlight_Controller_Action_PostDispatchSecure_Frontend_Checkout' => 'onPostDispatchCheckout',
        ];
    }

public function onPreDispatchCheckout(\Enlight_Event_EventArgs $args){
        $controller = $args->get('subject');
        $actionName = $controller->Request()->getActionName();

        switch($actionName){
            case 'confirm':
                $this->onPreConfirmAction($args);
                break;
            case 'payment':
                $this->onPrePaymentAction($args);
                break;
            case 'finish':
                $this->onPreFinishAction($args);
                break;
            default:
        }
}

public function onPostDispatchCheckout(\Enlight_Event_EventArgs $args) {
        $controller = $args->get('subject');
        $actionName = $controller->Request()->getActionName();

        if($actionName === 'finish') $this->onPostFinishAction($args);
}

Und die Lösung zu der Anfangsfrage war: Neben …Checkout_Finish soll man …Checkout_Payment benuzten. Die Zahlungsarte, die keine besondere Aktionen/Redirects machen (wie Nachnahme oder Vorkasse), steigen anscheinend gar nicht in …Checkout_Payment, aber die von Plugins wie PayPal Und Sofort verwenden …Checkout_Payment.

@rreimche

Ich schaffe es immer noch nicht, POST variablen nach dem checkout mit PayPal aus der Session zu holen … bzw in die session zu speichern… Irgendeine Idee ?