Returning the stock when the customer abandons the payment - mollie/magento2 GitHub Wiki

This scenario can occur frequently: a customer adds a product to the cart, selects a payment method, clicks Place Order, and is redirected to the hosted payment page. For some reason, they then decide to stop the payment. Maybe they chose the wrong payment method, or they do not have enough funds in their account.

Instead of clicking the Cancel option at the payment provider, they use the browser Back button to go back to the checkout page.

What happens with the stock?

When working with low-stock products, this behavior can be problematic.

  • The stock is reserved the moment the customer clicks Place Order and the Magento order is created.
  • At that point, the payment at Mollie is in a pending or open state.
  • When the customer uses the browser Back button, the payment at Mollie is still pending, so the stock reservation remains active.

When the customer visits the checkout page again, the cart (quote) is set to active again. However, because the first order reserves the remaining stock, Magento cannot add the same quantity again. The customer is redirected back to the cart with a message that there is insufficient stock for their product.

Why the system does not know the payment was abandoned

At the moment the customer clicks Place Order:

  • Magento creates an order (usually in pending_payment status).
  • Stock is reserved according to the inventory configuration.
  • A pending payment is created at Mollie.

Later, when the payment status changes, Mollie sends a webhook to Magento. Examples:

  • paid
  • canceled
  • expired
  • failed (depending on the method)

Magento then updates the order based on that status. If the payment failed, expired, or was canceled, the order can be canceled and the reserved stock is released.

If the customer closes the tab or uses the Back button, Mollie does not know that the customer has really abandoned the payment. The status at Mollie stays open or pending until:

  • The customer actively cancels the payment at the provider, or
  • The payment expires according to Mollie and the payment method settings.

Only at that moment does Mollie send an update to Magento and only then can Magento safely release the reserved stock.

Depending on the payment method and configuration, this can take some time:

  • For iDEAL payments, this usually happens fairly quickly.
  • For bank transfer payment,s this process can take much longer.

Why we do not create the order only after payment

A common question is:

Can we create the Magento order only when the customer finishes the payment, so that abandoned payments do not block stock?

In the Mollie Magento extension this is intentionally not supported. The order is always created in Magento first, before the customer is redirected to Mollie.

There are two important reasons for this design:

1. Avoiding paid transactions without an order

If we were to start the Mollie payment first and only then create the Magento order, there is a real risk that order creation fails after the payment has already been completed. For example:

  • A database error occurs during order creation.
  • A custom plugin throws an exception.
  • The Magento server has a temporary outage or timeout.

In that case Mollie would report a successful payment, but Magento would not have a corresponding order. That situation is very difficult to recover from and leads to manual work and a bad experience for both the merchant and the customer. By creating the order first and only then starting the payment, we guarantee that every successful payment can be linked to an existing Magento order.

2. Handling asynchronous webhooks reliably

Mollie sends payment status updates to Magento by webhook. These webhook calls are asynchronous. They can arrive before the customer returns to the shop, or even if the customer never returns at all. To process a webhook, Magento must be able to look up the corresponding order. The link between Mollie and Magento is stored on the order, for example by transaction ID. If the order did not exist yet at the moment that the webhook arrived, Magento would not be able to process the update correctly.

Because of these reasons, the supported and safe flow in the Mollie Magento plugin is:

  1. Customer clicks Place Order in Magento.
  2. Magento creates the order and reserves stock.
  3. Magento creates the Mollie payment and redirects the customer to Mollie.
  4. Mollie sends status updates to Magento by webhook.
  5. Magento updates the existing order and releases stock when appropriate.

This means that stock is always reserved before the payment starts, and that we cannot move order creation to “after payment” without introducing a higher risk of inconsistent data and paid transactions without a valid order.

Is there a real solution?

There is no reliable way to detect that a payment was abandoned at the exact moment the customer presses the browser Back button. As long as Mollie has not changed the payment status or called the webhook, Magento cannot safely assume that the payment will not be completed later.