コミケ向けキャッシュレス決済システムをサンプル公開します


電子書籍販売開始記念、ということで、以前にも紹介したコミケに向けて作ったキャッシュレス決済システムを、今をときめくナウなヤングにバカウケなFirebaseを使ってWebで公開してみました。

KaiPay
https://myprofileproject-8580b.firebaseapp.com/

といっても実際に使える動作するようなシロモノではなく、「どんな動作をするか」というのを見るためだけのサンプルですが。

このキャッシュレス決済システムは、当日の頒布で使う予定だったキャッシュレス決済をせっかくだからシステム化しようという思いに加え、「この本を読めばこのくらいは作れる」というサンプルとしての意味もありました。そのためコードとしては無駄に長く力業でゴリ押ししているところも多いので公開するのはお恥ずかしいのですが、本書を手に取っていただいた方の参考に少しでもなるのなら幸いです。

ファイル一式ダウンロードはこちらからどうぞ。試行錯誤しながら作っていたので最終的に使ってないコードとかもありそうですがそのあたりは優しくスルーしていただければ幸いです。

また、このプログラムは「フルHDの縦表示でタッチ操作」、つまりはSurface Goの縦置きで利用することを前提とした画面UIなので、横画面だといろいろとおかしな挙動があります。詳細は後述しますが、限られたコードで実現しているので動作がおかしいところもある程度大目に見てくださいませ。

Surface Goの縦表示でぴったりサイズ
Surface Goの縦表示でぴったりサイズ

本書を読めばこのシステムの作り方は「ほぼ」わかるのですが、このエントリーにてシステムの補足もしておきます。

画面遷移はclassListで表示・非表示を切り替え

あの7payも活用したことでおなじみCSSのdisplay: noneをフル活用し、ひたすら長い1つのHTMLの中で該当の箇所をclassListで表示・非表示することで画面遷移をコントロール。最初に全部index.htmlで読み込んでいるので動作が早いという地味なメリットがあります。

頒布品の数量と価格はletで個別にカウント

すべての頒布品に+と−ボタンおよびletによる変数を個別に用意し、addEventListenerを使って+を押したらletに1を追加して冊数をカウント。間違って追加した時のために−も用意しておきつつ、操作性向上のために「画像をタップしても+」という仕様にしました。さらに合計金額を算出するためのletも別途用意しておき、+と−を押すたびに頒布品の価格を合計金額のletへ加減することで計算しています。

画像またはプラスマイナスボタンで品数をカウント
画像またはプラスマイナスボタンで品数をカウント

選択した内容を確認画面で表示

自分がどれを選んだか決済前に確認できるように、上記で用意した頒布品ごとの数をカウントするletが0でない場合はアイテム名をcreateElementで作成し、テンプレートリテラルを使って作品名と選択数量をliでリスト表示。最後に合計金額のletも表示しました。また、作品を1つも選んでいない場合は合計金額もゼロのはず、なので「合計金額のletが0だったらエラー表示」という画面をifで構成しました。

確認画面で選択数と合計金額を表示
確認画面で選択数と合計金額を表示

Math.randomで「20回に1回当たり」のラッキーチャンス

PayPayの仕組みが面白かったのでMath.randomを使って再現。とはいえこのシステムでは委託させていただいている鳴海製作所の頒布品も選べてしまうので、ifを使って「自分の本の数量が0でない時だけラッキーチャンスを発動」としつつ、Math.randomで1から20の数字を算出、「数字が1だったらラッキーチャンス」という仕組みで20回に1回を実現しました。

自分以外の作品を含んでいる場合は900円引き
自分以外の作品を含んでいる場合は900円引き

まあこれ、デバッグ用に確率を1/2にしていたにも関わらず直すのを忘れて当日販売してしまい、結果として「Kyashを選んだ人は1/2の確率で1冊無料」という地獄を見たわけですが……。

決済用QRは100円単位で画像を出力

「エンジニアはぜったいこんなの実装しない」というお褒めの言葉をいただいた本システムの見せ場。最初は単に決済サービスを選ぶだけだったのが、複数まとめて選びたいというニーズに対応するため金額も必要となり、とはいえ決済サービスのAPIを叩くような仕組みはコンセプトから外れるしそんな知識も無い。

よろしいそれならあとは実力行使だ、ということで、今回使ったKyash、PayPay、Pixiv PayそれぞれのQRコードを100円単位で1万円まで用意する、というジェバンニ並みの力業を発動。システム作るよりこっちのほうが大変だったかもしれない……。

Kyashの場合、金額ごとのURLは生成できるのですがQRは発行できないので、URLを金額分発行した上でそれをQRコード化。PayPayはQRに金額を設定できるので、1つずつ金額を設定した上で画面をキャプチャし、必要な部分だけを切り出し。Pixiv Payは決済だけでなくレジシステムも兼ねているので、金額ごと販売アイテムを作成し、その画像をキャプチャして切り出しました。また、表示金額にエラーがあったときのために、金額を好きに指定できるQRもサブで表示しています。

しかしこれまたサービスそれぞれ癖がありその対応も大変。Kyashの場合URLはバーコードリーダーアプリから読み取る必要があり、Kyash内のQRコードリーダー機能だとエラーになってしまう。PayPayはもっとめんどくさくて、作成したQRコードが一定時間経つと無効になることに気がつき、24時間は大丈夫そうだという手応えから当日の朝出力して対応しました。そういやこの件、PayPayのサポートがまだ返事くれないな。

QRは2段階表示

プログラムで計算した金額に加えて、万が一計算が間違っていた時にすぐ対応できるよう、金額が入ってないQRも表示する2段階設計にしました。ただこれも問題があって、Pixiv Payはアイテム販売のための仕組みなので「好きな金額を指定できる」という機能がないんですよね……。仕方ないのでPixiv Payでは画面下部に「うまくいかない時は売り子に伝えてね」という文章を入れて対応しました。とはいえ当日少なからずキャッシュレス決済を選んだ人がいた中でもPixiv Payを選んだ人はゼロだったので結果オーライ的に助かったのですが。

上は金額入り、下は金額なしのQR
上は金額入り、下は金額なしのQR

location.reload();でリセット

一度キャッシュレスで決済した後、次の人のための初期化をするためにlocation.reload();でリセット。これ、本書では触れていないのでなんとかこれを使わず実現したかったのですが、実現方法はあるものの恐ろしく面倒になりそうだったので、時間が迫っていることもあり泣く泣く使ってしまいました。addEventListenerの中に location.reload();って書くだけなので許して……。

TOPページを下にスクロールするとリセットボタンがお目見え
TOPページを下にスクロールするとリセットボタンがお目見え

また、単にlocation.reload();だけだとページの位置もそのままなため、画面をスクロールしていた場合はそのスクロールした位置でトップに戻ってしまうため、正しい表示にならないという問題があります。

画面をスクロールした状態でリセットするとTOPが正しい位置で表示されない
画面をスクロールした状態でリセットするとTOPが正しい位置で表示されない

ただ画面をスクロールするのはリセットや後述する緊急対応のみで基本的には自分しか操作しないこと、リセットでTOPに戻るという仕組みは、本に書いていない内容をさらに深掘りしてしまうということで今回は泣く泣く割愛しました。繰り返しですが横画面だとリセット押した時の挙動が微妙ですが、基本的に縦画面で使うためのシステムなのでご了承ください。

決済がうまくいかない時の緊急避難ページ

金額エラーが出た時のために、金額を自分で指定できるQRだけが貼ってあるHTMLを作成、画面の一番下から飛べるようにしておきました。前述の通りPixiv Payは金額を指定できるQRがないので、緊急避難で表示できるQRもKyashとPayPayのみです。

KyashとPayPayのQRを表示した緊急避難ページ
KyashとPayPayのQRを表示した緊急避難ページ

システムの説明としてはこんなところかな。繰り返しながらとても稚拙なコードで無駄に長いのですが、初心者に大事なのはきれいなコードを書くことより「自分の持っている知識の中でなんとかする力」だと思っているので、本書1冊読めばこのくらいできるんだ! という参考になったらいいなという宣伝エントリーでした。

本書のご購入はこちらからどうぞ。

Amazon.co.jp: ゲーム脳で楽しむプログラミング: 初心者が捧ぐ超初心者向けのJavaScript入門書 eBook: カイ士伝: Kindleストア
https://www.amazon.co.jp/dp/B07XGCNV3R?tag=kai4den-22

ゲーム脳で楽しむプログラミング – 実用、同人誌・個人出版 カイ士伝(カイ士伝):電子書籍試し読み無料 – BOOK☆WALKER –
https://bookwalker.jp/def1a25255-0d2d-40d3-9c54-aa39096196b9/


コメントを残す

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください