1
votes

Unless I'm missing something, I cannot see any Cashier wrapper to provide the creation of a PaymentIntent, does this exist?

While Cashier v10 added some content to handle SCA it doesn't work for me because I am handling payment details via a font-end element, so redirecting to a new route is messy.

I need to handle it as per this guide https://stripe.com/docs/payments/payment-intents/migration

Which requires the creation of a PaymentIntent like so:

$intent = \Stripe\PaymentIntent::create([
    'payment_method' => $json_obj->payment_method_id,
    'amount' => 1099,
    'currency' => 'gbp',
    'confirmation_method' => 'manual',
    'confirm' => true,
]);

I can of course do this directly from the Stripe sdk as shown here, but given I am likely to add more functionality that will likely make use of Cashier's other features it would keep it cleaner to go through Cashier for everything.

Can I create a PaymentIntent via Cashier or has that been missed off? If so, how? Or should I be handling this differently?

3

3 Answers

2
votes

Having investigated this further, the answer is that the

Laravel\Cashier\Billable->charge($amount,$method,$options)

method does a \Stripe\PaymentIntent::create($options) under the covers.

There are some things to be aware of:

  • By default the options confirmation_method will be set to automatic and confirm to true
  • The currency option will be set and will use the Cashier default currency
  • The amount option will be set based on the $amount passed in and the payment_method option will be set based on the $method passed in.
  • These values can all be overridden with replacements by passing an equivalent value in the $options argument

And finally, if you require SCA (which I did) then you must catch a \Laravel\Cashier\Exceptions\PaymentActionRequired exception and either redirect to the built-in Cashier page for this, or handle it in your front-end via your API request.

1
votes

I'm not a Cashier user but it looks to be an interface to Stripe Billing, so it mostly handles primitives related to Billing. From what I can tell, it does use PaymentIntents under the hood (for authenticating invoice payments that require authentication) but doesn't expose PaymentIntent creation directly.

The Cashier docs recommend that your integration redirect to the "payment page" when authentication is required: https://laravel.com/docs/5.8/billing#payments-requiring-additional-confirmation (for cases where PaymentIntents are in state requires_action)

For creating PaymentIntents directly, the stripe-php API library would be the right approach.

1
votes

Extend the Laravel\Cashier\Billable Trait; and Laravel\Cashier\Concerns\PerformsCharges; and use it instead of the default Billable trait in the User model

<?php

namespace App\Traits\Stripe;

use Laravel\Cashier\Concerns\ManagesCustomer;
use Laravel\Cashier\Concerns\ManagesInvoices;
use Laravel\Cashier\Concerns\ManagesPaymentMethods;
use Laravel\Cashier\Concerns\ManagesSubscriptions;
use App\Traits\Stripe\CustomPerformCharges as PerformsCharges;

trait CustomBillable
{
    use ManagesCustomer;
    use ManagesInvoices;
    use ManagesPaymentMethods;
    use ManagesSubscriptions;
    use PerformsCharges;
}
trait CustomPerformCharges
{
    use PerformsCharges;
  
    public function authorize(int $amount): Payment
    {
        if (!$this->hasStripeId()) {
            throw new BadRequestException(__('User is not a stripe customer'));
        }
        
        $paymentMethod = $this->defaultPaymentMethod();

        $options = [
            'capture_method' => 'manual'
        ];

        return $this->charge($amount, $paymentMethod, $options);
    }


    public function capture(int $amount, string $paymentIntent): void
    {
        $intent = StripePaymentIntent::retrieve($paymentIntent, $this->stripeOptions());
        $intent->capture(['amount_to_capture' => $amount]);
    }
}