イントロダクション
LaravelキャッシャーはStripeによるサブスクリプション(定期課金)サービスの読みやすく、スラスラと記述できるインターフェイスを提供します。これにより書くことが恐ろしくなるような、サブスクリプション支払いのための決まりきったコードのほとんどが処理できます。基本的なサブスクリプション管理に加え、キャッシャーはクーポン、サブスクリプションの変更、購入数、キャンセル猶予期間、さらにインボイスのPDF発行まで行います。
設定
Composer
最初に、composer.json
ファイルに、Cashierパッケージを追加し、composer update
コマンドを実行します。
"laravel/cashier": "~5.0"(2015年2月18日以降のバージョン、およびStripe SDK 2.0まで)
"laravel/cashier": "~4.0"(2015年2月18日以降のバージョン)
"laravel/cashier": "~3.0"(2015年2月16日までのバージョン)
サービスプロバイダー
次にapp
設定ファイルへ、Laravel\Cashier\CashierServiceProvider
サービスプロバイダーを登録します。
マイグレーション
キャッシャーを使用する前に、データベースにいくつかカラムを追加する必要があります。心配ありません。cashier:table
Artisanコマンドで必要なカラムを追加するマイグレーションが生成されます。たとえばusersテーブルにカラムを追加するには、php artisan cashier:table users
を実行します。
マイグレーションを生成したら、後はmigrate
コマンドを実行するだけです。
モデルの準備
次にBillable
トレイトと適切な日付ミューテターをモデルで定義してください。
use Laravel\Cashier\Billable;
use Laravel\Cashier\Contracts\Billable as BillableContract;
class User extends Model implements BillableContract
{
use Billable;
protected $dates = ['trial_ends_at', 'subscription_ends_at'];
}
モデルの$dates
プロパティにカラムを追加することで、Eloquentに文字列ではなくCarbon/DateTimeインスタンスを指定カラムで返すように指示します。
Stripeキー
最後に、services.php
設定ファイルへStripeキーを設置します。
'stripe' => [
'model' => 'User',
'secret' => env('STRIPE_API_SECRET'),
],
サブスクリプション
サブスクリプション作成
サブスクリプションを作成するには最初にbillableなモデルのインスタンスを取得しますが、通常App\User
のインスタンスでしょう。モデルインスタンスが獲得できたら、モデルのサブスクリプションを管理するためにsubscription
メソッドを使います。
$user = User::find(1);
$user->subscription('monthly')->create($creditCardToken);
create
メソッドは自動的にStripeのサブスクリプションを作成すると同時に、StripeのカスタマーIDと関連する支払い情報をデータベースに保存します。Stripeでプランの試用期間を設定している場合、試用終了日も自動的に、ユーザーのレコードに設定されます。
Stripeの中で定義しているものではなく、アプリケーション独自の試用期間を実装したい場合は、試用終了日を自前で設定する必要があります。
$user->trial_ends_at = Carbon::now()->addDays(14);
$user->save();
ユーザー詳細情報の指定
ユーザーに関する詳細情報を追加したい場合は、create
メソッドの第2引数に渡すことができます。
$user->subscription('monthly')->create($creditCardToken, [
'email' => $email, 'description' => 'Our First Customer'
]);
Stripeがサポートしている追加のフィールドについては、顧客の作成に関するドキュメントを確認してください。
クーポン
サブスクリプションの作成時に、クーポンを適用したい場合は、withCoupon
メソッドを使用してください。
$user->subscription('monthly')
->withCoupon('code')
->create($creditCardToken);
サブスクリプション状態の確認
ユーザーがアプリケーションで何かをサブスクリプションしたら、バラエティー豊かで便利なメソッドでサブスクリプション状況を簡単にチェックできます。まず初めにsubscribed
メソッドがtrue
を返したら、サブスクリプションが現在試用期間であるにしても、そのユーザーはアクティブなサブスクリプションを持っています。
if ($user->subscribed()) {
//
}
subscribed
メソッドはルートミドルウェアで使用しても大変役に立つでしょう。ユーザーのサブスクリプション状況に基づいてルートやコントローラーへのアクセスをフィルタリングできます。
public function handle($request, Closure $next)
{
if ($request->user() && ! $request->user()->subscribed()) {
// このユーザーは支払っていない顧客…
return redirect('billing');
}
return $next($request);
}
ユーザーがまだ試用期間であるかを調べるには、onTrial
メソッドを使用します。このメソッドはまだ使用期間中であるとユーザーに警告を表示するために便利です。
if ($user->onTrial()) {
//
}
onPlan
メソッドはStripe
IDに基づく指定プランのサブスクリプション購入者であるかを調べます。
if ($user->onPlan('monthly')) {
//
}
キャンセルしたサブスクリプションの状態
ユーザーが一度アクティブなサブスクリプション購入者になってから、サブスクリプションをキャンセルしたことを調べるには、cancelled
メソッドを使用します。
if ($user->cancelled()) {
//
}
また、ユーザーがサブスクリプションをキャンセルしているが、まだ完全に期限が切れる前の「猶予期間」中であるかを調べることもできます。例えば、ユーザーが3月5日にサブスクリプションをキャンセルし、3月10日に無効になる場合、そのユーザーは3月10日までは「猶予期間」中です。subscribed
メソッドは、この期間中、まだture
を返すことに注目して下さい。
if ($user->onGracePeriod()) {
//
}
everSubscribed
メソッドにより、そのユーザーがアプリケーションの永久サブスクリプションプランを持っているかを決定することができます。
if ($user->everSubscribed()) {
//
}
プラン変更
アプリケーションのサブスクリプション済みユーザーが新しいサブスクリプションプランへ変更したくなるのはよくあるでしょう。ユーザーを新しいサブスクリプションに変更するには、swap
メソッドを使用します。例としてユーザーをささっとpremium
サブスクリプションプランへ変更してみましょう。
$user = App\User::find(1);
$user->subscription('premium')->swap();
ユーザーが試用期間中の場合、試用期間は通常通りに続きます。また、そのサブスクリプションに"quantity"(購入数)が存在する場合、その個数も維持されます。プランの変更時にprorate
メソッドを使うことで支払いの按分を指示することもできます。さらにswapAndInvoice
メソッドでプラン変更のインボイスを即座に発行することもできます。
$user->subscription('premium')
->prorate()
->swapAndInvoice();
購入数
しばしばサブスクリプションは「個数(quantity)」による影響を受けます。たとえばアプリケーションで毎月10ドルアカウントのユーザーごとに課金している場合です。購入数を簡単に増やしたり、減らしたりするには、increment
とdecrement
メソッドを使用します。
$user = User::find(1);
$user->subscription()->increment();
// 現在の購入数に5つ増やす…
$user->subscription()->increment(5);
$user->subscription()->decrement();
// 現在の購入数から5つ減らす…
$user->subscription()->decrement(5);
もしくは特定の数量を設置するには、updateQuantity
メソッドを使ってください。
$user->subscription()->updateQuantity(10);
購入数の詳細については、Stripeドキュメントを読んでください。
サブスクリプションの税金
キャッシャーを使えばStripeへ「税率(tax_percent
)」を送るのも簡単です。サブスクリプションに対する顧客の支払いの税率を指定するには、モデルにgetTaxPercent
メソッドをbillableモデルへ実装し、小数点以下の桁数が2桁以内で0から100までの数値を返します。
public function getTaxPercent() {
return 20;
}
これによりモデルごとに税率を適用できるため、多くの州や国に渡るユーザーベースで税率を決める場合に便利です。
サブスクリプションキャンセル
サブスクリプションをキャンセルするにはcancel
メソッドをユーザーのサブスクリプションに対して使ってください。
$user->subscription()->cancel();
サブスクリプションがキャンセルされるとキャッシャーは自動的に、データベースのsubscription_ends_at
カラムをセットします。このカラムはいつからsubscribed
メソッドがfalse
を返し始めればよいのか、判定するために使用されています。例えば、顧客が3月1日にキャンセルしたが、そのサブスクリプションが3月5日に終了するようにスケジュールされていれば、subscribed
メソッドは3月5日になるまでtrue
を返し続けます。
ユーザーがサブスクリプションをキャンセルしたが、まだ「猶予期間」が残っているかどうかを調べるにはonGracePeriod
メソッドを使います。
if ($user->onGracePeriod()) {
//
}
サブスクリプション再開
ユーザーがキャンセルしたサブスクリプションを、再開したいときには、resume
メソッドを使用してください。
$user->subscription('monthly')->resume($creditCardToken);
ユーザーがサブスクリプションをキャンセルし、それからそのサブスクリプションを再開する場合、そのサブスクリプションの有効期日が完全に切れていなければすぐに課金されません。そのサブスクリプションはシンプルに再度有効になり、元々の支払いサイクルにより課金されます
StripeのWebフック処理
サブスクリプション不可
顧客のクレジットカードが有効期限切れだったら? 心配いりません。キャッシャーは顧客のサブスクリプションを簡単にキャンセルできるWebフックコントローラーを含んでいます。コントローラーのルートを指定するだけです。
Route::post('stripe/webhook', '\Laravel\Cashier\WebhookController@handleWebhook');
これだけです! 課金の失敗はコントローラーにより捉えられ、処理されます。コントローラーはStripeによりサブスクリプションが不能だと判断されると(通常は課金に3回失敗時)、その顧客のサブスクリプションをキャンセルします。Stripeのコントロールパネル設定でWebフックURIを設定する必要があります。
StripeのWebフックはLaravelのCSRF確認を適用しない必要があるため、VerifyCsrfToken
ミドルウェアで除外するURIのリストへ確実に登録してください。
protected $except = [
'stripe/*',
];
その他のWebフック
処理したい追加のStripe
Webフックイベントがある場合、シンプルにWebフックコントローラーを拡張してください。メソッド名はCashierが期待する命名規則に従う必要があります。つまりメソッド名はhandle
で始まり、取り扱いたいStripeのWebフックを続けます。たとえばinvoice.payment_succeeded
Webフックを使用したいのなら、コントローラーにはhandleInvoicePaymentSucceeded
メソッドを追加しなければなりません。
<?php
namespace App\Http\Controllers;
use Laravel\Cashier\WebhookController as BaseController;
class WebhookController extends BaseController
{
/**
* StripeのWebフック処理
*
* @param array $payload
* @return Response
*/
public function handleInvoicePaymentSucceeded($payload)
{
// イベントの処理
}
}
一回だけの課金
定期サブスクリプションしている顧客のクレジットカードに対し「一回限り」の課金を行いたい場合は、billableモデルに対しcharge
メソッドを使用してください。charge
メソッドは通貨の最低単位の課金を引数に取ります。そのため次の例は100セント(1ドル)をクレジットカードへ課金します。
$user->charge(100);
charge
メソッドは配列で2つ目の引数も取り、裏で動作しているStrip課金の生成にオプションを渡すことができます。
$user->charge(100, [
'source' => $token,
'receipt_email' => $user->email,
]);
charge
メソッドがfalse
を返した場合は課金失敗です。通常これは課金が拒否されたことを意味します。
if ( ! $user->charge(100)) {
// 課金は拒否された…
}
課金が成功したら完全なStripeレスポンスがメソッドから返されます。
インボイス
invoices
メソッドにより、billableモデルのインボイスの配列を簡単に取得できます。
$invoices = $user->invoices();
顧客へインボイスを一覧表示するとき、そのインボイスに関連する情報を表示するために、インボイスのヘルパメソッドを表示に利用できます。ユーザーが簡単にダウンロードできるように、テーブルで全インボイスを一覧表示する例を見てください。
<table>
@foreach ($invoices as $invoice)
<tr>
<td>{{ $invoice->dateString() }}</td>
<td>{{ $invoice->dollars() }}</td>
<td><a href="/user/invoice/{{ $invoice->id }}">ダウンロード</a></td>
</tr>
@endforeach
</table>
インボイスPDF生成
ルートやコントローラーの中でdownloadInvoice
メソッドを使うと、そのインボイスのPDFダウンロードを生成できます。このメソッドはブラウザへダウンロードのHTTPレスポンスを正しく行うHTTPレスポンスを生成します。
Route::get('user/invoice/{invoice}', function ($invoiceId) {
return Auth::user()->downloadInvoice($invoiceId, [
'vendor' => 'Your Company',
'product' => 'Your Product',
]);
});