Google Apps Scriptでスプレットシートで管理しているタスクをslackにリマインドしてくれるbotを作ってみた

Google Apps Scriptでスプレレットシートのタスクをslackにリマインドしてくれるbotを作ってみた


## 背景
- スプレットシートのチームのタスクを管理していたのだが、タスクの期限切れが多く、タスク自体を失念しているケースが多かったため、出社時と退社時にリマンドしてくれるボットを作った。

##結果
- タスク確認のMTGがなくなった。
- 期限切れは無くならなかったが、タスク遅延期間が長くても1日遅れくらいに収まった
- タスクの内容も記載しているため、マネージャーとのコミュニケーションがいい意味で減った。（状況把握に時間がかからない。）


## コード
タスク管理しているスプレットシートによって、少々修正を加えなければならないです。ご注意ください。


```js
// トリガーする時間を設定
var postTimes = [
  [9, 45],
  [18, 30]  
];

(function(global){
  var Slack = (function() {

    function Slack(options){
      var options = options || {};
      this.url = options.url || "https://slack.com/api/chat.postMessage";
      this.token = options.token || UserProperties.getProperty('SlackAccessToken');
      this.channel = options.channel || "#" + UserProperties.getProperty('PostedChannelName');
      this.username = options.username || UserProperties.getProperty('SlackBotName');  // ボットの名前　（デフォルト値を設定）
      this.icon_emoji = options.icon_emoji || UserProperties.getProperty('SlackBotIcon');  // ボットのアイコン画像を指定　（デフォルト値を設定）
    }

    Slack.prototype.send =  function(text) {
      var self = this;
      UrlFetchApp.fetch(self.url, {
        "method" : "POST",
        "payload" : {
          token: self.token,
          channel: self.channel,
          username: self.username,
          icon_emoji: self.icon_emoji,
          text: text
        }
      });
    };

    return Slack;
  })();

  global.Slack = Slack;
})(this);

// triggerTimesに設定された全ての時間のトリガーを設定
function setTrigger() {
  var triggerDay = new Date();
  for(var i = 0; i < postTimes.length; i++) {
    triggerDay.setHours(postTimes[i][0], postTimes[i][1]);
    ScriptApp.newTrigger("main").timeBased().at(triggerDay).create();
  }
}

// その日のトリガーを削除する関数(消さないと残る)
function deleteTrigger() {
  var triggers = ScriptApp.getProjectTriggers();
  for(var i=0; i < triggers.length; i++) {
    if (triggers[i].getHandlerFunction() == "main") {
      ScriptApp.deleteTrigger(triggers[i]);
    }
  }
}

function isJapaneseHoliday(date) {
  var startDate = new Date(date.getTime());
  var endDate = new Date(date.getTime());
  startDate.setHours(0, 0, 0, 0);
  endDate.setHours(23, 59, 59, 999);

  var cal = CalendarApp.getCalendarById("ja.japanese#holiday@group.v.calendar.google.com");
  var holidays = cal.getEvents(startDate, endDate);

  return holidays.length != 0;
}

function isHoliday(date) {
  return date.getDay() == 0 // 日曜かどうか
    || date.getDay() == 6 // 土曜かどうか
    || isJapaneseHoliday(date); // 日本の祝日かどうか
}

function getMsgBody(data) {
  var line = "------------------------------------------\n";
  var msg = line + ":sunny:*本日期限のアクション一覧は以下の通りです。*:sunny:\n";

  if (data.today.length != 0) {　// 今日のアクションがある場合
    msg += (data.today.join("\n"));
  } else { // 今日のアクションがない場合
    msg += ":tada: なし :tada:\n";
  }
  
  if (data.past.length != 0) {
    msg += (
      
      "\n\n\n\n:zap::smiling_imp:*期限切れのアクション一覧は以下の通りです。*:smiling_imp::zap:\n" +
      data.past.join("\n")
    );
  } else { // 今日のアクションがない場合
    
    
    msg +=　"\n\n\n\n:zap::smiling_imp:*期限切れのアクション一覧は以下の通りです。*:smiling_imp::zap:\n" 
    　　 + "\n" + ":tada::tada::tada: なし :tada::tada::tada:\n";
  }
  
  msg += line;
  return msg;
}

function main() {  
  // 土日祝日はこの先の処理を行わない
  var today = new Date();
  today.setHours(0, 0, 0, 0);
  if (isHoliday(today)) return;

  // ここからの列を定義する変数は、各自調整が必要になります。
  var spreadsheetId = UserProperties.getProperty('SpreadsheetId');
  var sheetName = UserProperties.getProperty('SheetName');
  var sheet = SpreadsheetApp.openById(spreadsheetId).getSheetByName(sheetName);
  var lastRowIndex = sheet.getLastRow(); // データが入力されている最終行の行番号を取得
  var dateColumnIndex = 22;              // 「期限」カラムの列番号
  var clientColumnIndex = 2;             // 「顧客正式名称」カラムの列番号
  var siteColumnIndex = 3;               // 「サイト名称」カラムの列番号
  var managerColumnIndex = 7;            // 「担当者」カラムの列番号
  var actionColumnIndex = 21;            // 「ネクストアクション」カラムの列番号
  var mentionColumnIndex = 56;            // 「メンションアクション」カラムの列番号
  var data = { today: [], past: [] };    // slackに送信するメッセージを保持

  for(rowIndex = 1; rowIndex <= lastRowIndex; rowIndex++) {
    var displayedDate = sheet.getRange(rowIndex, dateColumnIndex).getDisplayValue();

    // セルの値が日付のフォーマット(xxxx/xx/xx)かどうか
    if(!/\d{4}\/\d{2}\/\d{2}/.test(displayedDate)) continue;

    var parsedDate = new Date(displayedDate);
    if (parsedDate.getTime() <= today.getTime()) { // 期限が今日以前の場合
      var clientName = sheet.getRange(rowIndex, clientColumnIndex).getDisplayValue();
      var siteName = sheet.getRange(rowIndex, siteColumnIndex).getDisplayValue();
      var managerName = sheet.getRange(rowIndex, managerColumnIndex).getDisplayValue();
      var action = sheet.getRange(rowIndex, actionColumnIndex).getDisplayValue();
      var mention = sheet.getRange(rowIndex, mentionColumnIndex).getDisplayValue();
      var item = "
                 + "クライアント名：" + clientName + "\n"
                 + "サイト名：" + siteName + "\n"
                 + "担当者：" + managerName + "( " + mention + " )" + "\n"
                 + "アクション内容:\n" + action + "\n"
                 + "\n";"

      var type = parsedDate.getTime() == today.getTime() ? 'today' : 'past';
      data[type].push(item);
    }
  }
  
  var slack = new Slack();
  var msg = getMsgBody(data);
  slack.send(msg);
}
```