💰

NFCカードを使ったPayPayの簡易決算システム

2023/11/17に公開

概要

イベントを企画した時、現金集金がめんどくさい!できれば全部電子決算したい!でも外部サービスを利用するにはコストがかかる。そんな時、PayPayで集金ができることを知り目からウロコでした。一方で、人によって金額が異なる場合に金額設定をしないと確認作業が増えるじゃないか! etc...と微妙に不便さを感じました。この少しの不便さを埋めるためにPayPay+NFCカード+Python+PHPを利用したシステムを作りました。限定的な使い方ですが、誰かのお役に立てば嬉しいです。

対象

  • PythonでNFCカードを扱うプログラムに興味がある人。
    • この部分の内容がメインかなと思います。
    • 今回はNFCを使っていますがQRコードをカメラで読み込む仕様へも応用できます。その場合コスト0です。
  • 現金集金に同じお悩みを抱えている人。

必要なもの

  • 空のNFCカード or NFCタグ
  • NFCの書き込みソフト(NFC Tools)
  • スマホ
  • PaSoRiリーダー
    • SONY RC-S380/Pを使っています。もともと持っていたので初期投資0円。
    • Mac非対応となっていますが、Python(nfcpy)で動かす場合は使えます。
    • 逆にRC-S300はMacに対応ですが、nfcpyに非対応です。
  • PC
    • Pythonが動けばなんでもいけるはずですが、Window+WSLだとPaSoRiを接続する時とwebbrowserモジュール周りで”?”が連発したのでMacにしました。
  • PayPay
    • 決算用のQRコードを発行するために使います。
  • オプション:適当なサーバー
    • PHPが動けばなんでも問題ありません。
    • 今回JSONファイルを使うのでデータベースは必要ありません。
    • もしかしたら本システムのソースをコピぺして使ってしまうと。無料サーバーなどで広告がつく場合にHTMLスタイルが崩れるかもしれません。その場合は修正してご利用いただければと思います。
  • 開発環境
    • Pythonはvenvで環境構築しています。
    • venvが入っていない場合は使わないか、入れるかしていただければと思います。
      • 依存はrequirements.txtに書いています。
    • PHPはローカルの開発環境を用意することをサボり、いきなり本番用サーバーで動かしました。

仕組み

仕組みはすごく単純です。PCでNFCカードに書き込まれているIDをPythonで読み取り、DBに保存している金額情報を取得。それに応じたPayPayの送金QR画像を読み出して画面に表示するだけです。

  • ローカルのディレクトリ構造(Python)
/ 
├- requirements.txt
└- main.py
  • サーバーのディレクトリ構造(PHP)
/ 
├- index.php
├- model.php
├- page.php
├- style.css
├- /image
|  ├- fin.png
|  ├- img
|  | └- 1001.png	
|  ├- paypay
|  | └- 0.png
|  └- cash
|    └- 0.png
└- /json
   └-db.json
  • 今回サーバーを使っている理由は、集金の状況をスマホから複数人で確認したかったからです。そのようなニーズがなければサーバー分は不要になります。
  • image/card/1001.png前回の記事でつくったカードを配置します。

ファイルの内容

  • 全体のコードはGithubにおいてあります。

https://github.com/kakera-lab/nfc_payment

  • main.py:NFCを読み込み、Webページにアクセルする処理までを書く。
  • index.php : アクセスするページで、行う処理を決める条件分岐を書く。
  • page.php:ページの見た目(HTML)を作るコードを書く。
    • Viewクラスとして実装。
  • model.php:各種処理の中身のコードを書く。
    • APIクラスとして実装。
  • style.css:ページの見た目(CSS)を書く。

支払い用画像を作る。

  • iPhone版のPayPayで送金QRを発行します。
  • 最後(右下)のページのスクリーンショットを撮り、<金額>.png として保存します。

  • オプション:QRコード部分を切り取って用意したカードに貼り付けます。
    • 今回は必要に駆られ現金支払い時に表示するカードも用意しました。
    • この作業は見た目のためなので、こだわりがない人は不要です。
    • 今回はこちらの画像に<金額>.pngと名前をつけてサーバーに置きました。

  • 支払い完了時に表示する画像を作る。

Python で NFCを読み込めるようにする。

  • 使用する外部ライブラリはnfcpyだけになります。
  • 今回の実装に必要な部分の説明だけを記載します。詳しくは公式のドキュメントを確認いただければと思います。
brew install libusb libusb-compat bzr
python3 -m venv env
source env/bin/activate

pip install -r requirements.txt
  • PaSoRiを繋ぐ。
  • 以下のコマンドを打ってその下のメッセージが出ればOKです。
python -m nfc

> This is the 1.0.4 version of nfcpy run in Python 3.9.6
> on macOS-14.0-arm64-arm-64bit
> I'm now searching your system for contactless devices
> ** found SONY RC-S380/P NFC Port-100 v1.11 at usb:000:006
> I'm not trying serial devices because you haven't told me
> -- add the option '--search-tty' to have me looking
> -- but beware that this may break other serial devs
  • 接続するPythonのコマンドは以下(実行すれば接続しているデバイス情報が見れるはず。)
with nfc.ContactlessFrontend("usb") as clf:
	 # 処理の中身
	print(clf)

> SONY RC-S380/P on usb:001:005
  • NFCの読み書き操作を行う。
clf.connect(rdwr={
		"on-connect": <カードを置いた時の操作>, 
		"on-release": <カードを話した時の操作>
})

サンプルコード(できるだけコードにコメントつけました。)

https://github.com/kakera-lab/nfc_payment/blob/c6e8e29335581812200d3db1e7490723deaa9865/python/main.py

  • 特に追加でコメントすることはないです。

データベース(db.json)の設計。

ほしい情報

  • JsonファイルのキーはIDにします。
    • URLのid=1001と揃える。
  • 名前:name
  • 金額:total
  • 支払った方法:payment
    • 支払い確認後、現金だと"cash" ,"PayPayだと"paypay"の印字を入れる。

ファイルの中身

  • 下記のように人数分用意してください。
  • <支払い金額>の部分を任意に変更してください。
{
	"1001":{"id":1001,"name":"A","total":<支払い金額>,"payment":""},
	"1002":{"id":1002,"name":"B","total":<支払い金額>,"payment":""}
}

PHPでサーバーサイド側の実装をする。

  • 実装の手抜きをしてしまったので、基本的に前回の記事と同じ書き方をします。
    • 前回の記事にコメントがあるものもあります。

サンプルコード(できるだけコードにコメントつけました。)

https://github.com/kakera-lab/nfc_payment/blob/c6e8e29335581812200d3db1e7490723deaa9865/php/index.php

  • 特に追加でコメントすることはないです。

https://github.com/kakera-lab/nfc_payment/blob/c6e8e29335581812200d3db1e7490723deaa9865/php/model.php

  • 特に追加でコメントすることはないです。

https://github.com/kakera-lab/nfc_payment/blob/c6e8e29335581812200d3db1e7490723deaa9865/php/page.php

  • 特に追加でコメントすることはないです。

まとめ

集金した後の勘定が不要かつ現金を扱わなくても良くなったので、非常にストレスが軽減されました。簡単なシステムですがヒューマンエラーを減らす面でも、十分意味のあるものかなと思っています。下準備が若干面倒ですが、大学サークルなどで、例えばNFCの代わりに学生証(読み込める場合に限る)をつかったシステムに応用してみるなど、何かと使えるかもしれませんね。NFCを用意せずにQRコードを使うこともできるので、発想だけでも参考にしていただければ嬉しいです。

その後

集金結果を表示するページが欲しくなったので追加で実装しました。GitHubにUpしているコードにはその分の実装も含めています。よければチェックしてみてください。

Discussion