Slack×GASで作った勤怠Botの話#7

UG Advent Calendar 2020 の7日目の記事です。

どうもbarusuです。知らない方は初めまして。
昨日の続きです。
フィクションと思って読んでいただければ幸いです。

Slack×GASで作った勤怠Botの話 #7

2020年5月。
良くも悪くもコロナ禍による新しい生活様式が定着しはじめた頃のお話。

―――――――ちょっとさ、勤怠システム作れない?

すべては法務部長の一言から始まった…

全10話分の5話目となります。
 2020/12/01:導入,初期の要望
 2020/12/02:設計
 2020/12/03:構築その1 :SlackBotを作る
 2020/12/04:構築その2 :GASを書く(基本メソッド編)
 2020/12/05:構築その3 :GASを書く(ユーティリティ編)
 2020/12/06:構築その4 :GASを書く(機能実装編:打刻処理)
 2020/12/07:構築その5 :GASを書く(機能実装編:ユーザー管理機能,リマインド機能)  ← 今日はココ
 2020/12/08:構築その6 :色々書く(機能実装編:,勤怠修正機能)
 2020/12/09:単体,ユーザーテスト
 2020/12/10:そして伝説へ...

Barusu
「ひひーん」

Barusu
「前回は打刻処理を追加したところまでだったな」

▼簡易設計
下準備:SlackAccessTokenを設定しておく
基礎
 投稿を受け取り、スプレッドシートに記載してSlackに返す
 投稿したユーザー名をSlackAPIを用いて取得
 ユーザーにDMを送る
 投稿内容に応じて異なる処理を実行する

各種ユーティリティ
 日付のフォーマットを変更する
 スプレッドシートの範囲から連想配列を作成する
 連想配列を二次元配列に変換する
 祝日一覧を取得してシートに転記
 GoogleWorkspaceのユーザー一覧を取得してシートに転記 

機能実装予定のもの
1. 打刻機能
 a.  出勤、退勤、中抜け に反応する仕組みを作る
 b. 出勤打刻を受け取ってスプレッドシートに今の時刻を記載する
  例外:出勤済ならば「出勤してます」と返す
 c. 中抜けを受け取ってスプレッドシートに記載する
  例外:未出勤ならば「出勤してません」と返す
  例外:時刻データが不正の場合は「形式が正しくありません」と返す
 d. 退勤打刻を受け取ってスプレッドシートに記載する
  例外:未出勤ならば「出勤してません」と返す
  例外:退勤済ならば「退勤済ですが上書きしますか?」と返す
---(今日はココから)---
2.ユーザー管理機能
 a. 初めて投稿したユーザーは勤怠ユーザーリストに追加する
 b. Gsuiteからメールアドレスを取得し、Slackユーザーリストと紐付ける
3. リマインド機能
 a. 今日が平日ならば→指定時間帯に未打刻のユーザーにDMを送る
 b. 退勤をしていないユーザーにDMを送る
---(今日はココまで)---
4. 勤怠修正機能
 a. Googleフォームで修正申請を受付
 b. 指定の承認者のみが承認できるようにする
 b. 別の勤怠修正フォームから承認された勤怠データとデータを合流させる
5. アラート機能
 a. 月末残業予測値を算出し、しきい値を超えた者はアラートを出す 

Barusu
「もはや見慣れた感ある」

Barusu
「とりあえず今日はユーザー管理機能,リマインド機能を追加する」

Barusu
「今回、ソースコードはすべてお見せできないので予めご容赦。
ざっくり、ユーザー管理機能とリマインド機能の設計について解説しておこう」

ユーザー管理機能

Barusu
「業務委託の勤怠を管理するためのBotなので、使う人、使わない人が存在する。
開発系の企業において業務委託の入退場って頻繁にあるし、アカウント追加削除のたびに手で作成/削除...なんてことはしたくない。更新漏れるし。
ユーザー管理なんていちいちやってられっか。
なので、Botに話しかけたらすぐに利用開始できるようにし、勤怠マスタに基本データを登録、SlackのメールアドレスからGsuiteの姓名を取得し、リストに記載、管理者に通知、そいつ専用の勤怠表を作成してリンク貼るまでの処理を自動にする。
プロセスを箇条書きにするとこうなる↓」

▼打刻~ユーザー管理機能実行まで
1. ユーザーからDMを受け取る(Slack EventSubscription→GAS発火)
2. ユーザーのDM内容から出勤,退勤,中抜け を判別
分岐check:ユーザーがリストに存在しない場合
 a. 別プロセスを起動するトリガーを追加
 b. [ UserList ] シートにSlackIDを記載する(AppendRow で行追加)
3. 各処理を実行して返す
~プロセス終了~
▼a.で追加されたトリガーにより自動起動
 IF:
[ UserList ] の先頭行が空白でなければ処理を開始する
  1.
[ UserList ] の先頭行からSlackユーザー名を取得
  2. Slackユーザー名からメールアドレスを取得(@domain.com つけるだけ)
  
3. [ UserList ] の行の先頭行を削除
  
4. 管理者宛にDMで通知(新規追加されたので稼働時間下限とか確認してねの連絡)
  5. 対象ユーザー用の勤怠データ表示シートを生成してリンクを記載する
 Else:([ UserList ] の先頭行が空白だった)
  1.このプロセスを起動するトリガーを削除する
 ~プロセス終了~

Barusu
「ほとんど白塗りだけど、シートはこんな感じ。
下限、上限、丸め単位、承認者メールアドレス欄は手動入力」

画像1

Barusu
「SlackBotから呼び出したプロセスの中でこの処理もやっちゃうと遅くなるので分離する必要があるのよね。
なのでトリガーセットしたって感じ。工夫したのはそこかしら」

リマインド機能

Barusu
「打刻忘れを防ぐために、リマインド機能をつける必要があった。
リマインドするケースは2つだけ。()内は条件。
・出勤打刻を忘れているケース(平日であり、10時を過ぎている)
・退勤打刻を忘れているケース(出勤打刻済であり、21:00を過ぎている)
まぁなんてことはない簡単な機能。
こちらはソース貼れるのでお見せしますわよ」

リマインド機能:出勤打刻忘れ

// 出勤打刻忘れをリマインドする
function checkTodaySignIn(){
 var sheet =SpreadsheetApp.getActiveSpreadsheet().getSheetByName('TodayAppendCheck');
 var lastRow = sheet.getLastRow();
 var lastCol = sheet.getLastColumn();
 var todayFlag = sheet.getRange(1,6).getValue();

 if (todayFlag > 0){ //今日が平日なら実行する

 //シートをまるごと変数にぶち込む
 var array = sheet.getRange(1,1,lastRow,3).getValues();

   var message = '打刻忘れてません??'
 
 var notYetUserid = [];
 for (var i =0;i<array.length;i++ ){
   if(array[i][1] != '' && array[i][2] == ''){
     Logger.log('nowArray Is... ' +array[i][1] +'' + array[i][2]);

     postMessage(array[i][1], message);

   }
   
 }
 }
 
}

Barusu「[ TodayAppendCheck ]のシート内容はこんな感じ↓。
A,B列はユーザーリストからUnique関数を使って引っ張ってきて、C,D列は当日勤怠データからVlookupで打刻データを持ってきている。
平日判定はNetworkDays関数と祝日一覧シートを使って判別してる。
起動したときに今日が平日かどうかはGASじゃなくて、スプレッドシート側で判別している感じ」

画像2

リマインド機能:退勤忘れ

//今日の退勤忘れをチェックする
function checkTodaySignOut(){
 var sheet =SpreadsheetApp.getActiveSpreadsheet().getSheetByName('TodayAppendCheck');
 var lastRow = sheet.getLastRow();
 var lastCol = sheet.getLastColumn();
 var todayFlag = sheet.getRange(1,6).getValue();

 if (todayFlag > 0){ //今日が平日なら実行する

 //シートをまるごと変数にぶち込む
 var array = sheet.getRange(1,1,lastRow,4).getValues();
 Logger.log(array);

   var message = 'まだ働いてんの??がんばるねぇー'
 //打刻忘れの場合のフラグ処理をする

 var notYetUserid = [];
 for (var i =0;i<array.length;i++ ){
   if(array[i][2] != '' && array[i][3] == ''){
     Logger.log('nowArray Is... ' +array[i][1] + array[i][2]);

     postMessage(array[i][1], message);

   }
   
 }
 }

   
}

Barusu「こちらも出勤打刻リマインドと同様で[ TodayAppendCheck ]のシートから取ってきている。
書いてて今気づいたのだが、出勤と退勤でFunction分けてる意味があんまりないし、これは一緒にしても良いな...」

Barusu
「はい!っということでね。
ユーザー管理機能とリマインド機能は実装できたわけですわ。
次回は勤怠修正フォームと承認、マスターデータとの合流をどうするのか?を解決していく」

次回予告

やっとこ勤怠機能の主要なとこを最低限実装できたBarusu。
現実の時間にして、ここまで3週間ちょっと!喫煙所で法務部長から無茶振りされたあの日から1ヶ月経ってないぞ!
客観すると納期には間に合いそうだが、実際はかなりヘロヘロだったぞ!

次回、「全員が正しく勤怠入れてくれればこんなものいらないのに」。デュエルスタンバイ!

画像3


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