Problem/Motivation

The PaymentNotificationController triggers the PaymentOrderUpdater to avoid a race condition. However, the PaymentOrderUpdater saves the order while it is still in draft status. This results in the order pre-save marking the order as needing a refresh on save. The OrderStorage dutifully refreshes the order. Refreshing in the order in a webhoook causes any promotions using coditions that require a session or user context to be removed. This can potentially result in the order paid event not being triggered and the order not being placed.

Steps to reproduce

Add a user based promotion (commerce_promotion) to an order (e.g. requiring a user to have a specific role).
Complete the payment with Datatrans.
Order refreshes in webhook.
Promotion removed from the cart.
Order paid subscriber not being triggered or other deleterious effect, such as giveway promotion product removed from the cart.

Proposed resolution

Don't refresh in the webhook. Instruct the order to skip the refresh and then pass the order directly to the updater (rather than calling PaymentOrderUpdater::updateOrders()), which reloads the order.

     // Immediately trigger the payment updater, as doing that during
      // the kernel destruct event might result in race conditions with
      // the user returning from Datatrans.
      $order->setRefreshState(OrderInterface::REFRESH_SKIP);
      $this->paymentOrderUpdater->updateOrder($order);

I am really not sure if this is the best place to fix the issue. Potentially it would be better to not refresh locked orders. However, I am not sure if there is a valid use case for refreshing locked orders. I am happy to open an issue in commerce core based on your feedback.

Remaining tasks

MR to follow.

User interface changes

None.

API changes

None.

Data model changes

None.

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

tcrawford created an issue. See original summary.

tcrawford’s picture

Version: 8.x-1.x-dev » 2.0.x-dev
Issue summary: View changes

tcrawford’s picture

Note:
This can be solved in some use cases by using a customer based commerce condition (where the user is got from the customer on the order, rather than from the session).

However, we have use cases where the commerce condition must be user (session) based, which causes the issue described. As we have issues with multiple payment gateways I believe the best solution is to address this in commerce_core. I will open an issue there (and link here once done).

tcrawford’s picture

Status: Active » Closed (duplicate)

Closing as a duplicate due to the creation of an issue in the commerce_core module, where this is better fixed.

tcrawford’s picture