見出し画像

民泊運用の効率化アイデア No.3 - Googleフォーム宿泊者名簿の運用改善!


民泊を運用されている方順調でしょうか?
理由は不明ですが、私の知り合いが運営している富士五湖の民泊は9月から10月は予約がかなり少ないようです。
その宿泊施設のみのようではなく、全体的に観光客が減っているということを聞きました。
いずれ戻ると思いますが、戻ったときに慌てないように準備をしたいと思います。
この記事では、民泊運用の効率化アイデアNo.3として、別記事でご紹介した宿泊者名簿の運用例をさらに改善するためのアイデアをご紹介します。
私が実際に利用する予定のもので、そのままご利用いただくことができます。

背景

私が利用しているGoogleフォームの宿泊者名簿ですが、すでにいくつか改善したい事項があります。
今回のご紹介するのは民泊運営側の効率化ではなく、ゲスト様の省力化を図るためのものです。

宿泊者名簿はGoogleフォームをゲストに送付し事前記入していただいています。
ただ、ゲスト側からするとエアビーなどで予約してあるものなので、基本的な情報、宿泊する期間、代表者氏名、宿泊人数などは二度手間です。
これまでご利用頂いたゲスト様はあまり気にせず入力された印象ですが、すでに伝えた情報を改めて再入力するのは、マイナスポイントですね。
改善したほうがいい点だと思います。
まー、私がゲストであったら、そうしてほしいと思う事項です。
ということで、ここでご紹介する方法は、宿泊に関しすでにいただいている情報を宿泊者名簿フォームに事前登録、準備する方法でそのためのテンプレートを公開したいと思います。

当然ご自由にご利用いただいて結構です。
質問などにはできるだけ答えさせていただきますが、あくまで自己責任でのご利用をお願いいたします。

宿泊者名簿フォームの改善に使う道具

前回の記事では、Googleフォームの標準機能のみで作成しましたが、今回はGoogle Apps Script(GAS)というスクリプト機能(Excelマクロのようなもの)を利用します。
実は、民泊運用の効率化アイデアとは別の記事でも利用していますので、よろしかったら参照ください。

使う道具についてはあくまでGoogleが提供するものに限定し、以下の二つの機能を活用します。

  1. Googleフォームの「事前入力したリンクを取得」機能

  2. Google Apps Script(GAS)スクリプト

1点目については、こちらのリンクの「フォームの回答を事前に入力する」の説明をご確認ください。

また、GASを利用した事前入力したリンクを作成するやり方についてもたくさんのブログで説明されています。
ただし、ほとんどのものがコードレベルのサンプル的なもので実運用として使えそうな感じにするにはコードの基本的な理解やプログラミングが必要になります。
私もいくつか参照しましたが、プログラミング経験のあまりない方には敷居の高いものでした。
例えば、Googleフォームで作成できる事前入力URLの文字列を分析してフォームの各項目の内部IDを抜き出し、それベースにプログラムし直すといった感じです。

今回の改善・実装で目標としたこと

今回GASを利用して改善をしましたが、以下の点に留意しました。

  • 実際に利用しているGoogleフォーム宿泊者名簿で利用できるもの

  • Googleフォーム自体の変更、例えば項目の追加などを実施してもスクリプトの変更なく対応できること

ただし、制約も当然ありますので、その点はご留意ください。

改善後の運用、処理イメージ

ここでは、実際に公開しているフォーム、スクリプトを利用して、宿泊者名簿の処理の流れをご紹介します。

#1  エアビーの予約確定メールを受領し、予約情報を確認の上、宿泊者名簿フォームにリンクする回答データ用スプレッドシートを開きます。

#2  リンクしたスプレッドシートが開くので、エアビーの予約情報を新規の行に入力します。

3行目に新しい予約情報を入力

分かっている予約情報は、チェックイン日、チェックアウト日、宿泊者人数、代表者氏名、代表者電話番号なのでその情報を新規の行、今回の例では3行目に記載します。

予約情報を入力した状態
処理対象となる条件

予約情報を入力する際、最初の列「Prefill_URL」と「チェックイン日」は注意が必要です。
Prefill_URLは空白のもののみが、GASスクリプトでの処理対象となります。
また、チェックイン日は必須で、ここに入力がないとこれも処理対象外になります。

#3  スプレッドシートのカスタムメニューから「事前入力データURL作成」を実行

スクリプトの処理が開始され、完了すると↓イメージのとおり、一列目にURLリンクが追加されています。

1列目にリンクが更新される

#4 リンクを開き、事前登録データが含まれてることを確認し、このURLをゲストに伝え、宿泊者名簿への登録を依頼する

すでに事前入力されたフォーム

処理の流れは以上です。
予約情報は複数まとめて処理ができます。
また注意として、今回作成したURLは事前入力用URLでゲストが回答した後には利用できません。
すでに一度回答された場合には、その回答データを更新する回答データ編集用の別URLが必要です。
そのURLはGoogleフォーム回答後にゲストに送付されますが、フォームを依頼する側では把握できません。
回答データ編集用URLを紛失するなどの場合に、再取得する必要があり、そのやり方を記事にしたものが、こちらになります。

今回ご紹介したGoogleフォームおよびリンクしているスプレッドシートはこちらのものになります。

実装のポイントおよびコードの概要

まず、今回の改善では効率化アイデアNo2でご紹介したGoogleフォーム側はなにも変更してありません。
大きくは以下の変更対応をしました。

  1. フォームにリンクするスプレッドシートの「フォームの回答1」シートをコピーし、「事前入力データ」シートを作成。

  2. 「事前入力データ」の1列名の 「Edit_URL」を「Prefill_URL」に変更し、2行目以降のデータ部分はすべてクリア・削除。
    なお、列名の変更は、分かりやすさのためだけで、処理に影響なし。

  3. スプレッドシートのメニューより「拡張機能」「Apps Script」を利用し事前入力URL作成スクリプト作成。
    コピーしたものをご利用いただく場合には、このコード編集画面にて、以下のformId部分を自分の環境に合わせて変更していただく必要があります。

コード中にコメントの記載のとおり、フォームを開いた際のURLからYYYYYYYYYYYYに該当する部分を置き換えます。

/**
 * フォームの事前入力ありURLを取得して、「事前入力データ」シートに挿入する。
 * 
 * 準備作業: このスクリプトを実行する前に確認、準備しておく
 *  1) フォーム回答データ用のスプレッドシート(シート名=フォームの回答1)をコピーし、「事前入力データ」シートを作成。
 *   ・残っているデータは1行目のヘッダーを除きすべてクリア・削除
 *  2) 上記のスプレッドシートの一列目の項目名を 'Edit_URL'から'Prefill_URL'に変更する。(項目名は何でも可)
 *  3) このスクリプトの formIdを下の記載例に従い更新する
 */
function genPrefillUrls(){

  // フォームの指定
  // formId : フォームを開いた際に表示されるURLの以下の YYYYYYYYYYYYY 部分。
  //          https://docs.google.com/forms/d/YYYYYYYYYYYYYYYY/edit
  const formId = '13fIzcNzESwYfUYNyFMivKHeSe2s4_7YnkbxZPq_Ccrs';

  // 前提となる固定文字列
  const target_sheet = "事前入力データ";
  const checkin_col_name = "チェックイン日 / Check-in date";


  // スプレッドシート&シートオブジェクトを取得
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const sheet = ss.getSheetByName(target_sheet);

  let lastRow = sheet.getLastRow();
  let lastCol = sheet.getLastColumn();

  let data = sheet.getRange(1,1,lastRow,lastCol).getValues();
  console.log("シート「" + sheet.getName() + "」の行数、列数: row=" + lastRow + " col=" + lastCol);

  // フォームの情報の取得
  let form = FormApp.openById(formId);
  let items = form.getItems();
  console.log("items length" + items.length);

  let formResponse;
  const reg = /^(TEXT|LIST|DATE)$/;

  // Check-in列に値があり、A列(Prefill_URL)が空の場合にシート各行をループ処理する

  console.log(data[0]);
  let i_checkin =  data[0].indexOf(checkin_col_name) + 1;
  console.log("Check-in record#=" + i_checkin);

  for (let i = 2; i <= lastRow; i++) {
    console.log("cell(" + i + ",1)=" + sheet.getRange(i,1).getDisplayValue());
    console.log("cell(" + i + ","+ i_checkin +")=" + sheet.getRange(i,i_checkin).getDisplayValue());
    
    if (sheet.getRange(i,1).isBlank() && !sheet.getRange(i,i_checkin).isBlank()) {

          console.log(">>Processing  i=" + i + " check-in="+ sheet.getRange(i,4).getValue());

          formResponse = form.createResponse();

          //質問項目ごとの回答作成
          for (let j = 2; j <= lastCol; j++) {

            if (sheet.getRange(i,j).isBlank()) continue;

            let col_name = sheet.getRange(1,j).getValue();
            let item = items.find(v => { return v.getTitle() == col_name; });

            console.log("i=" + i + " j=" + j + " name=" + col_name + " item == undefined? " + (item == undefined? true : false));
 
            if (!(item == undefined) && reg.test(item.getType())) {
              if (item.getType() == 'TEXT') {
                itemResponse = item.asTextItem().createResponse(sheet.getRange(i,j).getValue());
                console.log("TEXT>>>" + item.getTitle());
              } 
              else if (item.getType() == 'DATE') {
                let dt = Utilities.formatDate(sheet.getRange(i,j).getValue(), 'JST', 'yyyy-MM-dd');
                itemResponse = item.asDateItem().createResponse(sheet.getRange(i,j).getValue());
                console.log("DATE>>>" + item.getTitle());
              }
              else if (item.getType() == 'LIST') {
                itemResponse = item.asListItem().createResponse(sheet.getRange(i,j).getValue());
                console.log("LIST>>>" + item.getTitle());
              } else {}
             
              formResponse.withItemResponse(itemResponse);

            };
          };
          
          const prefillUrl = formResponse.toPrefilledUrl();
          const prefillStr = `=HYPERLINK("${prefillUrl}", "事前入力URL.${i - 1}")`;
          console.log(prefillUrl);

          // 事前編集URLをスプレッドシートにA列に挿入する
          sheet.getRange(i, 1).setValue(prefillStr);
    }
  }
}

コードを理解いただく必要はありませんが、このスクリプトを実行する上で以下のような前提、制約などがありますのでご注意ください。

  • 処理対象のシートはシート名が "事前入力データ" とする。

  • チェックイン日のフォーム上の項目名は「チェックイン日 / Check-in date」とする。また、スプレッドシートにも同じ項目が必要で、事前入力が必須となる。

  • フォームに項目を追加、または、項目名の変更などをした場合には、「事前入力データ」シートを再作成する。

  • 事前入力データの対象は、入力項目のタイプが日付型、テキスト型、または、リスト型の3タイプのみ。ラジオボタンなどは対象外。

  • 事前入力データの入力が一切ない場合にはエラーとなる。

まだ実績がしっかりあるものではありませんので、ご自身で運用される場合のテンプレートとしてご利用をお願いします。
また、ご質問・改善点などございましたら、コメントにてご連絡ください。

最後に

この記事はお気に入りいただけましたでしょうか?
内容お役にたちましたらうれしく思います。
また、サポートなど応援いただけましたら幸いです。

記事の内容を有効に活用できたなど、記事を気に入っていただけたようでしたらサポートしていただけますと嬉しいです。 また、こんなことを知りたい、あんなことができないかなど記事にしたいことがございましたら、サポートの有無にかかわらずお知らせくださいませ。