跳至主要内容

班表整合 · 07

將班表以 API 同步到 HR 人資系統

依門市與組別查詢 FREONE 最終班表,轉換後送往 HRIS API。

完成結果HRIS 取得台北信義店外場組 2026-10-07 的最終工時、班次、崗位與部分休假,並能用 shift id 與 updatedTime 安全重跑。

實際案例​

某餐飲集團要將台北信義店外場組的班表同步到 HRIS。整合程式先建立 FREONE 門市/組別索引,以示意 mapping 將「台北信義店」對應到 HRIS 店號 TPE-X01,再查詢日期區間內的 Shift。

本例中 S0001 王小明原排 13:00–17:00,核實後改為 13:00–16:00,並於 16:00–18:00 使用部分特別休假。HRIS 應採用 actual,同時保留 planned 與核實回覆供稽核。

資料流​

  1. 1建立可存取範圍索引整理 Merchant、Squad、Position 與 Group;問卷設定不參與本次同步。GET /v1/squads
  2. 2套用門市 mapping將 FREONE 台北信義店對應到 HRIS 店號 TPE-X01。integration mapping
  3. 3查詢班表區間依 squadId 與包含起訖日的日期範圍取得 Shift。GET /v1/shifts/{squadId}
  4. 4轉換最終班表以 actual 產生 HRIS payload,保留 duties、leaves 與跨日資訊。transform
  5. 5可重跑寫入以 shift id 作為識別,updatedTime 判斷是否需要更新 HRIS。HRIS API

門市與組別索引​

GET /v1/squads 可組出:

層級FREONE 欄位本例值
店名/店 IDmerchant.name、merchant.id台北信義店/tkfv5t
組別名/組別 IDname、id外場/sqmmhw5vonCzo
排序order1
崗位與需求人數positions[].name、headcount值班 1、櫃檯 1、跑菜 3、機動 2
群組與排序groups[].name、sortKeyA區 1、B區 2

串接端另行維護門市 mapping:

FREONE merchant.nameFREONE IDHRIS 店號
台北信義店tkfv5tTPE-X01

Request​

GET /v1/shifts/sqmmhw5vonCzo?from=2026-10-07&to=2026-10-07

Response​

{
"data": [
{
"id": "687e4726-7f46-4249-9cf1-ea4c808d69e4",
"assignee": {
"id": "a571cbd6-8795-4ccd-924b-63097c77314c",
"name": "王小明",
"alias": "小明",
"externalId": "S0001",
"identityTag": "正職",
"parttime": false
},
"squad": {
"id": "sqmmhw5vonCzo",
"name": "外場"
},
"merchant": {
"id": "tkfv5t",
"name": "台北信義店",
"timezone": "Asia/Taipei"
},
"date": "2026-10-07",
"createdBy": {
"id": "0dab2cd6-702a-4e94-876d-4a91c514a76e",
"name": "林小米店長"
},
"createdTime": "2026-09-20T02:25:00Z",
"updatedBy": {
"id": "0dab2cd6-702a-4e94-876d-4a91c514a76e",
"name": "林小米店長"
},
"updatedTime": "2026-10-07T10:00:00Z",
"publishedBy": {
"id": "0dab2cd6-702a-4e94-876d-4a91c514a76e",
"name": "林小米店長"
},
"publishedTime": "2026-09-25T03:25:00Z",
"planned": {
"dayOff": false,
"leaveType": null,
"duties": [
{
"slot": {
"name": "午班",
"start": "13:00",
"end": "17:00",
"breakDuration": 30,
"breakStart": null,
"overnight": false,
"externalId": "MID_1300-1700"
},
"positions": [
"值班"
]
}
],
"leaves": [
{
"slot": {
"start": "16:00",
"end": "18:00",
"overnight": false
},
"leaveType": {
"id": "47706123-8094-4c7f-ac69-2e59d638241f",
"name": "特別休假",
"abbreviation": "特",
"externalId": "ANNUAL"
}
}
],
"workingMinutes": 210
},
"actual": {
"dayOff": false,
"leaveType": null,
"duties": [
{
"slot": {
"name": "午班",
"start": "13:00",
"end": "16:00",
"breakDuration": 0,
"breakStart": null,
"overnight": false,
"externalId": "MID_1300-1600"
},
"positions": [
"值班"
]
}
],
"leaves": [
{
"slot": {
"start": "16:00",
"end": "18:00",
"overnight": false
},
"leaveType": {
"id": "47706123-8094-4c7f-ac69-2e59d638241f",
"name": "特別休假",
"abbreviation": "特",
"externalId": "ANNUAL"
}
}
],
"workingMinutes": 180
},
"latestAdjustmentConfirmation": {
"state": "replied",
"comment": "請確認核實後的下班時間"
},
"support": null
}
]
}

HRIS 欄位 mapping​

HRIS 資料FREONE 來源本例輸出
店號merchant.name → mappingTPE-X01
員工編號assignee.externalIdS0001
日期date2026-10-07
最終工時actual.workingMinutes180 分鐘
班次代碼/名稱actual.duties[].slot.externalId/nameMID_1300-1600/午班
上班時間actual.duties[].slot.start13:00
下班時間actual.duties[].slot.end16:00
休息時長actual.duties[].slot.breakDuration0 分鐘
崗位actual.duties[].positions['值班'],內容直接是名稱
部分休假actual.leaves[]16:00–18:00、假別 ANNUAL
同步識別id、updatedTimeShift ID+最後更新時間

休假與班表判讀​

情境dayOffleaveTypeduties[]leaves[]
純休假true有值空通常為空
有班+部分休假falsenull有值有值
休假日加班true有值有值通常為空

若同日有多段 duty,保留 actual.duties[] 原始順序;若 overnight=true,該段 end 的日期是 Shift date + 1 天。

驗收結果​

  • HRIS 收到店號 TPE-X01、員工 S0001、日期 2026-10-07。
  • 同步採用 actual.workingMinutes=180,但仍保存 planned=210 供稽核。
  • 部分休假沒有被誤判成整日休假,崗位也沒有當成 Position ID 再查一次。
  • 相同 shift id 與 updatedTime 重跑時不重複建立資料。
關鍵提醒

planned 是預排、actual 是最終班表,並非打卡出勤;多數時候兩者相同,兩者不同才代表當日以前的 Shift 曾經核實調整,可能同時有工時差異與 comment。latestAdjustmentConfirmation.state=replied 是介面上的「發問」且 comment 有值;acknowledged 是「確認」且 comment 為空字串。憑證與同步邏輯應放在後端服務,不要由瀏覽器直接呼叫 FREONE API。