今回はクラウドの勤怠管理システムであるIEYASUのAPIをGASから利用してみたいと思います。この記事を書いている時点のIEYASU APIのバージョンは、1.0.6です。
目次
今回作ったシステム概要
今回はGASのHTML画面からIEYASUの勤怠の打刻をするシステムになります。
とても単純なシステムですが、応用するなら、打刻時に社員へアンケートをとって、社員のメンタルヘルスを管理したり、日報を書いてもらうなどの活用をすることができます。
日報をなかなか書いてくれない社員がいたとしても、勤怠とセットにすることで、やらざる得なくなります。ぜひ今回の勤怠の打刻の仕組みを活用して、社内により良い仕組みを導入してみてください。
「出勤」ボタンを押すと、ieyasu側に送信されて出勤の打刻が打てます。また、出勤中の場合は、「退勤」ボタンに変わり、押すと退勤打刻が打てるというシステムです。
また、名前のところには、Googleにログインしているユーザーの名前が表示され、状態欄には、今自分が出勤中なのか退勤中なのかを示してくれます。
IEYASUのAPIを有効にする
まずはIEYASU側でAPIを利用できるようにしましょう。
IEYASUの管理者権限のアカウントでログインし、「システム管理」画面へ移動してください。
システム管理画面の左側のメニューの「システム設定」へ移動してください。
システム設定画面にある「編集」ボタンを押し、「API KEYの設定」欄からSecret Keyを発行してください。Secret Keyは、後で使用しますので、コピーしておいてください。
IEYASUのAPIの説明は、下記のページに書いてありますので、ここを参考にしてプログラムを作っていきましょう。
https://ieyasu.co/docs/api.html
トークンを取得する
IEYASUのAPIから各種操作を行うには、まず初めに認証用のトークンを取得する必要があります。
APIを利用する場合、POSTかGETの方法でGASからAPIへ情報を送ります。
(GETはURLに情報を渡す方法で、POSTはHTTPヘッダーに情報を渡す方法です)
ここで認証用トークンを取得するAPIの説明を見てみましょう。
まずGETと書かれているので、このAPIはGETで叩く(アクセスする)ことがわかります。
次に、curlと書かれています。カールと読みますが、PHPの場合はcURL関数というのがあり、それでアクセスすれば良いのですが、GASの場合はUrlFetchAppクラスのfetch関数というものがありますので、それを使ってアクセスします。
-H 'Authorization: Basic MGE3M2Y2NDA3MTIxZTRlMzNkMDFhOTgw' -H 'Content-Type:application/json'
と書かれていますが、「-H」はHTTPヘッダーを意味します。ヘッダーの頭文字です。
Basicの後に書かれているアルファベットと数字の羅列が、先程取得した Secret Key になります。
では実際にGASでトークンを取得するプログラムを書いてみましょう。
let headers =
{
"Authorization" : 'Basic '+ieyasu_api_key,
"Content-Type" : 'application/json'
};
let options =
{
"method" : "get",
"headers": headers
};
let response = UrlFetchApp.fetch('https://ieyasu.co/api/'+compay_name+'/v1/authentication/token', options);
let json = JSON.parse(response.getContentText());
ieyasu_api_keyの変数には、 Secret Key を格納してください。
また、compay_nameの変数には、企業IDが入ります。企業IDは、ieyasuにログインする時に使っているURLの「https://ieyasu.co/xxxxx」のxxxxx部分になりますので、確認してみてください。
これでieyasuのAPIのトークンを取得することができます。ではAPIを叩いた後にどのようなレスポンスがあるのか見ていきましょう。
先程のAPIの説明箇所に戻ってください。Response samplesと書かれた部分があります。
「200」と「default」と書かれたボタンが並んでいます。
200は、成功した場合のレスポンス 例 です。defaultは、失敗した場合のレスポンス例になります。
レスポンスはJSONという形式でデータが返ってきます。上記のプログラムでは、response変数にJSONデータが格納されます。
JSONデータのままではデータが出せませんので、配列に変換します。JSON.parseを使うと配列に変換できます。
打刻する
続いて打刻をするAPIをGASから叩いてみましょう!
今度は、GETではなく、POSTであることがわかります。
GETはURLからデータを渡すと書きましたが、先程のトークン取得のAPIではURLから何もデータを渡していませんでした。GETでデータを渡すときはURLの最後に?a=bのようにハテナを付けてデータを渡します。
POSTの場合は、HTTPヘッダーからデータを渡しますので、どんなデータがサーバーに渡っているのか、利用者は簡単に見ることができません。(GETの場合はURLを見ればわかります)
-H 'Authorization: Token Em94Vf961af8gSB2QtTVmGgn' -H 'Content-Type:application/json' -d '{"user_id":23,"stamp_type":1,"latitude": 34.6431, "longitude":131.9972,"address":"東京都港区北青山3-5-6"}'
APIを叩くときは認証があります。先程のトークン取得では、 Secret Key が認証キーとなっていました。今回はトークンが認証キーになります。
Authorization: Tokenの後に記載されている文字列がトークン情報になります。
また今回は、-dという箇所があります。-dはデータを表しています。-d以降にJSON形式でデータを渡しています。
ieyasuの場合、位置情報の座標と、住所も打刻と一緒に渡すことができます。今回のプログラムでは省略させていただきます。
let headers =
{
"Authorization" : 'Token '+token,
"Content-Type" : 'application/json'
};
var data = {
"user_id":ieyasu_id,
"stamp_type":stamp_type
}
let options =
{
"method" : "post",
"payload": JSON.stringify(data),
"headers": headers
};
let response = UrlFetchApp.fetch('https://ieyasu.co/api/'+compay_name+'/v1/stamp_logs', options);
let json = JSON.parse(response.getContentText());
上記が、GASのソースになります。token変数には最初に取得したトークン情報を格納してください。
ieyasu_id変数には、ieyasuで登録した社員のIDが入ります。
stamp_type変数には、 打刻区分が入ります。(打刻区分 1. 出勤, 2. 退勤, 7. 休憩開始, 8. 休憩終了)
出勤する場合は1を渡し、退勤する場合は2を渡します。
ログイン
今回のアプリでは、Googleアカウントにログインしないとアクセスできません。
Googleのアカウントと、ieyasuのIDを紐付けることで、ログインした社員の打刻が行えるようにします。両者の紐付けはスプレッドシートで行います。
今回はA列にieyasuのID、B列に名前、C列にGoogleアカウントで使用しているメールアドレス、D列にトークン、E列にトークンの有効期限を入れます。
D列とE列はプログラムから挿入しますので、空白で構いません。
let user = Session.getActiveUser();
let useremail = user.getEmail();
ログインしているユーザー情報は、Sessionクラスの getActiveUser 関数を利用します。
取得できるのは、ユーザーの名前(アルファベット)、メールアドレス、ユーザーIDの3つです。
上記ではメールアドレスを取得しています。
function get_user(useremail){
let spreadsheet = SpreadsheetApp.openById('スプレッドシートのID');
let sheet = spreadsheet.getSheetByName('シート名');
let textFinder = sheet.createTextFinder(useremail);
let cells = textFinder.findNext();
if(cells){
let NumRow = cells.getRow();
const ieyasu_id = sheet.getRange("A"+NumRow).getValue();
const user_name = sheet.getRange("B"+NumRow).getValue();
return {ieyasu_id,user_name,NumRow};
}else{
return '';
}
}
上記の関数は、スプレッドシートからieyasuのIDと社員の名前、行番号を取得するものです。
行番号を返したのは、後ほどトークンと有効期限をD列、E列に格納するためです。
関数の引数には先程取得したGoogleアカウントのメールアドレスを渡しています。
トークンを格納する
トークンは毎回新しいものを取得してもいいのですが、APIとの通信回数を減らすため、有効な期間は使い回すようにします。
function check_token(NumRow){
let spreadsheet = SpreadsheetApp.openById('スプレッドシートのID');
let sheet = spreadsheet.getSheetByName('シート名');
let token = sheet.getRange("D"+NumRow).getValue();
let expired_at = sheet.getRange("E"+NumRow).getValue();
if((token == '') || (expired_at == '')){
//トークンが空の場合は新規取得
let {new_token,unixTime} = get_token();
sheet.getRange("D"+NumRow).setValue(new_token);
sheet.getRange("E"+NumRow).setValue(unixTime);
return new_token;
}else{
//トークンの有効期限を確認
let now = Date.parse(new Date())/1000;
if((expired_at - now) > 3600){
//有効期限まで1時間以上ある
return token;
}else{
//有効期限まで1時間未満であるため、新規取得
let {new_token,unixTime} = get_token();
sheet.getRange("D"+NumRow).setValue(new_token);
sheet.getRange("E"+NumRow).setValue(unixTime);
return new_token;
}
}
}
check_token関数を作りました。引数には先程取得したスプレッドシートの行番号を渡します。
スプレッドシート内にトークンと有効期限がない場合は、新しいトークンを取得するget_token関数を実行します。
トークンと有効期限をスプレッドシートから取得できた場合は、トークンの有効期限を調べます。
ieyasuの場合、トークンの有効期限は24時間あるようです。念の為、トークンの有効期限まで1時間以上ある場合のみ利用することにしました。
日付の比較の際は、UNIX時間を使うととても簡単です。UNIX時間は、1970年1月1日午前0時0分0秒から何秒経ったかを表す時間です。秒数で表すため、日付同士を比較する時に引き算するだけで時間差がわかります。今回は1時間ですので、時間差が3600秒以上ならトークンをそのまま利用することにしました。
let now = Date.parse(new Date())/1000;
今のUNIX時間を取得する処理が上記になります。
また、トークンの有効期限は、先程のトークンの取得APIのレスポンスのサンプルを見るとわかるように、「2018-09-23T04:56:07.000+09:00」のように表記された値が取得できます。
これをUNIX時間に変換するには、先程のDateクラスと同じように処理してあげればできます。
let unixTime = Date.parse(json['expired_at'])/1000;
新規で取得したトークンと有効期限をUNIX時間に変更して格納すると、下の図のようになります。
HTML画面を表示させる
今回GASでHTML画面を表示しています。それについては、GASのHTMLにBootstrapを読み込ませる方法の記事も参照ください。
「名前」と「状態」をHTML画面に表示しています。これは変数をHTML側に渡す必要があります。
function doGet(e) {
let template = HtmlService.createTemplateFromFile('index');
template.username = '市川喬之';
template.status = '退勤中';
return template.evaluate();
}
GAS側では、HTMLを読み込ませたオブジェクトに変数を上記のように渡します。(実際は、名前はスプレッドシートから取得した社員名を変数に入れて渡します。)
<table>
<tr>
<th width="20%">名前</th>
<td><?=username?></td>
</tr>
<tr>
<th>状態</th>
<td><?=status?></td>
</tr>
</table>
HTML側では、<?=変数名?>と書くことで変数の値を出力することができます。
勤怠状態を表示する
先程HTML画面で表示する状態には、退勤中と固定で表示しましたが、実際は、勤務中なのか退勤中なのか判定する必要があります。
function get_stamplog(token,ieyasu_id,limit=1){
let headers =
{
"Authorization" : 'Token '+token,
"Content-Type" : 'application/json'
};
let options =
{
"method" : "get",
"headers": headers
};
let response = UrlFetchApp.fetch('https://ieyasu.co/api/'+compay_name+'/v1/stamp_logs/user/'+ieyasu_id+'?stamp_type=1&limit='+limit, options);
let json = JSON.parse(response.getContentText());
return json[0]['stamp_type'];
}
勤務情報を取得するAPIを利用して、現在の状態を確認します。最後の打刻が出勤なら、現在出勤していることになりますし、最後の打刻が退勤なら現在は退勤中ということになります。
上記のget_stamplog関数では、引数にトークンとieyasuのIDを渡しています。その他にlimit=1と渡していますが、これは取得する勤怠情報の数です。最新の1件を取得すれば良いため1を初期値として入れています。
今回のAPIはGETで情報を取得します。APIのURLの最後に「?stamp_type=1&limit=’+limit」と stamp_type 変数と、 limit 変数を渡しています。
get_stamplog関数の戻り値は、打刻区分になります。(打刻区分 1. 出勤, 2. 退勤, 7. 休憩開始, 8. 休憩終了)
フォームからPOSTする
今回のWebアプリでは、「出勤」または「退勤」ボタンを押すと、データがPOSTされます。
HTML画面では下記のようにフォームを作成しています。
<form method="POST" action='<?=posturl?>'>
<div class="table-responsive">
<table class="table">
<tr>
<th width="20%">名前</th>
<td><?=username?></td>
</tr>
<tr>
<th>状態</th>
<td><?=status?></td>
</tr>
</table>
</div>
<div id='realtime'></div>
<div class="text-center">
<input type="submit" value="<?=button_label?>" class="btn btn-primary">
<input type="hidden" name='type' value="<?=stamp_type?>">
</div>
</form>
button_label変数には、「出勤」か「退勤」の文字が入ります。勤怠の状態によって文字を切り替えています。
hidden値としてフォームに仕込まれているstamp_type変数には、打刻区分が入ります。出勤する場合は1、退勤する場合は2が入ります。
1行目のformタグの送信先はactionに指定します。
posturlにはこのWebアプリのURLが入るのですが、GASのWebアプリはデプロイするたびにURLが変わってしまいます。
template.posturl = ScriptApp.getService().getUrl();
上記のように、WebアプリのURLを取得する関数を実行して都度変数に格納するようにしましょう。
GASでは、GETされた場合は、doGet関数が最初に実行されますが、POSTの場合は、doPost関数が最初に実行されますので、POST値を受け取る場合は下記のように書きましょう。
function doPost(e){
set_stamp(token,ieyasu_id,e.parameter.type);
}
先程HTML画面のhidden値にセットしたtypeという名前の値を受信する場合、e.parameter.typeと記載すると値が取得できます。
値を取得したら「打刻する」で紹介したAPIを実行してieyasuから打刻しましょう。
デプロイする
プログラムが完成したら、デプロイしてWebアプリを動かしてみましょう。
デプロイする方法については、GASでWebアプリをデプロイするを参照ください。
このシステムはログインしているユーザー情報を取得していますので、下記のように「ウェブアプリケーションにアクセスしているユーザー」で実行されるように設定してください。
ソースコードのダウンロード
下記よりソースコードを一式ダウンロードしていただきます。※スプレッドシートはダウンロードできませんので、別途ご用意ください。
ダウンロードしたソースコードはすべてtxtファイルになっています。下記のようにGASのスクリプトエディタ上に配置してください。