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
「イベントのソースを選択」→ フォームから
「イベントの種類を選択」→ フォーム送信時
「エラー通知設定」→ 今すぐ通知を受け取る


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



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


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


詳解! Google Apps Script完全入門 [第3版]
詳解! Google Apps Script完全入門 [第3版]

by SimpleImageLink


***

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

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


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

・追記(2023-11-24)

-----

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

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

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

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


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


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

2021年9月20日月曜日

獣害対策「イノシシ避けマシン」を作った【結果 / 2021年】


先日より、稲刈りが始まりました。まずは、もち米(こがねもち)から。

この、もち米を作っている田んぼには、ここ数年イノシシが入るようになってしまいました。その対策として、今年は「イノシシ避けマシン」を作り、設置してみました。



「イノシシ避けマシン」には、びっくりさせるための「人感センサーが反応したら音声を流す」機能と、警戒させるための「定期的に音声を流す」機能の2つが付いています。電源は太陽光発電で取っています。防水仕様。


今回、設置した期間は、出穂の始まった8月2日〜9月5日の約1ヶ月間でした。

まず、結果として、イノシシの侵入は例年より少なかったです。

しかし、どこまで「イノシシ避けマシン」の効果なのかは、よく分からず。たまたまかもしれません。こういうのって、検証が難しいですね。

以下、雑感です。


1. 「人感センサーが反応したら音声を流す」機能は、今回役に立たず

草の生えた地面近くに設置したところ、センサーが無駄に反応してしまい、途中で機能を停止。後述のように設置の方法を変更したこともあり、田んぼへの設置においては、この機能は不要そうです。


2. 設置の方法が重要かも?


当初、農道や畦畔に設置したものの、1週間を過ぎたあたりでイノシシが侵入。

侵入以前から、近くまで来ている気配(足跡)はあったので、はじめは警戒していたものの、慣れてしまったのかもしれません。



思案の結果、コードを延長して片方のスピーカーを稲の中に隠れるように設置方法を変更。このタイミングで人感センサーは停止。結果、これ以降、設置箇所からのイノシシの侵入は無し。

3. 「びっくりさせる」ことよりも、いかに「警戒させ続ける」かが重要そうです。

そのために、どう設置するかですね。イノシシの身になって考えると、音の発生源が見えない方が怖い気がします。

ただし、ちょうど対角あたりからの若干の侵入がありました。これを、もう一台作成して、侵入箇所に同じように設置した時に、効果的に防いでくれるものなのか、警戒しつつ?も意を決して侵入してくるものなのか。


4. 太陽光発電での運用はけっこういける

8月後半からの長雨の時期に一度だけ電源が切れたのですが、思っていたよりは切れませんでした。切れた場合も、早めに回収してバッテリー充電器で充電すれば大丈夫そうです。

太陽光電源は、他にもいろいろ活用できそうです。


5. 防水機能

かなりの大雨でも、問題ありませんでした。洪水にでもならなければ、大丈夫そうです。


ということで、「イノシシ避けマシン」の設置結果でした。来年は、2台体制で、スピーカーを稲の中に隠し、実験してみたと思います。

それから、今年はおろそかになりましたが、検証方法も、もう少し考えたいところです。「効く気がする」では、おまじないと同じですからね。


・関連投稿
低コストで手間いらず、光と音によるイノシシ対策


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

2021年9月15日水曜日

「栽培データ検索システム」を作りました。


栽培データを、オープンデータとして登録・検索するための「栽培データ検索システム」を作りました。


ひとまず、テスト運用中です。

-----
・追記(2023-5-12)

ひとまず、テスト運用を終了しました。再度いろいろ考えたいと思います。
-----

ざっくり概要を説明しますと、栽培データを持っている人がオープンデータとして公開していいよーという場合に登録してもらいます。そうすると、みんなが検索して使えるよ、という(素朴な)ものです。

ライセンスは、商用・非商用にかかわらず、自由に再利用が可能となる Open Data Commons Public Domain Dedication and License(PDDL) での公開を想定しています。

やはり、スマート農業の普及においては、ハード部分だけでなく、ソフト部分の整備もセットで必要なんじゃないかと思うのです。

何か自分で便利な機器を作ろうと思ったときに、ネット等でたいていの部品は簡単に手に入ります。作り方も、調べれば何とかなります。あとは、例えば、指標になるような栽培データがあれば、自作した機器を、より一層、幅広く活用することができます。

まぁ、まだ登録データは、私の1件だけ(しかも原木椎茸)なので、お声がけもして、少しずつ増やしていけたらなと。

もちろん、栽培データは秘中の秘なり、というのが普通は当然な気もします(特に品目によっては)。一方で、みんながお互いにデータをうまく使って栽培技術を高めたり、はたまた経営改善につなげれば、全体としては底上げになるんじゃないかと思います。実験ですね。


今回のシステムは、静的なページはGoogle サイト、登録部分はGoogle フォーム、データの検索と削除部分はGAS(Google Apps Script)で作りました。いやはや、GASほんと便利。

当初は、どこかにサーバーを準備して、PHP + MySQLとかで作ろうかと考えていたのですが、GASで作れたので維持費はゼロ(ドメイン代のみ)。ありがたや。しかし、収益性もゼロなので、低燃費でやっていきます。


さてさて、いろいろ、楽しくなるといいなぁ。


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