Laravel上でStripeのサブスクプランのキャンセル方法を紹介します。
次の3つに分けて解説していきますね。
- Laravel上にキャンセルボタンを作る
- Stripeのカスタマーポータル上でキャンセルできるようにする
- 2.の方法+Webhookを利用
下記のようにメリット・デメリットが異なります。
面倒レベル
(◎→らくちん) |
Laravelテーブルへの反映 | カスタマイズしやすさ | |
①Laravel上 | △ 画面作りがメンドウ |
◎ | 〇 |
②Stripeカスタマーポータル上 | ◎ | × | × |
③Webhook利用 | △ 連携が最初メンドウ |
○ | 〇 |
状況に応じて、使い分けてくださいね。
なおLaravelとStripeを連携させてサブスク申込フォームを作る方法は、別記事にまとめてあります。
LaravelでStripeのキャンセル処理をする:Laravel上で実施
まずはLaravel上で処理を行う方法を解説します。
①Laravelにボタンを設置する
たとえば、次のようなキャンセルボタンを設置します。
blade.phpファイルには、次のように記述します。
$userはコントローラーで定義して受け渡してください。
1 2 3 4 5 |
契約のキャンセルはこちらから <form method="POST" action="{{route('stripe.cancel', $user) }}"> @csrf <button class="btn btn-success mt-2">キャンセルする</button> </form> |
②ルート設定を入れる
ルート設定例はこちら。
1 |
Route::post('/subscription/cancel/{user}', 'StripeController@cancelsubscription')->name('stripe.cancel'); |
③コントローラーにcancelメソッドを入れる
コントローラーはこちら。
cancelメソッドを使います。
1 2 3 4 |
public function cancelsubscription(User $user, Request $request){ $user->subscription('default')->cancel(); return back(); } |
解約に伴って実施したい処理があれば、コントローラー内に入れておきましょう。
④テストをしてみる
それではテストをしてみます。
実際にLaravel上でキャンセルボタンを押して解約手続きをします。
キャンセル後、usersテーブルをチェックしてみてください。
次のように ends_at カラムにサブスク終了予定日が入力されていれば成功!
Stripe側もチェックしておきましょう。
Stripeにログインし、左側のメニューから顧客/定期支払情報をチェックすると、次のように表示されます。
⑤今すぐ解約の場合はcancelNowメソッドを使う
cancelメソッドは次の解約日に更新しないようにできます。
「今すぐキャンセルにしたい」場合には、cancelNowメソッドが使えます。
1 |
$user->subscription('default')->cancelNow(); |
Laravel上での処理のメリット・デメリット
Laravel上で処理するメリットは、StripeにもLaravelのテーブルにも処理を反映させられます。
色々とカスタマイズも可能です。
デメリットとしては、Laravelのプロジェクト内にStripeのキャンセルボタンを設置したりする手間が増えること。
Stripe側にすべてお任せしたほうが、ラクですよね。
LaravelでStripeのキャンセル処理をする:カスタマーポータル上
次に、Stripeのカスタマーポータルを利用して行う処理を解説します。
Stripeに処理を任せられるので、ラクです。
なおカスタマーポータルを利用するには、登録はLaravel上で行っておき、データベースに情報が記録されている必要があります。
①カスタマーポータル用リンクを設置する
Laravel上にカスタマーポータルへのリンクを置いておきます。
redirectToBillingPortalメソッドで、ユーザー用のカスタマーポータルにリンクが貼れます。
コントローラーには、次のように記述します。
1 2 3 |
public function portalsubscription(User $user, Request $request){ return $request->user()->redirectToBillingPortal(); } |
ルート設定例はこちら。
1 |
Route::get('/subscription/portal/{user}', 'StripeController@portalsubscription')->name('stripe.portalsubscription'); |
ビューファイルへは、次のようなボタンを設置しておきます。
blade.phpファイル記述例はこちら。
$userはコントローラーで定義して受け渡してください。
1 2 3 |
<form action="{{route('stripe.portalsubscription', $user) }}"> <button class="btn btn-primary mb-3">Stripeポータルサイト</button> </form> |
これでLaravel側の処理は終わりです。
②Stripe側の設定をする
Stripe側でもカスタマーポータルの設定をしておきましょう。
Stripeにログインし、左側の設定メニューをクリック。
Billingメニューの中の【カスタマーポータル】を選択します。
ここで、「定期支払いをキャンセル」を有効にしておくと、カスタマーポータルを通じて、顧客がキャンセル処理を行えるようになります。
デフォルトでは有効になっていたかと思いますが、チェックしておいてくださいね。
③ テストをしてみる
ではテストをしてみます。
顧客としてサブスク申込後、カスタマーポータルボタンをログインしてみます。
すると、次のような画面が表示されます。
「プランをキャンセル」をクリックすると、次のような確認画面が表示されます。
再度「プランをキャンセル」を押すと、キャンセルが実行されます。
サブスクなので、次回更新日までは使用できますが、その後に自動更新はされなくなります。
Stripeにログインし、顧客/定期支払情報をチェックしてみましょう。
次のように記録されていれば成功。
ただし残念なことに、Laravel側のテーブルには処理が反映されていません。
subscriptionテーブルを見てみると、stripe_statusは【active】のままです。
カスタマーポータルでの処理のメリット・デメリット
このようにカスタマーポータル上で処理するとラクです。
ただし、Laravelのテーブル上に履歴が残せませんし、カスタマイズできないのが難点。
この不便さを補うには、次に解説するwebhookを利用する手があります。
LaravelでStripeのキャンセル処理をする:Webhookを利用
Webhookを利用する際には、次の流れで処理を行っていきます。
- Stripeのカスタマーポータル上で処理を実行(前項)
- Webhookを使ってLaravel側に通知
- Laravel側で処理を発動させる
1は前項で解説済みなので、そのあとの手順から説明していきます。
①Webhookの設定をする
まずはWebhookのキーをLaravelに入れ込んでおきましょう。
テスト環境の場合には、Stripe CliまたはNglokなどの設定も必要です。
このあたりは、下記の記事をご覧ください。
Webhookのエンドポイントで「customer subscription deleted」を選択しておきます。
②ルート設定をする
次のルート設定を追加します。
1 |
Route::post('stripe/webhook', 'WebhookController@handleWebhook'); |
なお、Webhookのルート設定に制限がかかっているとエラーになります。
ミドルウェアや認証の影響がないようにしておきましょう。
③コントローラーを追加する
新しくWebhook用のコントローラーを作成します。
1 |
php artisan make:controller WebhookController |
この中に処理をいれていきます。
たとえば、LaravelのSubscriptionテーブルにキャンセルの処理を反映させるようにしてみます。
【status_status】をcanceledにし、【ends_at】にCarbonを使って日付をいれてみましょう。
use宣言は次のようにします。
1 2 3 4 5 6 7 8 |
namespace App\Http\Controllers; use Laravel\Cashier\Http\Controllers\WebhookController as CashierController; use Illuminate\Http\Request; use Symfony\Component\HttpFoundation\Response; use Laravel\Cashier\Cashier; use Laravel\Cashier\Subscription; use App\Models\User; use Carbon\Carbon; |
ひとことメモ
ここでは【Carbon】を使います。Carbonは時間・日付操作のためのライブラリ。下記のコマンドでインストールできます。
1 |
composer require nesbot/carbon |
コントローラーはこちら。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
public function handleCustomerSubscriptionDeleted(array $payload){ // Stripeから送信されたデータからstripe_idを取得し、$id変数に代入 $id=$payload['data']['object']['id']; // Subscriptionテーブルのstripe_idが$idと同じものを取ってくる $subsc = Subscription::where('stripe_id', $id)->first(); // このデータのstripe_statusをcanceledにする $subsc->stripe_status='canceled'; // このデータのends_atに、Carbonを使って今の時間を入れる $subsc->ends_at=Carbon::now()->timestamp; $subsc->save(); return new Response('Webhook Handled', 200); } |
④テストをしてみる
それでは実際にテストしてみます。
Stripeのカスタマーポータル上でユーザーがキャンセル処理を実施します。
Stripe側の顧客/定期支払情報でキャンセル済になっているはずです。
さらにLaravelのSubscriptionテーブルにも処理が反映されていれば成功!
うまくいかない場合
もしうまくいかない場合には、Stripeにログインし、開発メニュー/Webhookから、Webhookをチェックしてみてください。
画面下部の【Webhook】で失敗した履歴をクリックすると、失敗の原因が表示されます。
HTTPステータスコードが500となっていれば、Laravel側の処理に問題がある可能性あり。
コントローラーの記述などチェックしてくださいね。
レスポンスの部分にエラーの原因がより詳細に記述されているので、参考になります。
Webhook処理のメリット・デメリット
Webhookは難易度的には一番メンドウ。
ただ、方法としては一番スマートな方法だと思います。
さいごに
LaravelとStripeの連携は一筋縄でいかないときもあります。
エラーが起こったら、それが連携部分にあるのか、Laravelのコントローラーの記述にあるのか。
原因を探りあてて、ひとつずつ解決していきましょう。
ハッキリ言って手間がかかりますが><
Stripeの需要は高まっていくと予想されるので、試行錯誤の経験はきっと役に立ちます。(←と、自分に言い聞かせ中)
LaravelとStripeの連携は他でもがっつり紹介中です。
下記がまとめ記事です。あわせてお役立てください。
コメント
はじめまして、拝見させていただきました。
【Laravel8にSTRIPEでサブスクリプション機能を付ける10ステップ】
から
【LaravelでStripeのサブスクキャンセル処理をする3つの方法】
をやらせてもらいました。
① ② ③を実施するとUndefined variable: user
になります。
$userが定義されていないためだと思われます。
記事では省略していましたが、記事を修正し、
「$userはコントローラーで定義して受け渡してください。」
の一文追記しました。