2021年9月27日月曜日

【GAS】Google フォームとスプレッドシートを連携して選択肢を動的に入力する。そして注文フォームを作ってみる。

-----
・追記(2022-4-30)

コードを一部修正しました。
-----

単体でも便利なGoogle フォームですが、GAS(Google Apps Script)を使うことで、いっそう便利になります。

例えば、スプレッドシートを連携することで、選択肢を動的に変更することができます。

ということで、スプレッドシートと連携して、動的に在庫の反映などをしてくれる「注文フォーム」を作ってみました。

追加で、確認メールの自動送信機能も付けました。


▼ Google フォームの準備


まずは、元となるフォームを作成します。

項目は以下の通りです。商品タイトル、及び各項目の選択肢は、後ほど、GASで入力します。


1) 商品 [プルダウン] ※1~複数個
2) お名前 [記述式](必須)
3) メールアドレス [記述式](必須)
4) お電話番号 [記述式]
5) 住所(都道府県) [プルダウン](必須)
6) 住所(続き) [記述式](必須)
7) お支払い方法 [ラジオボタン](必須)
8) アンケート [チェックリスト]

メールアドレスは、回答の検証を付けておいた方がいいですね。


▼ スプレッドシートの準備


フォームの回答先として、スプレッドシートを作成します。

回答先のシートの他に、「item」「pref」「paym」「ques」という4つのシートを作成します。

回答先のシート名はデフォルト(「フォームの回答 1」)でも問題ありませんが、今回は「form」という名前に変更しています。


各シートの役割は以下の通りです。シートそれぞれの書き方は → こちらを参考にしてください。

・「item」 → 1) 商品のデータ

商品名、価格、在庫数が記載された商品データを入力しておきます。商品数はいくつでも大丈夫です(フォームの商品項目の数を合わせます)。

注文を受けると、在庫が減っていきます。


・「pref」 → 5)住所(都道府県)のデータと対応する送料のデータ

47都道府県の一覧と、対応する送料のデータを入力しておきます。


・「paym」 → 7) お支払い方法のデータ

お支払い方法の一覧を入力しておきます。


・「ques」 → 8) アンケートのデータ

チェックリスト方式のアンケートを入力しておきます。

この項目は、スクリプトの例として、チェックリストを含めたかったために作ったので、不要であれば削除してください。


▼ スクリプトの作成


フォームより、スクリプトを作成します。フォームから作ることで、トリガー作成時に、イベントのソースとしてフォームを選択することができます。

スクリプトは2つ、スプレッドシートの内容に応じて選択肢を動的に入力するための「set-form.gs」と、在庫の計算と確認メールを送信をするための「order.gs」になります。

「set-form.gs」
function setForm() {
  const sp = SpreadsheetApp.openById("スプレッドシートID");
  const itemList = sp.getSheetByName("item");
  const prefList = sp.getSheetByName("pref");
  const paymList = sp.getSheetByName("paym");
  const quesList = sp.getSheetByName("ques");

  let itemNum = itemList.getLastColumn() - 1;

  const form = FormApp.openById("フォームID");
  const ques = form.getItems();
 
  //商品(プルダウン)
  for(let i = 0; i < itemNum; i++) {
    let que_item = ques[i];

    let itemName = itemList.getRange(1,i + 2).getValue();
    let itemAmt = itemList.getRange(2,i + 2).getValue();
    let stock = itemList.getRange(3,i + 2).getValue();
    let que_itemList = [];
    for(let x = 1; x <= stock; x++) {
      que_itemList.push(x); 
    }
    que_item.asListItem().setTitle(itemName + " / ¥" + itemAmt).setChoiceValues(Array.prototype.concat.apply([], que_itemList));
  }

  //都道府県(プルダウン)
  const que_pref = ques[itemNum + 3];
  let pref_lastRow = prefList.getLastRow() - 1;
  let que_prefList = prefList.getRange(2,1,pref_lastRow,1).getValues();
  que_pref.asListItem().setChoiceValues(Array.prototype.concat.apply([], que_prefList));

  //支払い方法(ラジオボタン)
  const que_paym = ques[itemNum + 5];
  let paym_lastRow = paymList.getLastRow() - 1;
  let paym_prefList = paymList.getRange(2,1,paym_lastRow,1).getValues();
  que_paym.asMultipleChoiceItem().setChoiceValues(Array.prototype.concat.apply([], paym_prefList));

  //アンケート(チェックボックス)
  const que_ques = ques[itemNum + 6];
  let ques_lastRow = quesList.getLastRow() - 1;
  let que_quesList = quesList.getRange(2,1,ques_lastRow,1).getValues();
  que_ques.asCheckboxItem().setChoiceValues(Array.prototype.concat.apply([], que_quesList));
  que_ques.asCheckboxItem().showOtherOption(true);
}

書き換えが必要な箇所は以下の通りです。

・4行目「スプレッドシートID」

スプレッドシートURLの下記部分です。

https://docs.google.com/spreadsheets/d/ここの値をコピペ/edit#gid=0


・12行目「フォームID」

フォーム(編集画面)URLの下記部分です。

https://docs.google.com/forms/d/ここの値をコピペ/edit


アンケートの項目が不要な場合は、8行目、及び41〜46行目を削除してください。


「order.gs」
function submitForm(e) {
  let quesResp = e.response.getItemResponses();

  const sp = SpreadsheetApp.openById("スプレッドシートID");
  const itemList = sp.getSheetByName("item");
  const prefList = sp.getSheetByName("pref");
  let itemNum = itemList.getLastColumn() - 1;

  //在庫再計算
  for(let i = 0; i < itemNum; i++) {
    let stock = itemList.getRange(3,i + 2).getValue() - quesResp[i].getResponse();
    itemList.getRange(3,i + 2).setValue(stock);
  }

  //メール
  //内容の作成
  let order = [];
  let total = 0;
  for(let i =0; i < itemNum; i++) {
    if(quesResp[i].getResponse() != null) {
      order.push(itemList.getRange(1,i + 2).getValue() + " 数量:" + quesResp[i].getResponse() + " ¥" + itemList.getRange(2,i + 2).getValue() * quesResp[i].getResponse() + "\n");

      total += itemList.getRange(2,i + 2).getValue() * quesResp[i].getResponse();
    }
  }
  let prefFinder = prefList.getRange("A2:A").createTextFinder(quesResp[itemNum + 3].getResponse()).findAll();
  let pstg = prefList.getRange(prefFinder[0].getRow(),2).getValue();
  total += pstg;
  let content = quesResp[itemNum].getResponse() + ' 様\n\n以下の内容でご注文を承りました。ご確認ください。\n\n-----\n' + order.join("") + '送料 ¥' + pstg + '\n\n合計 ¥' + total + '\n-----\n\nお支払い方法:' + quesResp[itemNum + 5].getResponse();

  //送信
  GmailApp.sendEmail(
    quesResp[itemNum + 1].getResponse(),
    'ご注文を承りました。',
    content,
    {
      from: '送信元メールアドレス',
      name: '送信者名'      
    }
  );
  
  //在庫をフォームに反映
  setForm();
}

書き換えが必要な箇所は以下の通りです。

・4行目「スプレッドシートID」

「set-form.gs」のスプレッドシートIDと同じです。


・37行目「送信元メールアドレス」
・38行目「送信者名」

送信元メールアドレスは、Google アカウントのGmail、もしくはエイリアスとして追加しているメールアドレスを指定できます。送信者名は、自由に指定。

GASによるメールの扱いは「Gmailで定期的にメールを自動送信する。」をご参照ください。


▼ トリガー設定


・「order.gs」のトリガー

「実行する関数を選択」→ submitForm
「実行するデプロイを選択」→ Head
「イベントのソースを選択」→ フォームから
「イベントの種類を選択」→ フォーム送信時
「エラー通知設定」→ 今すぐ通知を受け取る


▼ 自動送信される確認メール



今回のスクリプトの例ですと、自動送信される確認メールは、こんな感じの内容になります。適宜変更してください。


ということで、一通りできました。




***

あとは、決済部分ですね。

-----
・追記(2023-11-14)
フォームから決済までつなげてしまうならオンライン決済サービスの導入が必要になります。


それでも、フォームに直接は繋がらないので、メール等を介してワンクッションは必要になります。

・追記(2023-11-24)

-----

BASE等、簡単にネットショップを作ることができ、細かい便利機能もいろいろあるECサービスですが、結局、肝となるのは決済部分かと思います。

しかし、最近は、ネット銀行や送金アプリもとても便利なので、自前で用意可能な決済方法でも、それほど障壁にはならない(決済手段によって購入をやめてしまうことが少ない)のではないか、という気がするのですよね。

であれば、このくらいのざっくり自作フォームでも、ECをまかなえてしまうパターンが多々あるのではなかろうかと思います。

そんな仮説を立ててみたので、8年(内7年くらいは開店休業)使っていたBASEを、昨日退会しました。


そういえば、Googleがpringを買収したので今後の展開に期待しています。


Twitter(@nkkmd)日々更新中です。