GASでQRコードを使った同人頒布会向け予約システムを作った話

# はじめに
来る5/5(土)-6(日)、東京ビッグサイトで日本最大級のアナログゲーム頒布会「[ゲームマーケット2018春](http://gamemarket.jp/)」が開催されます。
今回ゲームマーケットに初めてサークル参加するにあたって、「**『ピロロン』する予約システムを作りたいなぁ**」という気持ちのもと、以下のような予約システムを開発しました。

**2018/05/07 実際に使ってみた感想を追記しました。**


## ユーザー体験
1. Google フォームで予約（必要事項を登録）する
1. 予約番号（QRコード）が添付されたメールが届く
1. 頒布会でサークルスタッフにQRコードを見せる
1. 本人確認完了＆購入する

![reserview_overview.png](https://qiita-image-store.s3.amazonaws.com/0/240213/8176074f-5b2b-4d4f-895a-702f10045aae.png)

## メリット
### サークル側
+ QRコードを読み取るだけで本人確認が完了する
  + ブースに用意するのは、一般的なスマートフォンのみでOK
+ 手作業で予約数／販売数を集計する手間がなくなる
  + 予約数が設定値に達したらアラートを受け取れる

### 一般参加者側
+ 他人に名前を使われて予約購入される「騙り」を排除できる


# アーキテクチャ
+ Google Apps Script (GAS)
+ Google スプレッドシート
+ Google フォーム

## 事前に用意するもの
+ macOS (or 他OSの開発環境)
+ Google アカウント
+ Node.js
+ Git

## 使い方
### 1. clasp の導入
「[clasp](https://github.com/google/clasp)」は、Google Apps Script をローカル環境で開発するためのツールです。

1. `npm` コマンドで clasp をインストールする

```bash:ターミナル
$ sudo npm install -g @google/clasp
$ clasp login
```

2. ブラウザが開くので、使用する Google アカウントを選択して [許可] する
![スクリーンショット 2018-05-01 12.48.39.png](https://qiita-image-store.s3.amazonaws.com/0/240213/c4cf5c1d-7b22-3915-b670-888ecfb733dc.png)


3. ブラウザに以下のようなメッセージが表示されればOK
> Logged in! You may close this page.

4. ブラウザで https://script.google.com/home/usersettings を開き、Google Apps Script API を有効（オン）に変更する



### 2. プロジェクトのクローン
1. 以下のコマンドを実行し、GitHub からプロジェクトをクローンする

```bash:ターミナル
$ git clone https://github.com/blachocolat/reserview.git
$ cd reserview
```

2. `scripts/Const.js` を開き、各項目を適宜修正する

```js:scripts/Const.js
PUBLISHER_NAME = 'こぐまやん';
EVENT_NAME = 'ゲームマーケット2018春';
EVENT_SHORT_NAME = 'ゲムマ2018春';
BOOTH_IDENTIFIER = '土-E65';
PUBLISHER_SIGNATURE = Utilities.formatString(
  '%s＠%s[%s]', 
  PUBLISHER_NAME, 
  EVENT_SHORT_NAME, 
  BOOTH_IDENTIFIER
);
RECEPT_START_DATE = new Date('2018-05-05T01:00:00.000Z');
RECEPT_END_DATE = new Date('2018-05-05T05:00:00.000Z');
```

### 3. フォーム／スプレッドシートの作成
1. [Google フォーム](https://docs.google.com/forms/) で \[+\] を選択し、新しいフォームを作成する
2. \[設定\] > \[全般\] > \[メールアドレスを収集する\] をチェックし、 \[保存\] する
3. 以下のように質問を追加する
![form_question.png](https://qiita-image-store.s3.amazonaws.com/0/240213/c52cf5a2-3537-58c1-cd1b-86aa912aca27.png)


4. \[回答\] > \[スプレッドシートの作成\] を選択し、 `予約管理表` という名前で新しいスプレッドシートを \[作成\] する
5. 作成したスプレッドシートを開き、シート名を `予約一覧` に変更する
6. `予約一覧` シートに以下の列を追加（挿入）する
  + 予約番号
  + 購入日時

7. `商品一覧` シートを追加（新規作成）し、以下のようにシートを編集する
![スクリーンショット 2018-05-01 13.49.44.png](https://qiita-image-store.s3.amazonaws.com/0/240213/835ecb64-b70c-ca13-653e-210333a94b5c.png)

8. [Google ドライブ](https://drive.google.com/drive/) を開き、マイドライブ直下に `EVENT_NAME` フォルダを作成する
9. 作成したフォルダ以下に、作成したフォームおよびスプレッドシートを移動させる

### 4. プロジェクトのデプロイ／公開
1. 上で作成したスプレッドシートで \[ツール\] > \[スクリプト エディタ\] を開き、適当なプロジェクト名を設定して \[ファイル\] > \[保存\] する
2. \[公開\] > \[ウェブ アプリケーションとして導入…\] を選択し、以下のように各項目を設定して \[導入\] する
![スクリーンショット 2018-05-01 13.57.01.png](https://qiita-image-store.s3.amazonaws.com/0/240213/f7462cb9-56d3-5412-1012-cb096779eb51.png)


~~3. スクリプトエディタの URL に含まれる `SCRIPT_ID` をコピーする~~
3. \[ファイル\] > \[プロジェクトのプロパティ\] > \[スクリプト ID\] を `SCRIPT_ID` としてコピーする

<!--
```
https://script.google.com/macros/d/<SCRIPT_ID>/edit?...
```
-->

4. 上でクローンしたフォルダ直下で、以下のコマンドを実行する

```bash:ターミナル
$ clasp clone <SCRIPT_ID>
Cloned 2 files.
└─ コード.js
└─ appsscript.json
$ clasp push
└─ appsscript.json
└─ scripts/Common.js
└─ scripts/Const.js
└─ scripts/Extension.js
└─ scripts/Purchase.js
└─ scripts/Reminder.js
└─ scripts/Reservation.js
└─ templates/email_alarm.html
└─ templates/email_confirm.html
└─ templates/email_remind.html
└─ templates/purchase_already.html
└─ templates/purchase_failure.html
└─ templates/purchase_success.html
└─ templates/style.css.html
Pushed 14 files.
```

5. \[スクリプト エディタ\] を再読み込みし、ソースコードが push されていることを確認する
6. \[編集\] > \[現在のプロジェクトのトリガー\] を選択し、以下のようなトリガーを追加して \[保存\] する
![スクリーンショット 2018-05-01 16.10.46.png](https://qiita-image-store.s3.amazonaws.com/0/240213/8f54ae7e-5870-4e9b-1189-436c9c8d1ed3.png)
  + `remindReservations` : 指定した日時に、予約商品をまだ購入していない人宛にリマインドメールを送信します（オプション）
  + `onFormSubmit` : フォームの送信時に、予約番号の発行および確認メールを送信します（必須）

### 5. 動作確認
1. 作成したフォームを開き、 \[送信\] から適当な方法を選んでフォームの URL を共有する
2. 適当にフォームを入力して \[送信\] すると、以下のように予約情報が `予約一覧` シートに記録され、入力したメールアドレス宛に確認メールが届く
![スクリーンショット 2018-05-01 14.51.49.png](https://qiita-image-store.s3.amazonaws.com/0/240213/8417244e-c18f-1c65-2609-c9d363134ec8.png)
![Screenshot_20180501-151941.png](https://qiita-image-store.s3.amazonaws.com/0/240213/d0fca84c-eacf-eced-b391-f7546057aa93.png)

3. メールに添付されたQRコードをスマートフォンなどで読み取り、取得した URL をスプレッドシートのアクセス権を持つ Google アカウントで開くと、予約情報が更新される
![Screenshot_20180501-145025.png](https://qiita-image-store.s3.amazonaws.com/0/240213/b6833cd9-79c4-ca1f-37b3-e479ab7fecc2.png)


## 補足（＋蛇足）
+ 初回以降、ローカルで修正したソースコードを反映したいときは `clasp push` を実行すればOKです。
+ 各 `clasp` コマンドの意味を知りたい方は、以下の参考記事をご一読することをオススメします。
+ この記事を見て、少しでもゲームマーケットに興味を持った方は、ぜひ [【土-E65】こぐまやん](http://gamemarket.jp/booth/gm2529/) ブースまでお立ち寄りください（ダイマ）。

## 実際に使ってみて（2018/05/07 追記）
「ゲームマーケット2018春」にて、実際にこの予約システムを使ってみたので、その感想を備忘録的にメモしておきます。
なお、予約確認メールがすぐに出てこなかった場合、スプレッドシート上で予約番号or名前を検索するという**運用でカバー**でどうにかしました。

+ （こちらからの声かけ後を含め）QRコードを提示してくれたのは6割弱
  + 0.5割くらいの人がガラケーないしキャリアメールのため、QRコード自体を受信できていない
+ QRコードの事前準備を徹底してもらえば、手元のスプレッドシートor印刷した予約表から名前を探すよりも速く列を捌ける気がする
  + 過激派なので、待機列を「QRコードを用意した予約者列」と「当日販売（QRコードを用意していない予約者含む）and/or商品説明列」の2列に分けたい
  + ただし、100くらいのオーダー（＝名前の衝突がほぼ起きないくらい）だと予約番号or名前で検索するほうが速そう？
+ 購入日時が記録されるため、予約受け取りピークを予測して、次回以降のサークルスタッフのシフト組みに活かせる？

# 参考記事
+ [claspを使い、Google Apps Scriptプロジェクトをgitでバージョン管理する](https://qiita.com/rf_p/items/7492375ddd684ba734f8)
+ [Google Apps Scriptの新しい3つの機能 その③ CLI Tool Clasp](https://qiita.com/soundTricker/items/354a993e354016945e44)

# 注意事項
+ 本プロジェクトの利用は、自己責任でお願いします。
+ 「QRコード」は、㈱デンソーウェーブの登録商標です。