【営業向け】インサイドセールスでお客様とアポイントが取れたとき、社内で空いている会議室を自動で確保する

#やりたいこと＆その理由

以前に以下の記事を書きました。

[【営業向け】インサイドセールスでアポ取得できたときのお客様へのメールを自動生成する](https://qiita.com/hirokobe26/items/3a6f1ce721bb833d735c)

WEB面談のアポイントが取れたときに社内の会議室を探すということをしておりましたが、お客様へのメールを生成するのと同時に、社内の会議室を確保できないかと思い、自動化いたしました。これで、会議室を探す時間を短縮し、さらに次のお客様へお電話することができます。

以前に書いたコードを少しリファクタリングしながら、新しくメソッドを追加しております。

#実装方法
１：　自分のGoogleカレンダーを取得
２：　現在から2か月先の予定を配列で取得
３：　2の配列の中で、一番最近に作られた予定を取得
４：　社内の会議室の予定を取得
５：　2で取得した予定と、4で取得した予定を付け合わせる
６：　もし、会議室が空いているようであれば、空いている会議室を確保する


#完成系

```コード.js
const CALENDAR_ID = 'カレンダーID';

//アポイントの予定をカレンダーから取得し、もし会議室がすでにセットされてあれば、
//メールの下書きを作成するのを止める
function judgeIfFunctionTrigger(){
  const calendar  = CalendarApp.getCalendarById(CALENDAR_ID);
  const startTime = new Date();
  const endTime   = new Date();
  endTime.setMonth(endTime.getMonth() + 2);
  var newestEvent = getNewestEvent(calendar, startTime, endTime);
  var guestArr = newestEvent.getGuestList();
  var count    = 0;
  for(let i = 0; i < guestArr.length; i++){
    if(guestArr[i].getEmail().match(/@resource.calendar.google.com/)){
      count += 1;
    }
  }
  if(count == 0){
    createEmailDraft(newestEvent);
  }
}

//お客様向けのメールを生成するメソッド。今回のメインになるメソッド。
function createEmailDraft(newestEvent) {
  if(newestEvent.getTitle().match(/WEBお打合せ/)){
    var checkIfMtgRoomIsEmpty = checkMeetingRoom(newestEvent);
    if(checkIfMtgRoomIsEmpty.boolean){
      bookMeetingRoom(newestEvent,checkIfMtgRoomIsEmpty.mtgEmail);
    }
  }
  
  var emailInformation = getInformationForEmail(newestEvent);
  var template_index   = HtmlService.createTemplateFromFile('body');
　template_index.arr = [emailInformation.companyName,
                       emailInformation.name,
                       emailInformation.mtgMonth + 1,
                       emailInformation.mtgDate,
                       emailInformation.mtgDay,
                       emailInformation.mtgHour,
                       emailInformation.mtgMinutes,
                       emailInformation.mtgUrl];

  var html             = template_index.evaluate().getContent();
  
  if(newestEvent.getTitle().match(/WEBお打合せ/) || newestEvent.getTitle().match(/往訪/) && newestEvent.isOwnedByMe() && newestEvent.getTitle().match(/確定/)){
    GmailApp.createDraft(emailInformation.toEmail, emailInformation.subject, html,{cc: emailInformation.ccEmail, htmlBody: html});
  }
}

//最新の予定（つまりアポイント）を取得するメソッド
function getNewestEvent(calendar, startTime, endTime){
  var events    = calendar.getEvents(startTime, endTime);
  var arrUpDate = [];
  for (var i = 0;i<events.length;i++){
    arrUpDate.push(events[i].getLastUpdated().getTime());
  }
  
  var maxDay = Math.max.apply(null,arrUpDate);//更新日時の最大値の取得
  var index  = arrUpDate.indexOf(maxDay);//インデックスの取得
  return events[index];
}


//社内で空いている会議室を探して、仮に会議室が空いていたらTrueを返している
function checkMeetingRoom(newestEvent){
  const newEventStartTime = newestEvent.getStartTime();
  const newEventEndTime   = newestEvent.getEndTime();
  var mtgRoom1 = "mtg1@resource.calendar.google.com";
  var mtgRoom2 = "mtg2@resource.calendar.google.com";
  var mtgRoom3 = "mtg3@resource.calendar.google.com";
  var mtgRoom4 = "mtg4@resource.calendar.google.com";
  var mtgRoom5 = "mtg5@resource.calendar.google.com";
  var mtgRoomArr = [mtgRoom1,mtgRoom2,mtgRoom3,mtgRoom4,mtgRoom5];
  for(let i = 0; i < mtgRoomArr.length; i++){
    var mtgCalendar = CalendarApp.getCalendarById(mtgRoomArr[i]);
    var checkEvent = mtgCalendar.getEvents(newEventStartTime, newEventEndTime);
    if(checkEvent[0] == null || checkEvent[1] == null){
      return {
        "boolean": true,
        "mtgEmail": mtgRoomArr[i]
      };
    }
  }
}

//会議室を予約するメソッド
function bookMeetingRoom(newestEvent,mtgRoomEmail){
  newestEvent.addGuest(mtgRoomEmail);
}

//メールに必要な情報を抜き出すメソッド
function getInformationForEmail(newestEvent){
  var dayOfWeekStr = ["日曜日", "月曜日", "火曜日", "水曜日", "木曜日", "金曜日", "土曜日"];
  
  var titleWithArr    = newestEvent.getTitle().split("　");
  var companyName     = titleWithArr[1];
  var name            = titleWithArr[2];
  var mtgMonth        = newestEvent.getStartTime().getMonth();
  var mtgDate         = newestEvent.getStartTime().getDate();
  var mtgHour         = newestEvent.getStartTime().getHours();
  var mtgMinutes      = newestEvent.getStartTime().getMinutes();
  if(mtgMinutes == 0){
    mtgMinutes = "00";
  }
  var mtgDay          = dayOfWeekStr[newestEvent.getStartTime().getDay()];
  var toEmail         = newestEvent.getGuestList()[0].getEmail();
  var ccEmail         = 'saasbiz@wealth-park.com';
  var subject         = name + ':お打合せの日程に関しまして/WealthPark奥野';
  var mtgUrl          = newestEvent.getLocation();
  return {
    "companyName": companyName,
    "name": name,
    "mtgMonth": mtgMonth,
    "mtgDate": mtgDate,
    "mtgHour": mtgHour,
    "mtgMinutes": mtgMinutes,
    "mtgDay": mtgDay,
    "toEmail": toEmail,
    "ccEmail": ccEmail,
    "subject": subject,
    "mtgUrl": mtgUrl
  };
}
```

#詰まったポイント

GoogleAppsScriptの仕様ですが、カレンダーが更新されるたびにメソッドがトリガーがされるようになっています。以下のようにカレンダーのゲストに会議室を入れるようにすると、それだけでカレンダーが更新されたと認識して再帰的に何度もメソッドが呼ばれてしまい、無駄なドラフトがたくさん作成されてしまいます。

```
function bookMeetingRoom(newestEvent,mtgRoomEmail){
  newestEvent.addGuest(mtgRoomEmail);
}
```

なので今回の実装ですが、createEmailDraftの前に、取得した予定のゲストに会議室が入っていないか判定をして、入っていないようであればcreateEmailDraftをトリガーするようにしています。

```
function judgeIfFunctionTrigger(){
  const calendar  = CalendarApp.getCalendarById(CALENDAR_ID);
  const startTime = new Date();
  const endTime   = new Date();
  endTime.setMonth(endTime.getMonth() + 2);
  var newestEvent = getNewestEvent(calendar, startTime, endTime);
  var guestArr = newestEvent.getGuestList();
  var count    = 0;
  for(let i = 0; i < guestArr.length; i++){
    if(guestArr[i].getEmail().match(/@resource.calendar.google.com/)){
      count += 1;
    }
  }
  if(count == 0){
    createEmailDraft(newestEvent);
  }
}
```

なので、今回は直接createEmailDraftを呼ぶのではなくて、judgeIfFunctionTriggerを先に呼ぶようにしています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271600/d8c928d9-99f2-6f96-acd3-5a664f84ae9e.png)



#会議室のIDの調べ方
ちなみに、会議室のIDの調べ方は、自分のカレンダーIDを調べる方法とまったく同じです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/271600/da82cf0c-f0a1-a44f-c57e-e85ce19f3cad.png)