craftcms / commerce-stripe

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

Stripe Checkout Doesn't Work #261

Closed bryantwells closed 8 months ago

bryantwells commented 1 year ago

Description

Stripe Checkout does not work as outlined in the docs. It seems Craft requires a relative path for a Cancel URL, which is incompatible with Stripe's requirement of an HTTPS Cancel URL.

Steps to reproduce

Scenario 1

Results in Stripe error: "Not a Valid URL"

<form method="POST">
    {{ csrfInput() }}
    {{ actionInput('commerce/payments/pay') }}
    {{ hiddenInput('gatewayId', gateway.id) }}

    {# Cancel URL #}
    {{ hiddenInput('cancelUrl', 'checkout' | hash) }}

    {% namespace gateway.handle|commercePaymentFormNamespace %}
        {{ gateway.getPaymentFormHtml({})|raw }}
    {% endnamespace %}
</form>

Scenario 2

Results in Craft error: "Request contained an invalid body param"

<form method="POST">
    {{ csrfInput() }}
    {{ actionInput('commerce/payments/pay') }}
    {{ hiddenInput('gatewayId', gateway.id) }}

    {# Cancel URL #}
    {{ hiddenInput('cancelUrl', currentSite.baseUrl ~ '/checkout'|hash) }}

    {% namespace gateway.handle|commercePaymentFormNamespace %}
        {{ gateway.getPaymentFormHtml({})|raw }}
    {% endnamespace %}
</form>

Fix?

I was only able to get this to work by changing line 537 in PaymentIntents.php:

// 'cancel_url' =>  $transaction->getOrder()->cancelUrl,
'cancel_url' => Craft::$app->getSites()->getCurrentSite()->baseUrl . $transaction->getOrder()->cancelUrl,

Additional info

bryantwells commented 1 year ago

For anyone having a similar issue and looking for a cleaner fix, I was able to get this working by creating a new module and tying into the buildGatewayRequest event

use craft\commerce\models\Transaction;
use craft\commerce\stripe\events\BuildGatewayRequestEvent;
use craft\commerce\stripe\gateways\PaymentIntents;
use yii\base\Event;
use craft\helpers\UrlHelper;

Event::on(
    PaymentIntents::class,
    PaymentIntents::EVENT_BUILD_GATEWAY_REQUEST,
    function(BuildGatewayRequestEvent $e) {
        /** @var Transaction $transaction */
        $transaction = $e->transaction;
        $order = $transaction->getOrder();

        $e->request['cancel_url'] = UrlHelper::baseUrl() . $order->cancelUrl;
    }
);
pixelmachine commented 1 year ago

@bryantwells I think the issue is the formatting of your URL and hash.

You're using:

{{ hiddenInput('cancelUrl', currentSite.baseUrl ~ '/checkout'|hash) }}

Which gives an output of:

<input type="hidden" name="cancelUrl" value="https://yoursite.com/[hash]/checkout">

Instead you need to format your URL so that the hash is added in the right place, for example:

{{ hiddenInput('cancelUrl', siteUrl('/checkout')|hash) }}  
{# Or url('/checkout')|hash or maybe just (currentSite.baseUrl ~ '/checkout')|hash #}

That should give you a correct output like:

<input type="hidden" name="cancelUrl" value="[hash]https://yoursite.com/checkout">

At least I can confirm this is working correctly for me.

lukeholder commented 8 months ago

Closed as confirmed the hashing of the URL was not done on the whole value. Thanks @pixelmachine