rabol/laravel-simplesubscription-stripe

只需几分钟即可在您的Laravel应用程序中设置订阅,而不是几天

1.1.1 2023-09-08 06:22 UTC

This package is auto-updated.

Last update: 2024-08-27 11:16:10 UTC


README

Latest Version on Packagist GitHub Tests Action Status GitHub Code Style Action Status Total Downloads

此包不是Laravel Cashier,Laravel Cashier功能更强大,具有其他几个功能。如果您想快速在Laravel应用程序中设置订阅和Stripe支付,则此包适合您。

它只包含1个迁移和一个辅助类。

设置Stripe超出了此包的范围

安装

您可以通过composer安装此包

composer require rabol/laravel-simplesubscription-stripe

您可以使用以下命令发布和运行迁移

php artisan vendor:publish --provider="Rabol\LaravelSimpleSubscriptionStripe\LaravelSimpleSubscriptionStripeServiceProvider" --tag="laravel-simplesubscription-stripe-migrations"
php artisan migrate

您可以使用以下命令发布配置文件

php artisan vendor:publish --provider="Rabol\LaravelSimpleSubscriptionStripe\LaravelSimpleSubscriptionStripeServiceProvider" --tag="laravel-simplesubscription-stripe-config"

这是已发布配置文件的内容

return [
    'stripe_key' => env('STRIPE_KEY'),
    'stripe_secret' => env('STRIPE_SECRET'),
    'stripe_webhook_secret' => env('STRIPE_WEBHOOK_SECRET'), // Web hook secret
    'stripe_webhook_tolerance' => env('STRIPE_WEBHOOK_TOLERANCE', 300) // max time diff in webhook signature
];

使用方法

以下是如何使用此包的简单示例。

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Rabol\LaravelSimpleSubscriptionStripe\LaravelSimpleSubscriptionStripe;
use Auth;

class StripeController extends Controller
{
    public function index()
    {
        return view('stripe.index')
            ->with('stripePrices', LaravelSimpleSubscriptionStripe::stripe()->prices->all());
    }

    public function gotoStripeCustomerPortal(Request $request)
    {
        return redirect(LaravelSimpleSubscriptionStripe::gotoStripeCustomerPortal(Auth::user(), route('stripe.index')));
    }

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

        if (!$user->stripe_id) {
            $options = [
                    'email' => $user->email,
                    'name' => $user->name,
                    'address' => [
                    'city' => $user->city ?? '',
                    'line1' => $user->adr_line_1 ?? '',
                    'line2' => $user->adr_line_2 ?? '',
                    'postal_code' => $user->postal_code ?? '',
                    'country' => $user->country ?? '',
                    'state' => $user->state ?? '',
                ]];

            // If the user should be Tax Exempt, and the information to the options array
            LaravelSimpleSubscriptionStripe::createAsStripeCustomer($options);
        }

        $priceId = $request->input('priceId');
        $session = LaravelSimpleSubscriptionStripe::createCheckoutSession([
            'allow_promotion_codes' => true,
            'success_url' => config('app.url') . '/stripe/success/{CHECKOUT_SESSION_ID}',
            'cancel_url' => config('app.url') . '/stripe/canceled',
            'customer' => $user->stripe_id,
            'customer_update' => [
                'name' => 'auto',
                'address' => 'auto',
            ],
            'payment_method_types' => [
                'card'
            ],
            'mode' => 'subscription',
            'tax_id_collection' => [
                'enabled' => true
            ],
            'line_items' => [[
                'price' => $priceId,
                // For metered billing, do not pass quantity
                'quantity' => 1,
            ]],
            'subscription_data' => [
                'metadata' => ['name' => 'Advanced'],
                //'default_tax_rates' => ['txr_xxxxxxxx'] // get the tax id from the Stripe dashboard
            ]
        ]);

        return redirect()->to($session->url);
    }

    public function cancled(Request $request)
    {
        return view('stripe.cancled')
            ->with('request', $request);
    }

    public function success(Request $request, string $session_id)
    {
        $session = LaravelSimpleSubscriptionStripe::stripe()->checkout->sessions->retrieve($session_id);
        $customer = LaravelSimpleSubscriptionStripe::stripe()->customers->retrieve($session->customer);

        return view('stripe.success')
            ->with('session', $session)
            ->with('customer', $customer);
    }
}

如果您有一个应免税的客户,请添加如下内容

'tax_id_data' => [
    [
        'type' => 'eu_vat',
        'value' => 'DK12345678'
    ]
    ],
    'tax_exempt' => 'exempt'

到创建Stripe客户时的$options中,并记住在订阅数据中添加有效的tax_rate

视图文件

索引 - /resources/views/stripe/index.blade.php

@extends('layouts.app')

@section('content')
    <div class="container">
        <div class="row justify-content-center">
            <div class="col-md-8">
                <div class="card shadow-sm">
                    <div class="card-header bg-warning">
                        <div>
                            <div class="row">
                                <div class="col-4">
                                    {{ __('Simple subsctiption Stripe') }}
                                </div>
                                @if(auth()->user()->stripe_id)
                                <div class="col-8 text-right">
                                    <form method="POST" action="{{ route('stripe.customer_portal') }}">
                                        @csrf
                                        <button class="btn btn-sm btn-primary" type="submit">Billing portal</button>
                                    </form>
                                </div>
                                @endif
                            </div>
                        </div>
                    </div>

                    <div class="card-body">
                        <table class="table">
                            <thead>
                                <th>Stripe Price Id</th>
                                <th>Name</th>
                                <th>Price</th>
                                <th>Actions</th>
                            </thead>
                            <tbody>
                            @foreach($stripePrices as $stripePrice)
                                <tr>
                                    <td>{{$stripePrice->id}}</td>
                                    <td>{{Rabol\LaravelSimpleSubscriptionStripe\LaravelSimpleSubscriptionStripe::stripe()->products->retrieve($stripePrice->product)->name}}</td>
                                    <td>
                                        @php
                                            $nf = new \NumberFormatter('es_ES', \NumberFormatter::CURRENCY);
                                            $value = $nf->formatCurrency(($stripePrice->unit_amount / 100), 'EUR');
                                        @endphp
                                        {{ $value}}
                                    </td>
                                    <td>
                                        <form action="{{ route('stripe.checkout') }}" method="POST">
                                        @csrf
                                            <input type="hidden" name="priceId" value="{{ $stripePrice->id }}" />
                                            <button class="btn btn-sm btn-primary" type="submit">Checkout</button>
                                        </form>
                                    </td>
                                </tr>
                            @endforeach
                            </tbody>
                        </table>
                    </div>
                </div>
            </div>
        </div>
    </div>
@endsection

已取消 - /resources/views/stripe/canceled.blade.php

@extends('layouts.app')

@section('content')
    <div class="container">
        <div class="row justify-content-center">
            <div class="col-md-8">
                <div class="card">
                    <div class="card-header">{{ __('Simple subsctiption Stripe') }}</div>

                    <div class="card-body">
                        Sorry to see that you canceled the checkout
                    </div>
                </div>
            </div>
        </div>
    </div>
@endsection

成功 - /resources/views/stripe/success.blade.php

@extends('layouts.app')

@section('content')
    <div class="container">
        <div class="row justify-content-center">
            <div class="col-md-8">
                <div class="card">
                    <div class="card-header">{{ __('Simple subsctiption Stripe') }}</div>

                    <div class="card-body">
                        <div class="row">

                        </div>
                        Thanks, {{$customer->name}} enjoy your subscription.
                    </div>
                </div>
            </div>
        </div>
    </div>
@endsection

web.php - /routes/web.php

Route::prefix('stripe')
    ->as('stripe.')
    ->middleware(['auth'])
    ->group(function () {
        Route::get('index', [StripeController::class, 'index'])->name('index');
        Route::post('customer_portal', [StripeController::class,'gotoStripeCustomerPortal'])->name('customer_portal');
        Route::post('checkout', [StripeController::class, 'checkout'])->name('checkout');

        Route::get('cancled', [StripeController::class, 'canceled'])->name('canceled');
        Route::get('success/{session_id}', [StripeController::class, 'success'])->name('success');
});

处理Stripe回调 - webhooks

要处理webhooks,创建一个新的控制器,并从Rabol\LaravelSimpleSubscriptionStripe\Http\Controllers\WebhookController扩展它,并为每个您想要处理的事件创建一个方法。

方法应该是事件的单复数形式名称,以handle开头,以Event结尾,如下所示

handleCustomerSubscriptionCreatedEvent($event)

示例

<?php

namespace App\Http\Controllers;


use App\Models\User;
use Rabol\LaravelSimpleSubscriptionStripe\Http\Controllers\WebhookController;

class StripeWebhookController extends WebhookController
{
    public function handleCustomerSubscriptionCreatedEvent($event)
    {

        $subscription = $event->data->object;
        $user = User::where('stripe_id',$subscription->customer)->first();

        // provision the subscription in the app
        
        return Response('All ok', 200);
    }
}

请注意,Stripe不能保证事件按照正确的顺序到达您的端点。一种处理方式是创建作业,当事件发生时执行这些作业,并且作业应该能够在'updated'事件在'created'事件之前到达时处理'重试'。

测试

composer test

变更日志

有关最近更改的更多信息,请参阅变更日志

贡献

有关详细信息,请参阅贡献指南

安全漏洞

有关如何报告安全漏洞的详细信息,请参阅我们的安全策略

鸣谢

许可

MIT许可(MIT)。有关更多信息,请参阅许可文件