ポータルサイトブログLaravel でのサブスク決済には Cachier を使おう

 



2020/1/16

ポータルサイトでもサブスクリプション制を導入するケースがありますが、Laravelでの手続きには「Cachier」が便利です。

Laravel Cashier とは

Laravel Cashier は Laravel が公式でリリースしている、決済用のライブラリです。
Cashier は「キャシア」と発音するようです。
基本的なサブスクリプション管理はもちろん、PDFでの請求書発行クーポン支払いプラン設定キャンセル時の猶予期間を設けるなどの仕組みも作成可能です。
もちろんサブスクリプション(定期課金)ではない、単発の決済手続きにも使用できます。

基本的には決済サービス Stripe のラッパーライブラリですので、まずは Stripe への登録手続きが必要になります。
Stripe はプログラム開発者が使いやすいAPIが用意されており、決済に関する機能はほぼ網羅されています。
多くの国・言語に対応しており、クレジット決済はJCB、Apple Pay、Google Pay なども利用できます。

Laravel Cashier のインストール

Composerでインストール可能です。

composer require laravel/cashier

マイグレーション用設定が用意されているので、マイグレーションします。

php artisan migrate

もしマイグレーション設定をカスタマイズしたい場合はコピーします。

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

Laravel Cashier の使い方

まずは支払う側となるユーザーモデルにトレイトを指定します。

<?php

namespace App;

use Illuminate\Foundation\Auth\User as Authenticatable;
...
use Laravel\Cashier\Billable;

class User extends Authenticatable
{
    use Billable;

    ...
}

対象モデルはデフォルトで App\User ですが、 .env ファイルで指定できます。

CASHIER_MODEL=App\Models\User

加えて .env ファイルに Stripe のAPI情報も追記します。

STRIPE_KEY=StripeのAPIキー
STRIPE_SECRET=StripeのAPIシークレット

フロント側では Stripe の外部JavaScriptライブラリを使って入力・バリデーションを行います。
バリデーションが通れば、Laravel側での処理になります。

そのほか、具体的な決済処理方法は 公式マニュアル をご覧ください。

テストについて

決済の処理は念入りにテストした方が良いでしょう。
Stripe にはサンドボックスモードのようなものはなさそうですが、テスト用のクレジットカード番号などがあるので、各決済方式用のテスト方法のドキュメントを参考にしてください。

Laravel側のテストとしては、フロント側の入力テストも含まれるため Laravel Dusk(ダスク) を使いましょう。
Dusk は Chromeドライバを使ってブラウザテストする公式ライブラリです。
以下、 Dusk を使ったクレジットカード入力テストの例です。

<?php

namespace Tests\Feature;

use Tests\DuskTestCase;
use App\User;

class PaymentTest extends DuskTestCase
{
    /**
     * @test
     * @throws \Throwable
     */
    public function inputCreditCard()
    {
        $user = factory(User::class)->create();

        $this->browse(function ($browser) use ($user) {
            $browser
                // 対象ユーザーでログイン
                ->loginAs($user)

                // 決済ページへ移動
                ->visit('/payment')

                // iframeのロードを待つ
                // (<div id="card-element"></div> にStripeフォームを読み込む想定)
                ->waitFor('#card-element iframe')
                ->withinFrame('#card-element iframe', function ($browser) {
                    $browser
                        // カード番号入力欄の表示を待つ
                        ->waitFor('input[name="cardnumber"]')

                        // フォーム入力
                        ->keys('input[name="cardnumber"]', '4242 4242 4242 4242')
                        ->keys('input[name="exp-date"]', '12 50')
                        ->keys('input[name="cvc"]', '123')

                        // フォーム送信
                        ->press('button[type="submit"]')

                        // iframeの表示が消えるのを待つ
                        ->waitUntilMissing('#card-element iframe');
                })
                // ウインドウのリロードを待つ
                ->waitForReload()
                // 決済後のURLに戻ってくるか検証
                ->assertPathIs('/home');
        });
    }
}

おわりに

決済まわりは複雑そうに思いますが、フレームワーク側が公式ライブラリを用意してくれているのは心強いです。
気軽に決済機能を付けられると良いですね。