Laravel6 - how to integrate stripe payment gateway using Laravel cashier

Stripe is one of the most popular payment processing platform with access to 120+ countries. Laravel provides direct integration with Stripe through Laravel Cashier.

Laravel Cashier provides easy and fast integration in Stripe's subscription billing services. It handles almost all Stripe subscription request handling coupons, swapping subscription, subscription "quantities", cancellation grace periods, and even generate invoice PDFs.

In this article, we will integrate Laravel's Cashier package to receive payments from users directly from your website. We will also create other methods.

Laravel installation and Integration setup

We will integrate Cashier from the scratch so first, create new Laravel project using bellow command.

composer create-project laravel/laravel stripe

This will create fresh Laravel project in your system. Make sure you have already installed LAMP and Composer.

Now first install Laravel Cashier package by the Composer.

composer require laravel/cashier

Also create an authentication scaffold with bellow command.

composer require laravel/ui --dev
php artisan ui vue --auth

Database Setup

We have configured Cashier, now we are going to setup database migration. First check .env file in the root folder and setup your database details.

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=stripe
DB_USERNAME=root
DB_PASSWORD=root

Remember to run migrate command after package install. It will add required field in users table and also add another subscriptions table.

php artisan migrate

If you want to change in migration, run the bellow command. It will copy migration files to /database/migrations.

php artisan vendor:publish --tag="cashier-migrations"

Cashier Model

Now add the Billable trait in your model. This trait provides different methods of Stripe information.

use Laravel\Cashier\Billable;

class User extends Authenticatable
{
    use Billable;
}

If you have used different model other than User, define it in your .env file.

CASHIER_MODEL=App\User

Stripe API Keys

If you already have account in Stripe, you can get Stripe Key and Secret Key from the developer tab[https://dashboard.stripe.com/apikeys] from the menu. Else you can create your Stripe account [https://dashboard.stripe.com/register]. Now set your Stripe Publishable key and Secret key in .env file.

STRIPE_KEY=your-stripe-key
STRIPE_SECRET=your-stripe-secret

Create Payment methods

There are two types of payment methods, Subscriptions or Single charge methods. It depends upon which methods you want to implement in your project.

Subscription based payment methods

First create new route or update route /home for Stripe payment view. For that, add this route in routes/web.php file.

Route::get('/home', 'StripeController@index');

Now create new controller to handle Stripe routes. run the bellow command.

php artisan make:controller StripeController

Add the index() method in the controller class

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class StripeController extends Controller
{
    public function index()
    {
        return view('stripe', [
            'intent' => Auth::user()->createSetupIntent()
        ]);
    }
}

After create routes, now create blade file resources/views/stripe.blade.php and add pass intent variable in the form. Put bellow html code in the <body> tag.

<input id="card-holder-name" type="text">

<!-- Stripe Elements Placeholder -->
<div id="card-element"></div>

<button id="card-button" data-secret="{{ $intent->client_secret }}">
    Update Payment Method
</button>

Then add Stripe.js library bellow the code above the closing </body> tag.

<script src="https://js.stripe.com/v3/"></script>

<script>
    const stripe = Stripe('stripe-public-key');

    const elements = stripe.elements();
    const cardElement = elements.create('card');

    cardElement.mount('#card-element');
</script>

Then add the event listner.

const cardHolderName = document.getElementById('card-holder-name');
const cardButton = document.getElementById('card-button');
const clientSecret = cardButton.dataset.secret;

cardButton.addEventListener('click', async (e) => {
    const { setupIntent, error } = await stripe.confirmCardSetup(
        clientSecret, {
            payment_method: {
                card: cardElement,
                billing_details: { name: cardHolderName.value }
            }
        }
    );

    if (error) {
        // Display "error.message" to the user...
    } else {
        // The card has been verified successfully...
        window.location = route('stripeCharge');
    }
});

After the card has been verified by Stripe, return to controller method to charge the card. So first create new controller method.

Route::post('stripe/charge', 'StripeController@charge')->name('stripeCharge');

Now add new method charge() in the StripeController where user is created new subscription.

public function charge(Request $request)
{
    $user = Auth::user();

    $plan = $user->addPaymentMethod($request->paymentMethod);
}

Single charge

If you only want single charge and don't have subscription plans, you can also make single charge.

$single_charge = $user->charge($amount, $paymentMethod);

You can also pass third parameter of array to describe charge details.

Refund

You can refund the Stripe charges.

$payment = $user->charge(100, $paymentMethod);

$user->refund($payment->id);

Invoice

You can also get array of invoices.

$invoices = $user->invoices();

Or also get including pending transactions.

$invoices = $user->invoicesIncludingPending();

Then you can display invoices in the blade table with following foreach loop.

<table>
    @foreach ($invoices as $invoice)
        <tr>
            <td>{{ $invoice->date()->toFormattedDateString() }}</td>
            <td>{{ $invoice->total() }}</td>
            <td><a href="/user/invoice/{{ $invoice->id }}">Download</a></td>
        </tr>
    @endforeach
</table>

And on click Download button, just call downloadInvoice method to download invoice.

use Illuminate\Http\Request;

Route::get('user/invoice/{invoice}', function (Request $request, $invoiceId) {
    return $request->user()->downloadInvoice($invoiceId, [
        'vendor' => 'Company Name',
        'product' => 'Product Name',
    ]);
});

Conclusion

This way, you can integrate and charge from Stripe through Laravel Cashier. This is just basic subscription services covered in this article. You can add many services offered by Laravel Cashier. Check this official Documentation for more services.

For latest articles follow HackTheStuff on Twitter and like us our Facebook page.