【Next.js】FirebaseでStripeの単発決済の実装
以前まとめたこちらの記事の続きとなります。
nekorokkekun.hatenablog.com
nekorokkekun.hatenablog.com
以前の段階で、StripeとFirestoreとFirebase Authenticationのユーザーを同時に作成することができました。
こちらの記事では、Next.js上にFirebaseでStripeの単発決済の実装を行っていきます。
図解
上記の仕組みを以下の流れで実装していきます。
- submitNewChargeというイベントを持った決済ボタン作成
- ボタンを押すとFirestore上に stripe_customers > user_id > charges に決済情報が記録される
- Firebase FunctionsのcreateStripeChargeが起動し、Stripe上に決済情報を送信
- Stripe上で決済が行われる
ユーザーが行うのはボタンのクリックだけとなります。
実装
決済ボタン作成
まずは「submitNewChargeというイベントを持った決済ボタン作成」を行います。
イベントは以下の通りです。
submitNewCharge = async (evt) => { evt.preventDefault(); await db.collection('stripe_customers') .doc(firebase.auth().currentUser.uid) .collection('charges') .add({ amount: 2000 }) }
また、ボタン自体は以下の通りです。
<button onClick={this.submitNewCharge}>決済</button>
amountを2000としていますが、実際には動的に商品の値段などをはめ込むシチュエーションが多いと思いますので、その場合は、以下のように記述しましょう。
submitNewCharge = async (evt) => { evt.preventDefault(); await db.collection('stripe_customers') .doc(firebase.auth().currentUser.uid) .collection('charges') .add({ amount: this.props.detail.monthlyFee }) }
createStripeChargeの作成
次にFirebase Functionsの作成を行います。
functions/index.js
exports.createStripeCharge = functions.firestore.document('stripe_customers/{userId}/charges/{id}').onCreate(async (snap, context) => { const val = snap.data(); try { // Look up the Stripe customer id written in createStripeCustomer const snapshot = await admin.firestore().collection(`stripe_customers`).doc(context.params.userId).get() const snapval = snapshot.data(); const customer = snapval.customer_id // Create a charge using the pushId as the idempotency key // protecting against double charges const amount = val.amount; const idempotencyKey = context.params.id; const charge = {amount, currency, customer}; if (val.source !== null) { charge.source = val.source; } const response = await stripe.charges.create(charge, {idempotency_key: idempotencyKey}); // If the result is successful, write it back to the database return snap.ref.set(response, { merge: true }); } catch(error) { // We want to capture errors and render them in a user-friendly way, while // still logging an exception with StackDriver console.log(error); await snap.ref.set({error: userFacingMessage(error)}, { merge: true }); return reportError(error, {user: context.params.userId}); } });
長いですが、要は「Firestoreの stripe_customers/{userId}/charges にドキュメントが作成されたら、その中から必要なデータを取得して、Stripeで決済処理をする」というだけです。
忘れずFunctionsをデプロイ しておきましょう。
$ cd functions $cd yarn deploy
確認
実装自体は以上で完了です。実際にページから動作の確認をしてみましょう。
ボタンを押すとFirestoreとStripeに反映されています。
Firestore
Stripe
ちなみに以前の記事でご紹介したクレジットカード登録処理していない状態で決済を行うと、Firestoreに以下のように反映されます。
クレジットカード登録時にsourceが生成され、sourceの紐付きがある状態でなければStripeでの決済はできないからです。
ちなみにこのようにFirestoreに反映された決済はStripeには表示されません。
以上で単発決済の実装は完了です。お疲れ様でした!