勤務時間、正しく登録していますか？freee 人事労務 API を使って隠れ残業を見破る

# リモートワークの課題
リモートワーク、テレワーク、在宅勤務など呼び方はいろいろありますが、コロナ禍では会社に出社しない方もいらっしゃると思います。また、そのような方の中には残業が増えてしまった方も多くいるのではないでしょうか。実際に新聞では残業時間が長くなった方は 51% いるという記事もありました。

[テレワーク「隠れ残業」増　「通常より長時間労働になった」５１％](https://www.tokyo-np.co.jp/article/46657)

この記事を読んでいる方の中にも残業時間が長くなった方がいるのではないかと思いますが、残業時間は漏れなく登録していますか？こんな働き方していないでしょうか？

|時刻  |打刻  |  |
|-----------:|:------------|:------------|
| 9:00|業務開始の打刻|「おはようございます。業務開始します。」とチャットやメール<br><img width="80" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320008/cafcde22-053c-bea0-5d61-68f50fbf41cd.png">|
|12:00| 昼休憩|「休憩入ります。13時から再開します。」|
|19:00| 業務終了の打刻|「本日の業務はこれにて終了します。お疲れ様でした。」|
|22:00|なし |（お、なんかメールが来てる。今日のうちに片付けておくか～）<br><img width="90" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320008/e4e8e766-642a-3dd0-f02f-b7c036b8015d.png">|
|24:00|なし |（よーし、やっと終わった。思ったより遅くなったけど明日の仕事も減ったしいいか～）<br><img width="90" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320008/528dc82d-f820-33ac-5d96-29c834f20341.png">|

この例では一日 8 時間労働すると、 19 時まで働くと登録上は 18 時から 19 時までの 1 時間分が残業ですが、実際には 22 時から 24 時まで働いているので正確には 3 時間の残業 (2 時間の登録漏れ) です。
これを毎日繰り返すと、なんと「1 か月の労働日数 20 日 × 1 日の登録漏れの残業時間 2時間 = 月 40 時間」をサービス残業していることになります。人事労務担当としてはこのような隠れ残業、登録漏れは見過ごせませんね。（あえて見過ごすという話もあるかもしれませんが触れません）

リモートワーク環境では会社のタイムカードで打刻する代わりに、自分で勤務時間を登録したり、タイムレコーダーのように出勤/退勤を記録するアプリを使ったりする方が多いのではないでしょうか。でも、このような場合、上司も人事労務担当者も登録を信用するしかありません。もし登録が正しいかを確認するとしても、チャットやメールをした時刻と登録された時間を照らし合わせてみるとか、あとはクライアント PC を監視する専用のソフトを使うなど、時間や費用がかかると思います。



# どうやって解決するか
そこで人事労務 freee の API を活用したいと思います。（うちの会社では freee を使っていないけど、個人的には使ってほしいなと思っている）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320008/d10a2465-0ae5-2046-c6dc-662cd94662aa.png)
https://www.freee.co.jp/hr/index2.html

(設定次第ですが) 通常は以下の画面の真ん中の「勤務時間」から自由に登録すると思いますが、API を使った出勤、退勤の打刻をすることもできます。 

勤務時間の登録について: [勤怠を入力・管理する](https://support.freee.co.jp/hc/ja/articles/202849560-%E5%8B%A4%E6%80%A0%E3%82%92%E5%85%A5%E5%8A%9B-%E7%AE%A1%E7%90%86%E3%81%99%E3%82%8B)

API の説明: [タイムレコーダー(打刻) のAPI](https://developer.freee.co.jp/docs/hr/reference#/%E3%82%BF%E3%82%A4%E3%83%A0%E3%83%AC%E3%82%B3%E3%83%BC%E3%83%80%E3%83%BC(%E6%89%93%E5%88%BB)) 

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320008/ec8aa95c-fd22-1e25-7b33-70c106e267f6.png)


リモートワークではノート PC を使っている方が多いと思いますが、仕事以外の時間は PC のカバーを閉じているんじゃないかと思います。なので、OS が動作している時間は常に労働時間とみなします。ただ、私の周りの様子を見ていると登録漏れの残業は以下のパターンで発生すると思います。

- 先の例のように一度業務を終了すると言ってから作業をする
- 他には業務開始するという前から少しだけメールを見てみる

そこで今回は PC を起動したら「出勤」の時間の登録を自動で行い（早朝残業防止）、その日何時まで PC を起動していたかを記録します。



# 実際に作ったもの
### ポイント
- freee では API を使って「出勤」「退勤」「休憩開始」「休憩終了」という 4 つの打刻ができる
- 出勤していない状態で最初に PC を起動 (またはスリーブからの復帰) した時刻を「出勤」とする
- 出勤している状態で最後に PC が起動していた時刻を「退勤」とみなす 
- 退勤の後に休憩といった整合性が取れない打刻をしようとしたときは freee の API がエラーを返す

以上のポイントを踏まえて、退勤については PC の最終起動日時していた時刻をデータとしてデータベースに記録しておくだけで、今回は freee 上での「退勤」打刻は自動では行わないことにしています。
データさえあれば人事労務担当や上司が勤務時間をチェックできたり、バッチでその日の締め処理として自動的に退勤を登録もできます。

### 仕組み
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320008/1b32c411-5444-4ace-17cd-7996acaa4b19.png)




登場人物は以下です。
- __Windows サービス__: 今回開発したバックグラウンドで動作するプログラム。__クライアント PC のハートビートの役割__を担う。PC の起動時に自動で起動して、1 分ごとにアクセストークンを Functions に送る。
- __Azure Functions__: 今回開発した関数を実行するサーバーレス基盤。人事労務 freee の API を使って、出勤していているか確認をしたり、出勤していなければ「出勤」打刻を行う。また、Table Storage に対してクライアント PC のハートビートの情報 (最終起動日時)を送る。
- __Azure Table Storage__: NoSQL DB、Key-Value ストア。ユーザー情報、クライアント PC のハートビートの情報 (最終起動日時) を記録する。
- __freee 認可サーバー__: 認可コードまたはリフレッシュトークンを送ることで、人事労務 freee の API の実行に必要なアクセストークンを発行する。
- __人事労務 freee API__: 出勤や退勤の打刻をしたり、打刻可能種別を返す(出勤済のときには退勤や休憩が可能)。

今回開発した Windows サービスと Azure Functions 上で動作する関数のソースコードは GitHubで公開しています。

 https://github.com/chyonek/freeeTimeClock/

MyNewService は Windows サービス、ClockInOutFunc は Azure Functions のプロジェクトの Visual Studio プロジェクトです。



### 使った API について
##### ログインユーザ (GET /api/v1/users/me)

打刻を行うためにはユーザーの所属する事業所 ID や事業所ごとの従業員 ID が必要です。
今回はそれらを取得するために利用します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320008/2de14423-8091-dfbe-997f-2baee17097fa.png)
https://developer.freee.co.jp/docs/hr/reference#/%E3%83%AD%E3%82%B0%E3%82%A4%E3%83%B3%E3%83%A6%E3%83%BC%E3%82%B6/show

#####打刻可能種別の取得 (GET /api/v1/employees/{emp_id}/time_clocks/available_types)

出勤してるかどうかの確認に使用しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320008/a9d6b567-235e-5a7b-ca9e-8aaf6e68c26a.png)

https://developer.freee.co.jp/docs/hr/reference#/%E3%82%BF%E3%82%A4%E3%83%A0%E3%83%AC%E3%82%B3%E3%83%BC%E3%83%80%E3%83%BC(%E6%89%93%E5%88%BB)/available_types

#####打刻情報の登録 (POST /api/v1/employees/{emp_id}/time_clocks)

今回は「出勤」打刻をするために使用しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/320008/5773997c-9486-bda6-ce2a-7ca4a715d398.png)
https://developer.freee.co.jp/docs/hr/reference#/%E3%82%BF%E3%82%A4%E3%83%A0%E3%83%AC%E3%82%B3%E3%83%BC%E3%83%80%E3%83%BC(%E6%89%93%E5%88%BB)/create


### 開発環境
- Visual Studio 2019
- .NET Framework 4.8 (C#)
- Azure Functions SDK v3
- [Azure](https://azure.microsoft.com/ja-jp/free/)


### デプロイ、起動方法
まだ実験中でもあるので freee のアプリとして公開はできておらず、またソースコードも散らかっているのでご注意ください...。

1. ソースコードを [GitHub リポジトリ](https://github.com/chyonek/freeeTimeClock/) から git clone または zip ダウンロードします。
2. Visual Studio で ClockInOutFunc のプロジェクトを開きます。
3. ClockInOutFunc という Azure Functions のプロジェクトについてはローカルで実行、または Azure Functions に[発行](https://docs.microsoft.com/ja-jp/azure/azure-functions/functions-create-your-first-function-visual-studio#publish-the-project-to-azure)します。
4. データを保存する用の Table Storage を作成し、接続文字列を Azure Functions のアプリケーション設定に AzureWebJobsStorage という名前で設定します。
5. 管理者として Visual Studio で MyNewService という Windows サービスのプロジェクトを開きます。
6. freee でまだアプリの申請など公開の準備ができていない、すみませんが各自で[アプリを作成](https://developer.freee.co.jp/tutorials/starting-api)、[認可コードの取得](https://developer.freee.co.jp/tutorials/getting-access-token)をします。（アクセストークンを取得する Windows サービスはローカルで実行するので、アプリのコールバック URL は「urn:ietf:wg:oauth:2.0:oob」とします。）
7. App.config の client_id、client_secret、code に自分で作成した freee のアプリの CLIENT ID、CLIENT SECRET、認可コードを入力します。


```App.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" />
    </startup>
    <appSettings>
      <add key="client_id" value="(自分の環境のクライアントIDを入力する)"/>
      <add key="client_secret" value="(自分の環境のクライアントシークレットを入力する)"/>
      <add key="code" value="(自分の環境の認可コードを入力する)"/>
    </appSettings>
</configuration>
```

8.べた書きなのですが、ここで事前に作成した Azure Functions のエンドポイントを入力します。

```MyNewService.cs
             client.BaseAddress = new Uri("http://localhost:7071/api/");
```
9.ビルドをした後、Windows サービスの[インストール](https://docs.microsoft.com/ja-jp/dotnet/framework/windows-services/how-to-install-and-uninstall-services#install-your-service-manually-using-installutilexe-utility)を行います。


# あとがき
これを応用することで各従業員の手動退勤はやめて、従業員全員の PC の最終起動時刻のデータを元にその日の締め時間に退勤処理をバッチで行うということもできると思います。ただ、PC の起動しっぱなしでしばらく離席、その後に再度仕事を再開するパターンなど、休憩の自動判定はなかなか難しい部分もあるので、そこは手動でしてもらうかなさそうです...
実際には各従業員の働き方や freee の権限設定などを元に運用方法をご検討いただければと思います。

深夜残業、早朝残業防止については他にも記事を書いているので、とりあえず開いてみて LGTM してください！
[脱深夜残業、脱早朝出勤！たった5分でkintoneの使用可能な時間帯を制限する方法
](https://qiita.com/chyonek/items/7111bc72b1fd0ac0e02e)