Magento – How to maintain checkout data and state after a failed payment in Magento 2

checkoutmagento2payment

We use a payment gateway that goes redirects offsite and then returns to the success or failed controllers.

Once there is a failed payment (and it goes to the payment failed controller) the user is redirected to the shopping cart and the error message is shown.

We want the user to instead be redirected to the payment part of the checkout process. We also want all checkout information such as shipping and billing address and customer email to stay.

So far I am saving the shipping details in a session variable on the Fail controller:

$order = $this->checkoutSession->getLastRealOrder();

if ($order) {
    $shipping = $order->getShippingAddress();
    if ($shipping) {
        $shippingData = $shipping->getData();
        $shipAr = array('firstName' => $shippingData['firstname'],
        'lastName' => $shippingData['lastname'],
        'region' => $shippingData['region'],
        'postcode' => $shippingData['postcode'],
        'street' => $shippingData['street'],
        'city' => $shippingData['city'],
        'company' => $shippingData['company'],
        'telephone' => $shippingData['telephone'],
        'country_id' => $shippingData['country_id'],
        'fax' => $shippingData['fax'],
        'email' => $shippingData['email']);

        $this->checkoutSession->setFailedPaymentShippingInfo($shipAr);
    }
}

Then I redirect to the checkout shipping section with:

$resultRedirect = $this->resultRedirectFactory->create();
$resultRedirect->setPath('checkout', ['_fragment'=>'payment']);
return $resultRedirect;

On the checkout page I am overriding LayoutProcessor::afterProcess()
and updating the $jsLayout with the values from the session variable.

It is not working too well. How can I do this?

Best Answer

I do not have the complete answer.

I use Ingenico Magento 2 module, and they integrate a specific page for the payment retry with the orderId as paramater.

Code exemple :

    $this->checkoutSession->setPaymentRetryFlow(true);
    $this->checkoutSession->setOrderOnRetry($order->getIncrementId());
    $quoteId = $order->getQuoteId();
    /** @var \Magento\Quote\Model\Quote $quote */
    $quote = $this->quoteRepository->get($quoteId);
    $this->checkoutSession->replaceQuote($quote);
    $resultPage = $this->pageFactory->create();

Another usefull code is from Mage Authorizenet module module located here :

vendor/magento/module-authorizenet/Controller/Directpost/Payment.php:140

The Magento core function is replaceQuote :

vendor/magento/module-checkout/Model/Session.php:458

/**
 * @param Quote $quote
 * @return $this
 */
public function replaceQuote($quote)
{
    $this->_quote = $quote;
    $this->setQuoteId($quote->getId());
    return $this;
}

You can check also the \Magento\Checkout\Model\Session::restoreQuote function