GoogleカレンダーにGoogleフォームから書き込む

## 目的
勤怠連絡先が多種にわたるためGoogleフォームを起点として、連携するために作成しました。

メーリングリストを起点とした連携は出来ていました。
1. メーリングリスト
2. Slack
3. Chatwork

連絡後にGoogleカレンダーへの記載を忘れたり、Googleカレンダーを記載しても連絡が漏れるケースがありました。  
そのためGoogleフォームで必要事項を記入後、GASでGoogleカレンダーへの記載、ならびに連絡が出来るようにします。

またログインしたユーザIDと同じカレンダーIDに書き込みをするようにしております。

## Google フォーム
1. 下記の様に作りました。

    ![https___qiita-image-store.s3.ap-northeast-1.amazonaws.com_0_34174_0f9d2c99-684b-341b-80ad-075ead7a98b0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34174/55ad64bb-9620-7396-4327-767b6cd1793b.png)



1. Googleアカウントによりログインしたメールアドレスを取得するために設定をします。
    ![2020-10-29_19h10_20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34174/91f90ac7-66cb-85c7-f92a-e954eb448e44.png)


## Google App Script
### スプレッドシートレイアウト
1. 回答は下記レイアウトでスプレッドシートに記載されます。上記で設定したメールアドレスも記載されます。

    | タイムスタンプ | 種別 | 日付 | 出社予定時刻(出社遅れのみ記入) | 登録理由 |  メールアドレス |
    |---------|----|----|------------------|------|------|

1. その他に必要な情報、メール送信内容を記載するための項目を追加しました。

    | タイムスタンプ | 種別 | 日付 | 出社予定時刻(出社遅れのみ記入) | 登録理由 | メールアドレス | 報告済み | カレンダーID| 名前 | 内容 |
    |---------|----|----|------------------|------|---------|------|---------|----|----|

### スプレッドシートからデータ取得
1. アクティブなシートを指定します。

    ```JavaScript:
    var mySheet = SpreadsheetApp.getActiveSheet();
    var dat = mySheet.getDataRange().getValues();
    ```

1. 指定したシートから"報告済み"になにも記載がない回答を取得します。

   ```JavaScript:
   // Googleフォームの回答結果が記載されているスプレッドシートから情報を取得する。
   // dat[i][6]に"報告済み"が記載させていないデータが対象
   for(var i=1;i<dat.length;i++){
     if(dat[i][6] == ""){
      // 回答を取得したあとの処理
   }
    ```
```
### カレンダーへの書き込み処理

1. 種別によりカレンダーの開始・終了時間を指定します。

    ```JavaScript:
      // 種別取得
      var selectedType = dat[i][1];
      
      if (selectedType == "終日休暇"){
        var fromDate = new Date(dat[i][2]); 
        fromDate.setHours(9);
        fromDate.setMinutes(30);
        
        var toDate = new Date(dat[i][2]);        
        toDate.setHours(17);
        toDate.setMinutes(30);        
        
      }else if(selectedType == "午前半休"){
        var fromDate = new Date(dat[i][2]); 
        fromDate.setHours(9);
        fromDate.setMinutes(30);
        
        var toDate = new Date(dat[i][2]);        
        toDate.setHours(14);
        toDate.setMinutes(30);

      }else if(selectedType == "午後半休"){    
        var fromDate = new Date(dat[i][2]); 
        fromDate.setHours(14);
        fromDate.setMinutes(30);

        var toDate = new Date(dat[i][2]);        
        toDate.setHours(17);
        toDate.setMinutes(30);

      }else if(selectedType == "出社遅れ"){
        var fromDate = new Date(dat[i][2]); 
        fromDate.setHours(9);
        fromDate.setMinutes(30);
        
        var toDate = new Date(dat[i][2]);
        var arriveAtWorkTime = new Date(dat[i][3]);
        toDate.setHours(arriveAtWorkTime.getHours());
        toDate.setMinutes(arriveAtWorkTime.getMinutes());
      }
`
```

1. カレンダーに書き込みます。カレンダーを共有していないときに発生するエラーを拾っています。

    ```JavaScript:
      // Googl フォーム機能により取得した回答したユーザのメールアドレスをスプレッドシートから取得
      var calendarID = dat[i][5];

      // カレンダーオプションjson作成
      var calDescription = dat[i][4];
      var options = {
        description: calDescription
      }
      
      try{
        //ログインユーザＩＤでカレンダー特定
        var myCal = CalendarApp.getCalendarById(calendarID);
     
        // カレンダー記入
        var myEvt = myCal.createEvent(selectedType,fromDate,toDate, options);
        var result = "";    
        
      }catch(e){
        var result = "エラーの内容:" + e;
      }
    ```

### メール送信処理

1. メール本文作成functionを書きます。

```JavaScript:
      // 本文生成  
      var mailBody = makeBody(selectedType,fromDate, toDate, calDescription,calendarID, result);  
  
　　　 // メールを送信する  
      GmailApp.sendEmail(toMail, subject, mailBody)  
```    

2. functionの中身となります

```JavaScript:
function makeBody(selectedType,fromDate, toDate, calDescription,calendarID, result){   
  // メール内容の分岐   
  if (selectedType == "出社遅れ"){   
    var workTime = Utilities.formatDate(toDate,"GMT+0900","HH:mm");   
    var message = "お疲れ様です。\n"+ calendarID + "です。\n\n" + calDescription + "のため" + selectedType + "とさせていただきます。\n"+ "出社は" + workTime + "を予定しています。\n\n以上、よろしくお願いいたします。"   
  }else{   
    var message = "お疲れ様です。\n"+ calendarID + "です。\n\n" + calDescription + "のため" + selectedType + "とさせていただきます。\n\n"+ "以上、よろしくお願いいたします。"   
  }   
 
  // エラーが有った場合の文言追加   
  if (result != ""){   
    message += "\n\n エラーのためカレンダーに書き込めませんでした。管理者にご連絡後、使用可能となります。" + result;   
  }  
  return message  
}   
```

### 結果をスプレッドシートに書き込むために配列に格納します。

```JavaScript:
      // 完了結果を配列に格納
      dat[i][6]="報告済み";
      dat[i][7]=calendarID;
      dat[i][8]=mailBody;    
```

### スプレッドシートに書き込みます。

```JavaScript:
  //完了内容記入
  mySheet.getRange(1,1,i,10).setValues(dat);

```

## トリガー設定
Google App Scriptが動作するためのトリガーを設定します。

![2020-10-29_19h50_56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34174/dfd35e08-7a20-bca0-893a-d0b13f9fb0ad.png)



## 結果
### スプレッドシートへの書き込みはこうなります。
ずれてました…。

![2020-10-29_19h30_52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34174/8e9e6212-63a6-585a-d893-13f5d1768d43.png)


### メール内容はこんな感じです。
![2020-10-26_20h19_041.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34174/7cf73998-0536-71f4-7c18-ae1062af9a9f.png)


### カレンダー内容はこんな感じです。
![2020-10-26_20h18_471.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34174/c89351ba-25bf-c5b4-c544-6c48ca4b240b.png)


## 悩んだところ。
当初メールアドレス取得は下記の様にしていました。

```JavaScript:
  // Googleにログインしているメールアドレスを取得  
  var emailaddress = Session.getActiveUser();
  
  // メールアドレスからフルネームを取得
  var contact = ContactsApp.getContact(emailaddress).getFullName();  
```

しかしこの方法だとGoogleフォームにログインしているメールアドレスが取得できないため、フォームの回答から取得するように変更しました。もうすこし上手い方法がありそうですが…。