見出し画像

申込依頼を自動化したよって話

おはこんばんにちは、かけるです。

普段はTwitterで細々と催眠の真似事をさせていただいてます。

今回はありがたいことに通話依頼を要領が悪い僕のキャパを超えた量いただきまして、スケジュール管理が大変になってきたので、「自動予約システムを自前でこしらえた」よ。というお話になります。

この記事は完全備忘目的で記載しており、後で何かの役に立てばよいなと思って残しています。
※なのでマネするのは自己責任でお願いします。(クレームは受け付けません)


自動予約システムってなーに?

さてさて、自動予約システムってなんなのさ、というと、例えば美容院とか、美容クリニックの予約システムみたいなものですね。

ホッ〇ペッパーBeautyとか楽〇Beautyとか。。。

あのシステムは予約したいときには近場の店舗を検索して、簡単なアンケートフォームに日時、担当者を選択してもらえたら予約が完了するというものです。

それを想像していただければイメージしやすいのかなと思っています。

今回作ったものは店舗検索や担当者選択などはありませんが

既存のシステムで使えるものも探しましたが、ちょうどいいものがなく、お金も時間もかけられませんでした。。


なぜ作ろうと思ったか

なんで作ろうと思ったのか、いくつか理由はあります。

1.依頼数が多く手作業でのスケジュール管理が大変だった

ありがたいことに評判が評判を呼び、依頼がここ一ヶ月で20名以上の方から依頼をいただき、合計で30名近くの方と通話をさせていただけるようになりました。

とっても忙しくさせていただいています。

3月-4月の申し込み状況(🧠マークの時間が入っているところが依頼枠)

せっかく勇気を出してお声がけしてくださったので、少しでも多くの方に、できる限りお応えしたいと思っていました。

が、さばききれない量の依頼が飛び込んでくるとどうなるのか。

ダブルブッキング、予約を忘れる、登録ミスがあって約束を反故にする、だれから来た依頼かを覚えていないなどなどせっかく依頼してくださった方に失礼に当たる恐れがあります。

もともと僕自身スケジュール管理能力に乏しいので、それらの不誠実なことは充分に起こり得るなと、容易に想像できました。

また、複数人並行で予定調整していると日程調整がむずかしく、調整のラリーをしている間にどんどん時間が埋まっていってしまい、「すみません。。そちらのお時間はすでに埋まってしまいました」と再調整することになってしまい、依頼してくださった方に大変余計な手間をおかけしてしまうこともありました。
(画像のようにスケジュールを提示させていただいていましたが、それでも更新が発生するとやりとりのラリーが増える。)

待ち時間が発生する間に予定が埋まってしまう

スケジュールをだれでも閲覧できるようフルオープンにすることも考えましたが、それはそれで怖い!

ということで、空き枠を提示して選んでいただいたものをリアルタイムで反映して消込がかかるような形(先着順形式)がいいなと考えていました。

日程調整を簡素化したいというのが一番でした。

2.依頼の内容を統一化し混乱を避けたかった

また、DMでの依頼の場合、内容について千差万別です。

「興味あります!」「したいです!」などの一言からしっかり悩みをご記入いただいて送っていただく方もいらっしゃいました。

経験者の方でもそうですが、初めましての方は特に、どう依頼をしたらよいのか、何を送ったらよいか、がやっぱりわからないという方もいらっしゃると思います。

なので、フォームを用意し、事前に簡単な質問項目を置いておくことである程度回答しやすくなるなと考えました。

依頼を受ける側としても事前に知りたいことが把握できるのはうれしいことです。

3.予約確定時には意外とやることが多い

さらに、予約が確定したときには何をしていたかというと、忘れないように使っているカレンダーアプリに日時や依頼者の情報を登録し、予約していただいた申込内容、日時の認識合わせや通話アプリのインストールや案内、当日の流れを一人一人に手作業で送信していました。

1,2件であればそれでよかったのですが、10件を超えてくると手打ちどころかコピペして内容を書き換えて。。。というのも大変になってきました。

さらに20件を超えるとそれだけで1日Twitterに張り付いてやり取りして。。。という塵積時間になってしまっていました。

4.無料で使えるサービスがなかった

そもそも無料で使えるものがあればそれを使うだけでよいのですが、無料でつかえる便利な既存サービスを調べてみたところ、あるにはあるのですが、個人で利用するにはハードルが高そうという結論になりました。

企業がサービスとして展開している(営利目的)、構築に時間もお金もかかりそう。。

そこまでのレベル感のものを導入するのはかなりしんどそうでした。

なので、できるだけ無料で、簡単に使えるものを組み合わせて、最小限で1人1人と交流する時間を多くとるために自動化できるところは自動化しようと思い、自作しようと考えました。


今回作ったもの

今回作ったものは大きく分けて二つの機能を持っています。

申し込みフォーム予約時処理機能

一つは申し込みフォーム予約時処理です。

これは申し込みフォームに依頼があった場合、予約日時と依頼内容をカレンダーに自動登録して、LINEに依頼者向けのメッセージを通知として送ってもらうような機能です。

フォームはGoogleフォームを使っており、Googleフォームにも自動で内容を記録したり、申し込みがあった際にメールで通知が届く標準機能があったのですがそれだけだと確認が漏れてしまったり、いちいちフォームを確認しにいかないといけないし何より見にくい。。。

スケジュールを抑えたりするときに手間にもなるし、間違えて登録してしまうことがあるので、自動でカレンダーまで予約を登録する機能を追加しました。

また、予約内容や依頼者へ送信する予約確定メッセージや、予約内容をLINEに送信することで通知の代わりになるうえに、そのままコピペで依頼者に案内のメッセージを送ることができるようになってます。

本当はTwitterのAPIを使ってフォームから依頼を送信したタイミングで、依頼者にそのまま案内DMを送信しようとしたのですが、Twitter API有料化に伴って自由にDMが送れなくなってしまったので、一旦LINEにメッセージを送り、それを依頼者に手作業でコピペで送るみたいな運用にしています。

コピペだけなのでそこまで手間では無いのですが、ここは今後の課題にしたいなと思ってます。

また、申込フォームにこちらで指定した通話希望日時を選んでいただく選択項目があるのですが、申込が入った場合、その日時については予約不可となるので、申込フォームの希望日時の選択肢から削除する必要があります。

そこも毎回申し込みフォームを編集するのが手間だったので、選択肢から埋まった予約日時を自動で削除するようにしています。

申込フォームや申込内容を登録するためのカレンダー等の基本的なツールについては、今回Googleのアプリを使用していますが、それらを連携させるところや、LINEにメッセージを送る部分についてはGoogleAppsScriptのプログラムを使っています。

申込フォーム予約時処理

予約空き枠のフォームへの反映機能

もう一つの機能が予約空き枠のフォームへの反映です。

こちらはカレンダーに登録された予約可能な日時(空き枠)を申込フォームの希望日時の選択肢に自動反映する機能になります。

申込フォームにこちらで指定した通話希望日時を選択肢から選んでいただく項目があるのですが、毎回更新があるたびに細かく選択肢を編集していく作業がそれなりに手間だったので、普段使っているGoogleのカレンダーアプリに予約枠を登録しておくだけの一手間でフォームの選択肢に希望日時の候補(空き枠)を追加できるような機能にしました。

予約空き枠のフォームへの反映

使われ方

今回作った予約ツールが実際にどのように使われていくのか、について説明していきたいと思います。

1.Googleカレンダーに空き時間(予約可能枠)を追加する

まずは、対応できる日時(予約可能枠)をカレンダーに登録します。

これが空き枠です。

Googleカレンダーアプリを開いて、予定の追加を押して、タイトルに🧠マークを入力、予約可能な時間帯も設定して保存します。

すると申込フォームの希望日時の選択肢に予約可能日時が反映されます。

こちらはカレンダーと申込フォームの選択肢を同期しています。

1時間おきに同期処理が走る設定にしているので、若干タイムラグがありますが、特に問題なく運用できています。
※もう少し短い間隔で同期したい場合には、スケジュールの設定で柔軟に対応できると思います。

そのあとは申込があるまで待つだけです。

予約可能日時をカレンダー登録(申込フォームに自動反映)

2.申込があった場合に自動で予約内容がカレンダーに反映される

申込があった場合には、その内容がカレンダーに自動反映されます。

特に人が何か作業する必要はありません。

予約確定時1 カレンダー更新

カレンダーへ反映される情報は次の通りです。

  • 時間、依頼者のTwitter名、Twitter ID、依頼者のアカウントへのリンク、フォームで入力いただいた内容をカレンダーメモに記載します。

  • 1日前、30分前、15分前にカレンダーからリマインダー通知が届くよう設定されます。

このような内容がカレンダーに自動で登録されることで、カレンダーさえ見れば予約情報がすべてわかるようになっています。

また、リマインダーも細かく設定することで、時間前に通知が届くので依頼忘れの防止ができます。

3.依頼者へ送信するメッセージがLINEに届く

依頼が発生した際にこちらからメッセージが届かない場合、予約がちゃんと届いているのか、依頼者も不安になるので依頼をいただいた方には、次のような内容を送ることにしています。

  • 予約確定のお知らせ(日時、依頼情報)

  • 申込後の案内について(通話アプリの案内や申請、予約日当日の案内)

こちらも依頼があった場合は、LINEに依頼者のTwitterプロフィールへのリンクと送信用のメッセージが届くので、文章をコピペして依頼者へDMします。

実際に送信するメッセージは、次の画像のような内容になります。

予約確定時2 依頼者へのメッセージ送信

以上が予約システムの使われ方になります。実質こちらの作業としては、対応可能な日時をカレンダーアプリから登録して、申込が来たら内容を確認してテキストを依頼者のDMにコピペするだけ、になります。

基本的にはカレンダーとLINEさえ見れば情報がすべて乗っているので、それでOKです。あとはリマインダーに従っておけば予約された日を忘れることもなくなります。


構築

ここまで読んで構築してみたいと思った方(いるか分かりませんが)、お待たせしました、お待たせし過ぎたのかもしれません(言いたいだけ)。ここからは予約システムの構築編になります。なるべく詳細な手順を記載していきます。

事前準備

まず、事前準備ですが次のものを準備する必要があります。※作業自体はPCで行うことを推奨します。

①Googleアカウント
②LINEアカウント(LINEに通知とメッセージを送りたい場合)

それぞれの手順は次の通りです。

①Googleアカウントを作成する方法:

  1. Googleのサイトにアクセスします(https://www.google.com)。

  2. 右上の「ログイン」ボタンをクリックします。

  3. 「アカウントを作成」ボタンをクリックします。

  4. 必要事項を入力し、アカウントを作成します。これには、名前、ユーザー名、パスワード、誕生日、性別、電話番号、およびメールアドレスが含まれます。

  5. セキュリティ情報の設定を行います。これには、復旧用の電話番号やメールアドレス、セキュリティ質問が含まれます。

  6. 利用規約とプライバシーポリシーに同意します。

  7. プロフィール画像をアップロードすることもできます。

②LINEアカウントを作成する方法:

  1. LINEアプリをダウンロードして、インストールします。

  2. アプリを起動し、下部の「新規登録」をタップします。

  3. 携帯電話番号を入力します。

  4. SMSで送信された認証番号を入力します。

  5. ユーザー名とプロフィール画像を設定します。

  6. 友達の検索やグループチャットに参加する場合は、電話帳にアクセスすることを許可するかどうかを確認します。

  7. 利用規約とプライバシーポリシーに同意します。

  8. ホーム画面に移動し、友達を追加したり、チャットを始めたりすることができます。

Google Form

Google Formを作る手順は以下の通りです:

  1. Googleアカウントにログインし、Google Driveを開きます。

  2. Google Driveの左上の「新規」ボタンをクリックし、「Googleフォーム」を選択します。

  3. 新しいフォームが開きます。タイトルを設定し、必要に応じて説明を追加します。

  4. 「質問を追加」ボタンをクリックして、フォームに質問を追加します。

  5. 質問タイプを選択し、必要に応じて回答の必須項目を設定します。

  6. 質問を追加したら、「送信」ボタンをクリックして、フォームの送信設定を構成します。

  7. 送信先のメールアドレス、回答のスプレッドシートを指定します。

  8. 設定が完了したら、「送信」ボタンをクリックして、フォームを送信できます。

今回作ったフォームはこちらになります。項目についてはフォームを確認いただければと思います。

また、フォームの設定として、メールアドレスの収集をしないに設定しておくと、依頼者は、Googleアカウントを作成せずにフォームへの登録ができます。

Google Spread Sheet

Google Formsには、回答が送信されたときに自動的にスプレッドシートに転記する機能があります。以下の手順に従って、フォームの設定を変更してこの機能を有効にすることができます。

  1. Google Formsで[回答を収集]タブをクリックして、[スプレッドシートに回答を表示]を選択します。

  2. [スプレッドシートに回答を表示]ダイアログが表示されます。[既存のスプレッドシート]を選択するか、[新しいスプレッドシート]を作成して選択します。[選択]ボタンをクリックします。

  3. [スプレッドシートに回答を表示]ダイアログが閉じられ、[回答を収集]タブに戻ります。

  4. [回答を収集]タブの右上隅にある[設定]アイコンをクリックします。

  5. [スプレッドシートに回答を表示する]の右側にある[編集]アイコンをクリックします。

  6. [スプレッドシートに回答を表示する]ダイアログが表示されます。スプレッドシートに表示される情報を選択します。

  7. [保存]ボタンをクリックして、[スプレッドシートに回答を表示する]ダイアログを閉じます。

  8. [回答を収集]タブに戻ります。右上隅にある[スイッチをオンにして回答を送信]をクリックして、スイッチをオンにします。

  9. [設定]アイコンをクリックして、[フォームを送信する]設定を確認してください。必要に応じて変更して、[保存]ボタンをクリックします。

これで、Google Formsに来たアンケートの回答がGoogle Spread Sheetに自動的に転記されます。フォームを送信するたびに、スプレッドシートに新しい行が追加されます。

自動作成されたGoogle Spread Sheet

また予約枠を管理するために、上記のスプレッドシートに新しくシートを追加して名前を予定取得にします。

LINE Bot

LINEにメッセージを送り、受け取るにはLINEのMessagingAPIを使ってLINEBotを作成する必要があります。このMessagingAPIを使えば、後述するGoogle Apps Scriptからメッセージを受け取ったり、送信したりできます。

LINEのMessaging APIを使用してLINE Botを作成する手順を以下に説明します。

  1. LINE Developersに登録: LINE Developersサイト(https://developers.line.biz/)にアクセスし、アカウントを作成またはログインしてください。

  2. 新しいプロバイダーを作成: ダッシュボードで、「新しいプロバイダー作成」をクリックして新しいプロバイダーを作成します。プロバイダーはアプリケーションやサービスを識別するためのものです。

  3. 新しいチャネルを作成: プロバイダーが作成されたら、ダッシュボードの左側のメニューから「チャネル」を選択し、新しいチャネルを作成します。チャネルはLINE Botが動作するための設定や機能を提供します。

  4. チャネル設定: チャネル作成後、チャネルの設定ページに移動します。基本的な情報(チャネル名、説明、アイコンなど)を入力し、チャネルタイプとして「Messaging API」を選択します。

  5. チャネルの設定: チャネル設定ページで、必要な情報を入力します。これには、チャネルアクセストークン(APIの認証に使用されるトークン)の生成、Webhook URLの設定、使用する機能(メッセージ、プッシュ通知、プロファイルなど)の有効化が含まれます。

Google Apps Script(コード)

最後にGoogle Apps Script(GAS)で裏側のロジックを作成する方法を説明します。

GASはGoogleアカウントがあれば使用できます。

該当のSpreadSheetを開き、拡張機能>Apps Scriptと選択するとコードを記入できる画面が表示されます。

GASの画面への遷移
GAS編集画面

上記が編集画面になりますが、初めは何も入力されていないと思います。

左上のファイル>+>スクリプトで3つのファイルを追加します。

  • フォーム送信時.gs

  • 予約枠更新.gs

  • Line通知.gs

フォーム送信時.gsは申込フォームが登録された際に動きだします(詳しくは今回作ったもの>申し込みフォーム予約時処理参照)。

予約枠更新.gsはGoogleカレンダーの対応可能日時(空き枠)を申込フォームに反映する部分を担当します(詳しくは今回作ったもの>予約空き枠のフォームへの反映を参照)。

また、Line通知.gsについてはLINEBotからメッセージを送信するために利用します。

コードについてもそれぞれ載せておきます。

//フォーム送信時.gs
function updateCalendar() {
  var formSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('フォームの回答 1');
  var scheduleSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('予定取得');
  
  var lastRow = formSheet.getLastRow();
  var twitterName = formSheet.getRange(lastRow, 2).getValue(); // 「フォームの回答 1」の最後の行から2列目の値(Twitter名)を取得
  var twitterId = formSheet.getRange(lastRow, 3).getValue(); // 「フォームの回答 1」の最後の行から3列目の値(TwitterId)を取得
  var idToSearch = formSheet.getRange(lastRow, 5).getValue(); // 「フォームの回答 1」の最後の行から5列目の値を取得
  var note = formSheet.getRange(lastRow, 10).getValue(); // 「フォームの回答 1」の最後の行から10列目(ご質問やご相談事項、特筆事項などあればご記入ください(不感症気味・中イキ未経験、こんなシチュエーションが好きetc...))の値を取得
  
  //ツイッターIDが存在するか確認
    //存在する場合、後続処理
  if(checkTwitterIDExistence(twitterId)){
    //予約時間を抑える
    var success = false;
    var scheduleId = '';
    var data = scheduleSheet.getDataRange().getValues();
    try{
      for (var i = 1; i < data.length; i++) {
        var dt = Utilities.formatDate(new Date(data[i][2]), 'JST', 'yyyy/MM/dd HH:mm')
        Logger.log(dt + "=" + convertToDate(idToSearch));
        if (dt == convertToDate(idToSearch)) { //予約枠があるか
          scheduleId = data[i][0];
          break;
        }
      }
      //Logger.log('scheduleId:' + scheduleId);
      if (scheduleId) { // スケジュールIDが取得できた場合
        var calendar = CalendarApp.getDefaultCalendar();
        var events = calendar.getEvents(new Date(), new Date(2100,1,1), {max: 100});
        for (var i = 0; i < events.length; i++) {
          var event = events[i];
          var eventId = event.getId();
          if(scheduleId == eventId && event.getTitle() == '🧠'){ //eventのタイトルが🧠かどうか確認する。※予約のバッティング
            var titleToSet = '🧠' + getTimeString(idToSearch) + '~ ' + twitterName
            var descriptionToSet = formSheet.getRange(1, 1).getValue() + ':\n'
              + formSheet.getRange(lastRow, 1).getValue() + '\n';
            for(var i= 2; i <= 10; i++){
              descriptionToSet= descriptionToSet + '\n' + formSheet.getRange(1, i).getValue() + ':\n'
              + formSheet.getRange(lastRow, i).getValue() + '\n';
            }

            //予約を確定する。
            //予約枠を更新する。
            event.setTitle(titleToSet); // タイトルを変更
            event.setLocation(getTwitterProfileLink(twitterId)); //プロフのURLを記載
            event.setDescription(descriptionToSet);  //詳細(メモ)を記載
            event.addEmailReminder(24*60); //24時間前にEmail通知
            event.addPopupReminder(0); //0min前にポップアップ通知
            event.addPopupReminder(15); //15min前にポップアップ通知
            event.addPopupReminder(60); //60min前にポップアップ通知
                    
            formSheet.getRange(lastRow, 11).setValue('済'); //予約確定済み
            formSheet.getRange(lastRow, 12).setValue(titleToSet); //予約タイトル
            formSheet.getRange(lastRow, 13).setValue(scheduleId); //予約予定ID
            //予約枠の更新
            updateReasevationSlot();

            //相手のTwitterに予約確定DMと案内をお送りする。(※LINEでの通知とする。)
            var shinchaku = createShinchakuLineMessage(twitterId);
            var mocriMessage = createMocriLineMessage(twitterName,dateRegex(idToSearch));
            var lineMessage = createCopyPasteLineMessage(twitterName,twitterId,dateRegex(idToSearch),note);
            
            formSheet.getRange(lastRow, 14).setValue(shinchaku); //ProfileLink
            formSheet.getRange(lastRow, 15).setValue(lineMessage); //DM
            sendLineMessage(lineMessage);
            sendLineMessage(mocriMessage);
            sendLineMessage(shinchaku);
            success = true;
            break;
          }
        }
      }
    }catch(e){ //スケジュールIDが取得できない場合や予約に失敗した場合
      //相手のTwitterにお知らせする。「予約がうまくいきませんでした。お手数ですが再度」
      sendLineMessage("【送信失敗通知】予約に失敗しました。\n" + twitterName + "\nhttps://twitter.com/" + twitterId.replace("@","") + "\n" + e.description);
    }
  }else{
    //TwitterIDが存在しない場合、自分にエラー&通知
    sendLineMessage("【送信失敗通知】予約に失敗しました。\n" + twitterName + "\nhttps://twitter.com/" + twitterId.replace("@","") + "\n" + e.description);
  }
}

//日付型に変換
function convertToDate(dateString) {
  var dateRegex = /\d{4}\/\d{2}\/\d{2}/; // 「yyyy/mm/dd」の形式にマッチする正規表現
  var timeRegex = /\d{2}:\d{2}/; // 「hh:mm」の形式にマッチする正規表現
  var date = dateRegex.exec(dateString)[0]; // 日付部分の文字列を抽出
  var time = timeRegex.exec(dateString)[0]; // 時間部分の文字列を抽出
  var startDateTime = new Date(date + ' ' + time); // 日付と時間を結合してDateオブジェクトに変換
  
  var localStartDateTime = Utilities.formatDate(startDateTime, 'JST', 'yyyy/MM/dd HH:mm'); // JSTタイムゾーンに変換
  return localStartDateTime
}

function getTimeString(dateString) {
  var timeRegex = /\d{2}:\d{2}/; // 「hh:mm」の形式にマッチする正規表現
  var time = timeRegex.exec(dateString)[0]; // 時間部分の文字列を抽出
  return time
}

function getTwitterProfileLink(twitterID) {
  return "https://twitter.com/" + twitterID.replace('@', '');
}

function checkTwitterIDExistence(twitterID) {
  return true;
}

function dateRegex(str) {
  var pattern = /(\d{4}\/)(\d{2}\/\d{2})\(([^\)]+)(?:\)\s)(\d{2}:\d{2}~)/;
  var result = str.replace(pattern, "$2 $4");
  return result
}
//予約枠更新.gs
//定数
const formId = "①Google FormのId"; //Google FormのId
const emptyKey = '🧠'; //カレンダーの空き枠のタイトル名

function updateReasevationSlot(){
  addEventsToSheet();
  updateForm();
  deleteOldEvents();
}

//Google Spread Sheetの「予定取得」シートの3列目について2行目から最終行まで取得し、Google FormのフォームID「XXX」のフォームの「テスト」項目の選択肢に設定するGoogle Apps Scriptのプログラムを教えてください。その際、選択肢の形式をyyyy/mm/dd(a) HH:MM~に変更する。
function updateForm() {
  // スプレッドシートのシート名を指定
  var sheetName = "予定取得";
  // スプレッドシートのデータを取得
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName);
  var data = sheet.getRange(2, 3, sheet.getLastRow()-1, 1).getValues();
  var choices = [];
  // 選択肢の形式をyyyy/mm/dd(a) HH:MM~に変更し、配列に追加
  for (var i = 0; i < data.length; i++) {
    var dateString = Utilities.formatDate(data[i][0], "JST", "yyyy/MM/dd(E) HH:mm~");
    choices.push(dateString);
  }
  // フォームの選択肢を更新
  var form = FormApp.openById(formId);
  var item = form.getItemById("854743201");
  item.asListItem().setChoiceValues(choices);
}

//Googleカレンダーから「🧠」というタイトルかつ、現在以降の予定を取得し、Google Spread Sheetの「予定取得」シートの最終行に予定ID、タイトル、開始日時、終了日時、を予定IDをキーにして重複なく追加するプログラムをGASで作成
function addEventsToSheet() {
  var sheetName = "予定取得"; // スプレッドシートのシート名
  var numEvents = 100; // 取得する予定の数

  var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName);
  var lastRow = sheet.getLastRow();

  var calendar = CalendarApp.getDefaultCalendar();
  console.log(calendar.getName());
  var events = calendar.getEvents(new Date(), new Date(2100,1,1), {search: emptyKey, max: numEvents});

  var eventArray = [];
   if (sheet.getLastRow() > 1) {
    sheet.deleteRows(2, sheet.getLastRow() - 1);
   }
  for (var i = 0; i < events.length; i++) {
    var event = events[i];
    var eventId = event.getId();
    var eventTitle = event.getTitle();
    if (eventTitle == emptyKey){
      var eventStart = event.getStartTime();
      var eventEnd = event.getEndTime();

      var exists = false;

      for (var j = 2; j <= lastRow; j++) {
        var rowEventId = sheet.getRange(j, 1).getValue();
        if (rowEventId == eventId) {
          exists = true;
          break;
        }
      }
  
      if (!exists) {
        eventArray.push([eventId, eventTitle, eventStart, eventEnd]);
      }
    }
  }
  if (eventArray.length > 0) {
    sheet.getRange(2, 1, eventArray.length, 4).setValues(eventArray);
  }
}

//Googleカレンダーから「🧠」というタイトルかつ、現在以前の予定を取得し、予定を削除するプログラムをGASで作成。
function deleteOldEvents() {
  var calendar = CalendarApp.getDefaultCalendar();
  var now = new Date();
  var events = calendar.getEvents(new Date('2000/01/01'), now, {search: emptyKey}); // 「🧠」が含まれる現在以降の全てのイベントを取得

  for (var i = 0; i < events.length; i++) {
    console.log(events[i].getTitle() & events[i].getStartTime());
    if (events[i].isAllDayEvent() || events[i].isRecurringEvent()) {
      continue; // 終日イベントや繰り返しイベントは削除しない
    }
    if (events[i].getTitle() == '🧠' && events[i].getStartTime() < now) {
      events[i].deleteEvent(); // 開始時間が現在以前のイベントは削除する
    }
  }
}
//Line通知.gs
var url = "https://api.line.me/v2/bot/message/push";

// line developersに書いてあるChannel Access Token
var token = "②line developersに書いてあるChannel Access Token";//"YOUR_CHANNEL_ACCESS_TOKEN";
var userId = "③送信したいユーザーのLINE内部ID"; // "USER_ID_TO_SEND_MESSAGE_TO";

function sendFormLineMessage(index){
  var formSheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('フォームの回答 1');
  var twitterName = formSheet.getRange(index, 2).getValue(); // 「フォームの回答 1」の最後の行から2列目の値(Twitter名)を取得
  var twitterId = formSheet.getRange(index, 3).getValue(); // 「フォームの回答 1」の最後の行から3列目の値(TwitterId)を取得
  var idToSearch = formSheet.getRange(index, 5).getValue(); // 「フォームの回答 1」の最後の行から5列目の値を取得
  var note = formSheet.getRange(index, 10).getValue(); // 「フォームの回答 1」の最後の行から10列目(ご質問やご相談事項、特筆事項などあればご記入ください(不感症気味・中イキ未経験、こんなシチュエーションが好きetc...))の値を取得
  
  var shinchaku = createShinchakuLineMessage(twitterId);
  var mocriMessage = createMocriLineMessage(twitterName,dateRegex(idToSearch));
  var lineMessage = createCopyPasteLineMessage(twitterName,twitterId,dateRegex(idToSearch),note);
  
  formSheet.getRange(index, 14).setValue(shinchaku); //ProfileLink
  formSheet.getRange(index, 15).setValue(lineMessage); //DM
  sendLineMessage(lineMessage);
  sendLineMessage(mocriMessage);
  sendLineMessage(shinchaku);
}

function sendReservedLineMessage(twitterName,userName,reservedDateTime, note){
  sendLineMessage(createCopyPasteLineMessage(twitterName,userName, reservedDateTime, note));
  sendLineMessage(createShinchakuLineMessage(userName));
}

function createShinchakuLineMessage(userName){
  return "【依頼者】\n" + "https://twitter.com/" + userName.replace("@",""); 
}

function createMocriLineMessage(twitterName,reservedDateTime){
  return twitterName + "さん " + reservedDateTime; 
}

function createCopyPasteLineMessage(twitterName,userName,reservedDateTime, note){
  var n = "";
  if(note == ""){
    n="なし";
  }else{
    n=note;
  }
  return "【通話依頼申込】\n" + twitterName + "(" + userName + ")さん、申込フォームからご連絡いただきありがとうございます🙇‍♀️\n\
かけるです!\n\
\n\
下記の通り予約を受け付けました。\n\
 ・時間:" + reservedDateTime + "\n\
 ・特筆事項:" + n + "\n\
\n\
よろしくお願いします!\n\
\n\
また、通話はもくりというアプリのご利用をお願いしております。\n\
お手数ですがインストールして友達申請いただけますと幸いです。\n\
\n\
ふらっと集まれる作業通話アプリ「mocri(もくり)」で、一緒に作業しましょう!\n\
https://mocri.jp/invite/?from_user=ikigaofechi&r=0f5026083b\n\
ID:ikigaofechi\n\
\n\
当日お時間になったらアプリを開いて「ルーム>" + twitterName + "さん " + reservedDateTime + "」とタップしていっていただければと思います!"
}

function sendLineMessage(sendMessage) {
  //var message = "Hello, World!";
  
  var headers = {
    "Content-Type": "application/json; charset=UTF-8",
    "Authorization": "Bearer " + token,
  };
  
  var data = {
    "to": userId,
    "messages": [
      {
        "type": "text",
        "text": sendMessage
      }
    ]
  }; 
  var options = {
    "method": "post",
    "headers": headers,
    "payload": JSON.stringify(data),
  }; 
  UrlFetchApp.fetch(url, options);
}

「①Google FormのId」についてはFormの編集画面でURLのe/以降から次の/までの値を設定します。

「②line developersに書いてあるChannel Access Token」はLINEBotを作成した際の管理画面のチャネルアクセストークンを設定します。

「③送信したいユーザーのLINE内部ID」についてはLINEBotを作成した際の管理画面のあなたのユーザーIDを設定します。

これでGASのコードの作成は完了です。

作成したスクリプトを保存してください。

そして、Googleカレンダーの空き枠と申込フォームの希望日時の選択肢の同期をとるために、定期的にプログラムを走らせる設定を追加します。

GASのトリガー設定をします。

GASの編集画面の左のメニューの時計マークのトリガーをクリックするとトリガー設定画面に移動します。

右下のトリガーを追加を押下して2つのトリガーを追加します。

それぞれ保存して設定終了です。

※GASについてより詳しく知りたい方はこちらもご参照ください。

以上が自動予約システムの作り方になります。


どの程度どんな依頼が来ているのか

今回構築した自動予約システムですが、実際どんな感じで依頼が来てるのかみたいな情報も参考として載せておきます。こういうのが見られるのもシステム化するメリットですね👏

脳イキ・催眠経験
依頼者の属性
依頼者の年代や地域分布

・たくさん言葉責めしてほしい
・中イキ・外イキ未経験
・男性経験なし
・不感症かもしれない
・動画やレビューに興味があったので依頼した

良くいただくご質問やご相談事項、特筆事項例(一部抜粋)

こんな感じで場所、年齢、パートナーの有無、経験、未経験問わずご依頼いただいているようです。

最後に

ここまで見ていただいたきありがとうございます。

以上が今回作成した自動予約システムの全容になります。

作るだけならChatGPTと組み合わせて半日でできるので割と作りやすかったです。

また、しばらく使ってみた感想としてはめちゃくちゃ快適です。

事務的な作業から解放されてその分を通話でお話しする時間に回せたり設けられたり、他のことにも注力できるので、とっても便利です。

ただ効率化でき、便利なのは確かなのですが、一方で、かなり機械的な対応になるので、人の温かみがないように感じると思います。

その点はご注意ください。

また、ご質問やこういった簡単なシステム作成のご依頼等ありましたら、遠慮なくご連絡ください。

お待ちしています。

この記事が気に入ったらサポートをしてみませんか?