Googleフォームの内容をGoogleカレンダーに反映させよう【連載4/5】

予約システム

連載「予約システムを自作しよう 」の4回目です。

前回までの作業で、予約状況を表示するカレンダーと予約受付フォームが完成しました。こちらは店舗を訪れるお客様のための画面、いわゆる「表側」の機能です。

今回からはフォームで受け付けた内容を、Googleカレンダーに反映したり、Gmailで自動返信したり、「裏側」の機能について説明していきます。

いよいよ、GAS(Google App Script)を用いてプログラムを作成する部分になります。

引き続き、少しずつ開発を進めていきましょう。

回答記録用のスプレッドシートの作成

「回答」タブをクリックします。

「スプレッドシートにリンク」をクリックします。

「新しいスプレッドシートを作成」を選択し、「予約受付フォーム(回答)」と表示されていることを確認します。

「作成」をクリックします。

スプレッドシートが開いたら、回答記録用のスプレッドシートの作成が完了です。

フォームの回答内容をGoogleカレンダーに反映するGAS実装

スプレッドシートが開いたら、「拡張機能」をクリックします。

拡張機能内の「Apps Script」をクリックすると、Google Apps Script(GAS)を記載できる画面に遷移します。

エディタを開いたらプロジェクト名をクリックします。

プロジェクトタイトルを「予約受付フォーム」に変更し、「名前を変更」をクリックします。

「プロジェクトの設定」をクリックします。

「appsscript.jsonマニフェスト ファイルをエディタで表示する」にチェックを入れます。

エディタの「appsscript.json」をクリックし、以下であることを確認します。その他の場合はいかに修正してください。

“timeZone”: “Asia/Tokyo”

エディタの「appsscript.json」をクリックし、赤枠あたりに以下を追記します。(赤枠と差し替えるといいと思います。)

"oauthScopes": [
"https://www.googleapis.com/auth/script.send_mail",
"https://www.googleapis.com/auth/gmail.modify",    "https://www.googleapis.com/auth/script.external_request",    "https://www.googleapis.com/auth/spreadsheets", 
"https://www.googleapis.com/auth/forms",
"https://www.google.com/calendar/feeds",
"https://www.googleapis.com/auth/calendar",
"https://www.googleapis.com/auth/calendar.readonly"
 ],
"dependencies": {
  },

カレンダーIDの設定

Googleカレンダーの右上の歯車マークから「設定」をクリックします。

予約状況確認用に作成したカレンダー「予約状況」をクリックし、「カレンダーの統合」内の「カレンダーID」をコピーします。

コピーしたIDを次に説明するGASの「予約状況カレンダーID」の””内(以下の黄色部分)と入れ替えます。

// 予約状況カレンダーID

let CalendarId01 = “XXXXXXXXXXXXXXXXXXXXX@group.calendar.google.com“;

GASを作っていく

エディタの「コード.gs」をクリックし、以下のコードをコピーして貼り付けてください。

function reserveForm(e) {
  /*********************************
   * 定義
   *********************************/
  // 何ヵ月後まで予約可能にしますか。
    let agoMonth = 3;

  // 予約枠時間の固定時間
   let TimeZone =1;

  // 営業開始時間
    let BusinessStartHours = "10:00";

  // 営業終了時間
    let BusinessEndHours = "18:00";

  // 予約状況カレンダーID
  let CalendarId01 = "XXXXXXXXXXXXXXXXXXXXX@group.calendar.google.com";

  /*********************************
   * 新規用定義
   *********************************/
  // フォームの回答を取得
  let [timestamp ,Email, Day ,Start_time ,Name ,Mnum] = e.values;

  // 表示データの加工
  // Googleカレンダー表示用タイトル作成
  let CalTitle = Name + "様";

  //Googleカレンダー表示用説明作成
  let Explanation = 
    "会員番号:" + Mnum + "\n" +
    "メール :" + Email ;

  // タイプ
  let NomalOperation = "正常";
  let Error01 = "時間帯逆転しています";
  let Error02 = "開始時間が既に過ぎています";
  let Error03 = "予約可能の最大日時外です";
  let Error04 = "営業時間外です";

  /*********************************
   * 日付データ加工
   *********************************/
  // 今日の日付取得
  const Today = new Date();
  const NowTime = new Date();

  // 予約可能の最大日時取得
  const TodayAgo = Today.setMonth(Today.getMonth() + agoMonth);

  // 日時の情報を加工・変換
  let DateDetailStart_time = Day + " " + Start_time;
  let DateDetailStart = new Date(DateDetailStart_time);

  let DateDetailEnd_time = Day + " " + Start_time;
  let DateDetailEnd0 = new Date(DateDetailEnd_time);
  let DateDetailEnd = new Date(DateDetailEnd0.setHours(DateDetailEnd0.getHours()+TimeZone));

  let DateDetalBusinessStartHours = Day + " " + BusinessStartHours;
  let DateDetalBusinessStart = new Date(DateDetalBusinessStartHours);

  let DateDetalBusinessEndHours = Day + " " + BusinessEndHours;
  let DateDetalBusinessEnd = new Date(DateDetalBusinessEndHours);

  /*********************************
   * 計算処理呼び出し
   *********************************/
  let CalResult01 = new Array();
  let CalResult02 = new Array();
  let CalResult03 = new Array();
  let CalResult04 = new Array();

  // 開始時間と終了時間の精査処理呼び出し
  CalResult01 = CheckTime(DateDetailStart, DateDetailEnd);

  // 開始時間が今より前の時間でないか精査呼び出し
  CalResult02 = CheckNowTime(NowTime,DateDetailStart);

  // 予約可能の最大日時内か精査呼び出し
  CalResult03 = CheckMaxHours(TodayAgo,DateDetailStart);

  // 営業時間内か精査呼び出し
  CalResult04 = CheckMaxHours(DateDetailStart,DateDetalBusinessStart,DateDetalBusinessEnd);

  if(CalResult01 == NomalOperation ){
    if(CalResult02 == NomalOperation ){
      if(CalResult03 == NomalOperation){
        if(CalResult04 == NomalOperation){
          // 新規予約処理呼び出し
          Logger.log("新規予約処理スタート");
          NewReservation(CalendarId01, DateDetailStart, DateDetailEnd,CalTitle, Explanation);

        } else {
          Logger.log("メール送信(営業時間外です)");
        }
      } else {
        Logger.log("メール送信(予約可能の最大日時外です)");
      }
    } else {
      Logger.log("メール送信(開始時間が既に過ぎています)");
    }
  } else {
    Logger.log("メール送信(時間帯逆転しています)");
  }

  /*********************************
   * 計算処理
   *********************************/
 /*********************************
     * 時間エラー処理
  *********************************/
  // 開始時間と終了時間の精査
  function CheckTime(StartTime, EndTime) {
    if (StartTime < EndTime) {

      Logger.log('開始時間と終了時間正常');
      CalResult01 = NomalOperation;
      return CalResult01;

    } else {

      Logger.log('開始時間と終了時間逆転');
      let Type = Error01;
      CalResult01[0] =Type;
      return CalResult01;

    } 
  }

  // 開始時間が今より前の時間でないかの精査
  function CheckNowTime(NowTime ,StartTime) {
    if (NowTime < StartTime) {

      Logger.log('開始時間正常');
      CalResult02 = NomalOperation;
      return CalResult02;

    } else {

      Logger.log('開始時間が既に過ぎている');
      let Type = Error02;
      CalResult02[0] =Type;
      return CalResult02;

    } 
  }

  // 予約可能の最大日時内か精査
  function CheckMaxHours(TodayAgo, StartTime) {
    if (StartTime <= TodayAgo) {

      Logger.log('予約可能日時');
      CalResult03 = NomalOperation;
      return CalResult03;

    } else {    
 
      Logger.log('予約可能の最大日時外');
      let Type = Error03;
      CalResult03[0] =Type;
      return CalResult03;

    } 
  }
  
 // 営業時間内か精査
  function CheckBusinessHours(StartTime, StartBusinessTime, EndBusinessTime) {
    if (StartBusinessTime <= StartTime) {
      if(StartTime <= EndBusinessTime){

        Logger.log('営業時間内');
        CalResult04 = NomalOperation;
        return CalResult04;

      }else{
        Logger.log('営業時間外(後)');
        let Type = Error04;
        CalResult04[0] =Type;
        return CalResult04;

      }
    } else {
      
      Logger.log('営業時間外(前)');
      let Type = Error04;
      CalResult04[0] =Type;
      return CalResult04;
    } 
  }

  /*********************************
     * 新規予約処理
  *********************************/
  function NewReservation(CalendarId, StartTime, EndTime,CalendarTitle, Explanation) {
    // カレンダーオブジェクトを取得
    let Calendar = CalendarApp.getCalendarById(CalendarId);

    // イベントがなければ実行する関数
    // "!"を用いることでBoolen化する
    if (!Calendar.getEvents(StartTime, EndTime).length) {
      // カレンダーに日程を追加
      Calendar.createEvent(CalendarTitle, StartTime, EndTime, { description: Explanation });

      Logger.log('カレンダー処理正常完了');

    } else {
      Logger.log('カレンダー処理失敗');
 }
  }
}

トリガー設定

作成したGASがどのタイミングで動いてほしいかトリガーをかけていきます。

左のメニューの中から「トリガー」をクリックします。

画面右下の「トリガーを追加」をクリックします。

イベントの種類は「フォーム送信時」を選択します。

エラー通知設定は、「今すぐ通知を受け取る」を選択し、「保存」ボタンをクリックします。

※承認を求められた場合は、実行権限を承認しましょう。

カレンダー公開範囲を確認しよう

カレンダー公開範囲の設定

カレンダーの公開範囲の設定は非常に重要です。万が一、間違ってしまうと個人情報を一般公開してしまうことになりかねません。

今回の予約状況カレンダーは、以下のような設定が必要になります。

  • 予約フォームからの自動入力は、「予定あり」のみが一般公開される(デフォルト設定)
  • お店の定休日やお店側が公開したい情報は、詳細まで一般公開される

やり方を知っている方は、「予約状況」カレンダーに以下の設定を行ってください。

  • 予定のアクセス権限「一般公開して誰でも利用できるようにする」にチェックする
  • 予定の表示(時間枠のみ、詳細は非表示)

カレンダー公開範囲の設定については以下の記事でご紹介しています。

定休日の登録

定休日は、Googleカレンダー「予約状況」で以下の設定で登録してください。

  • 毎週土日10:00~18:00(終日設定はしないでください。)
  • 公開

サイト上のカレンダーを見てみよう

一度、フォームURLから予約を送信してみて、以下のイメージのように表示されていれば、GASの実装、設定、カレンダーの公開範囲の設定ができています。

筆者(kei)
筆者(kei)

※普段使っているアカウント情報が残っているものだとうまく表示されませんので注意してください。シークレットモードで見ることをお勧めします。

定休日情報:テスト(公開)

フォームからの予約:テスト(公開なし)

Googleカレンダー

サイトで表示されたGoogleカレンダー

上手くいかなかった方は、以下でカレンダーの公開範囲の設定についてご紹介していますので、ご参照ください。

まとめ

今回は、連載「予約システムを自作しよう 」の第4回目「Googleフォームの内容をGoogleカレンダーに反映させよう」を説明してきました。

ここまでの作業で、予約受付フォームを入力すると予約が取れる場合のみ、予約状況カレンダーに予定が自動反映されるようになりました。

次回の連載は、「予約内容をGmailで自動返信させよう」です。

いよいよ、最終回です。最終回では、フォームで受け付けた内容を、Gmailで自動返信する機能について説明していきます。

連載目次: 予約システムを自作しよう

  1. 予約システムを自作しよう
  2. Googleカレンダーをサイトに載せよう
  3. Googleフォームで予約受付フォームを作ろう
  4. Googleフォームの内容をGoogleカレンダーに反映させよう
  5. 予約内容をGmailで自動返信させよう

コメント