カテゴリー: BackEnd

Stripe Connectを使って複合プランの継続課金を実装

はじめに

今回の記事は、Stripe Connectを使ってCheckoutを利用した継続課金を実装の続きとなります。

前回に引き続き、継続課金の実装について紹介していきます。今回は、実際のサービスでの利用を意識して、複数の継続課金を併用した場合について見ていきます。

想定する継続課金

企業向けの架空のファイルアップロードサービスを例にした継続課金になります。はじめに、ユーザ企業はプラン(定額)を契約し、その後、サービスを利用するユーザ数分のID(従量課金)を購入します。

プランは3種類あり、金額に応じて一人あたりのアップロード可能数が増加します。

  • プランA 1,000円/月 1GB/人まで
  • プランB 2,000円/月 5GB/人まで
  • プランC 3,000円/月 無制限

ID数の方は、一人あたり一律100円かかります。例えば、プランAを選択し、30人のユーザが利用する場合、毎月の費用は4,000円になります。

想定するシチュエーション

今回の記事では、以下のようなシチュエーションを想定しています。

  • プランAとID数を30契約
  • ID数をさらに20購入
  • プランAからプランBにアップグレード
  • ID数を10解約
  • プランBからプランAにダウングレード

継続課金商品の作成

プランの継続課金商品の作成

Stripeの管理画面の商品からプランとID数の継続課金商品を作成します。

プランの継続課金商品は、料金体系モデルで標準の料金体系を選択し、料金設定を行います。

 

更に料金を2つ追加すると、以下のようになります。

ID数の継続課金商品の作成

次にID数の継続課金商品を作成します。

ID数の継続課金商品は、数量ベースの料金体系を選択します。

この設定では、一人あたり毎月一律100円かかります。

実装

前回の記事では、継続課金商品の契約はCheckout画面で行いましたが、今回は請求タイミングを月末に固定したいので、コード上から契約を行います。

プランAとID数を30契約する

Subscription::create()メソッドで継続課金商品を契約します。このメソッドでは、以下のように一度に複数の継続課金商品を契約することができます。

billing_cycle_anchorで指定した日付に次回の請求が行われます。また、当月の請求は日割り計算となります。

function subscribe()
{
    Stripe::setApiKey(env('STRIPE_SECRET'));

    $subscription = Subscription::create([
        'customer' => 'your_customer_id',
        'items' => [
            [
                // プランA
                'price' => 'planA_price_id',
            ],
            [
                // ID数を30
                'price' => 'id_set_price_id',
                'quantity' => 30,
            ],
        ],
        'billing_cycle_anchor' => 1622473199, // 次回の請求日
    ]);
}

ID数をさらに20購入

継続課金商品の契約個数を更新する前に、追加の月額を計算することができます。

function calculate()
{
    Stripe::setApiKey(env('STRIPE_SECRET'));

    $proration_date = time(); // 継続課金の変更日時

    $subscription = \Stripe\Subscription::retrieve('sub_JZGRs56J8bebKP');

    $items = [
        [
            // ID数を30から50へ変更する
            'id' => $subscription->items->data[1]->id,
            'quantity' => 50,
        ],
    ];

    $invoice = \Stripe\Invoice::upcoming([
        'customer' => 'cus_JZGRPAUzlFmazf',
        'subscription' => 'sub_JZGRs56J8bebKP',
        'subscription_items' => $items,
        'subscription_proration_date' => $proration_date,
        'subscription_proration_behavior' => 'always_invoice',
    ]);
}

$invoiceの内容を抜粋すると以下の通りです。

{
    "object": "invoice",
    "account_country": "JP",
    "account_name": "hoge-test",
    "account_tax_ids": null,
    "amount_due": 149,
    "amount_paid": 0,
    "amount_remaining": 149,
    // ...
    "subtotal": 149,
    "tax": null,
    "total": 149,
    "total_discount_amounts": [],
    "total_tax_amounts": [],
    "transfer_data": null,
    "webhooks_delivered_at": null
}

proration_behavioralways_invoiceを指定すると、変更にかかる金額が即時決済されます。totalの金額が追加の決済金額です。

その後、実際にID数を50に変更する処理がこちらです。Subscription::update()メソッドで、IDの数量を変更しています。

    function update(int $subscriptionId)
    {
        Stripe::setApiKey(env('STRIPE_SECRET'));


        $proration_date = time();

        $subscription = \Stripe\Subscription::retrieve('sub_JZGRs56J8bebKP');

        $items = [
            [
                'id' => $subscription->items->data[1]->id,
                'quantity' => 50,
            ],
        ];

        $subscription = Subscription::update(
            'sub_JZGRs56J8bebKP',
            [
                'items' => $items,
                // Invoice::upcomingで渡した subscription_proration_date と同じ値にする
                'proration_date' => $proration_date,
                'proration_behavior' => 'always_invoice',
            ],
        );
    }

このように、追加分が即時決済されます。

プランAからプランBにアップグレード

プランの変更もID数の変更と同様にSubscription::update()メソッドで行います。

function update(int $subscriptionId)
{
    Stripe::setApiKey(env('STRIPE_SECRET'));


    $proration_date = time();

    $subscription = \Stripe\Subscription::retrieve('sub_JZGRs56J8bebKP');

    $items = [
        [
            'id' => $subscription->items->data[0]->id,
            'price' => 'pran_B_price_id',
        ],
    ];

    $subscription = Subscription::update(
        'sub_JZGRs56J8bebKP',
        [
            'items' => $items,
            // Invoice::upcomingで渡した subscription_proration_date と同じ値にする
            'proration_date' => $proration_date,
            'proration_behavior' => 'always_invoice',
        ],
    );
}

こちらも、ID数を変更する場合と同様に、プランを変更する前に追加の金額を表示する必要があるでしょう。

ID数を10解約

プランのダウングレードやID数を減らす場合、日割り計算はせず、次月の請求から変更が反映されるものとします。ID数を増やす場合と殆ど変わりませんが、Subscription::update()メソッドのパラメータのproration_behaviornoneで指定します(proration_dateは不要)。

    function update(int $subscriptionId)
    {
        Stripe::setApiKey(env('STRIPE_SECRET'));


        $proration_date = time();

        $subscription = \Stripe\Subscription::retrieve('sub_JZGRs56J8bebKP');

        $items = [
            [
                'id' => $subscription->items->data[1]->id,
                'quantity' => 40,
            ],
        ];

        $subscription = Subscription::update(
            'sub_JZGRs56J8bebKP',
            [
                'items' => $items,
                'proration_behavior' => 'none',
            ],
        );
    }

この場合のInvoce::upcoming()メソッドのレスポンスは以下のとおりです。

{
    "object": "invoice",
    "account_country": "JP",
    "account_name": "hoge-test",
    "account_tax_ids": null,
    "amount_due": 6000,
    "amount_paid": 0,
    "amount_remaining": 6000,
    // ...
    "total": 6000,
    "total_discount_amounts": [],
    "total_tax_amounts": [],
    "transfer_data": null,
    "webhooks_delivered_at": null
}

totalの値は、次回の請求金額になります。

ちなみに、ID数を減らした後、次の請求より前にID数を増やす場合、日割り金額は減らした後のID数をもとに計算されます。

プランBからプランAにダウングレード

最後に、プランBからプランAにダウングレードする場合です。こちらもID数を減らす場合とほとんど変わりません。

function update(int $subscriptionId)
{
    Stripe::setApiKey(env('STRIPE_SECRET'));


    $proration_date = time();

    $subscription = \Stripe\Subscription::retrieve('sub_JZGRs56J8bebKP');

    $items = [
        [
            'id' => $subscription->items->data[0]->id,
            'price' => 'pran_A_price_id',
        ],
    ];

    $subscription = Subscription::update(
        'sub_JZGRs56J8bebKP',
        [
            'items' => $items,
            'proration_behavior' => 'none',
        ],
    );
}

さいごに

前回に引き続き、継続課金について、複数の継続課金を併用し、途中で内容を変更する方法を紹介しました。

おすすめ書籍

Hiroki Ono

シェア
執筆者:
Hiroki Ono

最近の投稿

フロントエンドで動画デコレーション&レンダリング

はじめに 今回は、以下のように…

3週間 前

Goのクエリビルダー goqu を使ってみる

はじめに 最近携わっているとあ…

1か月 前

【Xcode15】プライバシーマニフェスト対応に備えて

はじめに こんにちは、suzu…

2か月 前

FSMを使った状態管理をGoで実装する

はじめに 一般的なアプリケーシ…

3か月 前