Laravel 8.x Laravel Cashier (Stripe)

イントロダクション

Laravel Cashierは、Stripeのサブスクリプション課金サービスに対する表現力豊かで流暢なインターフェイスを提供します。それはあなたが書くことを恐れている定型的なサブスクリプション請求コードのほとんどすべてを処理します。キャッシャーは、基本的なサブスクリプション管理に加えて、クーポン、サブスクリプションの交換、サブスクリプションの「数量」、キャンセルの猶予期間を処理し、請求書のPDFを生成することもできます。

Cashierのアップデート

キャッシャーの新しいバージョンにアップグレードするときは、アップグレードガイドを注意深く確認することが重要です。

Note: 重大な変更を防ぐために、Cashierは固定のStripe APIバージョンを使用します。キャッシャー12はStripeAPIバージョン2020-03-02を利用しています。StripeAPIバージョンは、新しいStripe機能と改善点を利用するために、マイナーリリースで更新されます。

インストール

まず、Composerパッケージマネージャーを使用して、StripeのCashierパッケージをインストールします。

composer require laravel/cashier

Note: CashierにすべてのStripeイベントを適切に処理させるには、キャッシャーのWebhook処理を忘れずに設定してください。

データベースマイグレーション

Cashierのサービスプロバイダは独自のデータベースマイグレーションディレクトリを登録しているため、パッケージのインストール後にデータベースをマイグレーションするのを忘れないでください。Cashierのマイグレーションにより、usersテーブルへ列がいくつか追加されるだけでなく、顧客のすべてのサブスクリプションを保持する新しいsubscriptionsテーブルが作成されます。

php artisan migrate

Cashierに同梱されているマイグレーションを上書きする必要がある場合は、vendor:publish Artisanコマンドを使用してそれらをリソース公開できます。

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

Cashierのマイグレーションを完全に実行しないようにする場合は、Cashierが提供するignoreMigrationsメソッドを使用してください。通常、このメソッドは、AppServiceProviderregisterメソッドで呼び出す必要があります。

use Laravel\Cashier\Cashier;

/**
 * 全アプリケーションサービスの登録
 *
 * @return void
 */
public function register()
{
    Cashier::ignoreMigrations();
}

Note: Stripeは、Stripe識別子の格納に使用される列では大文字と小文字を区別することを推奨しています。したがって、MySQLを使用する場合は、stripe_id列の列照合順序を確実にutf8_binへ設定する必要があります。これに関する詳細は、Stripeドキュメントにあります。

設定

Billableモデル

Cashierを使用する前に、Billableなモデルの定義へBillableトレイトを追加してください。通常、これはApp\Models\Userモデルになるでしょう。このトレイトはサブスクリプションの作成、クーポンの適用、支払い方法情報の更新など、一般的な請求タスクを実行できるようにするさまざまなメソッドを提供します。

use Laravel\Cashier\Billable;

class User extends Authenticatable
{
    use Billable;
}

Cashierは、BlillableなモデルがLaravelに同梱されているApp\Models\Userクラスであると想定しています。これを変更したい場合は、.envファイルで別のモデルを指定できます。

CASHIER_MODEL=App\Models\User

Note: Laravelが提供するApp\Models\Userモデル以外のモデルを使用する場合は、代替モデルのテーブル名と一致するように、提供されているCashierマイグレーションをリソース公開し、変更する必要があります。

APIキー

次に、アプリケーションの.envファイルでStripeAPIキーを設定する必要があります。StripeAPIキーはStripeコントロールパネルから取得できます。

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

通貨設定

デフォルトのCashier通貨は米ドル(USD)です。アプリケーションの.envファイル内でCASHIER_CURRENCY環境変数を設定することにより、デフォルトの通貨を変更できます。

CASHIER_CURRENCY=eur

Cashierの通貨の設定に加え、請求書に表示するの金額の値をフォーマットするときに使用するロケールを指定することもできます。内部的には、CashierはPHPのNumberFormatterクラスを利用して通貨ロケールを設定します。

CASHIER_CURRENCY_LOCALE=nl_BE

Note: en以外のロケールを使用するには、ext-intl PHP拡張機能を確実にサーバにインストールおよび設定してください。

ログ

Cashierを使用すると、Stripe関連のすべての例外をログに記録するときに使用するログチャネルを指定できます。アプリケーションの.envファイル内でCASHIER_LOGGER環境変数を定義することにより、ログチャネルを指定できます。

CASHIER_LOGGER=stack

カスタムモデルの使用

独自のモデルを定義し対応するCashierモデルを拡張することにより、Cashierが内部で使用するモデルを自由に拡張できます。

use Laravel\Cashier\Subscription as CashierSubscription;

class Subscription extends CashierSubscription
{
    // ...
}

モデルを定義した後、Laravel\Cashier\Cashierクラスを介してカスタムモデルを使用するようにCashierへ指示します。通常、アプリケーションのApp\Providers\AppServiceProviderクラスのbootメソッドで、カスタムモデルをキャッシャーへ通知する必要があります。

use App\Models\Cashier\Subscription;
use App\Models\Cashier\SubscriptionItem;

/**
 * 全アプリケーションサービスの初期起動処理
 *
 * @return void
 */
public function boot()
{
    Cashier::useSubscriptionModel(Subscription::class);
    Cashier::useSubscriptionItemModel(SubscriptionItem::class);
}

顧客

顧客の取得

Cashier::findBillableメソッドを使用して、StripeIDで顧客を取得できます。このメソッドは、Billableなモデルのインスタンスを返します。

use Laravel\Cashier\Cashier;

$user = Cashier::findBillable($stripeId);

顧客の作成

まれに、サブスクリプションを開始せずにStripeの顧客を作成したいことも起きるでしょう。これは、createAsStripeCustomerメソッドを使用して実行できます。

$stripeCustomer = $user->createAsStripeCustomer();

Stripeで顧客を作成しておき、あとからサブスクリプションを開始できます。オプションの$options配列を指定して、追加のStripeAPIでサポートされている顧客作成パラメーターを渡せます。

$stripeCustomer = $user->createAsStripeCustomer($options);

BillableなモデルのStripe顧客オブジェクトを返す場合は、asStripeCustomerメソッドを使用できます。

$stripeCustomer = $user->asStripeCustomer();

createOrGetStripeCustomerメソッドは、特定のBillableモデルのStripe顧客オブジェクトを取得したいが、BillableモデルがすでにStripe内の顧客であるかわからない場合に使用できます。このメソッドは、Stripeに新しい顧客がまだ存在しない場合、新しい顧客を作成します。

$stripeCustomer = $user->createOrGetStripeCustomer();

顧客の更新

たまに、Stripeの顧客を追加情報と一緒に直接更新したい状況が起こるでしょう。これは、updateStripeCustomerメソッドを使用して実行できます。このメソッドは、StripeAPIでサポートされている顧客更新オプションの配列を引数に取ります。

$stripeCustomer = $user->updateStripeCustomer($options);

請求ポータル

Stripeは、請求ポータルを設定する簡単な方法を提供しており、顧客はサブスクリプション、支払い方法を管理し、請求履歴を表示できます。コントローラまたはルートからBillableモデルでredirectToBillingPortalメソッドを呼び出すことにより、ユーザーを請求ポータルにリダイレクトできます。

use Illuminate\Http\Request;

Route::get('/billing-portal', function (Request $request) {
    return $request->user()->redirectToBillingPortal();
});

デフォルトでは、ユーザーがサブスクリプションの管理を終了すると、Stripe課金ポータル内のリンクを介してアプリケーションのhomeルートに戻ることができます。redirectToBillingPortalメソッドに引数としてURLを渡すことにより、ユーザーが戻る必要のあるカスタムURLを指定できます。

use Illuminate\Http\Request;

Route::get('/billing-portal', function (Request $request) {
    return $request->user()->redirectToBillingPortal(route('billing'));
});

HTTPリダイレクトレスポンスを生成せずに課金ポータルへのURLを生成したい場合は、billingPortalUrlメソッドを呼び出してください。

$url = $request->user()->billingPortalUrl(route('billing'));

支払い方法

支払い方法の保存

Stripeでサブスクリプションを作成したり、「1回限りの」料金を実行したりするには、支払い方法を保存し、Stripeからその識別子を取得する必要があります。これを実現するアプローチは、サブスクリプションに支払い方法を使用するか、単一料金を使用するかにより異なるため、以降で両方とも説明します。

サブスクリプションの支払い方法

サブスクリプションで将来使用するときのため顧客のクレジットカード情報を保存する場合、Stripeの"Setup Intents" APIを使用して、顧客の支払い方法の詳細を安全に収集する必要があります。"Setup Intent "は、顧客の支払い方法により課金する意図をStripeに示します。CashierのBillableトレイトには、新しいセットアップインテントを簡単に作成するためのcreateSetupIntentメソッドを用意しています。顧客の支払い方法の詳細を収集するフォームをレンダーするルートまたはコントローラからこのメソッドを呼び出す必要があります。

return view('update-payment-method', [
    'intent' => $user->createSetupIntent()
]);

セットアップインテントを作成してビューに渡したら、支払い方法を収集する要素にそのシークレットを添付する必要があります。たとえば、次の「支払い方法の更新」フォームについて考えてみます。

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

<!-- ストライプ要素のプレースホルダ -->
<div id="card-element"></div>

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

次に、Stripe.jsライブラリを使用して、Stripe要素をフォームに添付し、顧客の支払いの詳細を安全に収集します。

<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>

次に、カードを確認し、StripeのconfirmCardSetupメソッドを使用してStripeから安全な「支払い方法識別子」を取得します。

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) {
        // "error.message"をユーザーに表示…
    } else {
        // カードは正常に検証された…
    }
});

カードがStripeによって検証されたあとに、結果のsetupIntent.payment_method識別子をLaravelアプリケーションに渡して、顧客にアタッチします。支払い方法は、新しい支払い方法として追加またはデフォルトの支払い方法の更新に使用のいずれかです。すぐに支払い方法識別子を使用して新しいサブスクリプションを作成することもできます。

Tip!! セットアップインテントと顧客の支払いの詳細の収集について詳しく知りたい場合は、Stripeが提供しているこの概要を確認してください

一回限りの支払いの支払い方法

もちろん、お客様の支払い方法に対して1回請求を行う場合、支払い方法IDを使用する必要があるのは1回だけです。Stripeの制約により、顧客が保存したデフォルトの支払い方法を単一の請求に使用することはできません。Stripe.jsライブラリを使用して、顧客が支払い方法の詳細を入力できるようにする必要があります。たとえば、次のフォームについて考えてみます。

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

<!-- ストライプ要素プレースホルダ -->
<div id="card-element"></div>

<button id="card-button">
    Process Payment
</button>

このようなフォームを定義した後、Stripe.jsライブラリを使用してStripe要素をフォームに添付し、顧客の支払いの詳細を安全に収集します。

<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>

次にカードを確認し、StripeのcreatePaymentMethodメソッドを使用してStripeから安全な「支払い方法識別子」を取得します。

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

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

    if (error) {
        // "error.message"をユーザーに表示…
    } else {
        // カードは正常に検証された…
    }
});

カードが正常に確認されたら、paymentMethod.idをLaravelアプリケーションに渡して、一回限りの請求を処理できます。

支払い方法の取得

BillableなモデルインスタンスのpaymentMethodsメソッドは、Laravel\Cashier\PaymentMethodインスタンスのコレクションを返します。

$paymentMethods = $user->paymentMethods();

顧客のデフォルトの支払い方法を取得するには、defaultPaymentMethodメソッドを使用します。

$paymentMethod = $user->defaultPaymentMethod();

findPaymentMethodメソッドを使用して、Billableモデルに関連付けている特定の支払い方法を取得できます。

$paymentMethod = $user->findPaymentMethod($paymentMethodId);

顧客に支払い方法があるか判定

Billableなモデルのアカウントにデフォルトの支払い方法が関連付けられているかどうかを確認するには、hasDefaultPaymentMethodメソッドを呼び出します。

if ($user->hasDefaultPaymentMethod()) {
    //
}

hasPaymentMethodメソッドを使用して、Billableなモデルのアカウントに少なくとも1つの支払い方法が関連付けられているかを判定できます。

if ($user->hasPaymentMethod()) {
    //
}

デフォルト支払い方法の変更

updateDefaultPaymentMethodメソッドは、顧客のデフォルトの支払い方法情報を更新するために使用します。このメソッドは、Stripe支払い方法識別子を受け入れ、新しい支払い方法をデフォルトの請求支払い方法として割り当てます。

$user->updateDefaultPaymentMethod($paymentMethod);

デフォルトの支払い方法情報をStripeの顧客のデフォルトの支払い方法情報と同期するには、updateDefaultPaymentMethodFromStripeメソッドを使用できます。

$user->updateDefaultPaymentMethodFromStripe();

Note: 顧客のデフォルトの支払い方法は、新しいサブスクリプションの請求と作成にのみ使用できます。Stripeの制約により、1回だけの請求には使用できません。

支払い方法の追加

新しい支払い方法を追加するには、支払い方法IDを渡して、BillableモデルでaddPaymentMethodメソッドを呼び出してください。

$user->addPaymentMethod($paymentMethod);

Tip!! 支払い方法の識別子を取得する方法については、支払い方法の保存に関するドキュメントを確認してください。

支払い方法の削除

支払い方法を削除するには、削除したいLaravel\Cashier\PaymentMethodインスタンスでdeleteメソッドを呼び出してください。

$paymentMethod->delete();

deletePaymentMethodsメソッドは、Billableなモデルのすべての支払い方法情報を削除します。

$user->deletePaymentMethods();

Note: ユーザーがアクティブなサブスクリプションを持っている場合、アプリケーションはユーザーがデフォルトの支払い方法を削除することを許してはいけません。

サブスクリプション

サブスクリプションは、顧客に定期的な支払いを設定する方法を提供します。Cashierが管理するStripeサブスクリプションは、複数のサブスクリプションプラン、サブスクリプション数量、トライアルなどをサポートします。

サブスクリプションの作成

サブスクリプションを作成するには、最初にBillableなモデルのインスタンスを取得します。これは通常、App\Models\Userのインスタンスになります。モデルインスタンスを取得したら、newSubscriptionメソッドを使用してモデルのサブスクリプションを作成できます。

use Illuminate\Http\Request;

Route::post('/user/subscribe', function (Request $request) {
    $request->user()->newSubscription(
        'default', 'price_premium'
    )->create($request->paymentMethodId);

    // ...
});

newSubscriptionメソッドに渡す最初の引数は、サブスクリプションの名前です。アプリケーションが単一のサブスクリプションのみを提供する場合は、これをdefaultまたはprimaryと付けるのが良いでしょう。2番目の引数は、ユーザーがサブスクライブしている特定のプランです。この値は、Stripeのプランの価格識別子に対応している必要があります。

Stripe支払い方法識別子またはStripePaymentMethodオブジェクトを引数に取るcreateメソッドは、サブスクリプションを開始するのと同時に、BillableなモデルのStripe顧客IDおよびその他の関連する課金情報でデータベースを更新します。

Note: 支払い方法識別子をcreateサブスクリプションメソッドへ直接渡すと、ユーザーの保存済み支払い方法にも自動的に追加されます。

サブスクリプション数

サブスクリプションの作成時にプランに数量を指定する場合は、サブスクリプションを作成する前にビルダでquantityメソッドを呼び出してください。

$user->newSubscription('default', 'price_monthly')
     ->quantity(5)
     ->create($paymentMethod);

詳細の追加

Stripeがサポートしている顧客サブスクリプションオプションを指定する場合、createメソッドの2番目と3番目の引数に指定することで、追加できます。

$user->newSubscription('default', 'price_monthly')->create($paymentMethod, [
    'email' => $email,
], [
    'metadata' => ['note' => 'Some extra information.'],
]);

クーポン

サブスクリプションの作成時にクーポンを適用する場合は、withCouponメソッドを使用できます。

$user->newSubscription('default', 'price_monthly')
     ->withCoupon('code')
     ->create($paymentMethod);

または、Stripeプロモーションコードを適用する場合は、withPromotionCodeメソッドを使用します。

$user->newSubscription('default', 'price_monthly')
     ->withPromotionCode('promo_code')
     ->create($paymentMethod);

サブスクリプションの追加

すでにデフォルトの支払い方法を持っている顧客へサブスクリプションを追加する場合は、サブスクリプションビルダでaddメソッドを呼び出してください。

use App\Models\User;

$user = User::find(1);

$user->newSubscription('default', 'price_premium')->add();

Stripeダッシュボードからのサブスクリプション作成

Stripeダッシュボード自体からも、サブスクリプションを作成できます。その際、Cashierは新しく追加したサブスクリプションを同期し、それらにdefaultの名前を割り当てます。ダッシュボードから作成するサブスクリプションに割り当てるサブスクリプション名をカスタマイズするには、WebhookControllerを拡張し、newSubscriptionNameメソッドを上書きします。

また、Stripeダッシュボードから作成できるサブスクリプションのタイプは1つだけです。アプリケーションが異なる名前を使用する複数のサブスクリプションを提供している場合でも、Stripeダッシュボードから追加できるサブスクリプションのタイプは1つのみです。

最後に、アプリケーションが提供するサブスクリプションのタイプごとに、アクティブなサブスクリプションを1つだけ追加するようにしてください。顧客が2つのdefaultサブスクリプションを持っている場合、たとえ両方がアプリケーションのデータベースと同期されていても、最後に追加したサブスクリプションのみ、Cashierは使用します。

サブスクリプション状態のチェック

顧客がアプリケーションでサブスクリプションを購入すると、さまざまな便利なメソッドを使用して、サブスクリプションの状態を簡単に確認できます。まず、subscribedメソッドは、そのサブスクリプションが現在試用期間内であっても、顧客がアクティブなサブスクリプションを持っている場合は、trueを返します。subscribedメソッドは、最初の引数としてサブスクリプションの名前を受け入れます。

if ($user->subscribed('default')) {
    //
}

subscribedメソッドはルートミドルウェアの優れた候補にもなり、ユーザーのサブスクリプション状態に基づいてルートとコントローラへのアクセスをフィルタリングできます。

<?php

namespace App\Http\Middleware;

use Closure;

class EnsureUserIsSubscribed
{
    /**
     * 受信リクエストの処理
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        if ($request->user() && ! $request->user()->subscribed('default')) {
            // このユーザーは、支払い済みユーザーではない
            return redirect('billing');
        }

        return $next($request);
    }
}

ユーザーがまだ試用期間内であるかどうかを確認したい場合は、onTrialメソッドを使用します。このメソッドは、ユーザーがまだ試用期間中であるという警告をユーザーに表示する必要があるかどうかを判断するのに役立ちます。

if ($user->subscription('default')->onTrial()) {
    //
}

subscribedToPlanメソッドを使用して、特定のStripeプランの価格識別子に基づいてユーザーが特定プランのサブスクリプションを購入しているかを判定できます。この例では、ユーザーのdefaultサブスクリプションがアプリケーションの「月次(monthly)」プランにアクティブにサブスクライブされているかどうかを判別しています。指定したStripeプランの価格IDは、Stripeダッシュボードのプランの価格IDの1つに対応している必要があります。

if ($user->subscribedToPlan('price_monthly', 'default')) {
    //
}

配列をsubscribedToPlanメソッドに渡し、ユーザーのdefaultサブスクリプションがアプリケーションの「月次(monthly)」か「年次(yearly)」プランにアクティブにサブスクリプション購入されているかを判定できます。

if ($user->subscribedToPlan(['price_monthly', 'price_yearly'], 'default')) {
    //
}

recurringメソッドを使用して、ユーザーが現在サブスクリプションを購入してお​​り、試用期間でないことを判定します。

if ($user->subscription('default')->recurring()) {
    //
}

Note: ユーザーが同じ名前のサブスクリプションを2つ持っている場合、subscriptionメソッドは最新のサブスクリプションを常に返します。たとえば、ユーザーがdefaultという名前のサブスクリプションレコードを2つ持っているとします。この場合、サブスクリプションの1つは古い期限切れのサブスクリプションであり、もう1つは現在のアクティブなサブスクリプションである可能性があります。最新のサブスクリプションを常に返しますが、古いサブスクリプションは履歴レビューのためにデータベースに保持されます。

キャンセル済みサブスクリプション状態

ユーザーがかつてアクティブなサブスクリプション購入者であったが、そのサブスクリプションをキャンセルしたかを判定するには、cancelledメソッドを使用します。

if ($user->subscription('default')->cancelled()) {
    //
}

また、ユーザーがサブスクリプションをキャンセルしたが、サブスクリプションが完全に期限切れになるまで「猶予期間」にあるかを判定することもできます。たとえば、ユーザーが3月10日に期限切れになる予定のサブスクリプションを3月5日にキャンセルした場合、ユーザーは3月10日まで「猶予期間」になります。この間、subscribedメソッドは引き続きtrueを返すことに注意してください。

if ($user->subscription('default')->onGracePeriod()) {
    //
}

ユーザーがサブスクリプションをキャンセルし、「猶予期間」も過ぎていることを判断するには、endedメソッドを使用します。

if ($user->subscription('default')->ended()) {
    //
}

不完全および延滞ステータス

サブスクリプションの作成後に二次支払いアクションが必要な場合、サブスクリプションは「未完了(incomplete)」としてマークされます。サブスクリプションステータスは、Cashierのsubscriptionsデータベーステーブルのstripe_status列に保存されます。

同様に、プランを変更するときに二次支払いアクションが必要な場合、サブスクリプションは「延滞(past_due)」としてマークされます。サブスクリプションがこれらの状態のどちらかにある場合、顧客が支払いを確認するまでサブスクリプションはアクティブになりません。サブスクリプションの支払いが不完全であるかの判定は、BillableモデルまたはサブスクリプションインスタンスでhasIncompletePaymentメソッドを使用します。

if ($user->hasIncompletePayment('default')) {
    //
}

if ($user->subscription('default')->hasIncompletePayment()) {
    //
}

サブスクリプションの支払いが不完全な場合は、latestPayment識別子を渡して、ユーザーをCashierの支払い確認ページに誘導する必要があります。サブスクリプションインスタンスで使用可能なlatestPaymentメソッドを使用して、この識別子を取得できます。

<a href="{{ route('cashier.payment', $subscription->latestPayment()->id) }}">
    Please confirm your payment.
</a>

サブスクリプションがpast_due状態のときにアクティブであると見なしたい場合は、Cashierが提供するkeepPastDueSubscriptionsActiveメソッドを使用します。通常、このメソッドは、App\Providers\AppServiceProviderregisterメソッドで呼び出す必要があります。

use Laravel\Cashier\Cashier;

/**
 * 全アプリケーションサービスの登録
 *
 * @return void
 */
public function register()
{
    Cashier::keepPastDueSubscriptionsActive();
}

Note: サブスクリプションがincomplete状態の場合、支払いが確認されるまで変更できません。したがって、サブスクリプションがincomplete状態の場合、swapメソッドとupdateQuantityメソッドは例外を投げます。

サブスクリプションのスコープ

ほとんどのサブスクリプション状態はクエリスコープとしても利用できるため、特定の状態にあるサブスクリプションはデータベースで簡単にクエリできます。

// すべてのアクティブなサブスクリプションを取得
$subscriptions = Subscription::query()->active()->get();

// ユーザーのキャンセルしたサブスクリプションをすべて取得
$subscriptions = $user->subscriptions()->cancelled()->get();

使用可能なスコープの完全なリストは、以下のとおりです。

Subscription::query()->active();
Subscription::query()->cancelled();
Subscription::query()->ended();
Subscription::query()->incomplete();
Subscription::query()->notCancelled();
Subscription::query()->notOnGracePeriod();
Subscription::query()->notOnTrial();
Subscription::query()->onGracePeriod();
Subscription::query()->onTrial();
Subscription::query()->pastDue();
Subscription::query()->recurring();

プランの変更

顧客がアプリケーションでサブスクリプションを購入した後に、新しいサブスクリプションプランへ変更したい場合もあるでしょう。顧客を新しいプランへスワップするには、Stripeプランの価格識別子をswapメソッドに渡します。指定された価格IDは、Stripeダッシュボードで使用可能なStripeプランの価格IDに対応している必要があります。

use App\Models\User;

$user = App\Models\User::find(1);

$user->subscription('default')->swap('price_id');

その顧客が試用中の場合、試用期間は維持されます。さらに、サブスクリプションに「数量」が存在する場合、その数量も維持されます。

プランを交換して、顧客が現在行っている試用期間をキャンセルしたい場合は、skipTrialメソッドを呼び出してください。

$user->subscription('default')
        ->skipTrial()
        ->swap('price_id');

プランを交換して、次の請求サイクルを待たずにすぐに顧客に請求する場合は、swapAndInvoiceメソッドを使用します。

$user = User::find(1);

$user->subscription('default')->swapAndInvoice('price_id');

按分

デフォルトで、Stripeはプランを変更するときに料金を按分します。noProrateメソッドを使用すると、料金を按分せずにサブスクリプションのプランを更新できます。

$user->subscription('default')->noProrate()->swap('price_id');

サブスクリプションの按分について詳しくは、Stripeドキュメントを参照してください。

Note: swapAndInvoiceメソッドの前にnoProrateメソッドを実行しても、按分には影響しません。請求書は常に発行されます。

サブスクリプション数

サブスクリプションは「数量」の影響を受ける場合があります。たとえば、プロジェクト管理アプリケーションは、プロジェクトごとに月額$10を請求する場合があります。incrementQuantityメソッドとdecrementQuantityメソッドを使用して、サブスクリプション数量を簡単に増減できます。

use App\Models\User;

$user = User::find(1);

$user->subscription('default')->incrementQuantity();

// サブスクリプションの現在の数量へ5個追加
$user->subscription('default')->incrementQuantity(5);

$user->subscription('default')->decrementQuantity();

// サブスクリプションの現在の数量から5個減少
$user->subscription('default')->decrementQuantity(5);

または、updateQuantityメソッドを使用して特定の数量を設定することもできます。

$user->subscription('default')->updateQuantity(10);

noProrateメソッドを使用すると、料金を按分せずにサブスクリプションの数量を更新できます。

$user->subscription('default')->noProrate()->updateQuantity(10);

サブスクリプション数量の詳細については、Stripeドキュメントを参照してください。

マルチプランサブスクリプションの数量

サブスクリプションがマルチプランサブスクリプションの場合、増減時のの2番目の引数として、数量をインクリメントまたはデクリメントするプランの名前を渡す必要があります。

$user->subscription('default')->incrementQuantity(1, 'chat-plan');

マルチプランサブスクリプション

マルチプランサブスクリプションでは、1つのサブスクリプションに複数の課金プランを割り当てることができます。たとえば、基本サブスクリプションプランが月額$10のカスタマーサービス「ヘルプデスク」アプリケーションを構築しているとします。月額$15のライブチャットアドオン追加プランも提供しているとしましょう。マルチプランのサブスクリプション情報は、Cashierのsubscription_itemsデータベーステーブルへ保存されます。

newSubscriptionメソッドの2番目の引数にプランの配列を渡すことにより、特定のサブスクリプションへ複数のプランを指定できます。

use Illuminate\Http\Request;

Route::post('/user/subscribe', function (Request $request) {
    $request->user()->newSubscription('default', [
        'price_monthly',
        'chat-plan',
    ])->create($request->paymentMethodId);

    // ...
});

上記の例では、顧客はdefaultサブスクリプションに2つのプランを添付しています。どちらのプランも、それぞれの請求間隔で請求されます。必要に応じて、quantityメソッドを使用して、各プランの個数を指定できます。

$user = User::find(1);

$user->newSubscription('default', ['price_monthly', 'chat-plan'])
    ->quantity(5, 'chat-plan')
    ->create($paymentMethod);

既存のサブスクリプションに別のプランを追加する場合は、サブスクリプションのaddPlanメソッドを呼び出すことができます。

$user = User::find(1);

$user->subscription('default')->addPlan('chat-plan');

上記の例では、新しいプランを追加し、顧客は次の請求サイクルでその料金を請求されます。すぐに顧客に請求したい場合は、addPlanAndInvoiceメソッドを使用できます。

$user->subscription('default')->addPlanAndInvoice('chat-plan');

プランを追加する個数も指定する場合は、addPlanまたはaddPlanAndInvoiceメソッドの2番目の引数として数量を渡すことができます。

$user = User::find(1);

$user->subscription('default')->addPlan('chat-plan', 5);

removePlanメソッドを使用してサブスクリプションからプランを削除できます。

$user->subscription('default')->removePlan('chat-plan');

Note: サブスクリプションの最後のプランを削除することはできません。代わりに、単にサブスクリプションをキャンセルする必要があります。

プランの変更

マルチプランサブスクリプションに添付されているプラ​​ンを変更することもできます。たとえば、顧客がchat-planアドオンプランを備えたbasic-planサブスクリプションを持っていて、顧客をbasic-planからpro-planプランにアップグレードしたいとします。

use App\Models\User;

$user = User::find(1);

$user->subscription('default')->swap(['pro-plan', 'chat-plan']);

上記の例を実行すると、basic-planを含む基になるサブスクリプションアイテムが削除され、chat-planを含むサブスクリプションアイテムが保持されます。さらに、pro-planの新しいサブスクリプションアイテムが作成されます。

キー/値ペアの配列をswapメソッドに渡すことで、サブスクリプションアイテムのオプションを指定することもできます。たとえば、サブスクリプションプランの個数を指定する必要があるとしましょう。

$user = User::find(1);

$user->subscription('default')->swap([
    'pro-plan' => ['quantity' => 5],
    'chat-plan'
]);

あるサブスクリプションを単一のプランへ交換する場合は、そのサブスクリプションアイテム自体に対しswapメソッドを使用できます。このアプローチは、そのサブスクリプションの他のプランが持つ既存のメタデータをすべて保持する場合に特に役立ちます。

$user = User::find(1);

$user->subscription('default')
        ->findItemOrFail('basic-plan')
        ->swap('pro-plan');

按分

デフォルトで、Stripeはマルチプランサブスクリプションにプランを追加または削除するとき、料金を按分します。按分せずに調整したい場合は、noProrateメソッドをプランの操作へチェーンする必要があります。

$user->subscription('default')->noProrate()->removePlan('chat-plan');

個数

個々のサブスクリプションプランの個数を変更する場合は、既存の個数メソッドを使用して、プランの名前をメソッドの追加引数として渡すことで更新できます。

$user = User::find(1);

$user->subscription('default')->incrementQuantity(5, 'chat-plan');

$user->subscription('default')->decrementQuantity(3, 'chat-plan');

$user->subscription('default')->updateQuantity(10, 'chat-plan');

Note: サブスクリプションに複数のプランがある場合、Subscriptionモデルのstripe_plan属性とquantity属性はnullになります。個々のプラン属性にアクセスするには、Subscriptionモデルで使用可能なitemsリレーションを使用する必要があります。

サブスクリプションアイテム

サブスクリプションに複数のプランがある場合、データベースのsubscription_itemsテーブルに複数のサブスクリプション「アイテム」が保存されます。サブスクリプションのitemsリレーションを介してこれらにアクセスできます。

use App\Models\User;

$user = User::find(1);

$subscriptionItem = $user->subscription('default')->items->first();

// 特定のアイテムのStripeプランと個数を取得
$stripePlan = $subscriptionItem->stripe_plan;
$quantity = $subscriptionItem->quantity;

findItemOrFailメソッドを使用して特定のプランを取得できます。

$user = User::find(1);

$subscriptionItem = $user->subscription('default')->findItemOrFail('chat-plan');

従量制課金

従量制課金を使用すると、課金サイクル中の製品の使用状況に基づき顧客へ請求できます。たとえば、顧客が1か月に送信するテキストメッセージまたは電子メールの数に基づいて顧客に請求するケースが考えられます。

従量制課金を使用開始するには、最初に、Stripeダッシュボードの従量制価格(metered price)で新しい製品を作成する必要があります。次に、meteredPlanを使用して、従量制の価格IDを顧客のサブスクリプションに追加します。

use Illuminate\Http\Request;

Route::post('/user/subscribe', function (Request $request) {
    $request->user()->newSubscription('default', [])
        ->meteredPlan('price_metered')
        ->create($request->paymentMethodId);

    // ...
});

Stripeの支払いから従量制サブスクリプションを開始することもできます。

$checkout = Auth::user()
        ->newSubscription('default', [])
        ->meteredPlan('price_metered')
        ->checkout();

return view('your-checkout-view', [
    'checkout' => $checkout,
]);

資料状況の報告

顧客がアプリケーションを使用しているとき、正確な請求ができるように、使用状況をStripeへ報告します。従量制サブスクリプションの使用量を増やすには、reportUsageメソッドを使用します。

$user = User::find(1);

$user->subscription('default')->reportUsage();

デフォルトでは、「使用量」1が請求期間に追加されます。または、指定の「使用量」を渡して、請求期間中の顧客の使用量に追加することもできます。

$user = User::find(1);

$user->subscription('default')->reportUsage(15);

アプリケーションが単一のサブスクリプションで複数のプランを提供している場合は、reportUsageForメソッドを使用して、使用状況を報告する従量制プラン/価格を指定する必要があります。

$user = User::find(1);

$user->subscription('default')->reportUsageFor('price_metered', 15);

以前に報告した使用状況を更新する必要も起こるでしょう。これにはタイムスタンプまたはDateTimeInterfaceインスタンスを2番目のパラメータとしてreportUsageに渡します。その際、Stripeはその時点で報告された使用状況を更新します。指定する日時は現在の請求期間内であるため、以前の使用記録を引き続き更新できます。

$user = User::find(1);

$user->subscription('default')->reportUsage(5, $timestamp);

使用記録の取得

顧客の過去の使用状況を取得するには、サブスクリプションインスタンスのusageRecordsメソッドを使用します。

$user = User::find(1);

$usageRecords = $user->subscription('default')->usageRecords();

アプリケーションが1つのサブスクリプションで複数のプランを提供している場合は、usageRecordsForメソッドを使用して、使用記録を取得する従量制プラン/価格を指定します。

$user = User::find(1);

$usageRecords = $user->subscription('default')->usageRecordsFor('price_metered');

usageRecordsメソッドとusageRecordsForメソッドは、使用レコードの連想配列を含むCollectionインスタンスを返します。この配列を繰り返し処理して、顧客の合計使用量を表示できます。

@foreach ($usageRecords as $usageRecord)
    - Period Starting: {{ $usageRecord['period']['start'] }}
    - Period Ending: {{ $usageRecord['period']['end'] }}
    - Total Usage: {{ $usageRecord['total_usage'] }}
@endforeach

返されるすべての使用状況データの完全なリファレンスと、Stripeのカーソルベースのペジネーションの使用方法については、Stripe公式のAPIドキュメントを参照してください。

サブスクリプションの税率

ユーザーがサブスクリプションで支払う税率を指定するには、BillableなモデルにtaxRatesメソッドを実装し、Stripe税率IDを含む配列を返す必要があります。これらの税率は、Stripeダッシュボードで定義します。

/**
 * 顧客のサブスクリプションに適用する税率
 *
 * @return array
 */
public function taxRates()
{
    return ['tax-rate-id'];
}

taxRatesメソッドを使用すると、顧客ごとに税率を適用できます。これは、ユーザーベースが複数の国と税率にまたがる場合に役立つでしょう。

マルチプランサブスクリプションを提供している場合は、BillableなモデルにplanTaxRatesメソッドを実装することで、プランごとに異なる税率を定義できます。

/**
 * 顧客のサブスクリプションに適用する税率
 *
 * @return array
 */
public function planTaxRates()
{
    return [
        'plan-id' => ['tax-rate-id'],
    ];
}

Note: taxRatesメソッドはサブスクリプション料金にのみ適用されます。Cashierを使用して「1回限り」の料金を請求する場合は、その時点で税率を手動で指定する必要があります。

税率の同期

taxRatesメソッドから返すハードコードした税率IDを変更する場合、ユーザーの既存サブスクリプションの設定税率は同じままです。既存のサブスクリプションの税額を新しいtaxRates値で更新する場合は、ユーザーのサブスクリプションインスタンスでsyncTaxRatesメソッドを呼び出す必要があります。

$user->subscription('default')->syncTaxRates();

これにより、マルチプランサブスクリプションアイテムの税率も同期されます。アプリケーションがマルチプランサブスクリプションを提供している場合は、前で説明したように、Billableなモデルで確実にplanTaxRatesメソッドを実装する必要があります。

非課税

Cashierは、顧客が非課税であるかどうかを判断するために、isNotTaxExemptisTaxExemptreverseChargeAppliesメソッドも提供しています。これらのメソッドは、StripeAPIを呼び出して、顧客の免税ステータスを判定します。

use App\Models\User;

$user = User::find(1);

$user->isTaxExempt();
$user->isNotTaxExempt();
$user->reverseChargeApplies();

Note: これらのメソッドは、すべてのLaravel\Cashier\Invoiceオブジェクトでも使用できます。ただし、Invoiceオブジェクトで呼び出されると、メソッドは請求書が作成されたときの免除ステータスを用います。

サブスクリプション基準日

デフォルトの請求サイクル基準日は、サブスクリプションが作成された日付、または試用期間が使用されている場合は試用が終了した日付です。請求基準日を変更する場合は、anchorBillingCycleOnメソッドを使用します。

use Illuminate\Http\Request;

Route::post('/user/subscribe', function (Request $request) {
    $anchor = Carbon::parse('first day of next month');

    $request->user()->newSubscription('default', 'price_premium')
                ->anchorBillingCycleOn($anchor->startOfDay())
                ->create($request->paymentMethodId);

    // ...
});

サブスクリプションの請求サイクルの管理の詳細については、Stripe請求サイクルのドキュメントを参照してください。

サブスクリプションの取り消し

サブスクリプションをキャンセルするには、ユーザーのサブスクリプションでcancelメソッドを呼び出します。

$user->subscription('default')->cancel();

サブスクリプションがキャンセルされると、Cashierは自動的にsubscriptionsデータベーステーブルのends_atカラムを設定します。このカラムは、subscribedメソッドがfalseを返し始めるタイミングを決めるため使用されます。

たとえば、顧客が3月1日にサブスクリプションをキャンセルしたが、そのサブスクリプションが3月5日までに終了するようスケジュールされていなかった場合、subscribedメソッドは3月5日までtrueを返し続けます。この振る舞いを行うのは、ユーザーは請求サイクルが終了するまでアプリケーションの使用を通常継続できるためです。

onGracePeriodメソッドを使用して、ユーザーがサブスクリプションをキャンセルしたが、まだ「猶予期間」にあるかどうかを判断できます。

if ($user->subscription('default')->onGracePeriod()) {
    //
}

サブスクリプションをすぐにキャンセルする場合は、ユーザーのサブスクリプションでcancelNowメソッドを呼び出します。

$user->subscription('default')->cancelNow();

サブスクリプションをすぐにキャンセルし、従量制による使用量の未請求部分や、新規/保留中の請求項目を請求する場合は、ユーザーのサブスクリプションに対しcancelNowAndInvoiceメソッドを呼び出します。

$user->subscription('default')->cancelNowAndInvoice();

特定の時間に購読をキャンセルすることもできます。

$user->subscription('default')->cancelAt(
    now()->addDays(10)
);

サブスクリプションの再開

顧客がサブスクリプションをキャンセルし、それを再開する場合は、サブスクリプションに対しresumeメソッドを呼び出します。サブスクリプションを再開するには、顧客は「猶予期間」内である必要があります。

$user->subscription('default')->resume();

顧客がサブスクリプションをキャンセルし、サブスクリプションが完全に期限切れになる前にそのサブスクリプションを再開する場合、請求はすぐに顧客へ課せられれません。代わりに、サブスクリプションを再アクティブ化し、元の請求サイクルで請求します。

サブスクリプションの試用期間

支払い方法の事前登録

事前に支払い方法情報を収集し、顧客に試用期間を提供したい場合は、サブスクリプションの作成時にtrialDaysメソッドを使用します。

use Illuminate\Http\Request;

Route::post('/user/subscribe', function (Request $request) {
    $request->user()->newSubscription('default', 'price_monthly')
                ->trialDays(10)
                ->create($request->paymentMethodId);

    // ...
});

このメソッドは、データベース内のサブスクリプションレコードに試用期間の終了日を設定し、この日付が過ぎるまで顧客への請求を開始しないようにStripeに指示します。trialDaysメソッドを使用すると、CashierはStripeのプランに設定しているデフォルトの試用期間を上書きします。

Note: 試用期間の終了日より前に顧客のサブスクリプションがキャンセルされなかった場合、試用期間の終了時にすぐ課金されるため、試用期間の終了日をユーザーに必ず通知する必要があります。

trialUntilメソッドを使用すると、試用期間をいつ終了するかを指定するDateTimeインスタンスを渡せます。

use Carbon\Carbon;

$user->newSubscription('default', 'price_monthly')
            ->trialUntil(Carbon::now()->addDays(10))
            ->create($paymentMethod);

ユーザーインスタンスのonTrialメソッドまたはサブスクリプションインスタンスのonTrialメソッドのいずれかを使用して、ユーザーが試用期間内にあるかどうか判定できます。以下の2例は同じ働きです。

if ($user->onTrial('default')) {
    //
}

if ($user->subscription('default')->onTrial()) {
    //
}

endTrialメソッドを使用して、サブスクリプションの試用期間を即時終了できます。

$user->subscription('default')->endTrial();

ストライプ/Cashierでの試用期間日数の定義

プランが受け取るトライアル日数をStripeダッシュボードで定義するか、常にCashierを使用して明示的に渡すかを選択できます。Stripeでプランの試用日数を定義することを選択した場合、過去にそのサブスクリプションを購読していた顧客の新しいサブスクリプションを含む、新しいサブスクリプションは全部、明示的にtrialDays(0)メソッドを呼び出さない限り、常に試用期間が提供されることに注意してください。

支払い方法事前登録なし

ユーザーの支払い方法情報を事前に収集せずに試用期間を提供したい場合は、ユーザーレコードのtrial_ends_at列を希望の試用終了日に設定してください。これは通常、ユーザー登録時に行います。

use App\Models\User;

$user = User::create([
    // ...
    'trial_ends_at' => now()->addDays(10),
]);

Note: Billableなモデルのクラス定義内のtrial_ends_at属性にdatecastを必ず追加してください。

Cashierはこのタイプの試用期間を「一般的な試用期間(generic trial)」と呼んでいます。これは、既存のサブスクリプションに関連付けられていないからです。BillableなモデルインスタンスのonTrialメソッドは、現在の日付がtrial_ends_atの値を超えていない場合にtrueを返します。

if ($user->onTrial()) {
    // ユーザーは試用期間内
}

ユーザーの実際のサブスクリプションを作成する準備ができたら、通常どおりnewSubscriptionメソッドを使用できます。

$user = User::find(1);

$user->newSubscription('default', 'price_monthly')->create($paymentMethod);

ユーザーの試用終了日を取得するには、trialEndsAtメソッドを使用します。このメソッドは、ユーザーが試用中の場合はCarbon日付インスタンスを返し、そうでない場合はnullを返します。デフォルト以外の特定のサブスクリプションの試用終了日を取得する場合は、オプションのサブスクリプション名パラメーターを渡すこともできます。

if ($user->onTrial()) {
    $trialEndsAt = $user->trialEndsAt('main');
}

ユーザーが「一般的な」試用期間内であり、実際のサブスクリプションをまだ作成していないことを具体的に知りたい場合は、onGenericTrialメソッドを使用することもできます。

if ($user->onGenericTrial()) {
    // ユーザーは「一般的な」試用期間内
}

試用期間の延長

extendTrialメソッドを使用すると、サブスクリプションの作成後にサブスクリプションの試用期間を延長できます。試用期間がすでに終了していて、顧客にサブスクリプションの料金が既に請求されている場合でも、延長試用期間を提供できます。試用期間内に費やされた時間は、その顧客の次の請求から差し引かれます。

use App\Models\User;

$subscription = User::find(1)->subscription('default');

// 今から7日後に試用期間終了
$subscription->extendTrial(
    now()->addDays(7)
);

// 試用期間をさらに5日追加
$subscription->extendTrial(
    $subscription->trial_ends_at->addDays(5)
);

StripeのWebフックの処理

Tip!! Stripe CLIを使用して、ローカル開発中にWebhookをテストすることができます。

Stripeは、Webフックを介してさまざまなイベントをアプリケーションに通知できます。デフォルトでは、CashierのWebフックコントローラを指すルートは、Cashierサービスプロバイダにより自動的に登録されます。このコントローラは、すべての受信Webフックリクエストを処理します。

デフォルトでは、Cashier Webフックコントローラは、(Stripe設定で定義する)課金失敗が多すぎるサブスクリプションのキャンセル、顧客の更新、顧客の削除、サブスクリプションの更新、および支払い方法の変更を自動的に処理します。ただし、すぐにわかりますが、このコントローラを拡張して、任意のStripe Webフックイベントを処理できます。

アプリケーションがStripe Webフックを処理できるようにするには、StripeコントロールパネルでWebフックURLを設定してください。デフォルトでは、CashierのWebフックコントローラは/stripe/webhookURLパスに応答します。Stripeコントロールパネルで有効にする必要があるすべてのWebフックの完全なリストは次のとおりです。

Note: Cashierが持っているWebフック署名検証ミドルウェアを使用して、受信Stripe Webフックリクエストを保護してください。

WebフックとCSRF保護

Stripe WebフックはLaravelのCSRF保護をバイパスする必要があるため、アプリケーションのApp\Http\Middleware\VerifyCsrfTokenミドルウェアに例外としてURIをリストするか、webミドルウェアグループの外にルートをリストしてください。

protected $except = [
    'stripe/*',
];

Webフックイベントハンドラの定義

Cashierは、失敗した請求やその他の一般的なStripe Webフックイベントのサブスクリプションを自動的にキャンセル処理します。ただし、思い通りに処理したいWebフックイベントがある場合は、Cashier Webフックコントローラを拡張し処理できます。

コントローラのメソッド名は、Cashierのコントローラの規則に対応している必要があります。具体的には、メソッドのプリフィックスとしてhandleと、処理するWebフックの「キャメルケース」名を付ける必要があります。たとえば、invoice.payment_succeeded Webフックを処理する場合は、コントローラにhandleInvoicePaymentSucceededメソッドを追加する必要があります。

<?php

namespace App\Http\Controllers;

use Laravel\Cashier\Http\Controllers\WebhookController as CashierController;

class WebhookController extends CashierController
{
    /**
     * 請求の支払い処理に成功
     *
     * @param  array  $payload
     * @return \Symfony\Component\HttpFoundation\Response
     */
    public function handleInvoicePaymentSucceeded($payload)
    {
        // 受信イベントの処理…
    }
}

次に、アプリケーションのroutes/web.phpファイル内でCashier Webフックコントローラのルートを定義します。これにより、Cashierのサービスプロバイダが登録したデフォルトルートが上書きされます。

use App\Http\Controllers\WebhookController;

Route::post(
    '/stripe/webhook',
    [WebhookController::class, 'handleWebhook']
);

Tip!! Cashierは、Webフックを受信するとLaravel\Cashier\Events\WebhookReceivedイベントを発行し、WebフックがCashierによって処理されるとLaravel\Cashier\Events\WebhookHandledイベントを発行します。どちらのイベントにも、Stripe Webフックの全ペイロードが含まれています。

Webフック署名の確認

Webフックを保護するために、StripeのWebhook署名を使用できます。便利なように、Cashierには受信Stripe Webフックリクエストが有効であるかを検証するミドルウェアが自動的に含まれています。

Webフックの検証を有効にするには、STRIPE_WEBHOOK_SECRET環境変数がアプリケーションの.envファイルに設定されていることを確認してください。Webフックのsecretは、Stripeアカウントダッシュボードから取得できます。

一回限りの支払い

シンプルな支払い

Note: chargeメソッドは、アプリケーションで使用する通貨の最小単位で請求する金額を受け入れます。たとえば、米ドルを使用する場合、金額はペニーで指定する必要があります。

顧客に対して1回限りの請求を行う場合は、Billableなモデルインスタンスでchargeメソッドを使用します。chargeメソッドの2番目の引数として支払い方法識別子を指定する必要があります。

use Illuminate\Http\Request;

Route::post('/purchase', function (Request $request) {
    $stripeCharge = $request->user()->charge(
        100, $request->paymentMethodId
    );

    // ...
});

chargeメソッドは3番目の引数を取り、ベースにあるStripeの課金作成へのオプションを指定できます。課金作成時に利用できるオプションの詳細は、Stripeドキュメントを参照してください。

$user->charge(100, $paymentMethod, [
    'custom_option' => $value,
]);

また、基礎となる顧客やユーザーなしにchargeメソッドを使用することもできます。そのためには、アプリケーションのBillableなモデルの新しいインスタンスでchargeメソッドを呼び出します。

use App\Models\User;

$stripeCharge = (new User)->charge(100, $paymentMethod);

課金失敗の場合、chargeメソッドは例外を投げます。課金が成功すると、メソッドはLaravel\Cashier\Paymentのインスタンスを返します。

try {
    $payment = $user->charge(100, $paymentMethod);
} catch (Exception $e) {
    //
}

インボイス付きの支払い

時に1回限りの請求を行い、PDFレシートを顧客に提供する必要がおきるでしょう。invoiceForメソッドを使用すると、まさにそれを実行できます。たとえば、「メンテナンス料金」を顧客に$5.00請求するとします。

$user->invoiceFor('One Time Fee', 500);

インボイスは、ユーザーのデフォルトの支払い方法に対し即時請求されます。invoiceForメソッドは3番目の引数として配列も受け入れます。この配列には、インボイスアイテムの請求オプションを指定します。メソッドの4番目の引数も配列で、インボイス自体の請求オプションを指定します。

$user->invoiceFor('Stickers', 500, [
    'quantity' => 50,
], [
    'default_tax_rates' => ['tax-rate-id'],
]);

Note: invoiceForメソッドは、失敗した請求を再試行するStripeインボイスを作成します。課金に失敗した請求を再試行したくない場合は、最初の失敗した請求の後にStripe APIを使用し、インボイスをを閉じる必要があります。

支払いの払い戻し

Stripeの料金を払い戻す必要がある場合は、refundメソッドを使用します。このメソッドは、最初の引数にStripe支払いインテントIDを取ります。

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

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

インボイス

インボイスの取得

invoicesメソッドを使用して、Billableなモデルのインボイスの配列を簡単に取得できます。invoicesメソッドはLaravel\Cashier\Invoiceインスタンスのコレクションを返します。

$invoices = $user->invoices();

結果に保留中のインボイスを含めたい場合は、invoicesInclusivePendingメソッドを使用します。

$invoices = $user->invoicesIncludingPending();

findInvoiceメソッドを使用して、IDで特定のインボイスを取得できます。

$invoice = $user->findInvoice($invoiceId);

インボイス情報の表示

ある顧客のインボイスを一覧表示する場合、インボイスのメソッドを使用し関連するインボイス情報を表示すると思います。たとえば、テーブル中の全インボイスをリストする場合、ユーザーがどれでも簡単にダウンロードできるようにしたいことでしょう。

<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>

インボイスPDFの生成

ルートまたはコントローラ内から、downloadInvoiceメソッドを使用して、特定のインボイスのPDFダウンロードを生成できます。このメソッドは、インボイスのダウンロードに必要なHTTP応答を適切かつ自動的に生成します。

use Illuminate\Http\Request;

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

downloadInvoiceメソッドは3番目の引数により、カスタムファイル名を使用できます。このファイル名には、自動的に".pdf"という拡張子が付けられます。

return $request->user()->downloadInvoice($invoiceId, [
    'vendor' => 'Your Company',
    'product' => 'Your Product',
], 'my-invoice');

チェックアウト

Cashier Stripeは、Stripe Checkoutもサポートしています。Stripe Checkoutは、チェックアウトページを事前に構築しホストするという、支払いを受け入れるためカスタムページを実装する手間を省きます。

以下のドキュメントで、Stripe Checkoutをどのように利用開始するのかに関する情報を説明します。Stripe Checkoutの詳細は、StrepeのCheckoutに関するドキュメントを確認する必要があるでしょう

商品の支払い

Billableなモデル上のcheckoutメソッドを使用して、Stripeダッシュボード内に作成した既存の製品のチェックアウトを実行できます。checkoutメソッドは新しいStripeチェックアウトセッションを開始します。デフォルトで、Stripe価格IDを渡す必要があります。

$checkout = $user->checkout('price_12345');

return view('your-checkout-view', [
    'checkout' => $checkout,
]);

必要に応じて、製品数量を指定することもできます。

$checkout = $user->checkout(['price_12345' => 15]);

チェックアウトセッションインスタンスをビューに渡し、ユーザーをStripeチェックアウトに向かわせるボタンをbuttonメソッドを使用してレンダーできます。

{{ $checkout->button('Buy') }}

顧客がこのボタンをクリックすると、Stripeのチェックアウトページにリダイレクトされます。デフォルトでは、ユーザーが購入を正常に完了した場合、または購入をキャンセルすると、Homeルートへリダイレクトされますが、success_urlcancel_urlオプションを使ってカスタムコールバックURLを指定できます。

$checkout = $user->checkout(['price_12345' => 1], [
    'success_url' => route('your-success-route'),
    'cancel_url' => route('your-cancel-route'),
]);

プロモーションコード

Stripe Checkoutはデフォルトで、ユーザーが商品に使用できるプロモーションコードを許可していません。幸いわいに、チェックアウトページでこれを有効にする簡単な方法があります。そのためには、allowPromotionCodesメソッドを呼び出します。

$checkout = $user->allowPromotionCodes()->checkout('price_12345');

一回限りの支払い

ストライプダッシュボードに作成していない、アドホックな商品をシンプルに課金することもできます。これには、BillableなモデルでcheckoutChargeメソッドを使用し、課金可能な料金、製品名、およびオプションの数量を渡たします。

$checkout = $user->checkoutCharge(1200, 'T-Shirt', 5);

return view('your-checkout-view', [
    'checkout' => $checkout,
]);

チェックアウトセッションインスタンスをビューに渡し、ユーザーをStripeチェックアウトへ向かわせるボタンをbuttonメソッドでレンダーできます。

{{ $checkout->button('Buy') }}

顧客がこのボタンをクリックすると、Stripeのチェックアウトページにリダイレクトされます。

Note: checkoutChargeメソッドを使用する場合、Stripeは常にStripeダッシュボードに新しい製品と価格を作成します。したがって、代わりにStripeダッシュボードで事前に商品を作成し、checkoutメソッドを使用することを推奨します。

サブスクリプションの支払い

Note: Stripe Checkoutのサブスクリプションを使用するには、Stripeダッシュボードでcustomer.subscription.created Webフックを有効にする必要があります。このWebフックは、データベースにサブスクリプションレコードを作成し、すべてのサブスクリプション関連アイテムを保存します。

サブスクリプションを開始するには、Stripe Checkoutを使用することもできます。Cashierのサブスクリプションビルダメソッドを使用してサブスクリプションを定義した後に、checkoutメソッドを呼び出せます。

$checkout = Auth::user()
        ->newSubscription('default', 'price_xxx')
        ->checkout();

return view('your-checkout-view', [
    'checkout' => $checkout,
]);

製品のチェックアウトと同様に、成功およびキャンセルのURLをカスタマイズできます。

$checkout = Auth::user()->newSubscription('default', 'price_xxx')->checkout([
    'success_url' => route('your-success-route'),
    'cancel_url' => route('your-cancel-route'),
]);

もちろん、サブスクリプションチェックアウトのプロモーションコードを有効にすることもできます。

$checkout = Auth::user()->newSubscription('default', 'price_xxx')
    ->allowPromotionCodes()
    ->checkout();

チェックアウトセッションインスタンスをビューへ渡し、ユーザーをStripeチェックアウトに向かわせるボタンをbuttonメソッドを使用してレンダーできます。

{{ $checkout->button('Subscribe') }}

顧客がこのボタンをクリックすると、Stripeのチェックアウトページにリダイレクトされます。

Note: 残念ながらStripe Checkoutはサブスクリプションを開始するとき、すべてのサブスクリプション請求オプションをサポートしていません。サブスクリプションビルダのanchorBillingCycleOnメソッドを使用して、プロレーション動作の設定、または支払い動作の設定は、Stripeチェックアウトセッション中に全く効果はありません。どのパラメータが利用可能であるかを確認するには、Stripe CheckoutセッションAPIのドキュメントを参照してください。

Stripeの支払と試用期間

もちろん、Stripe Checkoutを使用して購読を作成する際、試用期間の完了時間を定義できます。

$checkout = Auth::user()->newSubscription('default', 'price_xxx')
    ->trialDays(3)
    ->checkout();

ただし、試用期間は最低48時間でなければならず、これはStripe Checkoutでサポートされている試行時間の最短時間です。

サブスクリプションとWebフック

StripeとCashierはWebフックを使いサブスクリプションの状態を更新することを覚えておいてください。そのため、顧客が支払い情報を入力した後でアプリケーションに戻った時点で、サブスクリプションが有効になっていない可能性があります。このシナリオを処理するには、ユーザーに支払いやサブスクリプションが保留中であることをユーザーに知らせるメッセージを表示することを推奨します。

支払いボタンのスタイル

チェックアウトボタンをレンダーするときは、classstyleオプションを使ってボタンスタイルをカスタマイズできます。これらのオプションは、連想配列としてbuttonメソッドへの第2引数に渡す必要があります。

{{ $checkout->button('Buy', ['class' => 'p-4 bg-blue-500 text-white']) }}

支払い失敗の処理

サブスクリプションまたは1回限りの支払いが失敗する場合もあります。これが起きると、Cashierはこの発生を通知するLaravel\Cashier\Exceptions\IncompletePayment例外を投げます。この例外をキャッチした後に続行する方法は、2つの選択肢があります。

1つ目はCashierが用意している専用の支払い確認ページに顧客をリダイレクトすることです。このページは、Cashierのサービスプロバイダを介して登録済みの名前付きルートがすでに割り振られています。したがって、IncompletePayment例外をキャッチして、ユーザーを支払い確認ページにリダイレクトできます。

use Laravel\Cashier\Exceptions\IncompletePayment;

try {
    $subscription = $user->newSubscription('default', $planId)
                            ->create($paymentMethod);
} catch (IncompletePayment $exception) {
    return redirect()->route(
        'cashier.payment',
        [$exception->payment->id, 'redirect' => route('home')]
    );
}

支払い確認ページで、顧客はクレジットカード情報を再度入力し、「3Dセキュア」確認などのStripeに必要な追加のアクションを実行するように求められます。支払いを確認すると、ユーザーは上記のredirectパラメータで指定したURLへリダイレクトされます。リダイレクト時に、message(文字列)およびsuccess(整数)クエリ文字列変数をURLへ追加します。

もう一つの方法として、Stripeに支払い確認の処理を任せることもできます。この場合、支払い確認ページにリダイレクトする代わりに、StripeダッシュボードでStripeの自動請求メールを設定してください。ただし、IncompletePayment例外がキャッチされた場合でも、支払い確認の手順を記載したメールがユーザーへ届くよう、通知する必要があります。

Billableトレイトを使用するモデルのchargeinvoiceForinvoiceメソッドでは、支払いの例外が投げられる場合があります。サブスクリプションを操作する場合では、SubscriptionBuildercreateメソッド、およびSubscriptionモデルのincrementAndInvoiceメソッドとswapAndInvoiceメソッドは、不完全な支払い例外を投げる可能性があります。

既存のサブスクリプションの支払いが不完全であるかどうかの判断は、BillableモデルまたはサブスクリプションインスタンスでhasIncompletePaymentメソッドを使用して行えます。

if ($user->hasIncompletePayment('default')) {
    //
}

if ($user->subscription('default')->hasIncompletePayment()) {
    //
}

現在、IncompletePaymentを拡張する2種類の支払い例外があります。ユーザーエクスペリエンスをカスタマイズできるように、必要に応じてこれらを個別にキャッチできます。

  • Laravel\Cashier\Exceptions\PaymentActionRequired:この例外は、Stripeが支払いを確認して処理するために追加の検証が必要であることを示します。
  • Laravel\Cashier\Exceptions\PaymentFailure:この例外は、利用可能な資金が不足しているなど、他のさまざまな理由で支払いが失敗したことを示します。

強力な顧客認証(SCA)

あなたのビジネスがヨーロッパに拠点を置いている場合は、EUの強力な顧客認証(SCA)法令を遵守する必要があります。これらの法令は、支払い詐欺を防ぐために2019年9月に欧州連合によって課されました。幸いにして、StripeとCashierは、SCA準拠のアプリケーションを構築する準備ができています。

Note: 使用開始前に、PSD2とSCAに関するStripeのガイド新しいSCA APIに関するドキュメントを確認してください。

追加の確認が必要な支払い

SCA法令では支払いを確認し処理するため、追加の検証が頻繁に必要になります。これが起きると、Cashierは追加の検証が必要であることを通知するLaravel\Cashier\Exceptions\PaymentActionRequired例外を投げます。こうした例外の処理方法の詳細は、失敗した支払いの処理のドキュメントを参照してください。

StripeとCashierが提供する支払い確認画面は、特定の銀行またはカード発行者の支払いフローに合わせて調整することができ、追加のカード確認、一時的な少額の支払い、個別のデバイス認証、その他の形式の検証を含むことができます。

不完了と期限超過の状態

支払いに追加の確認が必要な場合、サブスクリプションはstripe_statusデータベースカラムが示すように、incompletepast_due状態のままになります。Cashierは支払いの確認が完了し、アプリケーションがWebフックを介してStripeから完了の通知を受けるととすぐに、顧客のサブスクリプションを自動的にアクティブ化します。

incompleteおよびpast_due状態の詳細については、これらの状態に関する追加のドキュメントを参照してください。

オフセッション支払い通知

SCAの法令では、サブスクリプションがアクティブな場合でも、顧客は支払いの詳細を時々確認する必要があるため、Cashierはオフセッションでの支払い確認が必要なときに顧客に通知を送信できます。たとえばこれは、サブスクリプションの更新時に発生する可能性があります。Cashierの支払い通知は、CASHIER_PAYMENT_NOTIFICATION環境変数を通知クラスに設定することで有効にできます。デフォルトでは、この通知は無効になっています。もちろん、Cashierにはこの目的で使用できる通知クラスが含まれていますが、必要に応じて独自の通知クラスを自由に提供できます。

CASHIER_PAYMENT_NOTIFICATION=Laravel\Cashier\Notifications\ConfirmPayment

オフセッションでの支払い確認通知が確実に配信されるようにするため、アプリケーションでStripe Webフックが設定されていることと、Stripeダッシュボードでinvoice.payment_action_requiredwebhookが有効になっていることを確認してください。さらに、BillableモデルでLaravelのIlluminate\Notifications\Notizableトレイトを使用していることも確認する必要があります。

Note: 顧客が追加の確認を必要とする支払いを手動で行う場合でも、通知は送信されます。残念ながら、支払いが手動なのか「オフセッション」で行われたかをStripeが知る方法はありません。ただし、顧客が支払いを確認した後に支払いページへアクセスすると、「支払いが成功しました(Payment Successful)」というメッセージが表示されます。謝って顧客へ同じ支払いを2回確認させ、2回目の請求を行粉なってしまうことはありません。

Stripe SDK

Cashierのオブジェクトの多くは、StripeSDKオブジェクトのラッパーです。Stripeオブジェクトを直接操作したい場合は、asStripeメソッドを使用してオブジェクトを簡単に取得できます。

$stripeSubscription = $subscription->asStripeSubscription();

$stripeSubscription->application_fee_percent = 5;

$stripeSubscription->save();

updateStripeSubscriptionメソッドを使用して、Stripeサブスクリプションを直接更新することもできます。

$subscription->updateStripeSubscription(['application_fee_percent' => 5]);

テスト

Cashierを使用するアプリケーションをテストする場合、Stripe APIへの実際のHTTPリクエストをモックすることができます。ただし、これには、Cashier自身の動作を部分的に再実装する必要があります。したがって、テストが実際のStripe APIにヒットすることを許可することをおすすめします。これは遅いですが、アプリケーションが期待どおりに機能しているという確信が高まり、遅いテストは独自のPHPUnitテストグループ内に配置するのが良いでしょう。

テストするときは、Cashier自体には優れたテストスイートを既に持っていることを忘れないでください。したがって、基本的なCashierの動作すべてではなく、独自のアプリケーションのサブスクリプションと支払いフローのテストにのみ焦点を当てる必要があります。

テスト開始するには、Stripeシークレットのテストバージョンをphpunit.xmlファイルに追加します。

<env name="STRIPE_SECRET" value="sk_test_<your-key>"/>

これで、テスト中にCashierとやり取りするたびに、実際のAPIリクエストがStripeテスト環境に送信されます。便宜上、Stripeテストアカウントに、テスト中に使用できるサブスクリプション/プランを事前に入力する必要があります。

Tip!! クレジットカードの拒否や失敗など、さまざまな請求シナリオをテストするため、Stripeが提供しているさまざまなカード番号とトークンのテストを使用できます。

ドキュメント章別ページ

ヘッダー項目移動

注目:アイコン:ページ内リンク設置(リンクがないヘッダーへの移動では、リンクがある以前のヘッダーのハッシュをURLへ付加します。

移動

クリックで即時移動します。

設定

適用ボタンクリック後に、全項目まとめて適用されます。

カラーテーマ
和文指定 Pagination
和文指定 Scaffold
Largeスクリーン表示幅
インデント
本文フォント
コードフォント
フォント適用確認

フォントの指定フィールドから、フォーカスが外れると、当ブロックの内容に反映されます。EnglishのDisplayもPreviewしてください。

フォント設定時、表示に不具合が出た場合、当サイトのクッキーを削除してください。

バックスラッシュを含むインライン\Code\Blockの例です。

以下はコードブロックの例です。

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
     * ユーザに関連する電話レコードを取得
     */
    public function phone()
    {
        return $this->hasOne('App\Phone');
    }
}

設定を保存する前に、表示が乱れないか必ず確認してください。CSSによるフォントファミリー指定の知識がない場合は、フォントを変更しないほうが良いでしょう。

キーボード・ショートカット

オープン操作

PDC

ページ(章)移動の左オフキャンバスオープン

HA

ヘッダー移動モーダルオープン

MS

移動/設定の右オフキャンバスオープン

ヘッダー移動

T

最初のヘッダーへ移動

E

最後のヘッダーへ移動

NJ

次ヘッダー(H2〜H4)へ移動

BK

前ヘッダー(H2〜H4)へ移動

その他

?

このヘルプページ表示
閉じる