Google Apps Script 專案,用於管理員工加班與補休記錄的雙向同步與驗證系統。
主控台.xlsx (主要資料源)
├── 員工清單
├── 加班記錄總表
└── 補休申請總表
員工A-2025.xlsx, 員工B-2025.xlsx... (20個檔案)
└── 各月份分頁 (08月, 09月...)
員工總表
編號 姓名 表格ID 表格連結 狀態
EX:
E001 張OO asdfjkl-12345 [連結](https://docs.google.com/spreadsheets/..../edit) 啟用|暫停|已離職
加班統計總表 (主控台)
| 加班編號 | 員工編號 | 姓名 | 日期 | 星期 | 加班類型 | 加班時數 | 已使用補休 | 剩餘可補休 | 狀態 | 資料來源月份 | 用掉補休編號 | 錯誤提示 |
補休申請總表 (主控台)
| 補休編號 | 員工編號 | 姓名 | 申請日期 | 補休日期 | 使用時數 | 對應加班編號 | 備註 | 行政組查閱打勾 | 錯誤提示 |
員工月份分頁
| 員工 | 日期 | 星期 | 日期·加班屬性 | 上班打卡 | 下班打卡 | 應上下班時間 | 工作時數 | 午晚休時數 | 扣除午晚休後的工時 | 當日加班時數 | 備註 |
日期·加班屬性 可選值:
- 上班日 / 上班日加班 / 休息日 / 例假日
- 國定假日OO節 / 國定假日OO節的補休日 / 特別休假
- 節日名稱和特休原因請寫在備註欄
應上下班時間 公式範例:
// 方案A: 合併顯示 (G欄)
=IF(D4="上班日", "應上班" & TEXT(E4,"HH:MM") & CHAR(10) & "應下班" & TEXT(E4+TIME(8,0,0),"HH:MM"), "")
// 方案B: 分離顯示
G4: =IF(D4="上班日", "應上班" & TEXT(E4,"HH:MM"), "")
H4: =IF(D4="上班日", "應下班" & TEXT(E4+TIME(8,0,0),"HH:MM"), "")
個人補休表分頁 (員工個人試算表)
| 補休編號 | 員工編號 | 姓名 | 申請日期 | 補休日期 | 使用時數 | 對應加班編號 | 備註 | 狀態 |
- 員工填寫:員工編號、姓名、申請日期、補休日期、使用時數、備註
- 系統自動填寫:補休編號、對應加班編號、狀態
請假分頁
| 請假編號 | 員工編號 | 姓名 | 請假類型 | 開始日期 | 結束日期 | 請假時數 | 請假原因 | 行政組查閱打勾 |
- 請假類型:事假 / 病假 / 公假 / 婚假 / 喪假 / 產假 等
入口函數: checkAllEmployees()
流程:
- 從「員工清單」讀取所有啟用員工
- 對每位員工執行完整檢查
- 記錄執行結果到「執行紀錄」
函數: checkEmployeeData(employeeId, employeeFileId)
步驟:
- 讀取該員工試算表的所有分頁
- 篩選出符合格式的月份分頁(如 "8月", "9月")
- 依序處理每個月份
從每個月份分頁中提取:
- 日期
- 加班時數(非零值)
- 加班類型(上班日/上班日加班/休息日/例假日/國定假日/特別休假)
- 備註
- 例假日加班依法只能發加班費,不可選補休
- 系統須標記例假日加班為「不可補休」狀態
- 配對邏輯需排除例假日加班記錄
對每筆員工加班記錄:
IF 主控台「加班記錄總表」中不存在 (員工編號 + 日期) 的記錄
THEN 新增一行到「加班記錄總表」
- 自動產生加班編號(如 "OT-20250801-E001-1": 前綴+日期+員工編號+同一天流水號)
- 填入:員工編號、姓名、日期、加班時數、加班類型
- 如果加班類型 = "例假日":
* 已使用補休 = 0
* 剩餘可補休 = 0
* 狀態 = "例假日-僅發加班費"
- 否則:
* 已使用補休 = 0
* 剩餘可補休 = 加班時數
* 狀態 = "未使用"
- 資料來源月份 = 該分頁名稱
- 其他該月表格同一行之資料
函數: validateOvertimeRecords()
目的: 確保主控台的每筆加班記錄都能在員工檔案中找到對應數據
流程:
- 讀取「加班記錄總表」所有資料
- 對每一筆記錄:
根據 員工編號 → 找到員工試算表ID 根據 資料來源月份 → 找到對應分頁 根據 日期 → 在該分頁找到對應列 IF 找不到對應資料 THEN 標記為「資料異常」+ 記錄到錯誤日誌
函數: syncPersonalLeaveRequests()
目的: 將員工個人補休表的申請同步到主控台的補休申請總表
流程:
對每位啟用員工:
1. 讀取員工試算表的「個人補休表」分頁
2. 找出尚未同步的補休申請 (補休編號為空的列)
3. 驗證必要欄位:員工編號、申請日期、補休日期、使用時數對每筆新的補休申請:
1. 產生補休編號:LV-YYYYMMDD-員工編號-流水號
例如:LV-20250815-E001-1
2. 自動配對加班編號:
- 取得該員工所有「剩餘可補休 > 0」且「狀態 ≠ 例假日-僅發加班費」的加班記錄
- 按日期由舊到新排序
- 計算可配對的加班時數總計
- 如果使用時數 > 可配對時數總計:錯誤 = "補休時數超過可用加班時數"
3. 新增到「補休申請總表」:
- 補休編號 = 自動產生
- 員工編號、姓名、申請日期、補休日期、使用時數 = 來源資料
- 對應加班編號 = 自動配對結果 (多筆用逗號分隔)
- 備註 = 錯誤訊息 (如有)
- 行政組查閱打勾 = FALSE (核選方框)
4. 回寫補休編號到個人補休表驗證規則:
- 申請日期不可為空且格式正確
- 補休日期不可為空且格式正確
- 使用時數必須 > 0
- 員工編號必須在員工清單中存在
錯誤處理:
- 驗證失敗:在「補休申請總表」備註欄記錄錯誤原因
- 配對失敗:在「補休申請總表」備註欄記錄「補休時數超過可用加班時數」
- 仍然建立補休記錄,但標記錯誤供行政人員處理函數: matchLeaveWithOvertime()
步驟:
SELECT * FROM 補休申請總表
WHERE 對應加班編號 IS NULL OR 對應加班編號 = ""對每筆未配對的補休記錄:
1. 取得該員工的所有加班記錄(按日期由舊到新排序)
2. 篩選出「剩餘可補休 > 0」且「狀態 ≠ 例假日-僅發加班費」的加班記錄
3. 依序分配:
補休需求時數 = 使用時數
WHILE 補休需求時數 > 0:
找到最舊的可用加班記錄
IF 該加班記錄剩餘時數 >= 補休需求時數:
分配全部需求時數到該加班記錄
更新加班記錄:已使用補休 += 補休需求時數
更新加班記錄:剩餘可補休 -= 補休需求時數
補休需求時數 = 0
ELSE:
分配該加班記錄的全部剩餘時數
更新加班記錄:已使用補休 = 加班時數
更新加班記錄:剩餘可補休 = 0
更新加班記錄:狀態 = "已全數使用"
補休需求時數 -= 該加班記錄剩餘時數
更新補休記錄:對應加班編號 += 該加班編號 (用逗號分隔)
IF 補休需求時數 > 0:
標記錯誤:「補休時數超過可用加班時數」配對完成後,回寫補休編號到加班記錄:
1. 更新「加班記錄總表」的「用掉補休編號」欄位
2. 同步回寫到員工個人試算表的月份分頁
- 根據員工編號找到對應的員工試算表
- 根據資料來源月份找到對應分頁
- 根據日期找到對應列
- 在備註欄或新增欄位填入「補休編號:LV-XXXXXX」
回寫規則:
- 如果一筆加班被多個補休使用,用逗號分隔:LV-001,LV-002
- 如果配對失敗,不回寫補休編號更新加班記錄狀態:
- 例假日加班記錄 → 狀態 = "例假日-僅發加班費" (固定不變)
- 其他加班記錄:
- 剩餘可補休 = 0 → 狀態 = "已全數使用"
- 剩餘可補休 > 0 但 已使用補休 > 0 → 狀態 = "部分使用"
- 已使用補休 = 0 → 狀態 = "未使用"主函數 checkAllEmployees()
│
├─ Step 1: 對每位員工執行
│ └─ checkEmployeeData(employeeId, fileId)
│ ├─ 1.1 掃描月份分頁
│ ├─ 1.2 提取加班資料
│ └─ 1.3 比對並新增到主控台
│
├─ Step 2: 反向驗證
│ └─ validateOvertimeRecords()
│ └─ 檢查主控台每筆加班是否對應到員工資料
│
├─ Step 3: 個人補休表同步
│ └─ syncPersonalLeaveRequests()
│ ├─ 3.1 掃描所有員工的「個人補休表」分頁
│ ├─ 3.2 同步新的補休申請到中樞表
│ └─ 3.3 產生補休編號和配對加班編號
│
└─ Step 4: 補休與加班配對
└─ matchLeaveWithOvertime()
├─ 4.1 找出未配對補休
├─ 4.2 自動分配到最舊加班
├─ 4.3 更新剩餘時數與狀態
└─ 4.4 回寫用掉補休編號到加班記錄
- 員工檔案無法存取(權限問題)
- 月份分頁格式不正確
- 加班資料在主控台找不到對應
- 補休時數超過可用加班時數
- 資料格式錯誤(日期、數字格式)
| 時間戳記 | 錯誤類型 | 員工編號 | 詳細訊息 | 受影響資料 |
- Google Apps Script (clasp)
- SpreadsheetApp API
- 批次讀寫(避免逐筆操作)
- 使用
getValues()和setValues()而非getValue()/setValue() - 每位員工處理完記錄一次進度
- 所有寫入操作要有事前備份機制
- 關鍵操作加入 try-catch
- 失敗時不影響其他員工的處理
員工A在 2025-08 分頁有加班 8 小時
主控台「加班記錄總表」中沒有這筆資料
→ 應該新增一筆加班記錄,剩餘可補休 = 8
員工A有兩筆加班:
- 2025-08-01: 10小時 (剩餘10)
- 2025-08-05: 8小時 (剩餘8)
員工A申請補休 12 小時
→ 應該先用掉 8/1 的 10小時,再用掉 8/5 的 2小時
→ 8/1 狀態變「已全數使用」,8/5 剩餘6小時
員工A只有 5 小時可補休
員工A申請補休 8 小時
→ 應該標記錯誤,不執行配對
✅ 檢查完成報告
━━━━━━━━━━━━━━━━━━━━
處理員工數:20
新增加班記錄:35 筆
配對補休記錄:12 筆
發現錯誤:2 筆
詳細記錄請查看「執行紀錄」工作表
// Code.js
// ===== 主要流程 =====
function checkAllEmployees() { }
// ===== 員工資料檢查 =====
function checkEmployeeData(employeeId, fileId) { }
function scanMonthlySheets(fileId) { }
function extractOvertimeData(sheet) { }
function addOvertimeRecord(record) { }
// ===== 反向驗證 =====
function validateOvertimeRecords() { }
// ===== 補休配對 =====
function matchLeaveWithOvertime() { }
function allocateLeaveToOvertime(leaveRecord) { }
function updateOvertimeStatus(overtimeId) { }
// ===== 工具函數 =====
function getMasterSheet(sheetName) { }
function getEmployeeSheet(fileId, sheetName) { }
function generateOvertimeId(date) { }
function logError(type, employeeId, message) { }