タイムカードの集計処理を効率化した時の話

（更新予告）

https://github.com/duri0214/portfolio/issues/241

## 概要
2017年、地方移住したてのころにタイムカードの集計処理を効率化したときの話。できあがったツールは本当にシンプルなものだったが、旅館を手伝いながら作ろうとすると時間を捻出することが本当に難しい。ほんの少しの改善だったが効率化の実感は得られた

## 集計ツールをつくるまえ
まぁExcelだよね。使い方は単純。タイムカードで勤務時間を出して（Aさんの場合 33h）単価と掛け合わせて基本給を算出（26,400円）。８時間以上（または深夜時間）だった時間を「目で見て」出して（Aさんの場合 2h）、単価と掛け合わせて時間外手当を算出。さらに出勤回数と出勤手当単価と掛け合わせて通勤手当を算出。全部目検ですよ :eyes: 
![当初.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94562/f258e225-872c-1ac3-fde4-73f1e0e329de.png)

## ツールを作れないか考えた
そもそもこのタイムカードはPCに接続してCSVを出してくれる（当然旅館の事務方さんはそんなことを知らない）。ということはCSVで集計しちゃえばいいよね。

https://timepack.amano.co.jp/
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94562/f62e3ffc-6a80-9e8c-d990-8eefcc5192b7.png)

### オペ
https://timepack.amano.co.jp/products/software.html

#### ナビ画面
> TimeP@CKシリーズは「サッと勤怠 with」という専用ソフトが それぞれのパッケージの中に同梱されています。「サッと勤怠 with」のナビ画面は、矢印の順に従って直感的にわかるよう構成されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94562/2e69a759-3c9c-c1f2-b08e-59b53248452a.png)

#### データ取り込み
> データは月に1回でも、毎日でもお客様の使い方に合わせて取り込むことができます。何回取り込んでもデータが消えることはありませんので安心です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94562/51f99b92-60eb-96b4-2825-1928bf6787a2.png)

#### データチェック（日単位）
> タイムカードを見ながら作業している感覚で、直行・直帰や打ち忘れ、打ち間違いを日単位で全従業員のデータを修正することができます。打ち忘れ欄は一目でわかるよう赤表示されるので、修正時刻を直接入力するだけ。修正データは青文字に変わるので、修正した箇所もひと目で確認できます。その日誰が出勤しているかを確認したい時や打ち忘れをこまめにチェックしたい場合などに有効です。打ち忘れた人だけを抽出することもできます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94562/e7a08842-80b5-6b7c-00c2-6a3a20ea9e0a.png)

#### データチェック（月単位）
> タイムカードのイメージで編集・確認することもできます。個人単位で1か月分のデータを確認できます。有給休暇、出張などは不在理由として登録出来ます。会社オリジナルの休日も作成できます。また、「打ち忘れ」「時間外届あり」などのメモ書きはコメント欄を使うと便利です。手入力はもちろん、よく使うコメントはコメントメモボックスに最大20個まで登録しておくこともできます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94562/eb48b9e9-96ad-3f6e-aff1-200f3474ed12.png)

#### 集計作業
> データチェックから画面を切り替えるだけで集計があっという間に終了します。正社員・パート・アルバイトなど、事前に登録した勤務（最大99パターン）に合わせて正確に集計できます。時間計算の単位（「1分単位」、「15分単位」など）も、従業員一人一人の勤務時間に合わせて設定できます。また、週単位の集計、データ出力も可能です。日毎の集計結果、月毎の集計結果の修正はもちろん、法令改正にも対応しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/94562/773c9082-642e-286b-7935-0a4281b141cf.png)


### つくったSource
なつかしいソースだな。こんなもんいまgpt使ったら `output_d.csv`, `output_m.csv` なんて２つ出すこともなかったw

```r
#作業ディレクトリ決定
setwd('C:/TimeP@CK/TpPlus/@data/当月データ/')
inputFolder = getwd()

#CSV読み込み（日次勤怠データをタテ積みに）
csvfiles = list.files(path = inputFolder, full.names = T)
csv = do.call(rbind, lapply(csvfiles, read.csv))

#必要な項目のみ抽出
csv = csv[, c("従業員番号","従業員氏名","年.月.日","出勤打刻","外出打刻","戻打刻","退勤打刻","基準内時間","基準外時間","深夜時間")]

#日次
#サッと勤怠は10進数で「17:10」を「17.10」と表現し、月次集計すると「17:70」などの数字が発生してしまうため、60進数に変換する
csv$基準内時間60  = trunc(csv$基準内時間)*0.6+(csv$基準内時間%%1)
csv$基準外時間60  = trunc(csv$基準外時間)*0.6+(csv$基準外時間%%1)
csv$深夜時間60    = trunc(csv$深夜時間)*0.6+(csv$深夜時間%%1)
csv$時間外手当60  = (csv$基準外時間+csv$深夜時間)

#月次サマリー（30分以上は繰り上げ）
GetSum = function(key, data, newcolname){
  #合計値集計後データの取得
  agg = data.matrix(tapply(data, key, sum))
  #agg = tapply(data, key, sum)
  #データ列に名前をつける
  colnames(agg) = newcolname
  #matrixで返す
  return(data.frame(trunc((trunc(agg/0.6)+agg%%0.6)+0.30)))
}

agg1 = GetSum(csv$従業員氏名, csv$基準内時間60, "基準内時間60の月次")
agg2 = GetSum(csv$従業員氏名, csv$時間外手当60, "時間外手当60の月次")
output = cbind(agg1, agg2)
colnames(output) = c("基本稼働時間","時間外稼働時間")

#出力先フォルダの存在チェック
OutputFolder = "C:/TimeP@CK/TpPlus/@data/Output"
if(file.exists(OutputFolder) == "FALSE"){
  #出力先フォルダがなかったらフォルダを作成
  dir.create(OutputFolder)
}
setwd(OutputFolder)

#CSV出力
write.csv(csv, 'output_d.csv', row.names = FALSE, quote = FALSE)
write.csv(output, 'output_m.csv', row.names = TRUE, quote = FALSE)
```