Drupal Commerce integrates with a variety of payment APIs that are functionally onsite (via embedded iframes) but have to be implemented as offite (due to API integration requirements). Classic examples are the Stripe Payment Element and Authorize.Net Accept Hosted payment gateways. I think PayPal's Smart Payment Buttons are similar.
The issue is that these APIs confirm payment by redirecting the customer to a success or failure URL on the shopping cart application after submission. We use the return to tokenize the payment method and, depending on the API, either defer to the payment process pane for payment processing or else capture payment and redirect to checkout completion ourselves.
Our merchant add payment form should support any payment API, but for the sake of this ticket, let's just assume we only expect to support a hybrid method like this for now. This is simpler than having to figure out how to support the various methods of redirection.
Ideally, we would just need one additional route, a controller at admin/commerce/orders/###/payments/add/return. This controller would invoke the payment gateway plugin's relevant function but catch any redirect responses. The only challenge I see here is that we might need some way to save the selected transaction type and amount, but I'm not entirely certain ... it might depend on the payment API whether or not the values can be read from the form directly and used to provision / embed the relevant iframe.
In any case, let's do some research and decide if we need to essentially save the pending payment without a payment method, redirect to a admin/commerce/orders/###/payments/add/new-payment-method route, and embed the iframes and / or open the modals from there.
Issue fork commerce-3538210
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
Comment #4
adrianandres commentedComment #5
jsacksick commentedThis doesn't look correct to me. We're passing the $request object to be able to pass additional query parameters that are eventually needed by the gateway plugin. This additional route looks unnecessary.
Also, shouldn't this all be addressed from the other issue? #3538209: Provide a new "Add payment" form
Comment #6
adrianandres commentedComment #7
jsacksick commentedOk the only reason why this route would be needed I think is the access callback which depends on commerce_checkout.
If that is the only reason, perhaps we should fix the access callback and maybe make it require order update access instead?
To be discussed.
Comment #8
adrianandres commentedComment #9
vmarchuk@jsacksick
We need this route to handle the redirect from the payment gateway when we add a payment via OrderPaymentAddForm. Some payment gateways, such as Accept Hosted and Stripe, use a redirect URL to return the user to the site, even if they didn't leave the site (redirection occurs in any case).
And we can't use PaymentCheckoutController::returnPage() because it handles redirects during the checkout process, but here is a different case and we don't have checkout steps. Additionally, at the end of the process, we need to redirect the user to the entity.commerce_payment.collection page.
Here's a nice description added by Adrian https://git.drupalcode.org/project/commerce/-/merge_requests/500
Comment #10
vmarchukComment #11
jsacksick commentedLeft several feedbacks in the MR, but also realized we needed to port the "fixes" that already exist in PaymentCheckoutController::returnPage(). We need to call the loadForUpdate() method etc etc... Also please consider adding this route to the Authorize.net module directly.
To be discussed further internally.
Comment #12
vmarchukAs we discussed, we'll add this route to the commerce_authnet module for now, as there are no other payment gateways that will use it.
Issue for commerce_authnet is here.
Comment #14
jsacksick commentedWe've discussed this internally again and decided to implement the route in commerce on the following path: /admin/commerce/orders/{commerce_order}/payment-gateways/{commerce_payment_gateway}/merchant-return.
We should probably check for commerce_order.update access as well.
Comment #15
jsacksick commentedThe comment #11 still applies. We aren't calling loadForUpdate() which makes this code more prone to race conditions.
Comment #16
vmarchukAdded loadForUpdate to MR.
Comment #18
jsacksick commentedMerged! Thanks everyone!