Lang x Lang

Laravel Cashier (Paddle)

Table of Contents

Introduction

WARNING

このドキュメンテーションは、 Cashier Paddle 2.x が Paddle Billing と統合するためのものです。まだ Paddle Classic を使用している場合は、Cashier Paddle 1.x を使用する必要があります。

Laravel Cashier Paddle は、Paddle's subscription 課金 services に対して、表現豊かで流暢なインターフェースを提供します。ほとんどの既製の subscription 課金 code を処理します。基本的な subscription 管理に加えて、 Cashier は handle : subscriptions の切り替え、 subscription の"quantities"、 subscription の一時停止、キャンセル猶予期間、などを行うことができます。

まず、 Cashier Paddle を掘り下げる前に、Paddle の概念ガイド API ドキュメンテーション もレビューすることをお勧めします。

Upgrading Cashier

Cashier の新しいバージョンにアップグレードする際には、アップグレードガイド を慎重に確認することが重要です。

Installation

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

composer require laravel/cashier-paddle

次に、vendor:publish の Artisan command を使用して、 Cashier の移行ファイルを publish する必要があります。

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

次に、アプリケーションの database migrations を実行する必要があります。 Cashier migrations により、新しいcustomersテーブルが作成されます。さらに、お客様の subscriptions をすべて保存するための新しいsubscriptionsおよびsubscription_itemsテーブルが作成されます。最後に、お客様と関連付けられた Paddle の transactions をすべて保存するための新しいtransactionsテーブルが作成されます。

php artisan migrate

WARNING

Cashier が全ての Paddle events を適切に処理するためには、Cashier の webhook ハンドリングを設定することを忘れないでください。

パドル・サンドボックス

ローカルおよびステージングの開発中は、Paddle の Sandbox アカウントをregister する必要があります。このアカウントは、実際の支払いを行うことなくアプリケーションをテストおよび開発するためのサンドボックス化された environment を提供します。さまざまな支払いシナリオをシミュレートするために、Paddle のtest card numbers を使用できます。

Paddle Sandbox の environment を使用する際には、アプリケーションの.envファイル内でPADDLE_SANDBOX environment 変数をtrueに設定する必要があります:

PADDLE_SANDBOX=true

あなたが application の開発を終えたら、Paddle vendor アカウントを申請 することができます。あなたの application が production に配置される前に、Paddle はあなたのアプリケーションの domain を承認する必要があります。

Configuration

Billable Model

Cashier を使用する前に、Billable トレイトを user model の定義に追加する必要があります。このトレイトは、 subscriptions の作成や決済 method 情報の更新など、一般的な課金タスクを実行するための様々なメソッドを提供します。

use Laravel\Paddle\Billable;

class User extends Authenticatable
{
    use Billable;
}

もし、 users でない billable というエンティティがある場合、それらのクラスにもトレイトを追加することができます:

use Illuminate\Database\Eloquent\Model;
use Laravel\Paddle\Billable;

class Team extends Model
{
    use Billable;
}

API Keys

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

PADDLE_CLIENT_SIDE_TOKEN=your-paddle-client-side-token
PADDLE_API_KEY=your-paddle-api-key
PADDLE_RETAIN_KEY=your-paddle-retain-key
PADDLE_WEBHOOK_SECRET="your-paddle-webhook-secret"
PADDLE_SANDBOX=true

PADDLE_SANDBOX 環境 variable は、Paddle のサンドボックス環境を使用している場合にはtrueに設定する必要があります。PADDLE_SANDBOXvariable は、あなたの application を production にデプロイし、Paddle のライブベンダー環境を使用している場合にはfalseに設定する必要があります。

PADDLE_RETAIN_KEYは任意であり、Paddle をRetain と一緒に使用している場合のみ設定する必要があります。

Paddle JS

Paddle は、Paddle の checkout ウィジェットを開始するために独自の JavaScript library に依存しています。 JavaScript library は、あなたの application レイアウトの閉じタグ </head> の直前に @paddleJS Blade ディレクティブを配置することでロードできます。

<head>
    ...

    @paddleJS
</head>

Currency Configuration

請求書の表示用に金額の values をフォーマットする際に、使用する locale を指定することができます。内部的には、 Cashier は通貨の locale を設定するためにPHP の NumberFormatter class を使用しています。

CASHIER_CURRENCY_LOCALE=nl_BE

WARNING

en以外のロケールを使用するためには、サーバー上にext-intl PHP 拡張がインストールされ、設定されていることを確認してください。

Default Models のオーバーライド

あなたは自分の model を定義し、対応する Cashier model を拡張することで、 Cashier が内部的に使用する models を自由に拡張することができます。

use Laravel\Paddle\Subscription as CashierSubscription;

class Subscription extends CashierSubscription
{
    // ...
}

あなたの model を定義した後、あなたは Cashier にあなたの custom model を使うように指示することができます。これは、Laravel\Paddle\Cashier class を通じて行います。通常、アプリケーションのApp\Providers\AppServiceProvider class のboot method で、あなたの custom models について Cashier に知らせるべきです。

use App\Models\Cashier\Subscription;
use App\Models\Cashier\Transaction;

/**
 * Bootstrap any application services.
 */
public function boot(): void
{
    Cashier::useSubscriptionModel(Subscription::class);
    Cashier::useTransactionModel(Transaction::class);
}

Quickstart

Selling Products

NOTE

Paddle の Checkout を利用する前に、Paddle ダッシュボードで固定価格の製品を定義する必要があります。また、Paddle の webhook 処理を設定するべきです。

あなたの application を通じて商品と subscription の請求を提供することはたくさんの気後れを伴います。しかし、Cashier と、Paddle の CheckoutOverlay のおかげで、現代的で頑丈な支払い統合を簡単に作成することができます。

非反復的な、一度だけの請求商品に対して顧客から料金を請求するために、私たちは Cashier を利用して、Paddle の Checkout オーバーレイで顧客に請求します。そこで彼らは支払い詳細を提供し、購入を確認します。支払いが Checkout オーバーレイを介して行われた後、顧客は、お客様が選択した成功の URL にあなたの application 内でリダイレクトされます:

use Illuminate\Http\Request;

Route::get('/buy', function (Request $request) {
    $checkout = $request->user()->checkout('pri_deluxe_album')
        ->returnTo(route('dashboard'));

    return view('buy', ['checkout' => $checkout]);
})->name('checkout');

上記の例で見ることができるように、私たちは Cashier が提供する checkout method を利用して、指定された"price identifier"に対する Paddle checkout object Overlay を顧客に提示するための Checkout オブジェクト を作成します。Paddle を使用する場合、"prices"は特定の商品のために定義された価格 を指します。

必要に応じて、checkout method は自動的に Paddle で顧客を作成し、その Paddle 顧客記録をアプリケーションの database 内の対応する user に関連付けます。 checkout session を完了すると、顧客は専用の成功ページにリダイレクトされ、そこで顧客に対する情報メッセージを表示することができます。

buy view には、 Checkout オーバーレイを表示する button を含めます。 paddle-button Blade component は Cashier Paddle に含まれていますが、手動で render オーバーレイ checkout:も可能です。

<x-paddle-button :checkout="$checkout" class="px-8 py-4">
  Buy Product
</x-paddle-button>

Paddle Checkout に Meta Data を提供する

商品を販売する際、自身が定義した application 内のCartおよびOrderの models を利用して、完了した注文や購入された商品を追跡するのが一般的です。購入を完了するために顧客を Paddle の Checkout オーバーレイに redirect する際には、完了した購入を対応する注文と関連付けるために、既存の注文識別子を提供する必要があるかもしれません。その後、顧客があなたのアプリケーションに redirect されます。

これを達成するために、checkoutの method に custom data の array を提供することができます。 私たちの application 内で、 user が checkout process を開始するときに保留中のOrderが作られると想像してみましょう。 この例のCartOrderの models は、単なる説明用であり、 Cashier によって提供されていないことを覚えておいてください。 これらの概念をあなた自身の application のニーズに基づいて実装することは自由です。

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',
    ]);

    $checkout = $request->user()->checkout($order->price_ids)
        ->customData(['order_id' => $order->id]);

    return view('billing', ['checkout' => $checkout]);
})->name('checkout');

上記の例で見ることができるように、 user が checkout process を開始すると、私たちはカート/注文に関連するすべての Paddle price 識別子をcheckout method に提供します。もちろん、これらのアイテムを shopping cart または顧客が追加する注文に関連付けるのは、あなたの application の責任です。また、注文の ID を Paddle Checkout オーバーレイにcustomData method 経由で提供します。

もちろん、顧客が checkout process を完了したら、注文を"完了"とマークしたくなるでしょう。これを達成するために、Paddle によって発行され、 Cashier によって events として引き上げられる webhooks を聞くかもしれません。これにより、注文情報を database に保存することができます。

始めるには、TransactionCompleted event を Cashier が発行するのをリッスンします。通常、application のAppServiceProviderboot method で event listener を register するべきです:

use App\Listeners\CompleteOrder;
use Illuminate\Support\Facades\Event;
use Laravel\Paddle\Events\TransactionCompleted;

/**
 * Bootstrap any application services.
 */
public function boot(): void
{
    Event::listen(TransactionCompleted::class, CompleteOrder::class);
}

この例では、CompleteOrderリスナーは次のようになるかもしれません:

namespace App\Listeners;

use App\Models\Order;
use Laravel\Cashier\Cashier;
use Laravel\Cashier\Events\TransactionCompleted;

class CompleteOrder
{
    /**
     * Handle the incoming Cashier webhook event.
     */
    public function handle(TransactionCompleted $event): void
    {
        $orderId = $event->payload['data']['custom_data']['order_id'] ?? null;

        $order = Order::findOrFail($orderId);

        $order->update(['status' => 'completed']);
    }
}

詳細な情報については、Paddle のドキュメンテーションを参照してください。transaction.completed event に含まれる data についてです。

Selling Subscriptions

NOTE

Paddle の Checkout を利用する前に、Paddle のダッシュボードで固定価格の製品を定義する必要があります。さらに、Paddle の webhook ハンドリングを設定するべきです。

あなたの application を通じて商品や subscription 課金を提供することは、ちょっと怖いかもしれません。しかし、 Cashier とPaddle の Checkout オーバーレイ のおかげで、簡単に現代的で強固な支払い統合を build することができます。

Cashier と Paddle の Checkout オーバーレイを使用して subscriptions を販売する方法を学ぶために、基本的な月間(price_basic_monthly)プランと年間(price_basic_yearly)プランを提供する subscription service のシンプルなシナリオを考えてみましょう。これら 2 つの価格は、Paddle ダッシュボードの"Basic"商品(pro_basic)の下にグループ化することができます。さらに、私たちの subscription service は、Expert プランもpro_expertとして提供するかもしれません。

まず、お客様が我々の services に subscribe する方法を見つけてみましょう。もちろん、お客様が application の料金ページで Basic プランの subscribe button をクリックする可能性があることを想像することができます。この button は、選択したプランのための Paddle Checkout オーバーレイを呼び出します。始めるためには、 checkout method により checkout session を開始しましょう:

use Illuminate\Http\Request;

Route::get('/subscribe', function (Request $request) {
    $checkout = $request->user()->checkout('price_basic_monthly')
        ->returnTo(route('dashboard'));

    return view('subscribe', ['checkout' => $checkout]);
})->name('subscribe');

subscribeview には、checkout オーバーレイを表示するための button を含めます。paddle-buttonBladecomponent は Cashier Paddle に含まれていますが、手動で rendering のオーバーレイ checkoutも可能です。

<x-paddle-button :checkout="$checkout" class="px-8 py-4">
  Subscribe
</x-paddle-button>

これで、 Subscribe button がクリックされたとき、顧客は自分の支払い詳細を入力し、 subscription を開始できます。彼らの subscription が実際にいつ開始されたか(一部の支払い方法では process に数秒かかることがあるため)を知るためには、Cashier の webhook 処理を設定するべきです。

お客様が subscriptions を開始できるようになったため、 subscribed users だけがアクセスできるように、 application の一部を制限する必要があります。もちろん、Cashier の Billable trait が提供する method subscribed を使って、ユーザーの現在の subscription status を常に確認することができます:

@if ($user->subscribed())
    <p>You are subscribed.</p>
@endif

特定の製品や価格に user が加入しているかどうかも簡単に判断することができます:

@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

Building a Subscribed Middleware

便宜上、入ってくる request が subscribed user からのものかどうかを判断する middlewareを作成することをお勧めします。この middleware が定義されたら、 subscribed でない users が route にアクセスするのを防ぐために簡単にそれを route に割り当てることができます:

<?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('/subscribe');
        }

        return $next($request);
    }
}

middleware が定義されたら、それを route に割り当てることができます:

use App\Http\Middleware\Subscribed;

Route::get('/dashboard', function () {
    // ...
})->middleware([Subscribed::class]);

Allowing Customers to Manage Their Billing Plan

もちろん、お客様は subscription プランを他の商品や"tier"に変更したいと思うかもしれません。上記の例では、お客様が月間の subscription を年間の subscription に変更することを可能にしたいと考えています。そのためには、以下の route につながるような button を実装する必要があります:

use Illuminate\Http\Request;

Route::put('/subscription/{price}/swap', function (Request $request, $price) {
    $user->subscription()->swap($price); // With "$price" being "price_basic_yearly" for this example.

    return redirect()->route('dashboard');
})->name('subscription.swap');

プランの交換だけでなく、顧客が cancel (キャンセル)して subscription (サブスクリプション)を終了することを許可する必要があります。プランを交換するように、次の route (ルート)につながる button (ボタン)を提供してください:

use Illuminate\Http\Request;

Route::put('/subscription/cancel', function (Request $request, $price) {
    $user->subscription()->cancel();

    return redirect()->route('dashboard');
})->name('subscription.cancel');

そして今、あなたの subscription は、請求期間の終わりにキャンセルされます。

NOTE

あなたが Cashier の webhook の処理を設定していれば、Cashier は自動的に Paddle から来る webhooks を検査することで、application の Cashier 関連の database テーブルを sync に保ちます。例えば、Paddle のダッシュボードから顧客の subscription を cancel すると、Cashier は対応する webhook を受け取り、application の database で subscription を"cancel"とマークします。

Checkout Sessions

ほとんどの顧客請求業務は、Paddle のCheckout Overlay widget を使用するか、またはinline checkout を利用することで実行されます。

Paddle を使用して processing checkout の支払いを処理する前に、アプリケーションのdefault payment link を Paddle の checkout 設定ダッシュボードで定義するべきです。

オーバーレイ Checkout

Checkout オーバーレイウィジェットを表示する前に、 Cashier を使用して checkout session を生成する必要があります。 checkout session は、実行すべき課金操作を checkout ウィジェットに通知します。

use Illuminate\Http\Request;

Route::get('/buy', function (Request $request) {
    $checkout = $user->checkout('pri_34567')
        ->returnTo(route('dashboard'));

    return view('billing', ['checkout' => $checkout]);
});

Cashier はpaddle-buttonBlade コンポーネントを含みます。 チェックアウト session をこの component に"prop"として渡すこともできます。その後、この button がクリックされると、Paddle の checkout ウィジェットが表示されます。

<x-paddle-button :checkout="$checkout" class="px-8 py-4">
  Subscribe
</x-paddle-button>

default として、これは Paddle の defaultstyle を使用してウィジェットを表示します。ウィジェットは、data-theme='light' 属性などのPaddle がサポートする属性 を component に追加することでカスタマイズできます。

<x-paddle-button :url="$payLink" class="px-8 py-4" data-theme="light">
  Subscribe
</x-paddle-button>

Paddle の checkout ウィジェットは非同期です。一度 user がウィジェット内で subscription を作成すると、Paddle はあなたの application に webhook を送り、あなたがアプリケーションの database の subscription state を適切に update できるようにします。そのため、Paddle からの state の変更を適切に受け入れるために、適切にwebhooks の設定をすることが重要です。

WARNING

subscription state の変更後、 webhook を受信するまでの delay は通常最小限ですが、ユーザーの subscription が checkout 完了後すぐに利用できない可能性を考慮し、 application でこれを考慮する必要があります。

オーバーレイ Checkout を手動でレンダリング

また、Laravel の組み込みの Blade コンポーネントを使用せずに、 checkout のオーバーレイを手動で render することも可能です。始めるためには、前の例で示したように checkout session を生成してください。

use Illuminate\Http\Request;

Route::get('/buy', function (Request $request) {
    $checkout = $user->checkout('pri_34567')
        ->returnTo(route('dashboard'));

    return view('billing', ['checkout' => $checkout]);
});

次に、Paddle.js を使用して checkout を初期化することができます。この例では、paddle_button class を割り当てられたリンクを作成します。Paddle.js はこの class を検出し、リンクがクリックされたときにオーバーレイの checkout を表示します:

<?php
$items = $checkout->getItems();
$customer = $checkout->getCustomer();
$custom = $checkout->getCustomData();
?>

<a
    href='#!'
    class='paddle_button'
    data-items='{!! json_encode($items) !!}'
    @if ($customer) data-customer-id='{{ $customer->paddle_id }}' @endif
    @if ($custom) data-custom-data='{{ json_encode($custom) }}' @endif
    @if ($returnUrl = $checkout->getReturnUrl()) data-success-url='{{ $returnUrl }}' @endif
>
    Buy Product
</a>

インライン Checkout

Paddle の"overlay"スタイルの checkout ウィジェットを使用したくない場合、Paddle はウィジェットをインラインで表示するオプションも提供しています。このアプローチでは、チェックアウトの HTML フィールドを調整することはできませんが、ウィジェットをあなたの application 内に埋め込むことができます。

あなたがインライン checkout をすぐに始められるように、 Cashier は paddle-checkout Blade component が含まれています。始めるためには、まずcheckout session を生成する必要があります:

use Illuminate\Http\Request;

Route::get('/buy', function (Request $request) {
    $checkout = $user->checkout('pri_34567')
        ->returnTo(route('dashboard'));

    return view('billing', ['checkout' => $checkout]);
});

次に、 checkout session をコンポーネントのcheckout attribute に渡すことができます:

<x-paddle-checkout :checkout="$checkout" class="w-full" />

inline checkout component の高さを調整するには、 height attribute を Blade component に渡すことができます:

<x-paddle-checkout :checkout="$checkout" class="w-full" height="500" />

Paddle のインライン Checkout に関するガイド 利用可能な checkout 設定 をご参照ください。これらは、インラインチェックアウトのカスタマイズ options に関する詳細情報を提供しています。

手動でインラインの Checkout をレンダリングする

また、Laravel の組み込みの Blade コンポーネントを使用せずに、手動で render したインラインの checkout を表示することもできます。始めるには、前の例で示したように、 checkout session を生成してください。

use Illuminate\Http\Request;

Route::get('/buy', function (Request $request) {
    $checkout = $user->checkout('pri_34567')
        ->returnTo(route('dashboard'));

    return view('billing', ['checkout' => $checkout]);
});

次に、Paddle.js を使用して checkout を初期化することができます。この例では、Alpine.js を使用してこれをデモンストレーションしますが、自身のフロントエンド stack にこの例を自由に変更しても構いません:

<?php
$options = $checkout->options();

$options['settings']['frameTarget'] = 'paddle-checkout';
$options['settings']['frameInitialHeight'] = 366;
?>

<div class="paddle-checkout" x-data="{}" x-init="
    Paddle.Checkout.open(@json($options));
">
</div>

Guest Checkouts

時折、あなたの application にアカウントが不要な users のために、 checkout session を作成する必要があるかもしれません。その際、guest method を使用することができます:

use Illuminate\Http\Request;
use Laravel\Paddle\Checkout;

Route::get('/buy', function (Request $request) {
    $checkout = Checkout::guest('pri_34567')
        ->returnTo(route('home'));

    return view('billing', ['checkout' => $checkout]);
});

次に、Paddle buttonまたはinline checkoutの Blade コンポーネントに checkout session を提供することができます。

Price Previews

Paddle では、通貨ごとに価格をカスタマイズできます。つまり、各国ごとに異なる価格を設定することができます。 Cashier Paddle では、これらすべての価格をpreviewPrices method を使用して取得できます。この method では、価格を取得したい price ID を受け付けます:

use Laravel\Paddle\Cashier;

$prices = Cashier::previewPrices(['pri_123', 'pri_456']);

通貨はリクエストの IP アドレスに基づいて決定されますが、特定の国の価格を取得するために、オプションで国を指定することも可能です。

use Laravel\Paddle\Cashier;

$prices = Cashier::previewPrices(['pri_123', 'pri_456'], ['address' => [
    'country_code' => 'BE',
    'postal_code' => '1234',
]]);

価格を取得した後、あなたの希望する方法でそれらを表示することができます:

<ul>
    @foreach ($prices as $price)
        <li>{{ $price->product['name'] }} - {{ $price->total() }}</li>
    @endforeach
</ul>

あなたはまた、小計の price と税金額を別々に表示することもできます:

<ul>
    @foreach ($prices as $price)
        <li>{{ $price->product['name'] }} - {{ $price->subtotal() }} (+ {{ $price->tax() }} tax)</li>
    @endforeach
</ul>

詳細については、Paddle の API ドキュメンテーションで price プレビューを checkout してください。

顧客 Price プレビュー

もし user がすでに顧客であり、その顧客に適用される価格を表示したい場合は、顧客インスタンスから直接価格を取得することで表示することができます:

use App\Models\User;

$prices = User::find(1)->previewPrices(['pri_123', 'pri_456']);

内部的に、Cashier は user の顧客 ID を使用して、彼らの通貨で価格を取得します。例えば、アメリカに住む user は米ドルで価格を見ることになり、ベルギーに住む user はユーロで価格を見ることになります。一致する通貨が見つからない場合、商品の default の通貨が使用されます。Paddle コントロールパネルで製品や subscription プランのすべての価格をカスタマイズすることができます。

Discounts

また、割引後の価格を表示することも選択できます。previewPricesの method を呼び出すときには、discount_idオプションを通じて割引 ID を提供します:

use Laravel\Paddle\Cashier;

$prices = Cashier::previewPrices(['pri_123', 'pri_456'], [
    'discount_id' => 'dsc_123'
]);

次に、計算された価格を表示します:

<ul>
    @foreach ($prices as $price)
        <li>{{ $price->product['name'] }} - {{ $price->total() }}</li>
    @endforeach
</ul>

Customers

お客様の Defaults

Cashier は、 checkout セッションを作成する際に、お客様にとって役立つ defaults を定義することを可能にします。これらの defaults を設定することで、お客様の email アドレスや名前を事前に入力することで、お客様はすぐに checkout ウィジェットの支払い部分に進むことができます。 billable model 上の次のメソッドをオーバーライドすることで、これらの defaults を設定することができます:

/**
 * Get the customer's name to associate with Paddle.
 */
public function paddleName(): string|null
{
    return $this->name;
}

/**
 * Get the customer's email address to associate with Paddle.
 */
public function paddleEmail(): string|null
{
    return $this->email;
}

これらの defaults は、 Cashier 内で checkout session を生成するすべての action に使用されます。

Retrieving Customers

顧客は、Cashier::findBillableの method を使用して、Paddle Customer ID によって取り出すことができます。この method は、請求可能 model のインスタンスを返します:

use Laravel\Cashier\Cashier;

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

Creating Customers

たまに、 subscription を開始せずに Paddle の顧客を作成したいと思うかもしれません。これは、createAsCustomer method を使用して実現できます。

$customer = $user->createAsCustomer();

Laravel\Paddle\Customerのインスタンスが返されます。Paddle で顧客が作成されたら、後日 subscription を始めることができます。任意の$optionsアレイを提供して、追加の顧客作成パラメーターを PaddleAPI に渡すことができます。

$customer = $user->createAsCustomer($options);

Subscriptions

Creating Subscriptions

subscription を作成するには、まず database から billable model のインスタンスを取得します。これは通常、App\Models\Userのインスタンスになります。 model インスタンスを retrieved したら、そのモデルの checkout session を作成するためにsubscribe method を使用できます。

use Illuminate\Http\Request;

Route::get('/user/subscribe', function (Request $request) {
    $checkout = $request->user()->subscribe($premium = 12345, 'default')
        ->returnTo(route('home'));

    return view('billing', ['checkout' => $checkout]);
});

subscribe method に渡される最初の引数は、 user が購読する特定の price です。この value は、 Paddle の価格の識別子に対応しているべきです。returnTo method は、 user が checkout を正常に完了した後に redirect される URL を受け入れます。subscribe method に渡される二つ目の引数は、 subscription の内部"type"であるべきです。あなたの application が single subscription のみを提供している場合、これを default または primary と呼ぶことができます。この subscription type は、内部の application 使用のためだけで、 users に表示することを意図していません。また、スペースを含んではならず、 subscription を作成した後にこれを変更することは決してありません。

また、customDataの method を使用して、subscription に関する custommetadata の array を提供することもできます。

$checkout = $request->user()->subscribe($premium = 12345, 'default')
    ->customData(['key' => 'value'])
    ->returnTo(route('home'));

一度 subscription checkout session が作成されると、その checkout session は、 Cashier Paddle に含まれるpaddle-button Blade componentに提供できます。

<x-paddle-button :checkout="$checkout" class="px-8 py-4">
    Subscribe
</x-paddle-button>

user が checkout を終えた後、Paddle からsubscription_created webhooks が発行されます。 Cashier はこの webhook を受け取り、お客様のための subscription を設定します。すべての webhook があなたの application に適切に受け取られ、取り扱われることを確認するために、正しく webhook の処理を設定 していることを確認してください。

Checking Subscription Status

一度 user があなたの application に subscribed すると、その subscription status を確認するためのさまざまな便利な方法を使用することができます。まず、 subscribed method は、 user が有効な subscription を持っている場合、たとえその subscription が現在試用期間内であっても true を返します。

if ($user->subscribed()) {
    // ...
}

あなたの application が複数の subscriptions を提供している場合、subscribed method を呼び出すときに subscription を指定することができます:

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

subscribedの method は、ユーザーの subscription status に基づいて routes とコントローラへのアクセスをフィルタリングするためのroute middlewareとしても大いに有用です:

<?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()) {
            // This user is not a paying customer...
            return redirect('billing');
        }

        return $next($request);
    }
}

もし user がまだ試用期間内にいるかどうかを判断したい場合、onTrial method を使用することができます。この method は、試用期間中であることを user に警告を表示すべきかどうかを判断するのに役立つことがあります:

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

subscribedToPrice method は、与えられた Paddle price ID に基づいて、 user が特定のプランに subscribed しているかどうかを判断するために使用することができます。この例では、ユーザーのdefault subscription が月額 price に積極的に subscribed しているかどうかを判断します。

if ($user->subscribedToPrice($monthly = 'pri_123', 'default')) {
    // ...
}

recurring method は、 user が現在アクティブな subscription に存在し、試用期間や猶予期間が終了しているかどうかを判断するために使用することができます:

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

Canceled Subscription Status

user がかつて活動的な加入者であり、それが subscription をキャンセルしたかどうかを判断するには、canceled method を使用することができます:

if ($user->subscription()->canceled()) {
    // ...
}

また、 user が subscription を解約したが、まだ grace period にあるかどうかを決定することもできます。 subscription が完全に満了するまでの間です。例えば、 user が 3 月 5 日に subscription をキャンセルし、それが元々 3 月 10 日に満了する予定だった場合、 user は 3 月 10 日まで grace period になります。さらに、この期間中でもsubscribed method はtrueを返し続けます。

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

期限切れの Status

subscription の支払いが失敗した場合、それはpast_dueとマークされます。あなたの subscription がこの state にあるときは、顧客が支払い情報を更新するまでアクティブになりません。 subscription が過去に到着したかどうかを判断するには、 subscription のインスタンス上のpastDue method を使用できます

if ($user->subscription()->pastDue()) {
    // ...
}

subscription が未払いになった場合、 user にupdate するよう指示するべきです。

past_dueの状態であっても subscriptions を有効とみなしたい場合は、keepPastDueSubscriptionsActiveという Cashier が提供する method を使用することができます。通常、この method はAppServiceProviderregister method で呼び出されるべきです。

use Laravel\Paddle\Cashier;

/**
 * Register any application services.
 */
public function register(): void
{
    Cashier::keepPastDueSubscriptionsActive();
}

WARNING

subscription がpast_dueの state にある場合、支払い情報が更新されるまで変更することはできません。そのため、swapおよびupdateQuantityのメソッドは、 subscription がpast_dueの state にある場合に例外を throw します。

Subscription Scopes

ほとんどの subscription 状態は、指定した state にある subscriptions をあなたの database から簡単に query できるように、 query スコープとしても利用できます:

// Get all valid subscriptions...
$subscriptions = Subscription::query()->valid()->get();

// Get all of the canceled subscriptions for a user...
$subscriptions = $user->subscriptions()->canceled()->get();

利用可能なスコープの完全なリストは以下にあります:

Subscription::query()->valid();
Subscription::query()->onTrial();
Subscription::query()->expiredTrial();
Subscription::query()->notOnTrial();
Subscription::query()->active();
Subscription::query()->recurring();
Subscription::query()->pastDue();
Subscription::query()->paused();
Subscription::query()->notPaused();
Subscription::query()->onPausedGracePeriod();
Subscription::query()->notOnPausedGracePeriod();
Subscription::query()->canceled();
Subscription::query()->notCanceled();
Subscription::query()->onGracePeriod();
Subscription::query()->notOnGracePeriod();

Subscription Single の料金

Subscription single 料金は、購読者に対してその subscriptions の上に一回限りの料金を請求することを可能にします。あなたはcharge method を呼び出すときに一つまたは複数の price ID を提供する必要があります:

// Charge a single price...
$response = $user->subscription()->charge('pri_123');

// Charge multiple prices at once...
$response = $user->subscription()->charge(['pri_123', 'pri_456']);

charge method は、顧客の subscription の次の請求期間まで実際には請求しません。もしすぐに顧客に請求したい場合は、代わりにchargeAndInvoice method を使用することができます。

$response = $user->subscription()->chargeAndInvoice('pri_123');

支払情報の更新

Paddle は常に subscription ごとに支払いの method を保存します。 subscription の default の支払い method を update したい場合は、redirectToUpdatePaymentMethod method を使用して、お客様を Paddle のホストされた支払い method update ページに redirect する必要があります。

use Illuminate\Http\Request;

Route::get('/update-payment-method', function (Request $request) {
    $user = $request->user();

    return $user->subscription()->redirectToUpdatePaymentMethod();
});

user が情報の更新を終えたとき、Paddle によりsubscription_updatedの webhook が発行され、ご利用の application の database に subscription の詳細が更新されます。

プランの変更

user があなたの application に登録した後、彼らは時折新しい subscription プランに変更したいと思うかもしれません。 user の subscription プランを更新するには、Paddle 価格の識別子を subscription のswap method に渡すべきです。

use App\Models\User;

$user = User::find(1);

$user->subscription()->swap($premium = 'pri_456');

もし、次の請求サイクルを待つ代わりに、 user にすぐに請求書を送り、 swap プランを切り替えたい場合は、swapAndInvoice method を使用することができます。

$user = User::find(1);

$user->subscription()->swapAndInvoice($premium = 'pri_456');

Prorations

default では、Paddle はプラン間で変更する際に料金を按分します。 noProrate method は、料金を按分せずに subscriptions を更新するために使用することができます:

$user->subscription('default')->noProrate()->swap($premium = 'pri_456');

精算を無効にし、顧客にすぐに請求したい場合は、swapAndInvoice method をnoProrateと組み合わせて使用することができます:

$user->subscription('default')->noProrate()->swapAndInvoice($premium = 'pri_456');

または、顧客に subscription の変更を請求しないために、doNotBill method を利用することもできます:

$user->subscription('default')->doNotBill()->swap($premium = 'pri_456');

Paddle の精算 policies に関する詳細については、Paddle の精算ドキュメント をご覧ください。

Subscription Quantity

時には subscriptions は quantity に影響を受けます。例えば、project 管理 application は、project ごとに月額$10 を請求するかもしれません。あなたの subscriptions の quantity を簡単に increment またはデクリメントするには、 incrementQuantitydecrementQuantityの method を使用します。

$user = User::find(1);

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

// Add five to the subscription's current quantity...
$user->subscription()->incrementQuantity(5);

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

// Subtract five from the subscription's current quantity...
$user->subscription()->decrementQuantity(5);

別の方法として、updateQuantity method を使用して特定の quantity を設定することもできます:

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

noProratemethod は、料金の按分をせずに subscription の数量を更新するために使用できます:

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

Quantities for Subscriptions With Multiple Products

あなたの subscription が複数の製品の subscriptionである場合、increment または decrement したい price の ID を increment/ decrement methods の第二引数として渡すべきです:

$user->subscription()->incrementQuantity(1, 'price_chat');

Subscriptions With Multiple Products

Subscription with multiple products は、複数の課金製品を単一の Subscription に割り当てることができます。たとえば、月額 10 ドルの基本 Subscription 価格を設定し、さらに毎月 15 ドルのライブチャットの追加製品を提供する顧客 service ヘルプデスク application を構築することを想像してみてください。

subscribemethod の第一引数として array の価格を渡すことにより、特定の subscription に対して複数の製品を指定することができます:

use Illuminate\Http\Request;

Route::post('/user/subscribe', function (Request $request) {
    $checkout = $request->user()->subscribe([
        'price_monthly',
        'price_chat',
    ]);

    return view('billing', ['checkout' => $checkout]);
});

上記の例では、顧客はdefault subscription に 2 つの価格が付けられます。両方の価格はそれぞれの課金間隔で請求されます。必要に応じて、特定の quantity を示すためのキー/ value ペアの連想 array を渡すことができます。各 price について:

$user = User::find(1);

$checkout = $user->subscribe('default', ['price_monthly', 'price_chat' => 5]);

既存の subscription に別の price を追加したい場合は、その subscription のswapmethod を使用する必要があります。swapmethod を呼び出すときには、subscription の現在の価格と数量も含めるべきです:

$user = User::find(1);

$user->subscription()->swap(['price_chat', 'price_original' => 2]);

上記の例では、新しい price を追加しますが、顧客がそれに対して請求されるのは次の請求サイクルになります。顧客にすぐに請求したい場合は、swapAndInvoice method を使用することができます。

$user->subscription()->swapAndInvoice(['price_chat', 'price_original' => 2]);

あなたは、swapの method を使用して、削除したい price を省略することで、 subscriptions から価格を削除することができます:

$user->subscription()->swap(['price_original' => 2]);

WARNING

subscription の最後の price を削除することはできません。代わりに、単に subscription を cancel すべきです。

Multiple Subscriptions

Paddle は、お客様が複数の subscriptions を同時に持つことを可能にします。例えば、あなたがスイミングの subscription とウェイトリフティングの subscription を提供するジムを運営している場合、各 subscription には異なる価格設定があるかもしれません。もちろん、お客様はいずれかまたは両方のプランに subscribe することができるべきです。

あなたの application が subscriptions を作成するとき、 subscription の type を二つ目の引数としてsubscribe method に提供することができます。 type は、 user が開始している subscription の type を表す任意の string にすることができます。

use Illuminate\Http\Request;

Route::post('/swimming/subscribe', function (Request $request) {
    $checkout = $request->user()->subscribe($swimmingMonthly = 'pri_123', 'swimming');

    return view('billing', ['checkout' => $checkout]);
});

この例では、顧客に対して月額の subscription を開始しました。しかし、彼らは後で年間の subscription に swap することを希望するかもしれません。顧客の subscription を調整する際には、単にswimmingの subscription の price を swap するだけで済みます。

$user->subscription('swimming')->swap($swimmingYearly = 'pri_456');

Of course, you may also cancel the subscription entirely:

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

Subscriptions の一時停止

ユーザーの subscription を一時停止するには、ユーザーの subscription に対してpause method を呼び出します。

$user->subscription()->pause();

subscription が一時停止されると、 Cashier は自動的にあなたの database 内のpaused_atの column を設定します。この column は、pausedの method がいつからtrueを返し始めるべきかを判断するために使用されます。例えば、顧客が 3 月 1 日に subscription を一時停止し、しかし、その subscription が 3 月 5 日まで再発する予定がなかった場合、pausedの method は 3 月 5 日までfalseを返し続けます。これは、 user が通常、課金サイクルの終了まで application を使い続けることが許されているためです。

default では、顧客が支払った期間の残りを使用できるように、次の請求間隔で一時停止が発生します。すぐに subscription を一時停止したい場合は、pauseNow method を使用することができます:

$user->subscription()->pauseNow();

pauseUntil method を使用すると、特定の時間まで subscription を一時停止することができます:

$user->subscription()->pauseUntil(now()->addMonth());

または、pauseNowUntil method を使用して、指定された時点まで直ちに subscription を一時停止することもできます:

$user->subscription()->pauseNowUntil(now()->addMonth());

onPausedGracePeriod method を使用して、 user が subscription を一時停止し、しかしまだ猶予期間中であるかどうかを判断することができます。

if ($user->subscription()->onPausedGracePeriod()) {
    // ...
}

停止中の subscription を再開するには、 subscription 上でresume method を呼び出すことができます:

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

WARNING

subscription は一時停止中に変更することはできません。別のプランに swap したり、数量を update したい場合は、まず subscription を再開する必要があります。

Subscriptions のキャンセル

ユーザーの subscription に対してcancel method を呼び出して、 subscription を cancel します。

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

subscription がキャンセルされると、 Cashier は自動的にあなたの database の ends_at column を設定します。この column は、subscribed method がfalseを返すべきタイミングを決定するために使用されます。例えば、3 月 1 日に顧客が subscription をキャンセルしたが、その subscription が 3 月 5 日まで終了しない予定だった場合、subscribed method は 3 月 5 日まで続けてtrueを返します。これは、 user が通常、課金サイクルの終わりまで application を続けて使用できるからです。

onGracePeriod method を使用して、 user が subscription を cancel したが、まだ "grace period" にいるかどうかを判断することができます。

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

すぐに subscription を cancel したい場合は、 subscription の上でcancelNow method を呼び出すことができます。

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

その猶予期間中の subscription をキャンセルから停止するには、stopCancelation method を呼び出すことができます。

$user->subscription()->stopCancelation();

WARNING

Paddle の subscriptions は、キャンセル後に再開することはできません。お客様が subscription を再開したい場合は、新たに subscription を作成する必要があります。

Subscription Trials

With Payment Method Up Front

お客様にトライアル期間を提供しながら、前もって method 情報を集めることを希望する場合は、お客様が登録している price の Paddle ダッシュボードでトライアル時間を設定する必要があります。その後、通常通り checkout session を開始してください:

use Illuminate\Http\Request;

Route::get('/user/subscribe', function (Request $request) {
    $checkout = $request->user()->subscribe('pri_monthly')
                ->returnTo(route('home'));

    return view('billing', ['checkout' => $checkout]);
});

あなたの application が subscription_created event を受信したときに、 Cashier はお使いのアプリケーションの database の subscription レコード上の試用期間終了日を設定します。また、この日付まで顧客に請求を始めないように Paddle に指示します。

WARNING

お客様が subscription を試用期間終了日前にキャンセルしない場合、試用期間が終了するとすぐに課金されます。そのため、 users に試用期間終了日を通知するようにしましょう。

user がトライアル期間内かどうかを判断するには、user インスタンスのonTrial method または subscription インスタンスのonTrial method のいずれかを使用できます。以下の二つの例は同等です:

if ($user->onTrial()) {
    // ...
}

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

既存の試用期間が終了したかどうかを判断するためには、hasExpiredTrialメソッドを使用することができます:

if ($user->hasExpiredTrial()) {
    // ...
}

if ($user->subscription()->hasExpiredTrial()) {
    // ...
}

特定の subscription type に対して user が試用中かどうかを判断するためには、 type を onTrial または hasExpiredTrial メソッドに指定することができます。

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

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

Without Payment Method Up Front

ユーザーの支払い method 情報を前もって収集せずに試用期間を提供したい場合は、お客様の記録に付随するあなたの user のtrial_ends_at column を希望の試用終了日に設定することができます。これは通常、 user の登録時に行われます:

use App\Models\User;

$user = User::create([
    // ...
]);

$user->createAsCustomer([
    'trial_ends_at' => now()->addDays(10)
]);

Cashier は、既存の subscription に関連付けられていないため、一般的な試用期間と呼んでいます。Userインスタンス上のonTrial method は、現在の日付がtrial_ends_atの value を過ぎていない場合、trueを返します。

if ($user->onTrial()) {
    // User is within their trial period...
}

あなたが実際に user のための subscription を作成する準備ができたら、通常通りsubscribe method を使用することができます:

use Illuminate\Http\Request;

Route::get('/user/subscribe', function (Request $request) {
    $checkout = $user->subscribe('pri_monthly')
        ->returnTo(route('home'));

    return view('billing', ['checkout' => $checkout]);
});

ユーザーの試用期間終了日を取得するには、trialEndsAt method を使用できます。この method は、 user が試用期間中である場合は Carbon 日付インスタンスを返し、そうでない場合はnullを返します。また、特定の subscription の試用期間終了日を取得したい場合は、オプションで subscription type パラメータを指定することもできます。これは default のもの以外である場合に便利です:

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

onGenericTrialの method が使用可能です。これは、特に user が"generic"のトライアル期間内であり、まだ実際の subscription を作成していないかどうかを知りたい場合に利用できます:

if ($user->onGenericTrial()) {
    // User is within their "generic" trial period...
}

トライアルを延長または有効化する

既存の試用期間を延長するには、extendTrial method を呼び出し、試用期間が終了すべき時間を指定して subscription を延長できます:

$user->subscription()->extendTrial(now()->addDays(5));

または、activate method を subscription に呼び出すことにより、その試用期間を終了させてすぐに subscription をアクティブにすることもできます。

$user->subscription()->activate();

Handling Paddle Webhooks

Paddle は、webhooks を介して、さまざまな events をあなたの application に通知できます。default では、Cashier の webhook controller に指す route が Cashier.service provider によって登録されます。この controller は、すべての入ってくる webhookrequest を handle します。

default では、この controller は自動的に失敗した請求が多すぎる subscriptions のキャンセル、 subscription の更新、および支払い method の変更を handle します。しかし、すぐにわかるように、好きな Paddle webhook event を handle するために、この controller を拡張することができます。

あなたの application が Paddle の webhooks を handle できるようにするためには、Paddle の制御パネルで webhook URL を設定する ことを必ず確認してください。 default では、Cashier の webhook controller は /paddle/webhook URL path に対応しています。Paddle の制御パネルで有効にするべき全ての webhooks のリストは次の通りです:

  • お客様情報更新済み
  • Transaction 完了しました
  • Transaction 更新済み
  • Subscription が作成されました
  • Subscription 更新されました
  • Subscription 一時停止中
  • Subscription キャンセルされました

WARNING

Cashier に含まれるwebhook signature の確認 middleware を使用して、着信リクエストを保護することを確認してください。

Webhooks and CSRF Protection

Paddle の webhooks は webhooks のCSRF protectionを回避する必要があるため、 Laravel が CSRF の token を確認しようと attempt しないようにするべきです。これを達成するためには、アプリケーションのbootstrap/app.phpファイルでpaddle/*を CSRF protection から除外すべきです:

->withMiddleware(function (Middleware $middleware) {
    $middleware->validateCsrfTokens(except: [
        'paddle/*',
    ]);
})

Webhooks とローカル開発

Paddle がローカル開発中にあなたの application webhooks を送信できるようにするためには、Ngrok Expose などのサイト共有の service を介してあなたの application を公開する必要があります。もし、Laravel Sailを使ってローカルで application を開発しているのであれば、Sail のサイト共有 commandを使うことができます。

Defining Webhook Event Handlers

Cashier は、課金失敗やその他の一般的な Paddle の webhooks に対する subscription のキャンセルを自動的に処理します。しかし、追加の webhook events を handle したい場合は、 Cashier から発行される次の events を購読することで行うことができます。

  • Laravel\Paddle\Events\WebhookReceived
  • Laravel\Paddle\Events\WebhookHandled

両方の events は Paddle の webhook のフルペイロードを含んでいます。例えば、もしあなたがtransaction.billedの webhook を handle したい場合、 event を handle するlistenerを register することができます。

<?php

namespace App\Listeners;

use Laravel\Paddle\Events\WebhookReceived;

class PaddleEventListener
{
    /**
     * Handle received Paddle webhooks.
     */
    public function handle(WebhookReceived $event): void
    {
        if ($event->payload['event_type'] === 'transaction.billed') {
            // Handle the incoming event...
        }
    }
}

Cashier は、受け取った webhook の type に専用の events も発行します。Paddle からの完全なペイロードに加えて、 billable model 、 subscription 、またはレシートなど、 webhook を process するのに使用された関連 models も含まれています。

  • Laravel\Paddle\Events\CustomerUpdated
  • Laravel\Paddle\Events\TransactionCompleted
  • Laravel\Paddle\Events\TransactionUpdated
  • Laravel\Paddle\Events\SubscriptionCreated
  • Laravel\Paddle\Events\SubscriptionUpdated
  • Laravel\Paddle\Events\SubscriptionPaused
  • Laravel\Paddle\Events\SubscriptionCanceled

あなたはまた、application の.envファイルでCASHIER_WEBHOOKを定義することで、default で組み込まれている webhook route を上書きすることもできます。この value は webhook route への完全な URL であるべきで、Paddle のコントロールパネルで設定された URL と match する必要があります:

CASHIER_WEBHOOK=https://example.com/my-paddle-webhook-url

Verifying Webhook Signatures

あなたの webhooks を保護するために、Paddle の webhook 署名 を使用することができます。便利なことに、 Cashier は自動的に、受信した Paddle の webhook request が有効であることを検証する middleware を含めます。

webhook の検証を有効にするには、PADDLE_WEBHOOK_SECRETenvironment variables が application の.envファイルに定義されていることを確認してください。 webhook secret は、あなたの Paddle アカウントダッシュボードから取得することができます。

Single Charges

製品の課金

お客様のために製品の購入を開始したい場合、 checkout の method を billable model のインスタンスで使用して、購入のための checkout session を生成できます。 checkout の method は 1 つまたは複数の価格 ID を受け付けます。必要に応じて、関連する array が使用され、購入される製品の数量を提供することができます:

use Illuminate\Http\Request;

Route::get('/buy', function (Request $request) {
    $checkout = $request->user()->checkout(['pri_tshirt', 'pri_socks' => 5]);

    return view('buy', ['checkout' => $checkout]);
});

checkout session を生成した後、Cashier が提供するpaddle-button Blade componentを使用して、 user が Paddle checkout ウィジェットを view し、購入を完了することを許可できます:

<x-paddle-button :checkout="$checkout" class="px-8 py-4">
    Buy
</x-paddle-button>

checkout session には、customData method があり、希望する custom data を基礎となる transaction の作成に渡すことができます。 custom data を渡す際の利用可能な options については、Paddle のドキュメンテーション をご覧ください。

$checkout = $user->checkout('pri_tshirt')
    ->customData([
        'custom_option' => $value,
    ]);

Transactions の返金

transactions を返金すると、購入時に使用されたお客様の支払い method に返金額が戻ります。 Paddle の購入を返金する必要がある場合は、Cashier\Paddle\Transaction model 上のrefund method を使用することができます。 この method は、最初の引数として理由を受け付け、一つまたは複数の price ID を、任意の金額とともに関連 array として返金することができます。 特定の billable model の transactions をtransactions method を使用して取得することができます。

例えば、特定の transaction で、pri_123pri_456の価格を払い戻したいと想像してみてください。pri_123は全額払い戻しをしたいのですが、pri_456については 2 ドルだけ払い戻したいと考えています。

use App\Models\User;

$user = User::find(1);

$transaction = $user->transactions()->first();

$response = $transaction->refund('Accidental charge', [
    'pri_123', // Fully refund this price...
    'pri_456' => 200, // Only partially refund this price...
]);

上記の例では、 transaction 内の特定の明細を払い戻します。もし全体の transaction を払い戻したい場合は、理由を簡単に提供してください:

$response = $transaction->refund('Accidental charge');

返金に関する詳しい情報は、Paddle の返金ドキュメンテーション をご覧ください。

WARNING

返金は常に完全に processing する前に Paddle によって承認される必要があります。

Transactions のクレジット

返金と同様に、transactions もクレジットできます。transactions をクレジットすると、資金は顧客の balance に追加され、将来の購入に使用できます。ただし、手動で集めた transactions のみをクレジットでき、自動的に収集された transactions(subscriptions など)はクレジットできません。これは Paddle が subscription のクレジットを自動的に処理するためです。

$transaction = $user->transactions()->first();

// Credit a specific line item fully...
$response = $transaction->credit('Compensation', 'pri_123');

詳細な info については、Paddle のクレジットに関するドキュメンテーションを参照してください

WARNING

クレジットは、手動で収集された transactions にのみ適用できます。自動的に収集された transactions は、Paddle 自体がクレジットを付与します。

Transactions

transactionsプロパティを通じて、 billable モデルの transactions という array を容易に取得できます:

use App\Models\User;

$user = User::find(1);

$transactions = $user->transactions;

Transactions は商品や購入品に対する支払いを示し、請求書が添付されます。完了した transactions のみがあなたのアプリケーションの database に保存されます。

顧客の transactions をリスト表示する際には、 transaction インスタンスのメソッドを使用して関連する支払い情報を表示することができます。例えば、すべての transaction をテーブルにリスト表示し、 user が請求書を簡単に download できるようにするかもしれません:

<table>
  @foreach ($transactions as $transaction)
  <tr>
    <td>{{ $transaction->billed_at->toFormattedDateString() }}</td>
    <td>{{ $transaction->total() }}</td>
    <td>{{ $transaction->tax() }}</td>
    <td>
      <a
        href="{{ route('download-invoice', $transaction->id) }}"
        target="_blank"
        >Download</a
      >
    </td>
  </tr>
  @endforeach
</table>

download-invoice route は次のようになるかもしれません:

use Illuminate\Http\Request;
use Laravel\Cashier\Transaction;

Route::get('/download-invoice/{transaction}', function (Request $request, Transaction $transaction) {
    return $transaction->redirectToInvoicePdf();
})->name('download-invoice');

過去と今後の支払い

顧客の過去のまたは即時の定期的な subscriptions の支払いを取得して表示するために、lastPaymentおよびnextPaymentのメソッドを使用することができます。

use App\Models\User;

$user = User::find(1);

$subscription = $user->subscription();

$lastPayment = $subscription->lastPayment();
$nextPayment = $subscription->nextPayment();

これらの両方の方法は、Laravel\Paddle\Paymentのインスタンスを返します。しかし、lastPaymentは transactions がまだ webhooks によって同期されていないときにnullを返し、一方nextPaymentは課金サイクルが終了したとき( subscription がキャンセルされたときなど)にnullを返します。

Next payment: {{ $nextPayment->amount() }} due on {{ $nextPayment->date()->format('d/m/Y') }}

Testing

testing の間に、手動で請求フローをテストし、あなたのインテグレーションが期待通りに動作していることを確認すべきです。

自動化テストには、CI environment 内で実行されるものを含めて、Laravel の HTTP Clientを使用して、Paddle への fake HTTP コールを行うことができます。これにより、Paddle からの実際のレスポンスをテストしないで済ます一方で、Paddle の API を実際に呼び出すことなく application をテストする方法が提供されます。

当社サイトでは、Cookie を使用しています。各規約をご確認の上ご利用ください:
Cookie Policy, Privacy Policy および Terms of Use