Stripe Payment Elementを利用して、クレジットカード決済以外の決済方法に数行の変更で対応する

オンラインでの支払いには、クレジットカード以外の決済方法を利用することもすくなくありません。
日本であればコンビニ支払いや銀行振り込み、海外ではWeChat PayやSEPA Direct Debitなど、国や地域によって対応が必要な決済方法が異なります。

# Stripe Payment Elementが解決すること

Stripe Payment Elementを利用することで、「Stripeが対応している決済方法を、わずか数行のコード変更のみで全て提供」できるようになります。

https://stripe.com/docs/payments/payment-element

https://stripe.com/docs/payments/payment-card-element-comparison

![demo-element.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/96bc16ae-9f37-e091-79b2-65a75b6423e8.png)

# デフォルトでの表示

Elementで決済情報を入力するフォームを表示させる場合、まずはサーバー側で`PaymentIntent`を作成します。

```js
await stripe.paymentIntents.create({
  amount: 100,
  currency: 'jpy',
})
```

そして作成した値の`client_secret`を`@stripe/react-stripe-js`の`Elements`に渡してやると、決済フォームが表示されます。

```jsx
<Elements
  stripe={loadStripe(process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY}
  options={{
    appearance:{
      theme: 'stripe',
    },
    clientSecret: 'pi_xxxxx_xxxx_xxxx',
  }}>
  <PaymentElement />
</Elements>
```

標準では、クレジットカード入力画面だけが表示されています。

![スクリーンショット 0003-12-22 18.48.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/f1705909-37e3-3846-85e9-05b9a424b938.png)

# Stripe Payment Elementで、クレジットカード以外の決済方法をサポートする

ここからは、Stripe Payment Elementを使ってクレジットカード以外の決済方法を処理する方法を紹介します。

## 1:クレジットカード以外の決済方法を有効にする

クレジットカードとApple Pay / Google Pay以外の決済方法を有効にするには、Dashboardからの設定が必要です。

Dashboardの設定ページにある[支払い方法](https://dashboard.stripe.com/settings/payment_methods)から、サポートしたい決済方法を有効化しましょう。

![スクリーンショット 0003-12-22 18.53.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/ac527c52-9d29-e8f1-0354-a67ec6e05a10.png)


## 2: PaymentIntentのパラメータを変更する

続いてStripe Payment Elementで複数の決済方法を利用できるようにするフラグを、PaymentIntent経由で送るようにします。

作成する際のパラメータに`automatic_payment_methods[enabled]=true`をセットしましょう。

```diff_javascript
await stripe.paymentIntents.create({
  amount: 100,
  currency: 'jpy',
+  automatic_payment_methods: {
+    enabled: true,
+  },
})
```

これで「顧客がアクセスしてきた環境で、利用可能な決済方法」が自動的に表示されるようになります。

![demo-element.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/d292eb85-9181-6b95-99fc-060add55db56.png)


## 3: 支払いを確定する

最後にユーザーが選択・入力した支払い情報を利用して決済を行います。

`useStripe`と`useElements`を利用して決済処理を行うComponentを作成しましょう。

```jsx
const Payment: FC = () => {
  const stripe = useStripe();
  const elements = useElements();
  const submit = async () => {
    if (!stripe || !elements) return;
    const result = await stripe.confirmPayment({
      elements,
      confirmParams: {
        return_url: 'http://localhost:3000'
      }
    })
    console.log(result)
  }
  return (
    <form onSubmit={async e => {
      e.preventDefault()
      submit()
    }}>
        <PaymentElement />
        <button type="submit" style={{
          marginTop: '20px',
        }}>Submit</button>
    </form>
  )
}
```

`PaymentElement`をそのまま読み込んでいた部分を差し替えます。

```diff_javascript
<Elements
  stripe={loadStripe(process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY}
  options={{
    appearance:{
      theme: 'stripe',
    },
    clientSecret: 'pi_xxxxx_xxxx_xxxx',
  }}>
-  <PaymentElement />
+  <Payment/>
</Elements>
```

## 4:　動作確認
あとは実際にAlipayやWeChat Payでの決済を試してみましょう。

AlipayとWeChat Payでは、情報を入力する画面は表示されません。

![スクリーンショット 0003-12-22 19.05.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/ecb69bd3-e950-a9f0-642b-62be29046f7d.png)

formのSubmit操作を行い、決済処理を実行しましょう。

テスト（`pk_test`/`sk_test`を利用している）環境では、Stripeが用意しているテストページにリダイレクトされます。

![スクリーンショット 0003-12-22 19.07.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/6351d67f-a9b6-a6dc-9cf9-9141664b9fb5.png)

`Authorize test payment`をクリックすると決済が成功した扱いに、
`Fail test payment`をクリックすると、決済に失敗した扱いになります。

どちらかのボタンをクリックすると、`stripe.confirmPayment`の`return_url`で指定したURLにリダイレクトされます。

# Stripe Payment Elementの表示内容をカスタマイズする（決済方法編）

基本的な組み込み方法についてここまで紹介しました。
ここからは、表示する決済方法のカスタマイズなど、すこし応用的な使い方を紹介します。

## 特定の決済方法のみ対応する

商材やユーザー属性などに応じて、利用できる決済方法を変更したくなるケースもあります。
その場合は、PaymentIntentを作成する時に、「利用できる決済方法のリスト」を渡すようにしましょう。

```js
const intent = await stripe.paymentIntents.create({
  amount: 100,
  currency: 'jpy',
  payment_method_types: ['wechat_pay', 'alipay']
})
```

このサンプルコードでは、「WeChat PayもしくはAlipayのみ」利用できる決済画面が表示されます。

![スクリーンショット 0003-12-22 19.22.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/ae1875cc-3d60-53f3-a266-362ace38118b.png)

`payment_method_types`に渡す値については、以下の２ドキュメントをご確認ください。

https://stripe.com/docs/api/payment_methods/object#payment_method_object-type

https://stripe.com/docs/payments/payment-methods/integration-options

## どの決済方法が今選択されているかを取得する

選択された決済内容によって、テキストや表示を変更したい場合は、PaymentElementのchangeイベントを利用します。

```jsx
// Stripe JS SDKの場合
paymentElement.on('change', function(event) {
  console.log(event.value.type)
});

// @stripe/react-stripe-jsの場合
<PaymentElement onChange={e => {
  console.log(e.value.type)
}} />
```

決済方法のボタンや各種inputタグなど、なにか情報が変化した際にこのイベントは発火します。

`eps`や`card`など、PaymentIntentに渡した値と同じものが取得できますので、表示の変更などにお使いください。

## 決済方法の表示順序を変更する

Payment ElementのOptionを利用して、表示順序を変更することもできます。

`paymentMethodOrder`に、表示させたい順序で決済方法のコードを入力しましょう。

```jsx
<PaymentElement 
  options={{
    paymentMethodOrder: ['eps', 'card', 'p24', 'sofort'],
  }}
/>
```

![スクリーンショット 0003-12-22 19.49.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/d74692d9-4210-512c-5c2e-966e43f1989d.png)

`paymentMethodOrder`のリストに含まれなかった決済方法は、リストに記載された決済方法の後ろに表示されます。

## サービスごとの利用規約を簡易表示する

規約の表示ができる決済方法については、表示するかしないかの設定を個別に行うことができます。

デフォルトではすべて`auto`設定ですので、基本的には設定を省略して問題ありません。

```jsx
<PaymentElement 
  options={{
    business: {
        name: 'サンプル'
    },
    terms: {
        card: 'always',
        sofort: 'always',
        bancontact: 'auto',
        ideal: 'auto',
        sepaDebit: 'auto',
        auBecsDebit: 'auto',
        usBankAccount: 'auto',
    },
  }}
/>
```

![スクリーンショット 0003-12-22 19.53.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/931d710a-90a1-4471-1020-967c57ded9d8.png)

なお、`bussiness.name`を設定しない場合、Stripe Dashboardで設定したビジネス表示が自動で表示されます。

## Apple Pay / Google Payでの決済を行わない方法

特定の商品や顧客・ケースでApple Pay / Google Payの利用を停止したい場合、これもPayment Elementのoptionで設定できます。

```jsx
<PaymentElement 
  options={{
    wallets: {
        applePay: 'never',
        googlePay: 'never',
    }
  }}
/>
```

なお、こちらは`auto`または`never`で、`always`が存在しませんのでご注意ください。

# Stripe Payment Elementを利用して複数の決済方法に対応する際の注意点

最後に、実際に組み込むにあたって注意が必要な点をいくつか紹介します。

## 事前にアクションが必要な決済方法について
一部の決済方法は、事前に決済サービス会社による審査が必要です。  
[設定 > 支払い方法]ページで、`アクションが必要な支払い方法`に表示されている決済方法は、内容を確認して追加のアクションを完了させましょう。

![スクリーンショット 0003-12-22 19.13.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2366300/65b79ef8-9e04-d13c-5024-850e4a69e761.png)

## ローカル環境で、Apple Pay / Google Payが表示されない

Apple PayとGoogle Payは、`localhost`からのアクセスでは表示されません。
ブラウザの開発ツールでログを確認すると、以下のwarningが表示されています。

> If you are testing Apple Pay or Google Pay, you must serve this page over HTTPS as it will not work over HTTP. Please read https://stripe.com/docs/stripe-js/elements/payment-request-button#html-js-prerequisites for more details.

[ngrok](https://www.npmjs.com/package/ngrok)などを利用して、ドメインを設定するか、何かしらのサーバーにアップロードして動作確認をお願いします。

## PaymentIntent APIがエラーを出す

`payment_method_types`を利用している場合、以下のエラーに遭遇することがあります。


> StripeInvalidRequestError: The currency provided (eur) is invalid for one or more payment method types on this PaymentIntent. The payment method type wechat_pay only supports the following currencies: jpy, cny. Either correct the provided currency, or use a different PaymentIntent to accept this payment method type.

これはその通貨で利用できない（サポートされていない）決済方法をリストに含めた場合に表示されます。エラー文に決済方法のcodeと、対応している地域のリストが表示されていますので、確認して修正しましょう。

>  Error: The payment method type provided: klarna is invalid. This payment method is available to Stripe accounts in other countries but is not currently available your account's country, JP.

これはStripeアカウントを開設した地域でサポートしていない決済方法を設定した場合に表示されます。該当の決済方法をリストから削除しましょう。


# 参考URL
- https://stripe.com/docs/card-brand-choice
- https://stripe.com/docs/payments/payment-element
- https://stripe.com/docs/stripe-js/elements/payment-request-button
- https://stripe.com/docs/payments/payment-card-element-comparison


# [PR] Stripe開発者向け情報をQiitaにて配信中！
2021年12月よりQiitaにて、Stripe開発者のためのブログ記事更新を開始しました。

- [Stripe Updates]：開発者向けStripeアップデート紹介・解説
- ユースケース別のStripe製品や実装サンプルの紹介
- Stripeと外部サービス・OSSとの連携方法やTipsの紹介
- 初心者向けのチュートリアル(予定)

など、Stripeを利用してオンラインビジネスを始める方法について随時更新してまいります。