はじめに
弊社では、「⚪︎日は休暇で不在ですよー」とお知らせするSlackチャンネルがあります。
(正式な休暇申請のシステムとは別です)
この情報をワークフローで取得し、休暇取得者一覧としてGASで毎朝自動投稿する機能を作成しました。
通知までの流れ
- 休暇取得者がSlackのワークフローで情報をフォームに入力
- 入力した情報がチャンネルへ投稿&スプレッドシートに追記される
- 毎朝、スプレッドシートからその日の休暇取得者情報を取得
- チャンネルに自動投稿
使用技術
- Slackのワークフロー
- GAS(GoogleAppsScript)
- incoming webhooks(外部からSlackにメッセージを投稿するための機能)
Slackのワークフローの作成
ワークフローの開始イベント
- Slack内のリンクから開始
情報をフォームで収集する
- 申請者:Slackユーザー
- 休暇開始日:日付
- 休暇終了日:日付
- 予定時刻:短い回答
- 備考:リッチテキスト
- 休暇申請はしたか:チェックボックス
- カレンダーに休暇予定を記入したか:チェックボックス
チャンネルへメッセージを送信する
- ワークフローが使用されたチャンネル
Google Sheets
- 該当のスプレッドシートを選択
GASで通知機能を作成する
連日取得(例:金と月に取得)に対応するための日付分割.gsと、
Slackに通知するための通知用.gsの2つを作成します。
スプレッドシートの「拡張機能」から「Apps Script」を選択します。
日付を分割する処理
日付を分割してスプレッドシートに追記するとき、入力した日付とずれる現象が発生したため、タイムゾーン関連のコードをしつこく書いてます。
日付分割.gs
function onChange(e) {
const sheet = e.source.getSheetByName("休暇連絡");
const notificationSheet = e.source.getSheetByName("通知用");
// 編集されたシートが「休暇連絡」であることを確認
if (sheet.getName() === "休暇連絡") {
const lastRow = sheet.getLastRow();
const newData = sheet.getRange(lastRow, 1, 1, sheet.getLastColumn()).getValues()[0];
// データの取得
const username = newData[0];
const startDate = new Date(newData[1]);
const endDate = new Date(newData[2]);
const plannedTime = newData[3];
const remarks = newData[4];
// タイムゾーンを適用して日付をローカルタイムゾーンに設定
const timezone = Session.getScriptTimeZone();
startDate.setHours(0, 0, 0, 0);
endDate.setHours(0, 0, 0, 0);
// startDateをローカルタイムゾーンでの正しい日付に調整
const startDateLocal = Utilities.formatDate(startDate, timezone, "yyyy-MM-dd");
let settingDate = new Date(startDateLocal); // startDateLocal を元に settingDate を設定
let rowIndex = notificationSheet.getLastRow() + 1; // 書き込み開始行
// 休暇日数分、「通知用」シートにデータを追加
do {
// settingDate をローカルタイムゾーンに合わせてフォーマット
const formattedDate = Utilities.formatDate(settingDate, timezone, "yyyy-MM-dd");
// 都度書き込み
notificationSheet.getRange(rowIndex, 1, 1, 4).setValues([[formattedDate, username, plannedTime, remarks]]);
// 次の行へ
rowIndex++;
// 日付を進める
settingDate.setDate(settingDate.getDate() + 1); // 日付を進める
settingDate.setHours(0, 0, 0, 0); // 時間部分をリセット
} while (settingDate <= endDate);
}
}
Slackに通知する処理
Slackに通知するためにはincoming webhookのURLを設定する必要があります。
(この記事では設定方法は割愛させていただきます)
平日のみ通知されるようにgetDayメソッド
を使っています。
通知用.gs
function sendVacationList() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('通知用');
var data = sheet.getDataRange().getValues();
var today = new Date();
var month = today.getMonth()+1;
var date = today.getDate();
var vacationUsers = [];
var vacationTimes = [];
var vacationNotes = [];
// 今日の休暇取得者を抽出
for (var i = 1; i < data.length; i++) {
var vacationDate = new Date(data[i][0]); // 休暇日を1列目から取得
if (vacationDate.toDateString() == today.toDateString()) {
vacationUsers.push(data[i][1]); // ユーザー名を2列目から取得
vacationTimes.push(data[i][2]); // 予定時刻を3列目から取得
vacationNotes.push(data[i][3]); // 備考を4列目から取得
}
}
// 休暇取得者がいた場合かつ平日であればSlackに送信
if (today.getDay() === 0 || today.getDay() === 6){ // 0 (日曜日) ~ 6 (土曜日)
console.log("休日のため通知しない");
} else {
if (vacationUsers.length > 0) {
var message = month + '月' + date + '日の休暇予定の方:\n'
// ユーザー名とその休暇時間を組み合わせて改行で区切ってリストにする
for (var i = 0; i < vacationUsers.length; i++) {
message += vacationUsers[i] + ', ' + vacationTimes[i] + ', ' + vacationNotes[i] + '\n';
}
} else {
// 休暇取得者がいない場合
var message = month + '月' + date + '日の休暇予定の方:\n'
var message = '本日の休暇取得者はいませんでした。';
}
var webhookUrl = 'Webhook URLをここに入力する';
var payload = JSON.stringify({text: message});
var options = { method: 'POST', contentType: 'application/json', payload: payload };
UrlFetchApp.fetch(webhookUrl, options);
}
}
まとめ
GASとSlackワークフローで収集した情報を自動投稿する機能を作ることができました。
(知識不足で、var,let,constの使い分けが正しくできていないかも……)
今後は、「朝のお知らせ」としてその日の情報を一覧で通知できるように改良したいです。