LaravelでのStripe銀行振込・コンビニ支払導入とカスタムページ作成

Laravel/PHPの学習過程で、Stripe実装と銀行振込およびコンビニ支払いのカスタマイズ方法を調べました。
デフォルトでは、Stripeが提供する支払い手順モーダルが開きますが、「戻る」ボタンがなく、たとえばトップページなどの元のページへ戻る操作ができません。
そこで、Stripe APIを利用してカスタムページへ遷移させる方法を検討しました。

## 環境
- PHP 8.2
- Laravel 11.x

## 表示までの手順
銀行振込とコンビニ支払いではPaymentIntentを作成する必要があります。

### 銀行振込
#### PaymentIntentの作成
まずControllerでPaymentIntentの作成をします。
銀行振込に対応するには、以下のパラメータを設定する必要があります。
- `payment_method_types`
- `payment_method_data`
- `payment_method_options`

```php
$paymentIntent = PaymentIntent::create([
                'amount' => 1000,
                'currency' => 'jpy',
                'customer' => $customer->id, // 事前にCustomerを作成しておく
                'payment_method_types' => ['customer_balance'],
                'payment_method_data' => [
                    'type' => 'customer_balance'
                ],
                'payment_method_options' => [
                    'customer_balance' => [
                        'funding_type' => 'bank_transfer',
                        'bank_transfer' => [
                            'type' => 'jp_bank_transfer'
                        ],
                    ],
                ],
                'metadata' => [
                    'book_id' => $bookId, // 必要な情報はmetadataに格納
                ],
                'confirm' => true,
            ]);
```

### 振込先情報の取得
作成された`PaymentIntent`から、振込先情報を取得します。
`next_action->display_bank_transfer_instructions`内に下記のように格納されています。
```php
"display_bank_transfer_instructions": {
      "financial_addresses": [
        {
          "zengin": {
            "account_holder_address": {
              "city": "Shibuya-ku",
              "country": "JP",
              "line1": "Jingumae Tower Building 22F, 1-5-8 Jingumae",
              "line2": null,
              "postal_code": "150-0001",
              "state": "Tokyo"
            },
            "account_holder_name": "ストライプジャパン（カ　シュウノウダイコウ",
            "account_number": "TEST00000000",
            "account_type": "futsu",
            "bank_address": {
              "city": "Chiyoda-ku",
              "country": "JP",
              "line1": "1-1-2 Marunouchi",
              "line2": null,
              "postal_code": "100-0005",
              "state": "Tokyo"
            },
            "bank_code": "1234",
            "bank_name": "いろは銀行",
            "branch_code": "001",
            "branch_name": "中央支店"
          }
        }
```

上記から、今回の場合は`foreach`で必要な情報を抽出しました。
```php
$bankTransferDetails = $paymentIntent->next_action->display_bank_transfer_instructions->financial_addresses;
    $zenginDetails = null;
    foreach ($bankTransferDetails as $detail) {
        if ($detail['type'] === 'zengin') {
            $zenginDetails = $detail['zengin'];
            break;
        }
    }
```
これらの振込先情報を、Sessionに受け渡すことによって、カスタム支払い手順ページで表示させました。
```php
    session([
        'payment_intent' => $paymentIntent->id,
        'book_id' => $bookId,
        'zengin_details' => $zenginDetails,
    ]);
    return redirect()->route('instructions');
```

### コンビニ支払
#### PaymentIntentの作成
コンビニ決済にあたっては、`billing_details`に`name`と`email`が必要になります。
```php
$paymentIntent = PaymentIntent::create([
                'amount' => 1000,
                'currency' => 'jpy',
                'confirm' => true,
                'customer' => $customer->id,
                'payment_method_types' => ['konbini'],
                'payment_method_data' => [
                    'type' => 'konbini',
                    'billing_details' => [
                        'name' => $name, // 顧客の氏名
                        'email' => $email, // 顧客のメールアドレス
                    ],
                ],
                'metadata' => [
                    'book_id' => $bookId,
            ]);
```

### コンビニ支払い手順の表示
作成された`PaymentIntent`から、コンビニ支払い手順を取得します。
コンビニ支払の手順情報は、
`payment_intent->next_action`において下記のように格納されています。
```php
"next_action": {
    "konbini_display_details": {
      "expires_at": 1736348399, // 有効期限（Unixタイムスタンプ）
      "hosted_voucher_url": "https://xxx",
      "stores": {
        "familymart": {
          "confirmation_number": "00000000000",
          "payment_code": "000000"
        },
        "lawson" : //以下略
```

ビューにおいては、以下のようにして取得しました。
```php
// コントローラ
$konbiniDetails = $paymentIntent->next_action->konbini_display_details;
```
```php
// ビュー
$konbiniDetails->stores->familymart->payment_code;
$konbiniDetails->stores->familymart->confirmation_number;
```

## 参考
- [Stripe DOCS](https://docs.stripe.com/payments)
- [Stripe Billingを利用して銀行振込をサポートした定期購入サブスクリプションを管理する](https://qiita.com/hideokamoto/items/e03984b982574ab01c31)
- [Stripe Checkout / Elementsで、コンビニ決済のサポートを開始する３つの方法](https://qiita.com/hideokamoto/items/c59c4c4ee24b98ac997b)