rabol / laravel-simplesubscription-stripe
只需几分钟即可在您的Laravel应用程序中设置订阅,而不是几天
Requires
- php: ^8.0|^8.1|^8.2
- illuminate/contracts: ^8.37|^9.28|^10.0
- spatie/laravel-package-tools: ^1.4.3
- stripe/stripe-php: ^7.93
Requires (Dev)
- brianium/paratest: ^6.2
- nunomaduro/collision: ^5.3
- orchestra/testbench: ^6.15
- phpunit/phpunit: ^9.3
- spatie/laravel-ray: ^1.23
- vimeo/psalm: ^4.8
README
此包不是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)。有关更多信息,请参阅许可文件