この記事は、kintoneアドベントカレンダー3日目の記事です。
kintoneでは、JavaScriptを利用してアプリの表示や動作を拡張・カスタマイズすることができる、拡張機能機能が用意されています。
拡張機能は、kintoneのスタンダードコースから利用できますが、動作確認や拡張機能の開発などの目的などであれば、開発者ライセンスを利用して無料で試すこともできます。
kintoneアプリに、決済フォームを直接組み込む
kintoneはJavaScriptでアプリの機能や表示をカスタマイズできます。そしてStripeでは、JavaScriptで決済フォームを表示するSDK(@stripe/stripe-js)を提供しています。
ということは、実装方法さえわかれば、プラグインを利用して、kintoneアプリ内にStripeが用意する決済フォームを埋め込むことも可能です!
今回の記事では、kintoneプラグインで、Stripeの決済フォームを表示する方法を紹介します。
kintoneプラグインで、Stripeの決済フォームを表示・動作させる4STEP
プラグインにStripeを組み込むには、次の4ステップが必要です。
まず、「決済フォームを表示させる場所」をアプリ内に用意しましょう。ここではkintone UI Componentライブラリを利用して、ダイヤログを表示させます。
続いてStripe APIをよびだし、決済処理に必要なリソース(Payment Intent)を生成します。
3つ目のステップで、Stripe ElementsをStripeのJavaScript SDKで表示させます。ここではフォームの表示のみですので、実際に決済処理などはまだ行われません。
最後のステップで、生成したPayment IntentとStripe Elementsの情報を利用し、決済を実施します。
それでは、一つずつ見ていきましょう。
Step1: 決済フォームを表示するダイヤログを作成する
まずは決済フォームを表示させる場所の用意です。直接埋め込んでも良いのですが、今回はダイヤログに表示させましょう。
import { Button, Dialog } from "kintone-ui-component";
const PLUGIN_ID = kintone.$PLUGIN_ID;
kintone.events.on("app.record.index.show", function () {
const spaceElement = kintone.app.getHeaderSpaceElement();
if (spaceElement === null) {
throw new Error("The header element is unavailable on this page");
}
const buttonElement = new Button({
text: "決済フォームを表示",
type: "submit",
});
buttonElement.addEventListener("click", async function () {
const paymentElementPlaceholder = document.createElement("div");
paymentElementPlaceholder.id = "payment-element";
const dialog = new Dialog({
title: "Payment form",
content: paymentElementPlaceholder,
});
dialog.open();
});
spaceElement.appendChild(buttonElement);
});
kintone UI ComponentのButton
で「ダイヤログ表示ボタン」を、Dialog
で「ダイヤログそのもの」を実装しました。
コードをデプロイすると、プラグインを登録したアプリ(今回は見積書)の一覧画面に、[決済フォームを表示]ボタンが表示されます。
Button
要素にaddEventListener
でクリックイベントを設定しています。その中でダイヤログ要素の作成と表示を行っているため、追加されたボタンをクリックすることで、ダイヤログが開きます。
Step2: kintone API Proxyを利用して、Stripe APIを呼び出す
決済フォームを表示する場所が用意できましたので、続いて決済処理に必要な情報をStripeで生成しましょう。
Stripeでは、決済を行うためのリソースとして「Payment Intent API」が用意されています。このAPIを利用して、クレジットカード / Apple Pay / Google Payなどのさまざまな支払い手段をサポートした決済フローを実装します。
StripeのシークレットAPIキーを安全に保存する
このAPIを利用するために、Stripeが発行するシークレットAPIキーを利用する必要があります。安全にシークレットAPIキーをkintone内で取り扱うための、「APIプロキシー機能」の設定方法などについては、以下の記事をお読みください。
今回は次のようなAPIキー入力フォームと、保存処理を追加しています。
<section class="settings">
<h2 class="settings-heading">Stripe API連携</h2>
<p class="kintoneplugin-desc">Stripeと連携するためのAPIキーを設定します</p>
<form class="js-submit-settings" id="js-submit-settings">
<p class="kintoneplugin-row">
<label for="message">
Secret API KEY:
<input type="text" id="stripe-secret-api-key" class="js-text-message kintoneplugin-input-text">
</label>
</p>
<p class="kintoneplugin-row">
<button type="button" class="js-cancel-button kintoneplugin-button-dialog-cancel">Cancel</button>
<button class="kintoneplugin-button-dialog-ok" id="plugin-submit">Save</button>
</p>
</form>
</section>
const PLUGIN_ID = kintone.$PLUGIN_ID;
const form = document.querySelector(".js-submit-settings");
const cancelButton = document.querySelector(".js-cancel-button");
const messageInput =
document.querySelector<HTMLInputElement>(".js-text-message");
if (!(form && cancelButton && messageInput)) {
throw new Error("Required elements do not exist.");
}
form.addEventListener("submit", (e) => {
e.preventDefault();
const secretAPIKeyField = document.getElementById("stripe-secret-api-key");
if (!secretAPIKeyField) return;
const secretAPIKeyFieldValue = secretAPIKeyField.value;
if (!secretAPIKeyFieldValue) return;
const stripeAPIUrl = "https://api.stripe.com/v1";
const requestHeader = {
Authorization: `Bearer ${secretAPIKeyFieldValue}`,
};
kintone.plugin.app.setProxyConfig(stripeAPIUrl, "GET", requestHeader, {});
kintone.plugin.app.setProxyConfig(
stripeAPIUrl,
"POST",
{
...requestHeader,
"Content-Type": "application/x-www-form-urlencoded",
},
{}
);
alert("Saved");
});
cancelButton.addEventListener("click", () => {
window.location.href = "../../" + kintone.app.getId() + "/plugin/";
});
保存したAPIキーを利用したAPIリクエストを作成する
APIキーを利用できるようになりましたので、支払いを処理するためのデータ(Payment Intent)を作成しましょう。
決済フォームを表示
ボタンを作成していますので、このボタンをクリックした際に、StripeのAPIを呼び出してPayment Intentを作成します。
const buttonElement = new Button({
text: "決済フォームを表示",
type: "submit",
});
buttonElement.addEventListener("click", async function () {
+ const paymentIntentRequest = new URLSearchParams("");
+ paymentIntentRequest.set("amount", "1000");
+ paymentIntentRequest.set("currency", "jpy");
+ const paymentIntent = await new Promise((resolve, reject) => {
+ kintone.plugin.app.proxy(
+ kintone.$PLUGIN_ID,
+ "https://api.stripe.com/v1/payment_intents",
+ "POST",
+ {},
+ paymentIntentRequest.toString(),
+ (response) => {
+ const result = JSON.parse(response);
+ resolve(result);
+ },
+ (e) => reject(e)
+ );
+ });
const paymentElementPlaceholder = document.createElement("div");
paymentElementPlaceholder.id = "payment-element";
const dialog = new Dialog({
title: "Payment form",
content: paymentElementPlaceholder,
});
dialog.open();
});
StripeのAPIをkintoneのproxyで呼び出す場合、リクエストの本文(body)はURLSearchParams
を利用して設定します。下にリクエスト内容を設定している部分のコードだけピックアップしました。
const paymentIntentRequest = new URLSearchParams("");
paymentIntentRequest.set("amount", "1000");
paymentIntentRequest.set("currency", "jpy");
このコードでは、「価格(amount
)が1000
」「通貨(currency
)がjpy
」のPayment Intentを作成しています。
どのようなデータが生成されるかを確認したい場合、Dialog
要素のcontent
を次のように変更してみましょう。
const dialog = new Dialog({
title: "Payment form",
content: paymentElementPlaceholder,
content: JSON.stringify(result, null, 2),
});
kintoneアプリでボタンをクリックすると、次のようなJSONを表示するダイアログが確認できます。
Step3: Stripe Elementsで、決済フォームを表示する
ここからは、StripeのJavaScript SDKを利用して決済フォームを埋め込みましょう。
決済フォームを表示するには、StripeのJavaScript SDKを利用します。npmコマンドでライブラリをインストールしましょう。
% npm i @stripe/stripe-js
loadStripe
関数を利用しますので、インポートします。
import { Button, Dialog } from "kintone-ui-component";
+import { loadStripe } from "@stripe/stripe-js";
その後、Payment Intentを作成した処理の後に、インポートしたloadStripe
を呼び出しましょう。
const paymentIntent = await new Promise((resolve, reject) => {
kintone.plugin.app.proxy(
kintone.$PLUGIN_ID,
"https://api.stripe.com/v1/payment_intents",
"POST",
{},
paymentIntentRequest.toString(),
(response) => {
const result = JSON.parse(response);
resolve(result);
},
(e) => reject(e)
);
});
+ const stripe = await loadStripe(
+ "pk_test_から始まる、Stripeの公開可能キーを設定する"
+ );
+ if (!stripe) throw new Error("Failed to load Stripe client");
const paymentElementPlaceholder = document.createElement("div");
JS SDKのセットアップをloadStripe
で行いますので、セットアップに失敗した場合(戻り値がnull
の場合)用の処理も入れておきましょう。
Stripeの公開可能キーは、プラグインの設定情報に保存しよう
今回は便宜上プラグインコードに直接、Stripeの公開可能キーを記述しました。
しかしkintoneでは、プラグインごとに設定情報を保存する機能が用意されています。
実際の案件やプラグイン開発では、kintone.plugin.app.setConfig
を利用しましょう。
https://cybozu.dev/ja/kintone/docs/js-api/plugins/set-config/
セットアップに成功した後は、決済フォームを表示する処理を追加します。
if (!stripe) throw new Error("Failed to load Stripe client");
const paymentElementPlaceholder = document.createElement("div");
paymentElementPlaceholder.id = "payment-element";
const dialog = new Dialog({
title: "Payment form",
content: paymentElementPlaceholder,
});
dialog.open();
+ const elements = stripe.elements({
+ clientSecret: paymentIntent.client_secret,
+ appearance: {
+ theme: "stripe",
+ },
+ });
+ const paymentElement = elements.create("payment", {
+ layout: {
+ type: "accordion",
+ defaultCollapsed: false,
+ radios: false,
+ spacedAccordionItems: true,
+ },
+ });
+ paymentElement.mount("#payment-element");
Stripeでは、「すでにあるHTML要素に、決済フォームをマウントする」形で決済フォームを埋め込みます。そのため、mount()
関数はdialog.open()
処理を実行してから呼びだすようにしましょう。
変更をデプロイすると、ボタンをクリックした際のダイアログに、決済フォームが表示されます。
Step4: 決済を完了させよう
最後に、決済フォームに入力されたカード情報などを利用して、決済を完了させる処理を作りましょう。
まずは、注文操作を行うためのボタンをダイアログに追加します。
+ const paymentFormButton = new Button({
+ text: "注文する",
+ type: "submit",
+ });
const paymentElementPlaceholder = document.createElement("div");
paymentElementPlaceholder.id = "payment-element";
const dialog = new Dialog({
title: "Payment form",
content: paymentElementPlaceholder,
+ footer: paymentFormButton,
});
dialog.open();
追加したボタンのクリックイベントを設定しましょう。
dialog.open();
paymentElement.mount("#payment-element");
+ paymentFormButton.addEventListener("click", async () => {
+ const confirmResult = await stripe.confirmPayment({
+ elements,
+ redirect: "if_required",
+ });
+ console.log(confirmResult);
+ alert(`決済を完了しました。決済ID: ${confirmResult?.paymentIntent?.id}`);
+ dialog.close();
+ });
決済フォームの動作を確認するには、ドキュメントに公開されている「テスト用カード番号」を利用します。
テスト用のカード情報をフォームに入力し、注文ボタンをクリックしてみましょう。
処理に成功した場合、決済成功のメッセージが表示され、ダイアログが閉じられます。
これでkintoneアプリ内に、決済フォームを埋め込む作業が完了です。
終わりに
kintoneはJavaScriptを利用してアプリをカスタマイズできます。そのため、StripeのJavaScript系SDKと、APIを利用することで、決済や請求業務に関するカスタマイズや自動化も、kintone上で行うことが可能です。
特にkintoneでは、ゲストユーザー向けのスペースを用意することもできます。そのため、ゲストユーザーがアプリ内で注文や決済を行えるようなシステムを作りたい場合、今回のような決済フォームを埋め込む実装が役に立ちます。
そのほかにも、請求書処理や、支払いリンクの作成など、様々な連携サンプルについても紹介しています。
こちらも併せてごらんください。