はじめに
Laravel Cashier Stripe は、Stripe’s サブスクリプション請求サービスに対する表現力豊かで流暢なインターフェースを提供します。これは、あなたが書くことを恐れているほとんどすべてのボイラープレートサブスクリプション請求コードを処理します。基本的なサブスクリプション管理に加えて、Cashier はクーポン、サブスクリプションの交換、サブスクリプションの「数量」、キャンセルの猶予期間、さらには請求書 PDF の生成も処理できます。
Cashier のアップグレード
Cashier の新しいバージョンにアップグレードする際は、アップグレードガイド を注意深く確認することが重要です。
破壊的変更を防ぐために、Cashier は固定の Stripe API バージョンを使用します。Cashier 15 は Stripe API バージョン 2023-10-16
を利用しています。Stripe API バージョンは、新しい Stripe 機能や改善を利用するためにマイナーリリースで更新されます。
インストール
まず、Composer パッケージマネージャーを使用して Stripe 用の Cashier パッケージをインストールします:
composer require laravel/cashier
パッケージをインストールした後、vendor:publish
Artisan コマンドを使用して Cashier のマイグレーションを公開します:
php artisan vendor:publish --tag="cashier-migrations"
次に、データベースをマイグレーションします:
php artisan migrate
Cashier のマイグレーションは、users
テーブルにいくつかの列を追加します。また、すべての顧客のサブスクリプションを保持するための新しい subscriptions
テーブルと、複数の価格のサブスクリプション用の subscription_items
テーブルも作成します。
希望する場合は、vendor:publish
Artisan コマンドを使用して Cashier の設定ファイルを公開することもできます:
php artisan vendor:publish --tag="cashier-config"
最後に、Cashier がすべての Stripe イベントを適切に処理することを確認するために、Cashier の Webhook 処理を設定することを忘れないでください。
Stripe は、Stripe 識別子を保存するために使用される任意の列は大文字と小文字を区別するべきだと推奨しています。したがって、MySQL を使用する場合は、stripe_id
列の照合順序が utf8_bin
に設定されていることを確認する必要があります。この件に関する詳細は、Stripe ドキュメントで確認できます。
設定
請求可能モデル
Cashier を使用する前に、請求可能モデル定義に Billable
トレイトを追加します。通常、これは App\Models\User
モデルになります。このトレイトは、サブスクリプションの作成、クーポンの適用、支払い方法情報の更新など、一般的な請求タスクを実行するためのさまざまなメソッドを提供します:
use Laravel\Cashier\Billable;
class User extends Authenticatable
{
use Billable;
}
Cashier は、請求可能モデルが Laravel に付属する App\Models\User
クラスであると仮定します。これを変更したい場合は、useCustomerModel
メソッドを介して別のモデルを指定できます。このメソッドは通常、boot
クラスの AppServiceProvider
メソッド内で呼び出されるべきです:
use App\Models\Cashier\User;
use Laravel\Cashier\Cashier;
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Cashier::useCustomerModel(User::class);
}
Laravel の提供する App\Models\User
モデル以外のモデルを使用している場合は、Cashier マイグレーションを公開して、代替モデルのテーブル名に合わせて変更する必要があります。
API キー
次に、アプリケーションの .env
ファイルに Stripe API キーを設定する必要があります。Stripe コントロールパネルから Stripe API キーを取得できます:
STRIPE_KEY=your-stripe-key
STRIPE_SECRET=your-stripe-secret
STRIPE_WEBHOOK_SECRET=your-stripe-webhook-secret
STRIPE_WEBHOOK_SECRET
環境変数がアプリケーションの .env
ファイルに定義されていることを確認してください。この変数は、受信した Webhook が実際に Stripe からのものであることを確認するために使用されます。
通貨設定
デフォルトの Cashier 通貨は米ドル (USD) です。アプリケーションの CASHIER_CURRENCY
環境変数を設定することで、デフォルトの通貨を変更できます:
CASHIER_CURRENCY=eur
Cashier の通貨を設定することに加えて、請求書の表示用に金額をフォーマットする際に使用されるロケールを指定することもできます。内部的に、Cashier は PHP の NumberFormatter
クラス を利用して通貨ロケールを設定します:
CASHIER_CURRENCY_LOCALE=nl_BE
en
以外のロケールを使用するには、ext-intl
PHP 拡張がサーバーにインストールされ、設定されていることを確認してください。
税金設定
Stripe Tax のおかげで、Stripe によって生成されたすべての請求書の税金を自動的に計算することが可能です。自動税計算を有効にするには、アプリケーションの boot
メソッド内の calculateTaxes
メソッドを呼び出します:
use Laravel\Cashier\Cashier;
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Cashier::calculateTaxes();
}
税計算が有効になると、新しいサブスクリプションや生成される一回限りの請求書には自動税計算が適用されます。
この機能が正しく機能するためには、顧客の名前、住所、税 ID などの請求情報が Stripe に同期されている必要があります。これを達成するために、Cashier が提供する 顧客データの同期 および Tax ID メソッドを使用できます。
ロギング
Cashier は、致命的な Stripe エラーをログに記録するために使用されるログチャネルを指定することを許可します。アプリケーションの .env
ファイル内で CASHIER_LOGGER
環境変数を定義することで、ログチャネルを指定できます:
CASHIER_LOGGER=stack
Stripe への API 呼び出しによって生成された例外は、アプリケーションのデフォルトのログチャネルを介してログに記録されます。
カスタムモデルの使用
Cashier によって内部で使用されるモデルを拡張するために、自分自身のモデルを定義し、対応する Cashier モデルを拡張することができます:
use Laravel\Cashier\Subscription as CashierSubscription;
class Subscription extends CashierSubscription
{
// ...
}
モデルを定義した後、Laravel\Cashier\Cashier
クラスを介して Cashier にカスタムモデルを使用するよう指示できます。通常、アプリケーションの App\Providers\AppServiceProvider
クラスの boot
メソッド内で Cashier にカスタムモデルを通知する必要があります:
use App\Models\Cashier\Subscription;
use App\Models\Cashier\SubscriptionItem;
/**
* Bootstrap any application services.
*/
public function boot(): void
{
Cashier::useSubscriptionModel(Subscription::class);
Cashier::useSubscriptionItemModel(SubscriptionItem::class);
}
クイックスタート
製品の販売
Stripe Checkout を利用する前に、Stripe ダッシュボードで固定価格の製品を定義する必要があります。また、Cashier の Webhook 処理を設定する必要があります。
アプリケーションを通じて製品およびサブスクリプション請求を提供することは、圧倒されるかもしれません。しかし、Cashier と Stripe Checkout のおかげで、現代的で堅牢な支払い統合を簡単に構築できます。
非定期的な一回限りの製品に対して顧客に請求するために、Cashier を利用して顧客を Stripe Checkout に誘導し、そこで支払い情報を提供し、購入を確認します。Checkout を介して支払いが完了すると、顧客はアプリケーション内の選択した成功 URL にリダイレクトされます:
use Illuminate\Http\Request;
Route::get('/checkout', function (Request $request) {
$stripePriceId = 'price_deluxe_album';
$quantity = 1;
return $request->user()->checkout([$stripePriceId => $quantity], [
'success_url' => route('checkout-success'),
'cancel_url' => route('checkout-cancel'),
]);
})->name('checkout');
Route::view('/checkout/success', 'checkout.success')->name('checkout-success');
Route::view('/checkout/cancel', 'checkout.cancel')->name('checkout-cancel');
上記の例のように、Cashier が提供する checkout
メソッドを使用して、顧客を特定の「価格識別子」のために Stripe Checkout にリダイレクトします。Stripe を使用する際、「価格」は 特定の製品のために定義された価格 を指します。
必要に応じて、checkout
メソッドは自動的に Stripe に顧客を作成し、その Stripe 顧客レコードをアプリケーションの対応するユーザーに接続します。チェックアウトセッションが完了すると、顧客は情報メッセージを表示できる専用の成功またはキャンセルページにリダイレクトされます。
Stripe Checkout にメタデータを提供する
製品を販売する際、完了した注文や購入した製品を Cart
および Order
モデルを介して追跡することが一般的です。顧客を Stripe Checkout にリダイレクトして購入を完了させる際、顧客がアプリケーションにリダイレクトされる際に、完了した購入を対応する注文に関連付けるために既存の注文識別子を提供する必要があるかもしれません。
これを達成するために、checkout
メソッドに metadata
の配列を提供できます。ユーザーがチェックアウトプロセスを開始すると、保留中の Order
がアプリケーション内で作成されると想像してみましょう。この例の Cart
および Order
モデルは説明用であり、Cashier によって提供されていません。これらの概念は、アプリケーションのニーズに基づいて自由に実装できます:
use App\Models\Cart;
use App\Models\Order;
use Illuminate\Http\Request;
Route::get('/cart/{cart}/checkout', function (Request $request, Cart $cart) {
$order = Order::create([
'cart_id' => $cart->id,
'price_ids' => $cart->price_ids,
'status' => 'incomplete',
]);
return $request->user()->checkout($order->price_ids, [
'success_url' => route('checkout-success').'?session_id={CHECKOUT_SESSION_ID}',
'cancel_url' => route('checkout-cancel'),
'metadata' => ['order_id' => $order->id],
]);
})->name('checkout');
上記の例のように、ユーザーがチェックアウトプロセスを開始すると、カート/注文に関連するすべての Stripe 価格識別子を checkout
メソッドに提供します。もちろん、アプリケーションは、顧客がアイテムを追加する際にこれらのアイテムを「ショッピングカート」または注文に関連付ける責任があります。また、metadata
配列を介して Stripe Checkout セッションに注文の ID を提供します。最後に、Checkout 成功ルートに CHECKOUT_SESSION_ID
テンプレート変数を追加しました。Stripe が顧客をアプリケーションにリダイレクトすると、このテンプレート変数は自動的に Checkout セッション ID で埋められます。
次に、Checkout 成功ルートを構築しましょう。これは、ユーザーが Stripe Checkout を介して購入を完了した後にリダイレクトされるルートです。このルート内で、Stripe Checkout セッション ID と関連する Stripe Checkout インスタンスを取得し、提供されたメタデータにアクセスして顧客の注文を適切に更新できます:
use App\Models\Order;
use Illuminate\Http\Request;
use Laravel\Cashier\Cashier;
Route::get('/checkout/success', function (Request $request) {
$sessionId = $request->get('session_id');
if ($sessionId === null) {
return;
}
$session = Cashier::stripe()->checkout->sessions->retrieve($sessionId);
if ($session->payment_status !== 'paid') {
return;
}
$orderId = $session['metadata']['order_id'] ?? null;
$order = Order::findOrFail($orderId);
$order->update(['status' => 'completed']);
return view('checkout-success', ['order' => $order]);
})->name('checkout-success');
Checkout セッションオブジェクトに含まれるデータに関する詳細は、Stripe のドキュメントを参照してください Checkout セッションオブジェクトに含まれるデータ。
サブスクリプションの販売
Stripe Checkout を利用する前に、Stripe ダッシュボードで固定価格の製品を定義する必要があります。また、Cashier の Webhook 処理を設定する必要があります。
アプリケーションを通じて製品およびサブスクリプション請求を提供することは、圧倒されるかもしれません。しかし、Cashier と Stripe Checkout のおかげで、現代的で堅牢な支払い統合を簡単に構築できます。
Cashier と Stripe Checkout を使用してサブスクリプションを販売する方法を学ぶために、基本的な月額 (price_basic_monthly
) および年額 (price_basic_yearly
) プランを持つサブスクリプションサービスのシンプルなシナリオを考えてみましょう。これらの2つの価格は、Stripe ダッシュボードの「Basic」製品 (pro_basic
) の下にグループ化できます。また、サブスクリプションサービスは pro_expert
として Expert プランを提供するかもしれません。
まず、顧客が私たちのサービスにサブスクライブする方法を見てみましょう。もちろん、顧客はアプリケーションの価格ページで Basic プランの「サブスクライブ」ボタンをクリックすることを想像できます。このボタンまたはリンクは、顧客が選択したプランの Stripe Checkout セッションを作成する Laravel ルートにユーザーを誘導する必要があります:
use Illuminate\Http\Request;
Route::get('/subscription-checkout', function (Request $request) {
return $request->user()
->newSubscription('default', 'price_basic_monthly')
->trialDays(5)
->allowPromotionCodes()
->checkout([
'success_url' => route('your-success-route'),
'cancel_url' => route('your-cancel-route'),
]);
});
上記の例のように、顧客を Stripe Checkout セッションにリダイレクトし、Basic プランにサブスクライブできるようにします。成功したチェックアウトまたはキャンセルの後、顧客は checkout
メソッドに提供した URL にリダイレクトされます。サブスクリプションが実際に開始されたとき(いくつかの支払い方法は処理に数秒かかるため)、Cashier の Webhook 処理を設定する必要があります。
顧客がサブスクリプションを開始できるようになったので、特定のアプリケーションの一部を制限して、サブスクライブしたユーザーのみがアクセスできるようにする必要があります。もちろん、Cashier の Billable
トレイトによって提供される subscribed
メソッドを介して、ユーザーの現在のサブスクリプションステータスを常に確認できます:
@if ($user->subscribed())
<p>You are subscribed.</p>
@endif
特定の製品や価格にサブスクライブしているかどうかを簡単に判断することもできます:
@if ($user->subscribedToProduct('pro_basic'))
<p>You are subscribed to our Basic product.</p>
@endif
@if ($user->subscribedToPrice('price_basic_monthly'))
<p>You are subscribed to our monthly Basic plan.</p>
@endif
サブスクライブミドルウェアの構築
便利さのために、サブスクライブしたユーザーからのリクエストかどうかを判断する ミドルウェア を作成することをお勧めします。このミドルウェアが定義されると、サブスクライブしていないユーザーがルートにアクセスできないように、簡単にルートに割り当てることができます:
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class Subscribed
{
/**
* Handle an incoming request.
*/
public function handle(Request $request, Closure $next): Response
{
if (! $request->user()?->subscribed()) {
// Redirect user to billing page and ask them to subscribe...
return redirect('/billing');
}
return $next($request);
}
}
ミドルウェアが定義されたら、ルートに割り当てることができます:
use App\Http\Middleware\Subscribed;
Route::get('/dashboard', function () {
// ...
})->middleware([Subscribed::class]);
顧客が請求プランを管理できるようにする
もちろん、顧客はサブスクリプションプランを別の製品や「ティア」に変更したいかもしれません。これを許可する最も簡単な方法は、顧客を Stripe の 顧客請求ポータル に誘導することです。これにより、顧客は請求書をダウンロードしたり、支払い方法を更新したり、サブスクリプションプランを変更したりできます。
まず、アプリケーション内にユーザーを Laravel ルートに誘導するリンクまたはボタンを定義します。このルートを使用して請求ポータルセッションを開始します:
<a href="{{ route('billing') }}">
Billing
</a>
次に、Stripe 顧客請求ポータルセッションを開始し、ユーザーをポータルにリダイレクトするルートを定義します。redirectToBillingPortal
メソッドは、ユーザーがポータルを終了したときに戻るべき URL を受け取ります:
use Illuminate\Http\Request;
Route::get('/billing', function (Request $request) {
return $request->user()->redirectToBillingPortal(route('dashboard'));
})->middleware(['auth'])->name('billing');
Cashier の Webhook 処理を設定している限り、Cashier は Stripe からの受信 Webhook を検査することで、アプリケーションの Cashier 関連のデータベーステーブルを自動的に同期します。たとえば、ユーザーが Stripe の顧客請求ポータルを介してサブスクリプションをキャンセルすると、Cashier は対応する Webhook を受信し、アプリケーションのデータベースでサブスクリプションを「キャンセル済み」としてマークします。
顧客
顧客の取得
顧客の Stripe ID を使用して、Cashier::findBillable
メソッドで顧客を取得できます。このメソッドは、請求可能モデルのインスタンスを返します:
use Laravel\Cashier\Cashier;
$user = Cashier::findBillable($stripeId);
顧客の作成
時折、サブスクリプションを開始せずに Stripe 顧客を作成したい場合があります。createAsStripeCustomer
メソッドを使用してこれを実現できます:
$stripeCustomer = $user->createAsStripeCustomer();
顧客が Stripe に作成された後、後でサブスクリプションを開始できます。任意の追加の 顧客作成パラメータ を渡すために、オプションの $options
配列を提供できます:
$stripeCustomer = $user->createAsStripeCustomer($options);
請求可能モデルの Stripe 顧客オブジェクトを返したい場合は、asStripeCustomer
メソッドを使用できます:
$stripeCustomer = $user->asStripeCustomer();
createOrGetStripeCustomer
メソッドは、指定された請求可能モデルの Stripe 顧客オブジェクトを取得するために使用できますが、請求可能モデルがすでに Stripe 内の顧客であるかどうかが不明な場合に使用します。このメソッドは、顧客がまだ存在しない場合に Stripe に新しい顧客を作成します:
$stripeCustomer = $user->createOrGetStripeCustomer();
顧客の更新
時折、追加情報で Stripe 顧客を直接更新したい場合があります。updateStripeCustomer
メソッドを使用してこれを実現できます。このメソッドは、顧客更新オプション の配列を受け入れます:
$stripeCustomer = $user->updateStripeCustomer($options);
残高
Stripe は、顧客の「残高」をクレジットまたはデビットすることを許可します。後で、この残高は新しい請求書にクレジットまたはデビットされます。顧客の合計残高を確認するには、請求可能モデルで利用可能な balance
メソッドを使用できます。balance
メソッドは、顧客の通貨での残高のフォーマットされた文字列表現を返します:
$balance = $user->balance();
顧客の残高にクレジットを追加するには、creditBalance
メソッドに値を提供できます。必要に応じて、説明を提供することもできます:
$user->creditBalance(500, 'Premium customer top-up.');
debitBalance
メソッドに値を提供すると、顧客の残高がデビットされます:
$user->debitBalance(300, 'Bad usage penalty.');
applyBalance
メソッドは、顧客の新しい残高トランザクションを作成します。これらのトランザクションレコードは、balanceTransactions
メソッドを使用して取得でき、顧客が確認できるクレジットとデビットのログを提供するのに役立ちます:
// Retrieve all transactions...
$transactions = $user->balanceTransactions();
foreach ($transactions as $transaction) {
// Transaction amount...
$amount = $transaction->amount(); // $2.31
// Retrieve the related invoice when available...
$invoice = $transaction->invoice();
}
税 ID
Cashier は、顧客の税 ID を管理する簡単な方法を提供します。たとえば、taxIds
メソッドを使用して、顧客に割り当てられたすべての 税 ID をコレクションとして取得できます:
$taxIds = $user->taxIds();
特定の顧客の税 ID をその識別子で取得することもできます:
$taxId = $user->findTaxId('txi_belgium');
有効な タイプ と値を提供することで、新しい税 ID を作成できます:
$taxId = $user->createTaxId('eu_vat', 'BE0123456789');
createTaxId
メソッドは、VAT ID を顧客のアカウントに即座に追加します。VAT ID の検証も Stripe によって行われます; ただし、これは非同期プロセスです。検証の更新を通知されるには、customer.tax_id.updated
Webhook イベントにサブスクライブし、VAT IDs verification
パラメータを確認します。Webhook の処理に関する詳細は、Webhook ハンドラの定義に関するドキュメントを参照してください。
deleteTaxId
メソッドを使用して税 ID を削除できます:
$user->deleteTaxId('txi_belgium');
Stripe との顧客データの同期
通常、アプリケーションのユーザーが名前、メールアドレス、または Stripe にも保存されているその他の情報を更新する場合、Stripe に更新を通知する必要があります。これにより、Stripe の情報のコピーがアプリケーションの情報と同期されます。
これを自動化するために、請求可能モデルの updated
イベントに反応するイベントリスナーを定義できます。次に、イベントリスナー内でモデルの syncStripeCustomerDetails
メソッドを呼び出します:
use App\Models\User;
use function Illuminate\Events\queueable;
/**
* The "booted" method of the model.
*/
protected static function booted(): void
{
static::updated(queueable(function (User $customer) {
if ($customer->hasStripeId()) {
$customer->syncStripeCustomerDetails();
}
}));
}
これで、顧客モデルが更新されるたびに、その情報が Stripe と同期されます。便利なことに、Cashier は顧客の初回作成時に自動的に顧客の情報を Stripe と同期します。
顧客情報を Stripe と同期するために使用される列をカスタマイズするには、Cashier が提供するさまざまなメソッドをオーバーライドできます。たとえば、stripeName
メソッドをオーバーライドして、Cashier が顧客情報を Stripe に同期する際に考慮すべき「名前」と見なされる属性をカスタマイズできます:
/**
* Get the customer name that should be synced to Stripe.
*/
public function stripeName(): string|null
{
return $this->company_name;
}
同様に、stripeEmail
、stripePhone
、stripeAddress
、および stripePreferredLocales
メソッドをオーバーライドできます。これらのメソッドは、Stripe 顧客オブジェクトを更新する際に対応する顧客パラメータに情報を同期します。顧客情報の同期プロセスを完全に制御したい場合は、syncStripeCustomerDetails
メソッドをオーバーライドできます。
請求ポータル
Stripe は、顧客がサブスクリプション、支払い方法を管理し、請求履歴を表示できるようにする 請求ポータルの設定を簡単に行う方法 を提供します。請求可能モデルの redirectToBillingPortal
メソッドをコントローラーまたはルートから呼び出すことで、ユーザーを請求ポータルにリダイレクトできます:
use Illuminate\Http\Request;
Route::get('/billing-portal', function (Request $request) {
return $request->user()->redirectToBillingPortal();
});
デフォルトでは、ユーザーがサブスクリプションの管理を終えたとき、Stripe 請求ポータル内のリンクを介してアプリケーションの home
ルートに戻ることができます。ユーザーが戻るべきカスタム URL を提供するには、redirectToBillingPortal
メソッドに 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 で「一回限り」の請求を行ったりするには、支払い方法を保存し、その識別子を Stripe から取得する必要があります。これを達成するためのアプローチは、サブスクリプションまたは一回限りの請求に支払い方法を使用するかどうかによって異なるため、以下で両方を検討します。
サブスクリプション用の支払い方法
顧客のクレジットカード情報を将来のサブスクリプションで使用するために保存する場合、Stripe の「セットアップインテント」APIを使用して、顧客の支払い方法の詳細を安全に収集する必要があります。「セットアップインテント」は、顧客の支払い方法を請求する意図を Stripe に示します。Cashier の Billable
トレイトには、新しいセットアップインテントを簡単に作成するための createSetupIntent
メソッドが含まれています。このメソッドは、顧客の支払い方法の詳細を収集するフォームを表示するルートまたはコントローラーから呼び出す必要があります:
return view('update-payment-method', [
'intent' => $user->createSetupIntent()
]);
セットアップインテントを作成し、ビューに渡した後、そのシークレットを支払い方法を収集する要素に添付する必要があります。たとえば、次の「支払い方法の更新」フォームを考えてみましょう:
<input id="card-holder-name" type="text">
<!-- Stripe Elements Placeholder -->
<div id="card-element"></div>
<button id="card-button" data-secret="{{ $intent->client_secret }}">
Update Payment Method
</button>
次に、Stripe.js ライブラリを使用して、フォームに Stripe Element を添付し、顧客の支払い詳細を安全に収集します:
<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) {
// Display "error.message" to the user...
} else {
// The card has been verified successfully...
}
});
カードが Stripe によって確認された後、結果の setupIntent.payment_method
識別子を Laravel アプリケーションに渡し、顧客に添付できます。支払い方法は、新しい支払い方法として追加するか、デフォルトの支払い方法を更新するために使用できます。また、支払い方法識別子を使用して 新しいサブスクリプションを作成することもできます。
セットアップインテントと顧客の支払い詳細を収集する方法についての詳細は、Stripe が提供するこの概要を確認してください。
一回限りの請求用の支払い方法
もちろん、顧客の支払い方法に対して一回限りの請求を行う場合、支払い方法識別子を一度だけ使用する必要があります。Stripe の制限により、顧客の保存されたデフォルトの支払い方法を一回限りの請求に使用することはできません。顧客に Stripe.js ライブラリを使用して支払い方法の詳細を入力させる必要があります。たとえば、次のフォームを考えてみましょう:
<input id="card-holder-name" type="text">
<!-- Stripe Elements Placeholder -->
<div id="card-element"></div>
<button id="card-button">
Process Payment
</button>
このようなフォームを定義した後、Stripe.js ライブラリを使用して、フォームに Stripe Element を添付し、顧客の支払い詳細を安全に収集します:
<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) {
// Display "error.message" to the user...
} else {
// The card has been verified successfully...
}
});
カードが正常に確認された場合、paymentMethod.id
を Laravel アプリケーションに渡し、一回限りの請求を処理します。
支払い方法の取得
請求可能モデルインスタンスの paymentMethods
メソッドは、Laravel\Cashier\PaymentMethod
インスタンスのコレクションを返します:
$paymentMethods = $user->paymentMethods();
デフォルトでは、このメソッドはすべてのタイプの支払い方法を返します。特定のタイプの支払い方法を取得するには、type
を引数としてメソッドに渡すことができます:
$paymentMethods = $user->paymentMethods('sepa_debit');
顧客のデフォルトの支払い方法を取得するには、defaultPaymentMethod
メソッドを使用できます:
$paymentMethod = $user->defaultPaymentMethod();
請求可能モデルに添付された特定の支払い方法を取得するには、findPaymentMethod
メソッドを使用できます:
$paymentMethod = $user->findPaymentMethod($paymentMethodId);
支払い方法の存在確認
請求可能モデルにデフォルトの支払い方法が添付されているかどうかを判断するには、hasDefaultPaymentMethod
メソッドを呼び出します:
if ($user->hasDefaultPaymentMethod()) {
// ...
}
hasPaymentMethod
メソッドを使用して、請求可能モデルに少なくとも1つの支払い方法が添付されているかどうかを判断できます:
if ($user->hasPaymentMethod()) {
// ...
}
このメソッドは、請求可能モデルに支払い方法が存在するかどうかを判断します。特定のタイプの支払い方法がモデルに存在するかどうかを判断するには、type
を引数としてメソッドに渡します:
if ($user->hasPaymentMethod('sepa_debit')) {
// ...
}
デフォルトの支払い方法の更新
updateDefaultPaymentMethod
メソッドを使用して、顧客のデフォルトの支払い方法情報を更新できます。このメソッドは、Stripe の支払い方法識別子を受け入れ、新しい支払い方法をデフォルトの請求支払い方法として割り当てます:
$user->updateDefaultPaymentMethod($paymentMethod);
顧客のデフォルトの支払い方法情報を Stripe の顧客のデフォルトの支払い方法情報と同期するには、updateDefaultPaymentMethodFromStripe
メソッドを使用できます:
$user->updateDefaultPaymentMethodFromStripe();
顧客のデフォルトの支払い方法は、請求書の作成や新しいサブスクリプションの作成にのみ使用できます。Stripe によって課せられた制限により、一回限りの請求には使用できません。
支払い方法の追加
新しい支払い方法を追加するには、請求可能モデルで addPaymentMethod
メソッドを呼び出し、支払い方法識別子を渡します:
$user->addPaymentMethod($paymentMethod);
支払い方法識別子を取得する方法については、支払い方法の保存に関するドキュメントを確認してください。
支払い方法の削除
支払い方法を削除するには、削除したい Laravel\Cashier\PaymentMethod
インスタンスで delete
メソッドを呼び出します:
$paymentMethod->delete();
deletePaymentMethod
メソッドは、請求可能モデルから特定の支払い方法を削除します:
$user->deletePaymentMethod('pm_visa');
deletePaymentMethods
メソッドは、請求可能モデルのすべての支払い方法情報を削除します:
$user->deletePaymentMethods();
デフォルトでは、このメソッドはすべてのタイプの支払い方法を削除します。特定のタイプの支払い方法を削除するには、type
を引数としてメソッドに渡します:
$user->deletePaymentMethods('sepa_debit');
ユーザーがアクティブなサブスクリプションを持っている場合、アプリケーションはデフォルトの支払い方法を削除することを許可してはいけません。
サブスクリプション
サブスクリプションは、顧客のために定期的な支払いを設定する方法を提供します。Cashier によって管理される Stripe サブスクリプションは、複数のサブスクリプション価格、サブスクリプション数量、トライアルなどをサポートします。
サブスクリプションの作成
サブスクリプションを作成するには、まず請求可能モデルのインスタンスを取得します。通常、これは App\Models\User
のインスタンスになります。モデルインスタンスを取得したら、newSubscription
メソッドを使用してモデルのサブスクリプションを作成できます:
use Illuminate\Http\Request;
Route::post('/user/subscribe', function (Request $request) {
$request->user()->newSubscription(
'default', 'price_monthly'
)->create($request->paymentMethodId);
// ...
});
newSubscription
メソッドに渡される最初の引数は、サブスクリプションの内部タイプである必要があります。アプリケーションが単一のサブスクリプションのみを提供する場合、これを default
または primary
と呼ぶことができます。このサブスクリプションタイプは、内部アプリケーション使用のためのものであり、ユーザーに表示されることを意図していません。また、スペースを含めるべきではなく、サブスクリプションを作成した後に変更されるべきではありません。2 番目の引数は、ユーザーがサブスクライブする特定の価格です。この値は、Stripe の価格識別子に対応する必要があります。
create
メソッドは、Stripe 支払い方法識別子または Stripe PaymentMethod
オブジェクトを受け入れ、サブスクリプションを開始し、請求可能モデルの Stripe 顧客 ID およびその他の関連する請求情報でデータベースを更新します。
支払い方法識別子を直接 create
サブスクリプションメソッドに渡すと、それも自動的にユーザーの保存された支払い方法に追加されます。
請求メールを通じて定期支払いを収集する
顧客の定期支払いを自動的に収集する代わりに、Stripeに指示して、顧客の定期支払いが期限切れになるたびに請求書を顧客にメールで送信させることができます。顧客は請求書を受け取った後に手動で支払うことができます。請求書を通じて定期支払いを収集する際、顧客は事前に支払い方法を提供する必要はありません:
$user->newSubscription('default', 'price_monthly')->createAndSendInvoice();
顧客が請求書を支払うまでの時間は、days_until_due
オプションによって決まります。デフォルトでは、これは30日ですが、必要に応じてこのオプションに特定の値を提供することができます:
$user->newSubscription('default', 'price_monthly')->createAndSendInvoice([], [
'days_until_due' => 30
]);
数量
サブスクリプションを作成する際に価格に特定の[https://stripe.com/docs/billing/subscriptions/quantities]数量を設定したい場合は、サブスクリプションビルダーで`````quantity`````メソッドを呼び出す必要があります:
$user->newSubscription('default', 'price_monthly')
->quantity(5)
->create($paymentMethod);
追加の詳細
$user->newSubscription('default', 'price_monthly')->create($paymentMethod, [
'email' => $email,
], [
'metadata' => ['note' => 'Some extra information.'],
]);
クーポン
サブスクリプションを作成する際にクーポンを適用したい場合は、withCoupon
メソッドを使用できます:
$user->newSubscription('default', 'price_monthly')
->withCoupon('code')
->create($paymentMethod);
$user->newSubscription('default', 'price_monthly')
->withPromotionCode('promo_code_id')
->create($paymentMethod);
指定されたプロモーションコードIDは、プロモーションコードに割り当てられたStripe API IDであり、顧客向けのプロモーションコードではありません。顧客向けのプロモーションコードに基づいてプロモーションコードIDを見つける必要がある場合は、findPromotionCode
メソッドを使用できます:
// Find a promotion code ID by its customer facing code...
$promotionCode = $user->findPromotionCode('SUMMERSALE');
// Find an active promotion code ID by its customer facing code...
$promotionCode = $user->findActivePromotionCode('SUMMERSALE');
上記の例では、返された$promotionCode
オブジェクトはLaravel\Cashier\PromotionCode
のインスタンスです。このクラスは、基になるStripe\PromotionCode
オブジェクトを装飾します。coupon
メソッドを呼び出すことで、プロモーションコードに関連するクーポンを取得できます:
$coupon = $user->findPromotionCode('SUMMERSALE')->coupon();
クーポンインスタンスを使用すると、割引額を決定し、クーポンが固定割引かパーセンテージベースの割引かを判断できます:
if ($coupon->isPercentage()) {
return $coupon->percentOff().'%'; // 21.5%
} else {
return $coupon->amountOff(); // $5.99
}
現在顧客またはサブスクリプションに適用されている割引を取得することもできます:
$discount = $billable->discount();
$discount = $subscription->discount();
返されたLaravel\Cashier\Discount
インスタンスは、基になるStripe\Discount
オブジェクトインスタンスを装飾します。この割引に関連するクーポンをcoupon
メソッドを呼び出すことで取得できます:
$coupon = $subscription->discount()->coupon();
顧客またはサブスクリプションに新しいクーポンまたはプロモーションコードを適用したい場合は、applyCoupon
またはapplyPromotionCode
メソッドを使用できます:
$billable->applyCoupon('coupon_id');
$billable->applyPromotionCode('promotion_code_id');
$subscription->applyCoupon('coupon_id');
$subscription->applyPromotionCode('promotion_code_id');
覚えておいてください、プロモーションコードに割り当てられたStripe API IDを使用し、顧客向けのプロモーションコードではないことを確認してください。顧客またはサブスクリプションには、同時に1つのクーポンまたはプロモーションコードのみを適用できます。
この件に関する詳細については、[https://stripe.com/docs/billing/subscriptions/coupons]クーポンおよび[https://stripe.com/docs/billing/subscriptions/coupons/codes]プロモーションコードに関するStripeのドキュメントを参照してください。
サブスクリプションの追加
すでにデフォルトの支払い方法を持つ顧客にサブスクリプションを追加したい場合は、サブスクリプションビルダーでadd
メソッドを呼び出すことができます:
use App\Models\User;
$user = User::find(1);
$user->newSubscription('default', 'price_monthly')->add();
Stripeダッシュボードからのサブスクリプションの作成
Stripeダッシュボード自体からサブスクリプションを作成することもできます。その際、Cashierは新しく追加されたサブスクリプションを同期し、default
のタイプを割り当てます。ダッシュボードで作成されたサブスクリプションに割り当てられるサブスクリプションタイプをカスタマイズするには、Webhookイベントハンドラーを定義する必要があります。
さらに、Stripeダッシュボードを介して1種類のサブスクリプションのみを作成できます。アプリケーションが異なるタイプを使用する複数のサブスクリプションを提供している場合、Stripeダッシュボードを介して追加できるのは1種類のサブスクリプションのみです。
最後に、アプリケーションが提供するサブスクリプションのタイプごとに常に1つのアクティブなサブスクリプションのみを追加することを確認してください。顧客が2つのdefault
サブスクリプションを持っている場合、Cashierは最新の追加されたサブスクリプションのみを使用し、両方がアプリケーションのデータベースと同期されます。
サブスクリプションのステータスを確認する
顧客がアプリケーションにサブスクリプションを持っている場合、さまざまな便利なメソッドを使用してそのサブスクリプションのステータスを簡単に確認できます。まず、subscribed
メソッドは、顧客がアクティブなサブスクリプションを持っている場合、true
を返します。たとえそのサブスクリプションが現在トライアル期間中であってもです。subscribed
メソッドは、サブスクリプションのタイプを最初の引数として受け取ります:
if ($user->subscribed('default')) {
// ...
}
subscribed
メソッドは、ルートミドルウェア の優れた候補でもあり、ユーザーのサブスクリプションステータスに基づいてルートやコントローラーへのアクセスをフィルタリングできます:
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class EnsureUserIsSubscribed
{
/**
* Handle an incoming request.
*
* @param \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response) $next
*/
public function handle(Request $request, Closure $next): Response
{
if ($request->user() && ! $request->user()->subscribed('default')) {
// This user is not a paying customer...
return redirect('/billing');
}
return $next($request);
}
}
ユーザーがまだトライアル期間内にいるかどうかを判断するには、onTrial
メソッドを使用できます。このメソッドは、ユーザーにトライアル期間中であることを警告するメッセージを表示する必要があるかどうかを判断するのに役立ちます:
if ($user->subscription('default')->onTrial()) {
// ...
}
``````php
if ($user->subscribedToProduct('prod_premium', 'default')) {
// ...
}
`
``````php
if ($user->subscribedToProduct(['prod_basic', 'prod_premium'], 'default')) {
// ...
}
`
``````php
if ($user->subscribedToPrice('price_basic_monthly', 'default')) {
// ...
}
`
``````php
if ($user->subscription('default')->recurring()) {
// ...
}
`
ユーザーが同じタイプの2つのサブスクリプションを持っている場合、subscription
メソッドは常に最新のサブスクリプションを返します。たとえば、ユーザーがdefault
のタイプの2つのサブスクリプションレコードを持っている場合、1つのサブスクリプションは古い期限切れのサブスクリプションであり、もう1つは現在のアクティブなサブスクリプションである可能性があります。最新のサブスクリプションが常に返され、古いサブスクリプションは履歴レビューのためにデータベースに保持されます。
キャンセルされたサブスクリプションのステータス
ユーザーがかつてアクティブなサブスクライバーであったが、サブスクリプションをキャンセルしたかどうかを判断するには、canceled
メソッドを使用できます:
if ($user->subscription('default')->canceled()) {
// ...
}
ユーザーがサブスクリプションをキャンセルしたが、サブスクリプションが完全に期限切れになるまで「猶予期間」にあるかどうかを判断することもできます。たとえば、ユーザーが3月5日にサブスクリプションをキャンセルし、そのサブスクリプションが3月10日に期限切れになる予定であった場合、ユーザーは3月10日まで「猶予期間」にあります。この期間中、subscribed
メソッドはtrue
を返し続けます:
if ($user->subscription('default')->onGracePeriod()) {
// ...
}
ユーザーがサブスクリプションをキャンセルし、「猶予期間」を過ぎているかどうかを判断するには、ended
メソッドを使用できます:
if ($user->subscription('default')->ended()) {
// ...
}
不完全および過期のステータス
サブスクリプションが作成後に二次的な支払いアクションを必要とする場合、サブスクリプションはincomplete
としてマークされます。サブスクリプションのステータスは、Cashierのstripe_status
データベーステーブルのsubscriptions
列に保存されます。
同様に、価格を交換する際に二次的な支払いアクションが必要な場合、サブスクリプションはpast_due
としてマークされます。サブスクリプションがこれらの状態のいずれかにある場合、顧客が支払いを確認するまでアクティブにはなりません。サブスクリプションに不完全な支払いがあるかどうかを判断するには、請求可能モデルまたはサブスクリプションインスタンスでhasIncompletePayment
メソッドを使用できます:
if ($user->hasIncompletePayment('default')) {
// ...
}
if ($user->subscription('default')->hasIncompletePayment()) {
// ...
}
サブスクリプションに不完全な支払いがある場合、顧客をCashierの支払い確認ページに誘導し、latestPayment
識別子を渡す必要があります。サブスクリプションインスタンスで利用可能なlatestPayment
メソッドを使用して、この識別子を取得できます:
<a href="{{ route('cashier.payment', $subscription->latestPayment()->id) }}">
Please confirm your payment.
</a>
サブスクリプションがpast_due
またはincomplete
の状態にあるときもアクティブと見なされるようにしたい場合は、Cashierが提供するkeepPastDueSubscriptionsActive
およびkeepIncompleteSubscriptionsActive
メソッドを使用できます。通常、これらのメソッドはregister
メソッドのApp\Providers\AppServiceProvider
で呼び出す必要があります:
use Laravel\Cashier\Cashier;
/**
* Register any application services.
*/
public function register(): void
{
Cashier::keepPastDueSubscriptionsActive();
Cashier::keepIncompleteSubscriptionsActive();
}
サブスクリプションがincomplete
の状態にある場合、支払いが確認されるまで変更できません。したがって、swap
およびupdateQuantity
メソッドは、サブスクリプションがincomplete
の状態にあるときに例外をスローします。
サブスクリプションスコープ
ほとんどのサブスクリプション状態は、特定の状態にあるサブスクリプションをデータベースで簡単にクエリできるように、クエリスコープとしても利用可能です:
// Get all active subscriptions...
$subscriptions = Subscription::query()->active()->get();
// Get all of the canceled subscriptions for a user...
$subscriptions = $user->subscriptions()->canceled()->get();
利用可能なスコープの完全なリストは以下にあります:
Subscription::query()->active();
Subscription::query()->canceled();
Subscription::query()->ended();
Subscription::query()->incomplete();
Subscription::query()->notCanceled();
Subscription::query()->notOnGracePeriod();
Subscription::query()->notOnTrial();
Subscription::query()->onGracePeriod();
Subscription::query()->onTrial();
Subscription::query()->pastDue();
Subscription::query()->recurring();
価格の変更
顧客がアプリケーションにサブスクリプションしている場合、時折新しいサブスクリプション価格に変更したい場合があります。顧客を新しい価格にスワップするには、Stripe価格の識別子をswap
メソッドに渡します。価格を交換する際、ユーザーが以前にキャンセルされた場合、サブスクリプションを再アクティブ化したいと仮定します。指定された価格識別子は、Stripeダッシュボードで利用可能なStripe価格識別子に対応する必要があります:
use App\Models\User;
$user = App\Models\User::find(1);
$user->subscription('default')->swap('price_yearly');
顧客がトライアル中の場合、トライアル期間は維持されます。さらに、サブスクリプションに「数量」が存在する場合、その数量も維持されます。
価格を交換し、顧客が現在トライアル中の期間をキャンセルしたい場合は、skipTrial
メソッドを呼び出すことができます:
$user->subscription('default')
->skipTrial()
->swap('price_yearly');
価格を交換し、顧客に次の請求サイクルを待たずに請求したい場合は、swapAndInvoice
メソッドを使用できます:
$user = User::find(1);
$user->subscription('default')->swapAndInvoice('price_yearly');
按分
デフォルトでは、Stripeは価格を交換する際に料金を按分します。noProrate
メソッドを使用して、料金を按分せずにサブスクリプションの価格を更新できます:
$user->subscription('default')->noProrate()->swap('price_yearly');
サブスクリプションの按分に関する詳細については、Stripeのドキュメントを参照してください。
<a name="subscription-quantity"></a>
### サブスクリプション数量
時には、サブスクリプションは「数量」に影響されます。たとえば、プロジェクト管理アプリケーションは、プロジェクトごとに月額10ドルを請求するかもしれません。`````incrementQuantity`````および`````decrementQuantity`````メソッドを使用して、サブスクリプション数量を簡単に増減できます:
``````php
use App\Models\User;
$user = User::find(1);
$user->subscription('default')->incrementQuantity();
// Add five to the subscription's current quantity...
$user->subscription('default')->incrementQuantity(5);
$user->subscription('default')->decrementQuantity();
// Subtract five from the subscription's current quantity...
$user->subscription('default')->decrementQuantity(5);
`
または、updateQuantity
メソッドを使用して特定の数量を設定できます:
$user->subscription('default')->updateQuantity(10);
``````php
$user->subscription('default')->noProrate()->updateQuantity(10);
`
サブスクリプション数量に関する詳細については、Stripeのドキュメントを参照してください。
Laravel Cashier (Stripe)
- はじめに
- Cashierのアップグレード
- インストール
- 設定
- クイックスタート
- 顧客
- 支払い方法
- サブスクリプション
- サブスクリプショントライアル
- Stripe Webhookの処理
- 単一の請求
- チェックアウト
- 請求書
- 失敗した支払いの処理
- 強力な顧客認証 (SCA)
- Stripe SDK
- テスト
複数製品を持つサブスクリプション
特定のサブスクリプションに対して複数の製品を指定するには、newSubscription
メソッドの第二引数として価格の配列を渡します:
use Illuminate\Http\Request;
Route::post('/user/subscribe', function (Request $request) {
$request->user()->newSubscription('default', [
'price_monthly',
'price_chat',
])->create($request->paymentMethodId);
// ...
});
上記の例では、顧客はdefault
サブスクリプションに2つの価格が付いています。両方の価格は、それぞれの請求間隔で請求されます。必要に応じて、quantity
メソッドを使用して各価格の特定の数量を示すことができます:
$user = User::find(1);
$user->newSubscription('default', ['price_monthly', 'price_chat'])
->quantity(5, 'price_chat')
->create($paymentMethod);
既存のサブスクリプションに別の価格を追加したい場合は、サブスクリプションのaddPrice
メソッドを呼び出すことができます:
$user = User::find(1);
$user->subscription('default')->addPrice('price_chat');
上記の例では、新しい価格が追加され、顧客は次の請求サイクルで請求されます。顧客に即座に請求したい場合は、addPriceAndInvoice
メソッドを使用できます:
$user->subscription('default')->addPriceAndInvoice('price_chat');
特定の数量を持つ価格を追加したい場合は、addPrice
またはaddPriceAndInvoice
メソッドの第二引数として数量を渡すことができます:
$user = User::find(1);
$user->subscription('default')->addPrice('price_chat', 5);
``````php
$user->subscription('default')->removePrice('price_chat');
`
サブスクリプションの最後の価格を削除することはできません。代わりに、サブスクリプションをキャンセルする必要があります。
価格の交換
複数製品を持つサブスクリプションに添付された価格を変更することもできます。たとえば、顧客がprice_basic
サブスクリプションを持ち、price_chat
アドオン製品があり、price_basic
からprice_pro
価格にアップグレードしたいと想像してください:
use App\Models\User;
$user = User::find(1);
$user->subscription('default')->swap(['price_pro', 'price_chat']);
上記の例を実行すると、price_basic
を持つ基になるサブスクリプションアイテムが削除され、price_chat
を持つものが保持されます。さらに、price_pro
の新しいサブスクリプションアイテムが作成されます。
``````php
$user = User::find(1);
$user->subscription('default')->swap([
'price_pro' => ['quantity' => 5],
'price_chat'
]);
`
サブスクリプションの価格を1つ交換したい場合は、サブスクリプションアイテム自体のswap
メソッドを使用して行うことができます。このアプローチは、サブスクリプションの他の価格に関するすべての既存のメタデータを保持したい場合に特に便利です:
$user = User::find(1);
$user->subscription('default')
->findItemOrFail('price_basic')
->swap('price_pro');
按分
デフォルトでは、Stripeは複数製品を持つサブスクリプションから価格を追加または削除する際に料金を按分します。按分なしで価格調整を行いたい場合は、価格操作にnoProrate
メソッドをチェーンする必要があります:
$user->subscription('default')->noProrate()->removePrice('price_chat');
Laravel Cashier (Stripe)
- はじめに
- Cashierのアップグレード
- インストール
- 設定
- クイックスタート
- 顧客
- 支払い方法
- サブスクリプション
- サブスクリプショントライアル
- Stripe Webhookの処理
- 単一の請求
- チェックアウト
- 請求書
- 失敗した支払いの処理
- 強力な顧客認証 (SCA)
- Stripe SDK
- テスト
サブスクリプションアイテム
サブスクリプションに複数の価格がある場合、データベースのsubscription_items
テーブルに複数のサブスクリプション「アイテム」が保存されます。サブスクリプションのitems
リレーションシップを介してこれらにアクセスできます:
use App\Models\User;
$user = User::find(1);
$subscriptionItem = $user->subscription('default')->items->first();
// Retrieve the Stripe price and quantity for a specific item...
$stripePrice = $subscriptionItem->stripe_price;
$quantity = $subscriptionItem->quantity;
``````php
$user = User::find(1);
$subscriptionItem = $user->subscription('default')->findItemOrFail('price_chat');
`
複数のサブスクリプション
Stripeは顧客が同時に複数のサブスクリプションを持つことを許可します。たとえば、プールサブスクリプションとウエイトリフティングサブスクリプションを提供するジムを運営している場合、各サブスクリプションには異なる価格が設定される可能性があります。もちろん、顧客はどちらか一方または両方のプランにサブスクリプションできる必要があります。
アプリケーションがサブスクリプションを作成する際、newSubscription
メソッドにサブスクリプションのタイプを提供できます。タイプは、ユーザーが開始しているサブスクリプションのタイプを表す任意の文字列である可能性があります:
use Illuminate\Http\Request;
Route::post('/swimming/subscribe', function (Request $request) {
$request->user()->newSubscription('swimming')
->price('price_swimming_monthly')
->create($request->paymentMethodId);
// ...
});
この例では、顧客のために月額のプールサブスクリプションを開始しました。しかし、後で年額サブスクリプションにスワップしたい場合があります。顧客のサブスクリプションを調整する際、swimming
サブスクリプションの価格を単純にスワップできます:
$user->subscription('swimming')->swap('price_swimming_yearly');
もちろん、サブスクリプションを完全にキャンセルすることもできます:
$user->subscription('swimming')->cancel();
メーター請求
メーター請求を使用するには、まずStripeダッシュボードでメーター価格の新しい製品を作成する必要があります。その後、meteredPrice
を使用してメーター価格IDを顧客のサブスクリプションに追加します:
use Illuminate\Http\Request;
Route::post('/user/subscribe', function (Request $request) {
$request->user()->newSubscription('default')
->meteredPrice('price_metered')
->create($request->paymentMethodId);
// ...
});
https://stripe.com/docs/billing/subscriptions/metered-billingStripe Checkoutを介してメーターサブスクリプションを開始することもできます:
$checkout = Auth::user()
->newSubscription('default', [])
->meteredPrice('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);
時には、以前に報告した使用状況を更新する必要があるかもしれません。これを実現するには、reportUsage
に第二のパラメータとしてタイムスタンプまたはDateTimeInterface
インスタンスを渡すことができます。そうすることで、Stripeはその時点で報告された使用状況を更新します。指定された日付と時刻が現在の請求期間内である限り、以前の使用状況レコードを更新し続けることができます:
$user = User::find(1);
$user->subscription('default')->reportUsage(5, $timestamp);
使用状況レコードの取得
顧客の過去の使用状況を取得するには、サブスクリプションインスタンスのusageRecords
メソッドを使用できます:
$user = User::find(1);
$usageRecords = $user->subscription('default')->usageRecords();
アプリケーションが単一のサブスクリプションで複数の価格を提供している場合、usageRecordsFor
メソッドを使用して、使用状況レコードを取得したいメーター価格を指定できます:
$user = User::find(1);
$usageRecords = $user->subscription('default')->usageRecordsFor('price_metered');
``````php
@foreach ($usageRecords as $usageRecord)
- Period Starting: {{ $usageRecord['period']['start'] }}
- Period Ending: {{ $usageRecord['period']['end'] }}
- Total Usage: {{ $usageRecord['total_usage'] }}
@endforeach
`
返されるすべての使用データの完全なリファレンスと、Stripeのカーソルベースのページネーションの使用方法については、[https://stripe.com/docs/api/usage_records/subscription_item_summary_list公式Stripe APIドキュメント]を参照してください。
サブスクリプション税
税率を手動で計算する代わりに、[https://dashboard.stripe.com/test/tax-ratesStripe Taxを使用して自動的に税金を計算する]ことができます。
サブスクリプションに対してユーザーが支払う税率を指定するには、請求可能モデルでtaxRates
メソッドを実装し、Stripe税率IDを含む配列を返す必要があります。これらの税率は、[https://dashboard.stripe.com/test/tax-ratesStripeダッシュボード]で定義できます:
/**
* The tax rates that should apply to the customer's subscriptions.
*
* @return array<int, string>
*/
public function taxRates(): array
{
return ['txr_id'];
}
複数製品を持つサブスクリプションを提供している場合は、請求可能モデルで`````priceTaxRates`````メソッドを実装することで、各価格に異なる税率を定義できます:
``````php
/**
* The tax rates that should apply to the customer's subscriptions.
*
* @return array<string, array<int, string>>
*/
public function priceTaxRates(): array
{
return [
'price_monthly' => ['txr_id'],
];
}
`
<a name="syncing-tax-rates"></a>
#### 税率の同期
`````taxRates`````メソッドによって返されるハードコーディングされた税率IDを変更すると、ユーザーの既存のサブスクリプションの税設定はそのままになります。新しい`````taxRates`````値で既存のサブスクリプションの税値を更新したい場合は、ユーザーのサブスクリプションインスタンスで`````syncTaxRates`````メソッドを呼び出す必要があります:
``````php
$user->subscription('default')->syncTaxRates();
`
これにより、複数製品を持つサブスクリプションのアイテム税率も同期されます。アプリケーションが複数製品を持つサブスクリプションを提供している場合は、請求可能モデルが上記で説明したpriceTaxRates
メソッドを実装していることを確認してください。
税の免除
Cashierは、顧客が税免除であるかどうかを判断するためにisNotTaxExempt
、isTaxExempt
、およびreverseChargeApplies
メソッドも提供します。これらのメソッドは、顧客の税免除ステータスを判断するためにStripe APIを呼び出します:
use App\Models\User;
$user = User::find(1);
$user->isTaxExempt();
$user->isNotTaxExempt();
$user->reverseChargeApplies();
これらのメソッドは、任意の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_monthly')
->anchorBillingCycleOn($anchor->startOfDay())
->create($request->paymentMethodId);
// ...
});
サブスクリプションの請求サイクルを管理する方法についての詳細は、[https://stripe.com/docs/billing/subscriptions/billing-cycleStripe請求サイクルのドキュメント]を参照してください。
サブスクリプションのキャンセル
サブスクリプションをキャンセルするには、ユーザーのサブスクリプションでcancel
メソッドを呼び出します:
$user->subscription('default')->cancel();
サブスクリプションがキャンセルされると、Cashierは自動的にends_at
列をsubscriptions
データベーステーブルに設定します。この列は、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)
);
最後に、関連するユーザーモデルを削除する前に、常にユーザーのサブスクリプションをキャンセルする必要があります:
$user->subscription('default')->cancelNow();
$user->delete();
サブスクリプションの再開
顧客がサブスクリプションをキャンセルし、それを再開したい場合は、サブスクリプションで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で設定された価格のデフォルトのトライアル期間を上書きします。
顧客のサブスクリプションがトライアル終了日までにキャンセルされない場合、トライアルが終了するとすぐに請求されるため、ユーザーにトライアル終了日を通知することを確認してください。
``````php
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()) {
// ...
}
``````php
$user->subscription('default')->endTrial();
`
既存のトライアルが期限切れかどうかを判断するには、hasExpiredTrial
メソッドを使用できます:
if ($user->hasExpiredTrial('default')) {
// ...
}
if ($user->subscription('default')->hasExpiredTrial()) {
// ...
}
Stripe / Cashierでのトライアル日数の定義
価格のトライアル日数をStripeダッシュボードで定義するか、Cashierを使用して常に明示的に渡すことを選択できます。価格のトライアル日数をStripeで定義することを選択した場合、過去にサブスクリプションを持っていた顧客を含む新しいサブスクリプションは、skipTrial()
メソッドを明示的に呼び出さない限り、常にトライアル期間を受け取ります。
事前に支払い方法を提供しない場合
ユーザーの支払い方法情報を事前に収集せずにトライアル期間を提供したい場合は、ユーザーレコードのtrial_ends_at
列を希望するトライアル終了日に設定する必要があります。これは通常、ユーザー登録中に行われます:
use App\Models\User;
$user = User::create([
// ...
'trial_ends_at' => now()->addDays(10),
]);
Cashierは、このタイプのトライアルを「一般的なトライアル」と呼びます。これは、既存のサブスクリプションに関連付けられていないためです。請求可能モデルインスタンスの`````onTrial`````メソッドは、現在の日付が`````trial_ends_at`````の値を過ぎていない場合、`````true`````を返します:
``````php
if ($user->onTrial()) {
// User is within their trial period...
}
`
ユーザーのために実際のサブスクリプションを作成する準備ができたら、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()) {
// User is within their "generic" trial period...
}
トライアルの延長
``````php
use App\Models\User;
$subscription = User::find(1)->subscription('default');
// End the trial 7 days from now...
$subscription->extendTrial(
now()->addDays(7)
);
// Add an additional 5 days to the trial...
$subscription->extendTrial(
$subscription->trial_ends_at->addDays(5)
);
`
Stripe Webhookの処理
ローカル開発中にWebhookをテストするために、Stripe CLIを使用できます。
Stripeは、Webhookを介してさまざまなイベントをアプリケーションに通知できます。デフォルトでは、CashierのWebhookコントローラーを指すルートがCashierサービスプロバイダーによって自動的に登録されます。このコントローラーは、すべての受信Webhookリクエストを処理します。
デフォルトでは、CashierのWebhookコントローラーは、失敗した請求が多すぎるためにキャンセルされたサブスクリプション(あなたのStripe設定で定義された通り)、顧客の更新、顧客の削除、サブスクリプションの更新、支払い方法の変更を自動的に処理します。しかし、すぐにわかるように、このコントローラーを拡張して、任意のStripe Webhookイベントを処理することができます。
アプリケーションがStripe Webhookを処理できるようにするために、StripeコントロールパネルでWebhook URLを設定してください。デフォルトでは、CashierのWebhookコントローラーは/stripe/webhook
URLパスに応答します。Stripeコントロールパネルで有効にすべきすべてのWebhookの完全なリストは次のとおりです:
customer.subscription.created
customer.subscription.updated
customer.subscription.deleted
customer.updated
customer.deleted
payment_method.automatically_updated
invoice.payment_action_required
invoice.payment_succeeded
便利なことに、Cashierにはcashier:webhook
Artisanコマンドが含まれています。このコマンドは、Cashierが必要とするすべてのイベントをリッスンするWebhookをStripeに作成します:
php artisan cashier:webhook
デフォルトでは、作成されたWebhookはAPP_URL
環境変数で定義されたURLと、Cashierに含まれるcashier.webhook
ルートを指します。異なるURLを使用したい場合は、コマンドを呼び出すときに--url
オプションを提供できます:
php artisan cashier:webhook --url "https://example.com/stripe/webhook"
作成されたWebhookは、あなたのCashierのバージョンと互換性のあるStripe APIバージョンを使用します。異なるStripeバージョンを使用したい場合は、--api-version
オプションを提供できます:
php artisan cashier:webhook --api-version="2019-12-03"
作成後、Webhookはすぐにアクティブになります。Webhookを作成したいが、準備ができるまで無効にしておきたい場合は、コマンドを呼び出すときに--disabled
オプションを提供できます:
php artisan cashier:webhook --disabled
受信するStripe WebhookリクエストをCashierに含まれるWebhook署名検証ミドルウェアで保護してください。
WebhookとCSRF保護
Stripe WebhookはLaravelのCSRF保護をバイパスする必要があるため、Laravelが受信するStripe WebhookのCSRFトークンを検証しないようにする必要があります。これを実現するには、アプリケーションのbootstrap/app.php
ファイルでstripe/*
をCSRF保護から除外する必要があります:
->withMiddleware(function (Middleware $middleware) {
$middleware->validateCsrfTokens(except: [
'stripe/*',
]);
})
Webhookイベントハンドラーの定義
Cashierは、失敗した請求やその他の一般的なStripe Webhookイベントのためにサブスクリプションのキャンセルを自動的に処理します。しかし、処理したい追加のWebhookイベントがある場合は、Cashierによってディスパッチされる次のイベントをリッスンすることで実行できます:
Laravel\Cashier\Events\WebhookReceived
Laravel\Cashier\Events\WebhookHandled
両方のイベントには、Stripe Webhookの完全なペイロードが含まれています。たとえば、invoice.payment_succeeded
Webhookを処理したい場合は、イベントを処理するリスナーを登録できます:
<?php
namespace App\Listeners;
use Laravel\Cashier\Events\WebhookReceived;
class StripeEventListener
{
/**
* Handle received Stripe webhooks.
*/
public function handle(WebhookReceived $event): void
{
if ($event->payload['type'] === 'invoice.payment_succeeded') {
// Handle the incoming event...
}
}
}
Webhook署名の検証
Webhookを保護するために、StripeのWebhook署名を使用できます。便利なことに、Cashierは受信したStripe Webhookリクエストが有効であることを検証するミドルウェアを自動的に含めています。
Webhook検証を有効にするには、アプリケーションの.env
ファイルでSTRIPE_WEBHOOK_SECRET
環境変数が設定されていることを確認してください。Webhooksecret
は、Stripeアカウントのダッシュボードから取得できます。
単一の請求
シンプルな請求
顧客に対して一度限りの請求を行いたい場合は、請求可能なモデルインスタンスのcharge
メソッドを使用できます。charge
メソッドの第2引数として支払い方法識別子を提供する必要があります:
use Illuminate\Http\Request;
Route::post('/purchase', function (Request $request) {
$stripeCharge = $request->user()->charge(
100, $request->paymentMethodId
);
// ...
});
``````php
$user->charge(100, $paymentMethod, [
'custom_option' => $value,
]);
`
``````php
use App\Models\User;
$stripeCharge = (new User)->charge(100, $paymentMethod);
`
``````php
try {
$payment = $user->charge(100, $paymentMethod);
} catch (Exception $e) {
// ...
}
`
<a name="charge-with-invoice"></a>
### 請求書による請求
時には、一度限りの請求を行い、顧客にPDF請求書を提供する必要があります。`````invoicePrice`````メソッドを使用すると、これを実現できます。たとえば、5枚の新しいシャツの請求書を顧客に発行しましょう:
``````php
$user->invoicePrice('price_tshirt', 5);
`
請求書は、ユーザーのデフォルトの支払い方法に対して即座に請求されます。invoicePrice
メソッドも第三引数として配列を受け入れます。この配列には、請求項目の請求オプションが含まれています。メソッドが受け入れる第4引数も配列で、請求書自体の請求オプションを含む必要があります:
$user->invoicePrice('price_tshirt', 5, [
'discounts' => [
['coupon' => 'SUMMER21SALE']
],
], [
'default_tax_rates' => ['txr_id'],
]);
``````php
$user->tabPrice('price_tshirt', 5);
$user->tabPrice('price_mug', 2);
$user->invoice();
`
または、invoiceFor
メソッドを使用して、顧客のデフォルトの支払い方法に対して「一度限り」の請求を行うこともできます:
$user->invoiceFor('One Time Fee', 500);
`````invoice`````、`````invoicePrice`````、および`````invoiceFor`````メソッドは、失敗した請求の試行を再試行するStripe請求書を作成します。失敗した請求を再試行したくない場合は、最初の失敗した請求の後にStripe APIを使用してそれらを閉じる必要があります。
<a name="creating-payment-intents"></a>
### 支払い意図の作成
請求可能なモデルインスタンスの`````pay`````メソッドを呼び出すことで、新しいStripe支払い意図を作成できます。このメソッドを呼び出すと、`````Laravel\Cashier\Payment`````インスタンスでラップされた支払い意図が作成されます:
``````php
use Illuminate\Http\Request;
Route::post('/pay', function (Request $request) {
$payment = $request->user()->pay(
$request->get('amount')
);
return $payment->client_secret;
});
`
支払い意図を作成した後、クライアントシークレットをアプリケーションのフロントエンドに返して、ユーザーがブラウザで支払いを完了できるようにします。Stripe支払い意図を使用して完全な支払いフローを構築する方法については、Stripeのドキュメントを参照してください。
``````php
use Illuminate\Http\Request;
Route::post('/pay', function (Request $request) {
$payment = $request->user()->payWith(
$request->get('amount'), ['card', 'bancontact']
);
return $payment->client_secret;
});
`
<a name="refunding-charges"></a>
### 請求の返金
Stripeの請求を返金する必要がある場合は、`````refund`````メソッドを使用できます。このメソッドは、最初の引数としてStripeの[支払い意図ID](#payment-methods-for-single-charges)を受け入れます:
``````php
$payment = $user->charge(100, $paymentMethodId);
$user->refund($payment->id);
`
請求書
請求書の取得
請求可能なモデルの請求書の配列を簡単に取得するには、invoices
メソッドを使用します。invoices
メソッドは、Laravel\Cashier\Invoice
インスタンスのコレクションを返します:
$invoices = $user->invoices();
保留中の請求書を結果に含めたい場合は、invoicesIncludingPending
メソッドを使用できます:
$invoices = $user->invoicesIncludingPending();
特定の請求書をIDで取得するには、findInvoice
メソッドを使用できます:
$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>
今後の請求書
顧客の今後の請求書を取得するには、upcomingInvoice
メソッドを使用します:
$invoice = $user->upcomingInvoice();
同様に、顧客が複数のサブスクリプションを持っている場合、特定のサブスクリプションの今後の請求書を取得することもできます:
$invoice = $user->subscription('default')->upcomingInvoice();
サブスクリプション請求書のプレビュー
``````php
$invoice = $user->subscription('default')->previewInvoice('price_yearly');
`
``````php
$invoice = $user->subscription('default')->previewInvoice(['price_yearly', 'price_metered']);
`
請求書PDFの生成
請求書PDFを生成する前に、Composerを使用してDompdfライブラリをインストールする必要があります。これはCashierのデフォルトの請求書レンダラーです:
composer require dompdf/dompdf
ルートまたはコントローラー内から、downloadInvoice
メソッドを使用して特定の請求書のPDFダウンロードを生成できます。このメソッドは、請求書をダウンロードするために必要な適切なHTTPレスポンスを自動的に生成します:
use Illuminate\Http\Request;
Route::get('/user/invoice/{invoice}', function (Request $request, string $invoiceId) {
return $request->user()->downloadInvoice($invoiceId);
});
デフォルトでは、請求書のすべてのデータはStripeに保存されている顧客および請求書データから派生します。ファイル名はapp.name
設定値に基づいています。ただし、downloadInvoice
メソッドの第2引数として配列を提供することで、一部のデータをカスタマイズできます。この配列を使用して、会社や製品の詳細などの情報をカスタマイズできます:
return $request->user()->downloadInvoice($invoiceId, [
'vendor' => 'Your Company',
'product' => 'Your Product',
'street' => 'Main Str. 1',
'location' => '2000 Antwerp, Belgium',
'phone' => '+32 499 00 00 00',
'email' => '',
'url' => 'https://example.com',
'vendorVat' => 'BE123456789',
]);
``````php
return $request->user()->downloadInvoice($invoiceId, [], 'my-invoice');
`
カスタム請求書レンダラー
Cashierは、カスタム請求書レンダラーを使用することも可能にします。デフォルトでは、CashierはDompdfInvoiceRenderer
実装を使用しており、これはdompdf PHPライブラリを使用してCashierの請求書を生成します。ただし、Laravel\Cashier\Contracts\InvoiceRenderer
インターフェースを実装することで、任意のレンダラーを使用できます。たとえば、サードパーティのPDFレンダリングサービスへのAPI呼び出しを使用して請求書PDFをレンダリングすることができます:
use Illuminate\Support\Facades\Http;
use Laravel\Cashier\Contracts\InvoiceRenderer;
use Laravel\Cashier\Invoice;
class ApiInvoiceRenderer implements InvoiceRenderer
{
/**
* Render the given invoice and return the raw PDF bytes.
*/
public function render(Invoice $invoice, array $data = [], array $options = []): string
{
$html = $invoice->view($data)->render();
return Http::get('https://example.com/html-to-pdf', ['html' => $html])->get()->body();
}
}
請求書レンダラー契約を実装したら、アプリケーションのconfig/cashier.php
設定ファイルでcashier.invoices.renderer
設定値を更新する必要があります。この設定値は、カスタムレンダラー実装のクラス名に設定する必要があります。
チェックアウト
Cashier Stripeは、Stripe Checkoutのサポートも提供します。Stripe Checkoutは、支払いを受け入れるためのカスタムページを実装する手間を省き、事前に構築されたホストされた支払いページを提供します。
以下のドキュメントには、Cashierを使用してStripe Checkoutを開始する方法に関する情報が含まれています。Stripe Checkoutについて詳しく知りたい場合は、StripeのCheckoutに関するドキュメントも確認してください。
製品チェックアウト
Stripeダッシュボードで作成された既存の製品のチェックアウトを、請求可能なモデルのcheckout
メソッドを使用して実行できます。checkout
メソッドは、新しいStripe Checkoutセッションを開始します。デフォルトでは、Stripe Price IDを渡す必要があります:
use Illuminate\Http\Request;
Route::get('/product-checkout', function (Request $request) {
return $request->user()->checkout('price_tshirt');
});
必要に応じて、製品の数量を指定することもできます:
use Illuminate\Http\Request;
Route::get('/product-checkout', function (Request $request) {
return $request->user()->checkout(['price_tshirt' => 15]);
});
顧客がこのルートにアクセスすると、StripeのCheckoutページにリダイレクトされます。デフォルトでは、ユーザーが購入を成功裏に完了またはキャンセルすると、home
ルートの場所にリダイレクトされますが、success_url
およびcancel_url
オプションを使用してカスタムコールバックURLを指定できます:
use Illuminate\Http\Request;
Route::get('/product-checkout', function (Request $request) {
return $request->user()->checkout(['price_tshirt' => 1], [
'success_url' => route('your-success-route'),
'cancel_url' => route('your-cancel-route'),
]);
});
``````php
use Illuminate\Http\Request;
use Stripe\Checkout\Session;
use Stripe\Customer;
Route::get('/product-checkout', function (Request $request) {
return $request->user()->checkout(['price_tshirt' => 1], [
'success_url' => route('checkout-success').'?session_id={CHECKOUT_SESSION_ID}',
'cancel_url' => route('checkout-cancel'),
]);
});
Route::get('/checkout-success', function (Request $request) {
$checkoutSession = $request->user()->stripe()->checkout->sessions->retrieve($request->get('session_id'));
return view('checkout.success', ['checkoutSession' => $checkoutSession]);
})->name('checkout-success');
`
プロモーションコード
デフォルトでは、Stripe Checkoutはユーザーが引き換え可能なプロモーションコードを許可していません。幸いなことに、これをCheckoutページで有効にする簡単な方法があります。これを実現するには、allowPromotionCodes
メソッドを呼び出します:
use Illuminate\Http\Request;
Route::get('/product-checkout', function (Request $request) {
return $request->user()
->allowPromotionCodes()
->checkout('price_tshirt');
});
単一の請求チェックアウト
Stripeダッシュボードで作成されていないアドホック製品に対しても、単純な請求を行うことができます。これを実現するには、請求可能なモデルのcheckoutCharge
メソッドを使用し、請求可能な金額、製品名、およびオプションの数量を渡します。顧客がこのルートにアクセスすると、StripeのCheckoutページにリダイレクトされます:
use Illuminate\Http\Request;
Route::get('/charge-checkout', function (Request $request) {
return $request->user()->checkoutCharge(1200, 'T-Shirt', 5);
});
<a name="subscription-checkouts"></a>
### サブスクリプションチェックアウト
サブスクリプションにStripe Checkoutを使用するには、Stripeダッシュボードで`````customer.subscription.created````` Webhookを有効にする必要があります。このWebhookは、データベースにサブスクリプションレコードを作成し、すべての関連するサブスクリプションアイテムを保存します。
また、Stripe Checkoutを使用してサブスクリプションを開始することもできます。Cashierのサブスクリプションビルダーのメソッドでサブスクリプションを定義した後、`````checkout `````メソッドを呼び出すことができます。顧客がこのルートにアクセスすると、StripeのCheckoutページにリダイレクトされます:
``````php
use Illuminate\Http\Request;
Route::get('/subscription-checkout', function (Request $request) {
return $request->user()
->newSubscription('default', 'price_monthly')
->checkout();
});
`
製品チェックアウトと同様に、成功およびキャンセルのURLをカスタマイズできます:
use Illuminate\Http\Request;
Route::get('/subscription-checkout', function (Request $request) {
return $request->user()
->newSubscription('default', 'price_monthly')
->checkout([
'success_url' => route('your-success-route'),
'cancel_url' => route('your-cancel-route'),
]);
});
もちろん、サブスクリプションチェックアウトのためにプロモーションコードを有効にすることもできます:
use Illuminate\Http\Request;
Route::get('/subscription-checkout', function (Request $request) {
return $request->user()
->newSubscription('default', 'price_monthly')
->allowPromotionCodes()
->checkout();
});
残念ながら、Stripe Checkoutはサブスクリプションを開始する際にすべての請求オプションをサポートしていません。サブスクリプションビルダーのanchorBillingCycleOn
メソッドを使用して、比例配分の動作を設定したり、支払いの動作を設定したりしても、Stripe Checkoutセッション中には効果がありません。どのパラメータが利用可能かを確認するには、Stripe CheckoutセッションAPIドキュメントを参照してください。
Stripe Checkoutとトライアル期間
もちろん、Stripe Checkoutを使用して完了するサブスクリプションを構築する際にトライアル期間を定義できます:
$checkout = Auth::user()->newSubscription('default', 'price_monthly')
->trialDays(3)
->checkout();
ただし、トライアル期間は少なくとも48時間でなければならず、これはStripe Checkoutがサポートする最小のトライアル時間です。
サブスクリプションとWebhook
StripeとCashierはWebhookを介してサブスクリプションのステータスを更新するため、顧客が支払い情報を入力した後にアプリケーションに戻ったときにサブスクリプションがまだアクティブでない可能性があります。このシナリオを処理するために、ユーザーに支払いまたはサブスクリプションが保留中であることを通知するメッセージを表示することをお勧めします。
税IDの収集
Checkoutは、顧客の税IDを収集することもサポートしています。チェックアウトセッションを作成する際に、collectTaxIds
メソッドを呼び出してこれを有効にします:
$checkout = $user->collectTaxIds()->checkout('price_tshirt');
このメソッドが呼び出されると、顧客が会社として購入しているかどうかを示すチェックボックスが新たに利用可能になります。そうであれば、税ID番号を提供する機会が与えられます。
すでにアプリケーションのサービスプロバイダーで自動税収集を設定している場合、この機能は自動的に有効になり、collectTaxIds
メソッドを呼び出す必要はありません。
ゲストチェックアウト
``````php
use Illuminate\Http\Request;
use Laravel\Cashier\Checkout;
Route::get('/product-checkout', function (Request $request) {
return Checkout::guest()->create('price_tshirt', [
'success_url' => route('your-success-route'),
'cancel_url' => route('your-cancel-route'),
]);
});
`
既存のユーザーのためにチェックアウトセッションを作成する場合と同様に、Laravel\Cashier\CheckoutBuilder
インスタンスで利用可能な追加のメソッドを使用してゲストチェックアウトセッションをカスタマイズできます:
use Illuminate\Http\Request;
use Laravel\Cashier\Checkout;
Route::get('/product-checkout', function (Request $request) {
return Checkout::guest()
->withPromotionCode('promo-code')
->create('price_tshirt', [
'success_url' => route('your-success-route'),
'cancel_url' => route('your-cancel-route'),
]);
});
ゲストチェックアウトが完了すると、Stripeはcheckout.session.completed
Webhookイベントを送信できます。したがって、実際にこのイベントをアプリケーションに送信するためにStripe Webhookを設定することを確認してください。WebhookがStripeダッシュボード内で有効になったら、CashierでWebhookを処理できます。Webhookペイロードに含まれるオブジェクトは、顧客の注文を履行するために調査できるcheckout
オブジェクトです。
失敗した支払いの処理
時には、サブスクリプションや単一の請求の支払いが失敗することがあります。この場合、CashierはLaravel\Cashier\Exceptions\IncompletePayment
例外をスローし、これが発生したことを通知します。この例外をキャッチした後、進める方法は2つあります。
まず、Cashierに含まれる専用の支払い確認ページに顧客をリダイレクトすることができます。このページには、Cashierのサービスプロバイダーを介して登録された関連する名前付きルートがあります。したがって、IncompletePayment
例外をキャッチして、ユーザーを支払い確認ページにリダイレクトできます:
use Laravel\Cashier\Exceptions\IncompletePayment;
try {
$subscription = $user->newSubscription('default', 'price_monthly')
->create($paymentMethod);
} catch (IncompletePayment $exception) {
return redirect()->route(
'cashier.payment',
[$exception->payment->id, 'redirect' => route('home')]
);
}
支払い確認ページでは、顧客は再度クレジットカード情報を入力し、Stripeによって要求される追加のアクション(「3Dセキュア」確認など)を実行するように促されます。支払いを確認した後、ユーザーは上記のredirect
パラメータで指定されたURLにリダイレクトされます。リダイレクト時に、message
(文字列)およびsuccess
(整数)クエリ文字列変数がURLに追加されます。支払いページは、次の支払い方法タイプをサポートしています:
- クレジットカード
- Alipay
- Bancontact
- BECSダイレクトデビット
- EPS
- Giropay
- iDEAL
- SEPAダイレクトデビット
または、Stripeに支払い確認を処理させることもできます。この場合、支払い確認ページにリダイレクトするのではなく、StripeダッシュボードでStripeの自動請求メールを設定できます。ただし、IncompletePayment
例外がキャッチされた場合は、ユーザーにさらなる支払い確認手順が記載されたメールが届くことを通知する必要があります。
支払い例外は、charge
、invoiceFor
、invoice
メソッドに対してスローされる可能性があります。Billable
トレイトを使用しているモデルでサブスクリプションとやり取りする場合、create
メソッドはSubscriptionBuilder
、incrementAndInvoice
およびswapAndInvoice
メソッドはSubscription
およびSubscriptionItem
モデルで不完全な支払い例外をスローする可能性があります。
既存のサブスクリプションに不完全な支払いがあるかどうかを判断するには、請求可能なモデルまたはサブスクリプションインスタンスでhasIncompletePayment
メソッドを使用できます:
if ($user->hasIncompletePayment('default')) {
// ...
}
if ($user->subscription('default')->hasIncompletePayment()) {
// ...
}
例外インスタンスのpayment
プロパティを調査することで、不完全な支払いの具体的なステータスを導き出すことができます:
use Laravel\Cashier\Exceptions\IncompletePayment;
try {
$user->charge(1000, 'pm_card_threeDSecure2Required');
} catch (IncompletePayment $exception) {
// Get the payment intent status...
$exception->payment->status;
// Check specific conditions...
if ($exception->payment->requiresPaymentMethod()) {
// ...
} elseif ($exception->payment->requiresConfirmation()) {
// ...
}
}
支払いの確認
一部の支払い方法では、支払いを確認するために追加のデータが必要です。たとえば、SEPA支払い方法では、支払いプロセス中に追加の「委任」データが必要です。このデータをwithPaymentConfirmationOptions
メソッドを使用してCashierに提供できます:
$subscription->withPaymentConfirmationOptions([
'mandate_data' => '...',
])->swap('price_xxx');
支払いを確認する際に受け入れられるすべてのオプションを確認するには、Stripe APIドキュメントを参照してください。
強力な顧客認証
ビジネスまたは顧客のいずれかがヨーロッパに拠点を置いている場合、EUの強力な顧客認証(SCA)規制に従う必要があります。これらの規制は、支払い詐欺を防ぐために2019年9月に欧州連合によって導入されました。幸いなことに、StripeとCashierはSCA準拠のアプリケーションを構築する準備が整っています。
始める前に、StripeのPSD2およびSCAに関するガイドおよび新しいSCA APIに関するドキュメントを確認してください。
追加確認が必要な支払い
SCA規制では、支払いを確認して処理するために追加の検証が必要な場合があります。この場合、CashierはLaravel\Cashier\Exceptions\IncompletePayment
例外をスローし、追加の検証が必要であることを通知します。これらの例外を処理する方法に関する詳細は、失敗した支払いの処理に関するドキュメントで確認できます。
StripeまたはCashierによって提示される支払い確認画面は、特定の銀行またはカード発行者の支払いフローに合わせて調整され、追加のカード確認、一時的な小額請求、別のデバイス認証、またはその他の検証方法を含むことがあります。
不完全および過去の状態
支払いに追加の確認が必要な場合、サブスクリプションはincomplete
またはpast_due
状態のままとなり、stripe_status
データベース列によって示されます。Cashierは、支払い確認が完了し、StripeがWebhookを介して完了を通知すると、顧客のサブスクリプションを自動的にアクティブにします。
<a name="off-session-payment-notifications"></a>
### オフセッション支払い通知
SCA規制により、顧客はサブスクリプションがアクティブである間でも、時折支払い詳細を確認する必要があります。Cashierは、オフセッションの支払い確認が必要な場合に顧客に通知を送信できます。たとえば、サブスクリプションが更新されるときにこれが発生する可能性があります。Cashierの支払い通知は、`````CASHIER_PAYMENT_NOTIFICATION`````環境変数を通知クラスに設定することで有効にできます。デフォルトでは、この通知は無効になっています。もちろん、Cashierにはこの目的のために使用できる通知クラスが含まれていますが、必要に応じて独自の通知クラスを提供することもできます:
``````ini
CASHIER_PAYMENT_NOTIFICATION=Laravel\Cashier\Notifications\ConfirmPayment
`
オフセッションの支払い確認通知が配信されることを確認するには、アプリケーションのためにStripe Webhookが設定されていることを確認し、invoice.payment_action_required
WebhookがStripeダッシュボードで有効になっていることを確認してください。さらに、Billable
モデルもLaravelのIlluminate\Notifications\Notifiable
トレイトを使用する必要があります。
顧客が追加の確認が必要な支払いを手動で行っている場合でも、通知は送信されます。残念ながら、Stripeは支払いが手動で行われたか「オフセッション」であるかを知る方法はありません。しかし、顧客は支払いを確認した後に支払いページにアクセスすると、「支払い成功」のメッセージが表示されます。顧客は、同じ支払いを誤って二重に確認して二重請求を受けることは許可されません。
Stripe SDK
Cashierの多くのオブジェクトは、Stripe SDKオブジェクトのラッパーです。Stripeオブジェクトと直接やり取りしたい場合は、asStripe
メソッドを使用して便利に取得できます:
$stripeSubscription = $subscription->asStripeSubscription();
$stripeSubscription->application_fee_percent = 5;
$stripeSubscription->save();
``````php
$subscription->updateStripeSubscription(['application_fee_percent' => 5]);
`
``````php
use Laravel\Cashier\Cashier;
$prices = Cashier::stripe()->prices->all();
`
テスト
Cashierを使用するアプリケーションをテストする際、Stripe APIへの実際のHTTPリクエストをモックすることができます。ただし、これにはCashierの動作を部分的に再実装する必要があります。したがって、テストが実際のStripe APIにヒットすることをお勧めします。これは遅くなりますが、アプリケーションが期待通りに動作していることに対する信頼性が高まり、遅いテストは独自のPest / PHPUnitテストグループに配置できます。
テスト中は、Cashier自体がすでに優れたテストスイートを持っていることを忘れないでください。したがって、サブスクリプションと支払いフローのテストにのみ焦点を当て、すべての基盤となるCashierの動作をテストする必要はありません。
始めるには、Stripeシークレットのテストバージョンをphpunit.xml
ファイルに追加します:
<env name="STRIPE_SECRET" value="sk_test_<your-key>"/>
これで、テスト中にCashierとやり取りするたびに、実際のAPIリクエストがStripeテスト環境に送信されます。便利なことに、テスト中に使用できるサブスクリプション/価格でStripeテストアカウントを事前に埋めておくべきです。
クレジットカードの拒否や失敗など、さまざまな請求シナリオをテストするために、Stripeが提供するテストカード番号とトークンの広範な範囲を使用できます。