craftcms / commerce-stripe

Stripe payment gateway for Craft Commerce
https://plugins.craftcms.com/commerce-stripe
MIT License
30 stars 51 forks source link

EVENT_BEFORE_CONFIRM_PAYMENT_INTENT no longer functional #297

Open phillmorgan28 opened 5 months ago

phillmorgan28 commented 5 months ago

Description

Previously, the server would confirm the PaymentIntent, allowing additional request parameters to be added through the EVENT_BEFORE_CONFIRM_PAYMENT_INTENT event. Our code injected the MOTO flag for mail order payments using this hook. This is no longer functional. Instead, the PaymentIntents are being confirmed client side, preventing the server from injecting any additional parameters.

Steps to reproduce

  1. Install plugin
  2. Create hook as below to inject moto parameter for mail order payments
  3. Hook is never run
        Event::on(PaymentIntents::class, PaymentIntents::EVENT_BEFORE_CONFIRM_PAYMENT_INTENT, static function (PaymentIntentConfirmationEvent $event) {
            if (Craft::$app->user->getIdentity()) {
                $event->parameters['payment_method_options'] = [
                    'card' => [
                        'moto' => true
                    ]
                ];
            }
        });

Additional info

linear[bot] commented 5 months ago

PT-1574 EVENT_BEFORE_CONFIRM_PAYMENT_INTENT no longer functional

nfourtythree commented 4 months ago

Hi @phillmorgan28

A quick question on this, is it for both people entering their card details correctly and for those choosing to pay with an existing payment method? Or just one or the other?

Thanks!

phillmorgan28 commented 4 months ago

Hi, this is for customers who enter their card details each time. We are not using saved payment methods in our implementation.

Just for clarification, our client uses the front end of their site to enter customer card details from their customers over the phone. We then hook the above event to inject to MOTO flag. Whether the transaction is completed on the front end or admin area doesn't matter, payment intents are never confirmed from the server side anymore, making it impossible to use the moto flag per Stripes docs.

Thanks!

phillmorgan28 commented 3 months ago

Hi @lukeholder I see you took ownership of this issue, has there been any progress?

abbywelford commented 3 months ago

Hi @lukeholder Just wondering if there's been any movement on this please? My client is chasing for an update so would be good to ideally get resolved or let them know a realistic timeline or if we need to look at alternative options

abbywelford commented 2 months ago

Looking for an update on this

abbywelford commented 1 month ago

I am disappointed by the lack of support/response here.

lukeholder commented 1 month ago

Apologies, it looks like the issue was assigned to me, but it was not on my radar.

The confirm event will continue to trigger for those using a custom payment form HTML and Javascript, but if you are using the standard getPaymentFormHtml(), and therefore using new stripe element payment form that's now the default (since plugin version 4.0.0), the confirm action on the payment intent is made on the client side, so there is no opportunity to hook into the confirm event with PHP.

If you want to modify the payment intent (when it is created) you can use the existing \craft\commerce\stripe\base\Gateway::EVENT_BUILD_GATEWAY_REQUEST event. See docs for it here: https://github.com/craftcms/commerce-stripe#buildgatewayrequest

so in effect you would replace you previous code:

Event::on(
    \craft\commerce\stripe\gateways\PaymentIntents::class,
    \craft\commerce\stripe\gateways\PaymentIntents::EVENT_BEFORE_CONFIRM_PAYMENT_INTENT,
    function(\craft\commerce\stripe\events\PaymentIntentConfirmationEvent $event) {
        $event->parameters['myParam'] = 'x';
    }
);

with this:

Event::on(
    \craft\commerce\stripe\gateways\PaymentIntents::class,
    \craft\commerce\stripe\gateways\PaymentIntents::EVENT_BUILD_GATEWAY_REQUEST,
    function(\craft\commerce\stripe\events\BuildGatewayRequestEvent $event) {
        if($event->type = 'payment_intent') {
            $event->request['myParam'] = 'x';
        }
    }
);

Which will give you the same effect if you just need to modify the payment intent.

If there is a specific reason you need to modify the payment intent only at the time of confirmation, please let me know, and we can find another solution.

Thanks

phillmorgan28 commented 1 month ago

Hi @lukeholder thanks for the response.

Unfortunately I've already attempted that solution before creating this ticket and I'm afraid it doesn't work. Stripe responds with:

image

        Event::on(
            \craft\commerce\stripe\gateways\PaymentIntents::class,
            \craft\commerce\stripe\gateways\PaymentIntents::EVENT_BUILD_GATEWAY_REQUEST,
            function (\craft\commerce\stripe\events\BuildGatewayRequestEvent $event) {
                if ($event->type == 'payment_intent') {
                    $event->request['payment_method_options']['card']['moto'] = true;
                }
            }
        );

Unfortunately, I'm not able to set confirm to true at this stage as the plugin has not captured payment details so that request would fail (I've tried this too). The MOTO flag MUST be passed when the payment is confirmed, and since it's confirmed from the client side it's impossible to set it securely from server side in this version of the plugin. Setting this flag from the client side would essentially permit someone to disable 3D Secure which is not an acceptable risk.

Thanks for your assistance.

lukeholder commented 1 month ago

@phillmorgan28

It sounds like you are trying to do a MOTO transaction using the new Stripe elements form UI, which by design seems incompatible with it being a customer-supplied payment collection and confirmation flow (not a mail order or telephone card payment). If you are using the new stripe elements form, your phone operator would need to validate a 3DS card over the phone, which is against the spirit of the SCA inherent in that UI.

If you want to just use the old payment form that supports the legacy simple credit card form (that existed before the new payment intents form), you can use gateway.getOldPaymentFormHtml(). This outputs the previous simple card form, and would run the confirm event as you previously expected.

Is that an acceptable compromise?

phillmorgan28 commented 1 month ago

Fantastic. If the old flow is observed, then that looks to be our solution. You're absolutely right about SCA which is our client's primary complaint at the moment.

I've implemented the changes and will wait for feedback from them before closing this issue down to ensure it's resolved.

Many thanks for your help.