Node-REDでLINE Payを使ったデジタルお賽銭botを作ってみた

2021/12/24に公開

LINE DCAdvent Calendarもついに最終日です!

最終日は2本立てで書きました。

もう一本はアップデートしたLIFFのSDKでQRコードリーダーを紹介しているので、そちらもよかったらぜひご覧ください。

https://zenn.dev/kmiura55/articles/liff-qr-code-reader-vuejs

先日、LINE DCの忘年会LTにてNode-REDでLINE Payを使えるようにするオリジナルノードを公開した話をしました。

その時のスライドはこちら

このスライドでの予告通り、今回はNode-REDでLINE Payを使って決済機能をLINE botに実装する方法を紹介します。

クリスマス真っ只中ですが、メターバース(?)な初詣をテーマにスマホでお賽銭をする仕組みをLINEでやってみたらというテーマで作ってみたいと思いますw

事前準備

今回はIBM CloudでNode-REDの実行環境を構築する例を紹介します。

Node-REDが動けばお好みの環境で構築してもらってOKです。

IBM Cloudのアカウントを以下のURLから作成します(アカウント作成にはクレジットカードを使用した本人確認が必要です)。

https://cloud.ibm.com/registration

環境構築(IBM Cloudの例)

Node-REDのセットアップ

IBM Cloudのアカウントにログインしたら、画面上部のリソース検索画面からNode-REDと検索して表示される「Node-RED App」を選択します。

アプリの作成画面が表示されるので、作成タブをクリックします。

作成画面ではアプリ名を必要に応じて好きな名前に設定します。アプリ名はそのままURLに使われるのでユニークな名前に設定する必要があります(ユニークじゃないときは作成時にエラーになります)。

他の設定はデフォルトのままでOKです。

最後に作成ボタンをクリックします。

しばらくするとCloudant(Node-REDで使うデータベース)のプロビジョニングが行われるので完了するまで待ちます。

プロビジョニングが完了したらデプロイメントの自動化の項目にあるアプリのデプロイをクリックします。

以下の画面が表示されますので、デプロイメントの自動化無料枠でも使えるCloud Foundryを選択します。

IBM Cloud API 鍵新規をクリックして作成します。

API鍵の作成のときに以下のダイアログが表示されたら特に何も設定せずにOKをクリックします。

画面の下部にある次へボタンをクリックします。

DevOpsツールチェーンの詳細設定がありますが、ここも特に設定はなしで作成ボタンをクリックします。

作成完了してデプロイメントのパイプラインが実行されます。ci-pipelineをクリックすると別タブでデプロイの進行状況を確認できます。実行が完了すると左上のアプリURLが表示されたら環境構築が完了です。

Node-REDの設定

最初にアプリURLを開くと以下のようにWelcome画面が表示されるので、Nextをクリックします。

Node-REDのログイン情報を登録します。登録しないという選択肢もありますが、何も設定しないと誰でもフローが編集される上、今回のようにAPIを扱うノードだと簡単にアクセストークンがバレてしまうので、必ず登録しておきましょう。

またAllow anyonw to view the editor, but not make any changesはフローは誰でも閲覧できますが、編集をするためにはログインするというオプションです。

拡張ノードのインストール方法に関する説明が書かれています。この後の手順でも解説しますのでここではNextをクリックします。

最後にNode-REDの環境変数の設定について説明があるので、確認してFinishをクリックします。

完了後にNode-REDにログインして以下のようなフローエディタが表示されたらNode-REDの設定は完了です。

ノードのインストール

Node-REDの実行環境を構築したところで、今回使用するノードをインストールします。

Node-REDのフローエディタから右上のハンバーガメニューから パレットの管理を選択します。

ノードを追加タブから以下のノードを検索、インストールします。

  • node-red-contrib-line-pay
  • node-red-contrib-line-messaging-api

フローのコピー

インストールしたところで、今回使用するフローを用意します。

以下のJSONをコピーして、Node-REDのフローエディタの右上のハンバーガーメニューから 読み込みを選択します。

[{"id":"c9ac6da.8acb79","type":"tab","label":"お賽銭ボット","disabled":false,"info":""},{"id":"58111ba3.325234","type":"http in","z":"c9ac6da.8acb79","name":"","url":"callback","method":"post","upload":false,"swaggerDoc":"","x":120,"y":100,"wires":[["c8c6a378.8cccb","b9005e4b.5e7dd"]]},{"id":"20a15ce9.34b624","type":"http response","z":"c9ac6da.8acb79","name":"","statusCode":"","headers":{},"x":520,"y":80,"wires":[]},{"id":"544d0c5a.a6a174","type":"ReplyMessage","z":"c9ac6da.8acb79","name":"","replyMessage":"","x":1020,"y":180,"wires":[]},{"id":"c8c6a378.8cccb","type":"switch","z":"c9ac6da.8acb79","name":"","property":"payload.events","propertyType":"msg","rules":[{"t":"empty"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":310,"y":100,"wires":[["20a15ce9.34b624"],["fd958718.a8f038"]]},{"id":"b9005e4b.5e7dd","type":"debug","z":"c9ac6da.8acb79","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":194,"y":160,"wires":[]},{"id":"fd958718.a8f038","type":"switch","z":"c9ac6da.8acb79","name":"","property":"payload.events.0.message.text","propertyType":"msg","rules":[{"t":"eq","v":"支払い","vt":"str"},{"t":"else"}],"checkall":"true","repair":false,"outputs":2,"x":390,"y":160,"wires":[["9ef5ffb5.21132"],["544d0c5a.a6a174"]]},{"id":"9ef5ffb5.21132","type":"change","z":"c9ac6da.8acb79","name":"","rules":[{"t":"set","p":"payload.events.0.message.type","pt":"msg","to":"flex","tot":"str"},{"t":"set","p":"payload.events.0.message.altText","pt":"msg","to":"奉納お願いします","tot":"str"},{"t":"set","p":"payload.events.0.message.text","pt":"msg","to":"{\"type\":\"bubble\",\"direction\":\"ltr\",\"header\":{\"type\":\"box\",\"layout\":\"vertical\",\"contents\":[{\"type\":\"spacer\"}]},\"hero\":{\"type\":\"image\",\"url\":\"https://1.bp.blogspot.com/-lahlkRgDJn4/Wjnwx_ibCxI/AAAAAAABI1s/uOO0UrjRAqYdRj79P6gC0WezeLFsw388ACLcBGAs/s180-c/saisenbako_denshi_smartphone.png\",\"size\":\"full\",\"aspectRatio\":\"1.51:1\",\"aspectMode\":\"fit\"},\"body\":{\"type\":\"box\",\"layout\":\"vertical\",\"contents\":[{\"type\":\"text\",\"text\":\"奉納お願いします\",\"align\":\"center\",\"contents\":[]}]},\"footer\":{\"type\":\"box\",\"layout\":\"horizontal\",\"contents\":[{\"type\":\"button\",\"action\":{\"type\":\"uri\",\"label\":\"LINE Payでお支払い\",\"uri\":\"https://linecorp.com\"},\"color\":\"#1FF036FF\",\"style\":\"primary\"}]}}","tot":"json"},{"t":"set","p":"hookEvent","pt":"msg","to":"payload","tot":"msg"},{"t":"set","p":"payload","pt":"msg","to":"{\"amount\":100,\"currency\":\"JPY\",\"orderId\":\"\",\"packages\":[{\"id\":\"package-999\",\"amount\":100,\"name\":\"LINE神社\",\"products\":[{\"id\":\"product-001\",\"name\":\"お賽銭\",\"imageUrl\":\"https://www.linefriends.jp/m/img/ic-brown_00_v03.7d3c4e0d.png\",\"quantity\":1,\"price\":100}]}],\"redirectUrls\":{\"confirmUrl\":\"\",\"cancelUrl\":\"\"},\"options\":{\"payment\":{\"payType\":\"PREAPPROVED\"}}}","tot":"json"}],"action":"","property":"","from":"","to":"","reg":false,"x":540,"y":120,"wires":[["4029fe47.5344f"]]},{"id":"4029fe47.5344f","type":"function","z":"c9ac6da.8acb79","name":"リクエストパラメータの用意","func":"// Node-REDのURL(自分のものに書き換える)\nvar appUrl = \"\";\nvar userId = msg.hookEvent.events[0].source.userId;\nmsg.payload.redirectUrls.confirmUrl = `${appUrl}/confirm_offering/${userId}`;\nmsg.payload.redirectUrls.cancelUrl = `${appUrl}/cancel`;\n\n// orderIdの定義(ユニークな値である必要があるためここで設定する)\nmsg.payload.orderId = `LS_${new Date().getTime()}`;\nreturn msg;","outputs":1,"noerr":0,"x":760,"y":120,"wires":[["68b01b1.a8536e4"]]},{"id":"68b01b1.a8536e4","type":"Request","z":"c9ac6da.8acb79","name":"","linepayConfig":"","x":980,"y":120,"wires":[["5773410a.e7014"]]},{"id":"f0228d6d.1081","type":"http in","z":"c9ac6da.8acb79","name":"","url":"confirm_offering/:userId","method":"get","upload":false,"swaggerDoc":"","x":160,"y":280,"wires":[["c440e6df.5d3f48"]]},{"id":"2aef75b9.62149a","type":"http response","z":"c9ac6da.8acb79","name":"","statusCode":"","headers":{},"x":870,"y":280,"wires":[]},{"id":"813f06b8.63e708","type":"template","z":"c9ac6da.8acb79","name":"","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"<head>\n    <link href=\"https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css\" rel=\"stylesheet\" integrity=\"sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC\" crossorigin=\"anonymous\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n</head>\n<body>\n    <h1>奉納完了</h1>\n    <p>orderId: {{ payload.info.transactionId }}</p>\n    <img width=200 src=\"https://1.bp.blogspot.com/-rNHLEYba6no/Wj4InHuNzUI/AAAAAAABJN4/_VlYonboxTMLc6rCg4IA6R0m_OvdvVwRgCLcBGAs/s800/omairi_family_kimono.png\">\n</body>\n","output":"str","x":720,"y":280,"wires":[["2aef75b9.62149a"]]},{"id":"c440e6df.5d3f48","type":"change","z":"c9ac6da.8acb79","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\"amount\":100,\"currency\":\"JPY\"}","tot":"json"},{"t":"set","p":"transactionId","pt":"msg","to":"req.query.transactionId","tot":"msg"},{"t":"set","p":"userId","pt":"msg","to":"req.params.userId","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":380,"y":280,"wires":[["162cf4a7.903f8b"]]},{"id":"162cf4a7.903f8b","type":"Confirm","z":"c9ac6da.8acb79","name":"","linepayConfig":"","x":560,"y":280,"wires":[["813f06b8.63e708","b3d7495.ba858b8"]]},{"id":"5773410a.e7014","type":"function","z":"c9ac6da.8acb79","name":"返信用メッセージの作成","func":"var resBody = msg.payload;\nmsg.payload = msg.hookEvent;\nmsg.payload.events[0].message.text.footer.contents[0].action.uri = resBody.info.paymentUrl.web; \nreturn msg;","outputs":1,"noerr":0,"x":1190,"y":120,"wires":[["544d0c5a.a6a174"]]},{"id":"b3d7495.ba858b8","type":"function","z":"c9ac6da.8acb79","name":"支払い完了メッセージの作成","func":"var accessToken = \"YOUR_ACCESS_TOKEN\"\n// ヘッダーを設定\nmsg.headers = {};\nmsg.headers[\"Content-Type\"] = \"application/json\";\nmsg.headers[\"Authorization\"] = `Bearer ${accessToken}`;\n\n// 送信するメッセージを定義\nmsg.payload = {\n    \"to\": msg.userId,\n    \"messages\":[\n        {\n            \"type\":\"text\",\n            \"text\":\"ようこそお参りくださいました\"\n        },\n        {\n          \"type\": \"sticker\",\n          \"packageId\": \"6136\",\n          \"stickerId\": \"10551380\"\n        }\n    ]\n}\nreturn msg;","outputs":1,"noerr":0,"x":560,"y":340,"wires":[["4e9a4026.5a1cf"]]},{"id":"4e9a4026.5a1cf","type":"http request","z":"c9ac6da.8acb79","name":"","method":"POST","ret":"obj","paytoqs":false,"url":"https://api.line.me/v2/bot/message/push","tls":"","persist":false,"proxy":"","authType":"","x":790,"y":340,"wires":[["592b7839.bfb118"]]},{"id":"592b7839.bfb118","type":"debug","z":"c9ac6da.8acb79","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":970,"y":340,"wires":[]}]

各認証情報の設定

これでフローは用意できましたが、必要なAPIキーがまだ設定されてないので、それぞれ設定していきます。

LINE Payの設定

まずはLINE Payの設定を行います。

Requestノードをダブルクリックすると、以下のようにノードの設定画面が開きます。

Configの項目の右端にある鉛筆マークをクリックします。

以下の画面が出るので、それぞれ設定していきます。

設定項目に書く内容はドキュメントを参照してください。

LINE bot(Messaging API)の設定

それではMessaging APIの設定を行います。

LINE Developerコンソールにログインして、Messaging APIのチャネルを作成します。

その後チャネルシークレットとアクセストークンを取得します。

ReplyMessageノード

ReplyMessageノードをダブルクリックして設定画面を開いたら先程メモしたチャネルシークレットとアクセストークンを設定します。

Functionノード

続いてFunctionノードの中で支払い完了メッセージの作成と書かれたノードをダブルクリックしてコードの編集画面を開きます。

コードの1行目のアクセストークンをご自分のものに書き換えます。

var accessToken = "YOUR_ACCESS_TOKEN";

なぜPushMessageノードがあるのにわざわざFunctionノードを使用しているかというと、PushMessageノードでは送信先のUserIDを予め決め打ちでやる必要があるため特定のユーザーにしかメッセージが送れないので不採用となりました(いつか修正してPR出そうと思います)。

動かしてみる

それでは一通り準備出来たところで動作確認です。動作確認の前にフローエディタの右上のデプロイボタンがグレーじゃなかった場合は、デプロイボタンを押して変更を適用しておきます。

その後ボットを友だち追加して、「支払い」というテキストを送信してみます。

すると、以下のように支払いするようにFlexメッセージが表示されるのでボタンを押して決済を始めます。

ボタンをタップすると、自動ログインして以下の決済画面が表示されます。

PAY NOWボタンをクリックして、決済を完了させます。

決済が完了するとこんな感じでメッセージとスタンプが表示されます。

一通り動かすとこんな感じで動きます

https://twitter.com/k_miura_io/status/1473662943317598209

おわりに

今回はNode-REDとLINE Payを使ってお賽銭ボットを作成しました。

いらすとやでなんとなく徘徊していたらいい感じのイラストを見つけて今回のネタを思いつきましたw。

改めてNode-REDで実装してみると「LINE Payってこんな簡単に使えてしまうんだ」と感心しました。

今回は超簡単にLINE botにLINE Payを組み込むサンプルとして紹介しましたが、応用すればモバイルオーダーも実装できると思うので、ぜひ色々作ってみましょう。

それではよいお年を!

Discussion