# Zhsports API
---
## 更新紀錄
- 2024/02/16
- [取得場地資訊(for預約)](#取得場地資訊(for預約)) 新增了paid,occupied_name兩個欄位
- 新增場地類別相關 [場地類別](#場地類別)
- 2024/02/19
- [建立使用者資料](#建立使用者資料), [修改使用者基本資料](#修改使用者基本資料) 多了緊急聯絡人欄位
- [場地關閉維護](#場地關閉維護), [場地價格維護](#場地價格維護) 多一個欄位==until==可以指定結束日期
- 2024/02/21
- 修改[取得場地列表](#取得場地列表), 新增[修改場地資料](#修改場地資料), [上傳場地圖片](#上傳場地圖片)
- 2024/02/25
- 修改[透過場地類別取得場地資訊(for預約)](#透過場地類別取得場地資訊(for預約)) and [取得場地資訊(for預約)](#取得場地資訊(for預約)) 的已經預約資料會多一個==reservation==
- 新增[商品價格試算](#商品價格試算)目前只支援場地預約
- 2024/03/03
- 新增[透過場地類別取得場地價格設定列表](#透過場地類別取得場地價格設定列表),[透過場地類別設定場地預設價格](#透過場地類別設定場地預設價格),[透過場地類別新增場地價格](#透過場地類別新增場地價格),[透過場地類別刪除場地價格](#透過場地類別刪除場地價格),[透過場地類別取得場地關閉設定列表](#透過場地類別取得場地關閉設定列表),[透過場地類別新增場地關閉](#透過場地類別新增場地關閉),[透過場地類別刪除場地關閉](#透過場地類別刪除場地關閉)共七支API
- 修改[透過場地類別修改場地價格](#透過場地類別修改場地價格)
- 2024/03/05
- 修改[預約](#預約),多一個==occupied_name==會自動建立資料
- 2024/04/02
- 新增[其他功能](#其他功能)
- 2024/04/12
- 新增[卡片相關功能](#卡片相關功能)
- 2024/04/22
- 新增[批次場地預約](#預約)
- 2024/04/23
- 新增[搜尋預約記錄(透過場地類別)](#搜尋預約記錄(透過場地類別))
- 2024/04/25
- 新增[重新預約(限定已取消且時段都還沒過期的)](#重新預約(限定已取消且時段都還沒過期的))
- 2024/05/22
- 新增[固定電話驗證碼](#固定電話驗證碼)
- 2024/05/23
- 新增[修改固定驗證碼](#修改固定驗證碼)
- 2024/06/05
- 新增[課程](#課程)
- 修改[商品價格試算](#商品價格試算)新增支援課程報名結帳試算
- 2024/06/11
- 修改[課程](#課程)新增[刪除課程(還未有人報名時)](#刪除課程(還未有人報名時)),[修改課程(還未有人報名時)](#修改課程(還未有人報名時)),[刪除單堂(還未有人報名時)](#刪除單堂(還未有人報名時)),[取得選課資料(for繳費)](#取得選課資料(for繳費))
- 2024/07/01
- 新增[發票入庫(兩種做法)](#發票入庫(兩種做法))
- 2024/07/15
- 修改[拿敬老卡列表(沿用舊系統的員工卡列表加上參數)](#拿敬老卡列表(沿用舊系統的員工卡列表加上參數))加了月卡相關的回應
- 2024/07/18
- 新增[透過QRCode課程報到](#透過QRCode課程報到)
- 2024/07/22
- 新增[補票查詢](#補票查詢),[補票](#補票),[列印信用卡簽單](#列印信用卡簽單)
- 2024/08/01
- 修改[取得選課資料(for繳費or點名)](#取得選課資料(for繳費or點名))新增回應的欄位==invoice==
- 修改[取得場地資訊(for預約)](#取得場地資訊(for預約))新增回應的資料==order_info==
- 2024/08/09
- 修改[拿敬老卡列表(沿用舊系統的員工卡列表加上參數)](#拿敬老卡列表(沿用舊系統的員工卡列表加上參數))新增type參數==app_monthly==
- 2024/08/16
- 新增[交易紀錄查詢](#交易紀錄查詢),[交易紀錄查詢(單筆)](#交易紀錄查詢(單筆)),[交易紀錄作廢/折讓](#交易紀錄作廢/折讓)
- 2024/08/20
- 新增[統計(會員人數)](#統計(會員人數))
- 2024/08/26
- 修改[預約](#預約)加入了==備註==
- 2024/08/27
- 修改[交易紀錄查詢](#交易紀錄查詢),新增參數==by==
- 2024/09/10
- 新增[Kiosk相關](#Kiosk相關), [結帳](#結帳), [取得結帳紀錄](#取得結帳紀錄)
- 2024/09/11
- 修改[取得場地資訊(for預約)](#取得場地資訊(for預約))新增回應的資料==order_info中的vat==
- 2024/09/16
- 新增[結帳(POS版)](#結帳(POS版)), [取得結帳紀錄(POS版)](#取得結帳紀錄(POS版))
- 2024/09/19
- 新增[課程欄位解說](#課程欄位解說)的數個新欄位:==enable_returning_student_discount, previous_course, returning_student_threshold, returning_student_after_discount_unit_price, returning_student_after_discount_total_price==
- 2024/09/24
- 修改[商品價格試算](#商品價格試算)新增支援==課程舊生優惠==
- 2024/09/26
- 新增[確認有無符合舊生優惠](#確認有無符合舊生優惠)
- 2024/10/11
- 新增[取得Kiosk印表機狀態(建議每30秒call一次)](#取得Kiosk印表機狀態建議每30秒call一次)
- 2024/10/21
- 修改[取得結帳紀錄](#取得結帳紀錄)
- 修改[取得結帳紀錄(POS版)](#取得結帳紀錄(POS版))
- 2024/10/23
- 新增[取得Kiosk設定及狀態(POS及KIOSK用)](#取得Kiosk設定及狀態(POS及KIOSK用))
- 新增[設定Kiosk(POS用)](#設定Kiosk(POS用))
- 2024/10/26
- 新增KIOSK的api[Heartbeat](#Heartbeat)
- 修改[取得Kiosk設定及狀態(POS及KIOSK用)](#取得Kiosk設定及狀態(POS及KIOSK用)),回傳多一個欄位==app_alive==
- 2024/10/27
- 修改[取得Kiosk設定及狀態(POS及KIOSK用)](#取得Kiosk設定及狀態(POS及KIOSK用))及[設定Kiosk(POS用)](#設定Kiosk(POS用)),多一個欄位==enable==
- 2024/11/13
- 新增[查詢場地預約紀錄](#查詢場地預約紀錄)
- 2025/01/03
- 新增[建立APP通知任務](#建立APP通知任務)
- 新增[取得APP通知任務列表](#取得APP通知任務列表)
- 新增[修改APP通知任務](#修改APP通知任務正在執行中的無法修改date-time)
- 新增[刪除/取消APP通知任務](#刪除取消APP通知任務會將執行到一半的任務取消)
- 2025/01/13
- 新增[發票相關特別操作](#發票相關特別操作)
- 2025/02/26
- 修改[交易紀錄查詢](#交易紀錄查詢),多一個欄位:==transaction_id==
- 2025/03/07
- 新增[建立APP的操作](#建立APP的操作)
- 新增[修改APP的操作](#修改APP的操作)
- 新增[刪除APP的操作](#刪除APP的操作)
- 新增[取得APP的操作列表](#取得APP的操作列表)
- 2025/03/14
- 新增[建立月卡的操作](#建立月卡的操作)
- 新增[執行月卡的操作](#執行月卡的操作)
- 新增[刪除月卡的操作](#刪除月卡的操作)
- 新增[取得月卡的操作列表](#取得月卡的操作列表)
- 2025/04/14
- 修改[建立月卡的操作](#建立月卡的操作),多一個欄位:==specific==
- 2025/04/29
- 修改[建立APP的操作](#建立APP的操作),多了兩個欄位:==comment==, ==reason==
- 2025/05/08
- 修改[查詢場地預約紀錄](#查詢場地預約紀錄),多一個欄位:==canceled_at==
- 新增[建立報表類別](#建立報表類別)
- 新增[修改報表類別](#修改報表類別)
- 新增[刪除報表類別](#刪除報表類別)
- 新增[取得報表類別列表](#取得報表類別列表)
- 2025/05/29
- 修改[建立報表類別](#建立報表類別) [修改報表類別](#修改報表類別) [取得報表類別列表](#取得報表類別列表) 多一個欄位:==childrn==
- 2025/06/11
- 修改[建立報表類別](#建立報表類別) [修改報表類別](#修改報表類別) [取得報表類別列表](#取得報表類別列表) 多一個欄位:==code==
- 2025/07/29
- 修改[取得使用者列表](#取得使用者列表),修改成支援分頁排序及搜尋
- 2025/08/19
- 新增[補印](#補印)
---
```
Test Url: http://192.168.5.206:8964
Product Url: http://192.168.5.200:8964
```
## 注意事項
- 他們會需要編輯自己的商品id, 所以零售商品/購課他們都會有自己編的id
- 除了登入以外所有的Request都會需要Authorization Header: zhs [token]
## 登入員工
```
POST /staff
```
- Body
```jsonld=
{
"account": "richard",
"password": "richard"
} // or curtis/curtis allen/allen
```
- Response
```
[token] // 將這個token放到之後所有的Request中的Header: Authorization=zhs [token]
```
## 取得登入員工帳號的資訊
```
GET /me
```
- Response
```jsonld=
{
"expired_at": 1707143598, // [unix timstamp] 這個token過期的時間
"functions": [
{
"desc": "建立員工帳號",
"method": "POST",
"path": "/staff",
"type": "api"
},
{
"desc": "結帳",
"method": "POST",
"path": "/checkout",
"type": "api"
},
{
"desc": "編輯使用者帳號",
"method": "PUT",
"path": "/user/:id",
"type": "api"
},
{
"desc": "取得角色列表",
"method": "GET",
"path": "/roles",
"type": "api"
},
{
"desc": "取得使用者清單",
"method": "GET",
"path": "/users",
"type": "api"
},
{
"desc": "建立使用者帳號",
"method": "POST",
"path": "/user",
"type": "api"
},
{
"desc": "建立角色",
"method": "POST",
"path": "/role",
"type": "api"
},
{
"desc": "取得員工帳號列表",
"method": "GET",
"path": "/staffs",
"type": "api"
},
{
"desc": "編輯零售商品",
"method": "PUT",
"path": "/retail/:id",
"type": "api"
},
{
"desc": "建立權限功能",
"method": "POST",
"path": "/function",
"type": "api"
},
{
"desc": "刪除權限功能",
"method": "DELETE",
"path": "/function/:id",
"type": "api"
},
{
"desc": "取得後台統計數字",
"method": "GET",
"path": "/statistics",
"type": "api"
},
{
"desc": "刪除員工帳號",
"method": "DELETE",
"path": "/staff/:id",
"type": "api"
},
{
"desc": "編輯員工帳號",
"method": "PUT",
"path": "/staff/:id",
"type": "api"
},
{
"desc": "取得零售商品列表",
"method": "GET",
"path": "/retails",
"type": "api"
},
{
"desc": "建立零售商品",
"method": "POST",
"path": "/retail",
"type": "api"
},
{
"desc": "取得權限列表",
"method": "GET",
"path": "/functions",
"type": "api"
},
{
"desc": "編輯角色權限",
"method": "PUT",
"path": "/role/:id",
"type": "api"
}
],
"id": "e6a590ea-8eba-4b99-9ec1-0ab321d1de88",
"name": "richard",
"role": "super"
}
```
---
# 會員系統
## 建立使用者資料
```
POST /user
```
- Body
```jsonld=
{
"phone": "+886972957297", // 這個是主key之後app登入也是用這個務必要用+886開頭
"profile": {
"name": "Richard",
"email": "test@gmail.com",
"gender": "男", // 男/女/不指定
"birthday": "1984/01/01",
"emergencyContactName": "tester",
"emergencyContactPhone": "0212345678"
}
}
```
- Response
```jsonld=
{
"banned": false,
"id": "pos_bfc40179-6e27-4ce5-97a0-e78fecd5e221",
"inserted_at": "2024-02-05T02:40:06",
"latest_sync": 1707100806,
"phone": "+886972957297",
"profile": {
"birthday": "1984/01/01",
"email": "test@gmail.com",
"gender": "男",
"name": "Richard",
"emergencyContactName": "tester",
"emergencyContactPhone": "0212345678"
},
"updated_at": "2024-02-05T02:40:06",
"headshot": "http://zhs.toolset.biz:8964/user/headshot/pos_bfc40179-6e27-4ce5-97a0-e78fecd5e221"
}
```
## 上傳使用者頭像
```
POST /user/[user id]/headshot
```
- Body [form-data]
```
headshot: [頭像檔案.png/.jpg]
```
- Response
```
ok
```
## 取得使用者列表
```
GET /users
```
- Query Parameters
- search_key: phone(預設) or name or id
- term: 關鍵字,電話(可以是09/9/+886/886/其他號碼開頭)
- size: 每頁的筆數
- page: 第幾頁
- dir: asc or desc排序方向(目前寫死以電話排序)
- Response(無參數時)
```jsonld=
[
{
"banned": false,
"id": "pos_bfc40179-6e27-4ce5-97a0-e78fecd5e221",
"headshot": [頭像url],
"inserted_at": "2024-02-05T02:40:06",
"latest_sync": 1707100806,
"phone": "+886972957297",
"profile": {
"birthday": "1984/01/01",
"email": "test@gmail.com",
"gender": "男",
"name": "Richard",
"emergencyContactName": "tester",
"emergencyContactPhone": "0212345678"
},
"updated_at": "2024-02-05T02:40:06"
}
]
```
- Response(有參數時)
```jsonld=
{
"count": 17144, // 總筆數
"dir": "desc", // 排序方向
"list": [
{
"banned": false,
"headshot": "https://zhs.mraytec.com/user/headshot/pos_83500963-89cb-417b-8c7c-23dd6f741c86?t=43224",
"id": "pos_83500963-89cb-417b-8c7c-23dd6f741c86",
"inserted_at": "2024-09-17T02:18:21",
"latest_sync": 1726539501,
"phone": "+886999999999",
"profile": {
"name": "維修中"
},
"updated_at": "2024-09-17T02:18:21"
},
...
],
"max_page": 858, // 總頁數
"page": 1, // 目前是第幾頁
"size": 20 // 每頁的筆數
}
```
## 搜尋使用者
```
GET /users/search
```
- Query Parameters
- term: 會員電話關鍵字(可以是09/9/+886/886/其他號碼開頭)
- Response
```jsonld=
[
{
"banned": false,
"id": "pos_bfc40179-6e27-4ce5-97a0-e78fecd5e221",
"inserted_at": "2024-02-05T02:40:06",
"latest_sync": 1707100806,
"phone": "+886972957297",
"profile": {
"birthday": "1984/01/01",
"email": "test@gmail.com",
"gender": "男",
"name": "Richard",
"emergencyContactName": "tester",
"emergencyContactPhone": "0212345678"
},
"updated_at": "2024-02-05T02:40:06"
}
]
```
## 修改使用者基本資料
```
PUT /user/[user_id]
```
- Body
```jsonld=
{
"name": "Richard123",
"email": "test123@gmail.com",
"gender": "男",
"birthday": "1984/02/01",
"emergencyContactName": "tester",
"emergencyContactPhone": "0212345678"
}
```
- Response
```
ok
```
---
# 其他功能
## 開門
```
PUT /gate/pass
```
- Body
```jsonld=
{
"position": "pool", // "pool" 泳池 "fitness" 健身房
"direction": "enter" // "enter" 進去 "exit" 出來
}
```
- Response
```
ok
```
## 取得人流
```
GET /state/:position
```
- position: "pool" 泳池 "fitness" 健身房
- Response
```jsonld=
{
"value": 0 // 人數
}
```
## 統計(會員人數)
```
GET /statistics/users
```
- Response
```jsonld=
{
"app": 5088, // APP註冊的
"pos": 1630 // POS建的
}
```
## 取得Kiosk印表機狀態(建議每30秒call一次)
```
GET /machine/notify
```
- Response
```jsonld=
{
"alert": false, // 當為true時將下面message的訊息show出來
"message": "所有印表機狀態正常"
}
```
## 取得Kiosk設定及狀態(POS及KIOSK用)
```
GET /machine/kiosks
```
- Response (POS的)
```jsonld=
{
"kiosks": [
{
"alive": false, // 機台狀態
"comment": "", // 備註
"course_attend": false, // 啟用課程報到
"fitness_compansate": false, // 啟用健身房補票
"fitness_ticket": false, // 啟用健身房全票
"ip": "192.168.17.41", // ip
"location": "unknown", // 位置
"name": "櫃台售票機", // 名稱
"pool_ticket": false, // 啟用泳池全票
"printer": false, // 印表機狀態
"app_alive": false, // Kiosk APP狀態
"enable": true // 啟用?true/false
},
{
"alive": false,
"comment": "",
"course_attend": false,
"fitness_compansate": false,
"fitness_ticket": false,
"ip": "192.168.17.43",
"location": "unknown",
"name": "Kiosk3",
"pool_ticket": false,
"printer": false,
"app_alive": false,
"enable": true
},
{
"alive": false,
"comment": "",
"course_attend": false,
"fitness_compansate": false,
"fitness_ticket": false,
"ip": "192.168.17.42",
"location": "大廳",
"name": "櫃台售票機2",
"pool_ticket": false,
"printer": false,
"app_alive": false,
"enable": true
}
]
}
```
- Response (KIOSK的會給的資料是根據送request的ip)
```jsonld=
{
"alive": false,
"comment": "",
"course_attend": false,
"fitness_compansate": false,
"fitness_ticket": false,
"ip": "192.168.17.42",
"location": "大廳",
"name": "櫃台售票機2",
"pool_ticket": false,
"printer": false,
"app_alive": false,
"enable": true
}
```
## 設定Kiosk(POS用)
```
PUT /machine/kiosks/[ip]
```
- Body
```jsonld=
{
"name": "櫃台售票機2", // 名稱
"location": "大廳", // 位置
"fitness_ticket": false, // 啟用健身房全票
"pool_ticket": false, // 啟用泳池全票
"fitness_compansate": false, // 啟用健身房補票
"course_attend": false, // 啟用課程報到
"enable": false, // 啟用?true/false
"comment": "" // 備註
}
```
- Response
```
ok
```
## 補印
### 小白單
```
PUT /print/course_detail
```
- Body
```jsonld=
{
"order_id": "xxxxxxxxx", // 訂單id
}
```
### 報到QRCode
```
PUT /print/course_attendance
```
- Body
```jsonld=
{
"phone": "+886912345678",
"course": "course id"
}
```
- Response
```
ok
```
---
# APP相關
## 建立APP通知任務
```
POST /notifications
```
- Body
```jsonld=
{
"course": "課程id",
"phone": "+886xxxxxxxxx", // 使用者電話 phone跟student必須要有一個
"student": "xxxxxxxxx" // 學生id phone跟student必須要有一個
}
```
- Response
```
ok
```
## 取得APP通知任務列表
```
GET /notifications
```
- Response
```jsonld=
[
{
"id": "935aa73d-94d2-4134-bfb4-f9f4fff54a84",
"status": "未執行", // 目前狀態
"date": "2025/01/03",
"time": "12:25",
"progress": null, // 目前進度 會以(已發送/總數)顯示如:10/999 還沒開始會是null
"title": "test title",
"comment": "test",
"content": "test content",
"inserted_at": "2025/01/03 12:17",
"updated_at": "2025/01/03 12:17"
}
]
```
## 修改APP通知任務(正在執行中的無法修改date, time)
```
PUT /notifications/[notification id]
```
- Body
```jsonld=
{
"date": "2025/01/03", // 日期 *無法比目前早
"time": "12:30", // 時間
"title": "test title", // 標題
"content": "test content", // 內容
"comment": "test" // comment
}
```
- Response
```
ok
```
## 刪除/取消APP通知任務(會將執行到一半的任務取消)
```
DELETE /notifications/[notification id]
```
- Response
```
ok
```
## 建立APP的操作
```
POST /app_operations
```
- Body
```jsonld=
// 建立app公告
{
"comment": "xxoo",
"reason": "ooxx",
"type": "announce", // 公告必定是announce
"start": "2025-03-06 00:00:00", // 開始
"until": "2025-03-08 23:00:00", // 結束
"announce_title": "重大公告", // 公告標題
"announce_content": "系統將於2025年3月6日進行維護,預計維護時間為2025年3月6日00:00:00至2025年3月8日23:00:00。維護期間,系統將無法正常使用,請您提前做好準備。" // 公告內容
}
// 建立app的售票,場地,課程這三項服務的關閉
{
"comment": "xxoo",
"reason": "ooxx",
"type": "service", // 服務必定是service
"start": "2025-03-06 00:00:00", // 開始
"until": "2025-03-08 23:00:00", // 結束
"ticket": false, // 售票false是關閉預設是開啟
"reservation": false, // 場地預約
"course": false // 課程報名
}
```
- Response
```jsonld=
// 公告
{
"announce_content": "系統將於2025年3月6日進行維護,預計維護時間為2025年3月6日00:00:00至2025年3月8日23:00:00。維護期間,系統將無法正常使用,請您提前做好準備。",
"announce_title": "重大公告",
"comment": "xxoo",
"reason": "ooxx",
"created_by": "722543ea-bdcc-48c4-aa9e-baf4e0f2fac4",
"enabled": true, // 這個設定的開關true是開false是關
"id": "a32bb1f4-bf64-4037-9aa0-7527664089be",
"inserted_at": "2025/03/07 10:57:44",
"start": "2025/03/06 00:00:00",
"type": "announce",
"until": "2025/03/08 23:00:00",
"updated_at": "2025/03/07 10:57:44",
"updated_by": "722543ea-bdcc-48c4-aa9e-baf4e0f2fac4"
}
// 服務
{
"enabled": true, // 這個設定的開關true是開false是關
"id": "23958b65-90dc-4904-8c5d-a1fc5a25f33f",
"start": "2025/03/06 00:00:00",
"type": "service",
"until": "2025/03/06 23:00:00",
"comment": "xxoo",
"reason": "ooxx",
"ticket": false,
"inserted_at": "2025/03/07 11:42:21",
"updated_at": "2025/03/07 11:42:21",
"course": false,
"created_by": "722543ea-bdcc-48c4-aa9e-baf4e0f2fac4",
"updated_by": "722543ea-bdcc-48c4-aa9e-baf4e0f2fac4",
"reservation": false
}
```
## 修改APP的操作
```
PUT /app_operations/[app operation id]
```
- Body
```jsonld=
// 公告
{
"announce_title": "test123"
}
// 服務
{
"ticket": true,
"reservation": true,
"course": true
}
```
- Response
```
同建立
```
## 刪除APP的操作
```
DELETE /app_operations/[app operation id]
```
- Response
```
ok
```
## 取得APP的操作列表
```
GET /app_operations
```
- Response
```jsonld=
{
"count": 2,
"rows": [
{
"enabled": true,
"id": "a32bb1f4-bf64-4037-9aa0-7527664089be",
"start": "2025/03/06 00:00:00",
"type": "announce",
"until": "2025/03/08 23:00:00",
"comment": "xxoo",
"reason": "ooxx",
"inserted_at": "2025/03/07 10:57:44",
"updated_at": "2025/03/07 11:00:58",
"created_by": "722543ea-bdcc-48c4-aa9e-baf4e0f2fac4",
"updated_by": "722543ea-bdcc-48c4-aa9e-baf4e0f2fac4",
"announce_content": "系統將於2025年3月6日進行維護,預計維護時間為2025年3月6日00:00:00至2025年3月8日23:00:00。維護期間,系統將無法正常使用,請您提前做好準備。",
"announce_title": "test123"
},
{
"enabled": true,
"id": "23958b65-90dc-4904-8c5d-a1fc5a25f33f",
"start": "2025/03/06 00:00:00",
"type": "service",
"until": "2025/03/06 23:00:00",
"comment": "ooxx",
"reason": "xxoo",
"ticket": false,
"inserted_at": "2025/03/07 11:42:21",
"updated_at": "2025/03/07 11:42:21",
"course": false,
"created_by": "722543ea-bdcc-48c4-aa9e-baf4e0f2fac4",
"updated_by": "722543ea-bdcc-48c4-aa9e-baf4e0f2fac4",
"reservation": false
}
]
}
```
---
---
# Kiosk相關
## Tokens
- Kiosk1: k_125dddf4-4a11-4ac3-a092-e57fa15331ce
- Kiosk2: k_acd1854a-915e-4e8e-a79f-c15c537c9a56
- Kiosk3: k_ff8066f1-1f9e-4f57-b5f7-abff8620e744
## HTTP Header
```
Authorization: Kiosk [token]
```
## 結帳
```
PUT /creditcardsettlement
```
- Body
```jsonld=
{
"token": "[token]", // 請用[員工登入]拿到的token
"data": { // 隨便要放什麼都可以
"test1": "value1",
"test2": "value2"
}
}
```
- Response
```
ok
```
## 取得結帳紀錄
```
GET /creditcardsettlement
```
- Query Parameters
- token: 請用[員工登入]拿到的token,必填
- filter: today/week/month/date 可以用這三個參數不給的時候預設today,其他就代表從今天往後7天/30天
- date: yyyy/MM/dd 只有當filter為date時才會生效
- Response:
```jsonld=
{
"count": 1,
"datas": [
{
"data": { // 結帳時用存入的資料
"test1": "value1",
"test2": "value2"
},
"date": "2024/09/10", // 結帳的日期
"time": "14:35:10", // 結帳的時間
"from": "127.0.0.1", // 哪一臺結的帳
"by": "richard" // 哪個帳號結的帳
}
]
}
```
## Heartbeat
```
PUT /machine/kiosks/heartbeat
```
- Response:
```
ok
```
---
---
# 一般POS功能
## 上架零售商品
```
POST /retail
```
- Body
```jsonld=
{
"id": "R001",
"name": "毛巾(小)",
"desc": "小條毛巾",
"price": 300
}
```
- Response
```jsonld=
{
"comment": null,
"created_by": "6bf4f54c-9e69-40a8-87f9-0e2ab6b2b1fa",
"desc": "小條毛巾",
"hide": null,
"id": "R001",
"inserted_at": "2024-02-05T05:00:25",
"name": "毛巾(小)",
"price": 300,
"updated_at": "2024-02-05T05:00:25"
}
```
## 取得零售商品列表
```
GET /retails?all=false
```
- Query Parameters
- all: false就不會包括hide=true的
- Response
```jsonld=
[
{
"comment": null,
"created_by": "6bf4f54c-9e69-40a8-87f9-0e2ab6b2b1fa",
"desc": "小條毛巾",
"hide": false,
"id": "R001",
"inserted_at": "2024-02-05T05:00:25",
"name": "毛巾(小)",
"price": 300,
"updated_at": "2024-02-05T05:00:25"
}
]
```
## 使用id搜尋零售商品
```
GET /retails/search
```
- Query Parameters
- key: 商品id的內容 ex: R
- Response
```jsonld=
[
{
"comment": null,
"created_by": "6bf4f54c-9e69-40a8-87f9-0e2ab6b2b1fa",
"desc": "小條毛巾",
"hide": false,
"id": "R001",
"inserted_at": "2024-02-05T05:00:25",
"name": "毛巾(小)",
"price": 300,
"updated_at": "2024-02-05T05:00:25"
}
]
```
## 修改零售商品資料
```
PUT /retail/[retail id]
```
- Body
```jsonld=
{
"price": 1000,
"hide": true,
"comment": "test"
}
```
- Response
```
ok
```
## 商品價格試算
```
PUT /checkout/calculate
```
- Body
```jsonld=
{
"items": [
// 以下是當場地預約試算價格時要傳
{
"type": "reservation",
"field": "3樓羽球場A",
"date": "2024/02/26",
"time": "12:00",
"duration": 150
},
// 以下是當課程報名試算價格時要傳
{
"type": "course",
"takes": [...] // 報名id array
}
]
}
```
- Response
```jsonld=
{
"items": [
{
"date": "2024/02/26",
"duration": 150,
"field": "3樓羽球場A",
"price": 1250, // 各個品項的價格
"time": "12:00",
"type": "reservation"
},
{
"type": "course",
"takes": [...], // 報名id array
"price": 100,
"match_returning_student_discount": true/false, // 有無符合舊生優惠
"origin_price": 200 // 原價,當match_returning_student_discount==true時才會有
}
],
"total": 2250 // 總金額
}
```
## 結帳
```
POST /checkout
```
- Body
```jsonld=
{
"items": [
{
"type": "retail",
"item": "R001",
"price": 300,
"count": 2,
"cost": 550
},
{
"type": "retail",
"item": "R001",
"price": 300,
"count": 2,
"cost": 600
}
]
}
```
- Response
```
ok
```
## 發票入庫(兩種做法)
```
POST /invoices
```
- Body [form-data] (上傳CSV)
```
file: [.csv] // 一定要是財政部的csv
```
- Body (手動)
```jsonld=
{
"month": "113/09~113/10", // 發票的月份
"word_track": "CC", // 發票頭兩碼
"begin": "00000000", // 發票起
"finish": "00000100" // 發票迄
}
```
- Response
```
ok
```
## 補票查詢
```
GET /pass/[掃到的內容]
```
- Response
```jsonld=
{
"overtime": 60, // 超時的秒數,
"enter_at": "2024/07/22 05:19", // 進場的時間
"name": "ooxx", //票券名稱
"compensate": 50, // 試算出的補票金額
"after_compensate": "2024/07/22 07:19" // 補票後要什麼時候之前離開
}
```
## 補票
```
POST /sales
```
- Body (欄位與結帳的一模一樣,但是多了一個欄位)
```jsonld=
{
"amount": 50,
"carrier_num": "/14ZREPR",
"carrier_type": 0,
"creditcard": "",
"items": [
{
"count": 1,
"item": 4,
"price": 50,
"type": 0,
"ticket": "ooxx" // 讀卡機讀取到的內容,必填不然不會自動補票,只會產生一筆交易
}
],
"love_code": "",
"paymentType": 0,
"print_detail": true,
}
```
## 列印信用卡簽單
```
PUT /print/creditcardtx
```
- Body
```jsonld=
卡機給的所有資料的json
```
- Response
```
ok
```
---
## 交易紀錄查詢
```
GET /orders
```
- Query Parameters (date預設當日,start必須與end一起使用不然沒有效果,date與start/end一起用時只會生效date,==用by的時候其他條件都會忽略==)
- date: 指定日期(yyyy/MM/dd)
- start: 開始日期(yyyy/MM/dd)
- end: 結束日期日期(yyyy/MM/dd)
- ==by: 訂單擁有者(+886開頭會員,目前不支援pos機)==
- Response
```jsonld
{
"count": 123, //筆數
"rows": [
{
"id": 2024080100001, // 訂單編號
"fid": "20240801000030", // 訂單假編號(APP上顯示)
"status": "已付款", // 狀態直接顯示就好
"date": "20240801", // 日期
"time": "00:00:30", // 時間
"source": "APP", // 訂單來源
"pay_type": "APP線上刷卡", // 付款方式
"invoice": "DN02586742", // 發票號碼
"by": "+886970363575", // 訂單擁有者+886開頭是會員 pos機會用uuid
"cost": 300, // 總金額
"transaction_id": "txxxxxxx" // 金流平台上的交易編號
}
...
]
}
```
## 交易紀錄查詢(單筆)
```
GET /orders/[訂單編號]
```
- Response
```jsonld
{
"id": 2024080100001, // 訂單編號
"fid": "20240801000030", // 訂單假編號(APP上顯示)
"status": "已付款", // 狀態直接顯示就好
"date": "20240801", // 日期
"time": "00:00:30", // 時間
"source": "APP", // 訂單來源
"pay_type": "APP線上刷卡", // 付款方式
"invoice": "DN02586742", // 發票號碼
"by": "+886970363575", // 訂單擁有者+886開頭是會員 pos機會用uuid
"cost": 300, // 總金額
"items": [
{
"name": "3樓羽球場E", // 品名
"count": 1, // 數量
"price": 300, // 單價
"cost": 300, // 總價
}
]
}
```
## 交易紀錄作廢/折讓
```
DELETE /orders/[訂單編號]
```
- Response
```jsonld
ok or 下載折讓單
```
## 結帳(POS版)
```
PUT /creditcardsettlement
```
- Body
```jsonld=
{
"token": "[Kiosk的token]", // 不放時下面的api from會是call api的機器ip, 有給的話就會是token
"data": { // 隨便要放什麼都可以
"test1": "value1",
"test2": "value2"
}
}
```
- Response
```
ok
```
## 取得結帳紀錄(POS版)
```
GET /creditcardsettlement
```
- Query Parameters
- filter: today/week/month/date 可以用這三個參數不給的時候預設today,其他就代表從今天往後7天/30天
- date: yyyy/MM/dd 只有當filter為date時才有用
- Response:
```jsonld=
{
"count": 1,
"datas": [
{
"data": { // 結帳時用存入的資料
"test1": "value1",
"test2": "value2"
},
"date": "2024/09/10", // 結帳的日期
"time": "14:35:10", // 結帳的時間
"from": "127.0.0.1", // 哪一臺結的帳
"by": "richard" // 哪個帳號結的帳
}
]
}
```
## 發票相關特別操作
```
PUT /invoices/[invoice_number]/[method]
```
- methods
- ==cancel_creditnote== 取消折讓
- ==force_cancel== 直接作廢(超過一天以上也可以)
- ==undo_cancel== 取消作廢
*==取消的操作不會回復場地預約跟課程報名==
- Response
```
ok
```
# 場地預約
## 取得場租類型列表
```
GET /reservation_types
```
- Response
```jsonld=
[
{
"id": "handicapped",
"name": "身心障礙",
"color": "#d20382" // 區塊背景顏色
},
{
"id": "normal",
"name": "臨租長租",
"color": "#b37a1f"
},
{
"id": "event",
"name": "活動包場",
"color": "#7d00f0"
},
{
"id": "classroom",
"name": "課程使用",
"color": "#77c137"
}
]
```
## 取得場地列表
```
GET /fields
```
### 欄位解說
* id: 場地的id
* disabled: 這個場地無法預約(也不會顯示在app)
* image: 場地的圖片網址
* profile: app上面顯示的訊息有可能為null(目前先用introduction)
- Response
```jsonld=
[
{
"disabled": false,
"id": "3樓羽球場A",
"profile": null,
"image": [url]
},
{
"disabled": false,
"id": "3樓羽球場B",
"profile": {
"introduction": "ooxx"
},
"image": [url]
},
...
]
```
## 上傳場地圖片
```
POST /field/[field id]/image
```
- Body [form-data]
```
image: [.png/.jpg]
```
- Response
```
ok
```
## 修改場地資料
```
PUT /field/[field_id]
```
- Body
```jsonld=
{
"introduction": "介紹..."
}
```
- Response
```
ok
```
## 場地價格維護
### 注意事項
- 當時間有重疊時會選擇較高金額(不包含預設)
### 欄位解說
- date: 開始的日期格式必須要是yyyy/MM/dd
- repeat_type: `base在新增的時候不會用上`
```jsonld
[
{
"id": "base",
"name": "預設"
},
{
"id": "no_repeat",
"name": "不重複"
},
{
"id": "daily",
"name": "每日"
},
{
"id": "weekly",
"name": "每週"
},
{
"id": "monthly",
"name": "每月"
},
{
"id": "yearly",
"name": "每年"
}
]
```
- until: 結束日期,有給repeat_type才生效,不給就是不會結束,格式與date一樣==會計算到當天結束==
- price: 金額
- start_time: 開始時間格式請用hh:mm(24小時制),可以不給代表整天
- end_time: 有給start_time才需要給,格式一樣,一定要大於start_time
- comment: 備註, 加強可讀性
### 取得場地價格設定列表
```
GET /field/[場地id]/price
```
- Response
```jsonld=
[
{
"id": "233a6aba-e8c9-48da-b59e-7533307f4394",
"date": "1980/01/01",
"comment": "預設價格",
"inserted_at": "2024-02-06T07:34:33",
"updated_at": "2024-02-06T08:37:27",
"end_time": "23:59",
"price": 1000,
"repeat_type": "base",
"start_time": "00:00"
},
{
"id": "f6a5e476-2721-463a-bd36-568a3dc8d240",
"date": "2024/01/06",
"comment": "每個週六的06:00~20:00價格提高到3000直到2024/02/28",
"inserted_at": "2024-02-06T08:44:49",
"updated_at": "2024-02-06T08:44:49",
"end_time": "20:00",
"price": 3000,
"repeat_type": "weekly",
"until": "2024/02/28",
"start_time": "06:00"
}
]
```
### 設定場地預設價格
```
PUT /field/[場地id]/price/base
```
- Body
```jsonld=
{
"price": 1000
}
```
- Response
```
ok
```
### 新增場地價格
```
POST /field/[場地id]/price
```
- Body
```jsonld=
{
"date": "2024/01/06",
"repeat_type": "weekly",
"until": "2024/02/28",
"price": 3000,
"start_time": "06:00",
"end_time": "20:00",
"comment": "每個週六的06:00~20:00價格提高到3000"
}
```
- Response
```
ok
```
### 刪除場地價格
```
DELETE /field/[場地id]/price/[場地價格id]
```
- Response
```
ok
```
## 場地關閉維護
### 欄位解說
- date: 開始的日期格式必須要是yyyy/MM/dd
- repeat_type:
```jsonld
[
{
"id": "no_repeat",
"name": "不重複"
},
{
"id": "daily",
"name": "每日"
},
{
"id": "weekly",
"name": "每週"
},
{
"id": "monthly",
"name": "每月"
},
{
"id": "yearly",
"name": "每年"
}
]
```
- until: 結束日期,有給repeat_type才生效,不給就是不會結束,格式與date一樣==會計算到當天結束==
- start_time: 開始時間格式請用hh:mm(24小時制),可以不給代表整天
- end_time: 有給start_time才需要給,格式一樣,一定要大於start_time
- comment: 備註, 加強可讀性
### 取得場地關閉設定列表
```
GET /field/[場地id]/close
```
- Response
```jsonld=
[
{
"id": "f6a5e476-2721-463a-bd36-568a3dc8d240",
"date": "2024/01/06",
"comment": "每個週六的06:00~20:00休息直到2024/02/28",
"inserted_at": "2024-02-06T08:44:49",
"updated_at": "2024-02-06T08:44:49",
"end_time": "20:00",
"repeat_type": "weekly",
"until": "2024/02/28",
"start_time": "06:00"
}
]
```
### 新增場地關閉
```
POST /field/[場地id]/close
```
- Body
```jsonld=
{
"date": "2024/01/06",
"repeat_type": "weekly",
"until": "2024/02/28",
"start_time": "06:00",
"end_time": "20:00",
"comment": "每個週六的06:00~20:00休息直到2024/02/28"
}
```
- Response
```
ok
```
### 刪除場地關閉
```
DELETE /field/[場地id]/close/[場地關閉id]
```
- Response
```
ok
```
## 場地類別
### 取得場地類別列表
```
GET /field/categories
```
- Response
```jsonld=
[
{
"id": "羽球",
"fields": null
}
]
```
### 新增場地類別
```
POST /field/category
```
- Body
```jsonld=
{
"id": "羽球"
}
```
- Response
```
ok
```
### 修改場地類別包含的場地
```
PUT /field/category/[類別id]
```
- Body
```jsonld=
{
"fields": ["3樓羽球場A","3樓羽球場B"]
}
```
- Response
```
ok
```
### 刪除場地類別
```
DELETE /field/category/[類別id]
```
- Response
```
ok
```
### 透過場地類別取得場地資訊(for預約)
```
GET /field/category/[類別id]
```
- Query Parameters
- mode: half 時段模式(不給的話是1小時一個時段,給half是半小時一個時段)
- date: 指定日期
- Response
```jsonld=
[
{
"field": "[場地id]",
"blocks": [
...// 結構跟 [取得場地資訊(for預約)] 一樣
]
},
...
]
```
### 透過場地類別取得場地價格設定列表
```
GET /field/category/[類別id]/price
```
- Response
```jsonld=
[
{
"id": "233a6aba-e8c9-48da-b59e-7533307f4394",
"date": "1980/01/01",
"comment": "預設價格",
"inserted_at": "2024-02-06T07:34:33",
"updated_at": "2024-02-06T08:37:27",
"end_time": "23:59",
"price": 1000,
"repeat_type": "base",
"start_time": "00:00"
},
{
"id": "f6a5e476-2721-463a-bd36-568a3dc8d240",
"date": "2024/01/06",
"comment": "每個週六的06:00~20:00價格提高到3000直到2024/02/28",
"inserted_at": "2024-02-06T08:44:49",
"updated_at": "2024-02-06T08:44:49",
"end_time": "20:00",
"price": 3000,
"repeat_type": "weekly",
"until": "2024/02/28",
"start_time": "06:00"
}
]
```
### 透過場地類別修改場地價格
```
PUT /field/category/[類別id]/price/:fp_id
```
==fp_id是base時是設定預設價格其他就用上面的API拿到的id==
- Body
```jsonld=
{
"price": 1000
}
```
- Response
```
ok
```
### 透過場地類別新增場地價格
```
POST /field/category/[類別id]/price
```
- Body
```jsonld=
{
"date": "2024/01/06",
"repeat_type": "weekly",
"until": "2024/02/28",
"price": 3000,
"start_time": "06:00",
"end_time": "20:00",
"comment": "每個週六的06:00~20:00價格提高到3000"
}
```
- Response
```
ok
```
### 透過場地類別刪除場地價格
```
DELETE /field/category/[類別id]/price/[場地價格id]
```
- Response
```
ok
```
### 透過場地類別取得場地關閉設定列表
```
GET /field/category/[類別id]/close
```
- Response
```jsonld=
[
{
"id": "f6a5e476-2721-463a-bd36-568a3dc8d240",
"date": "2024/01/06",
"comment": "每個週六的06:00~20:00休息直到2024/02/28",
"inserted_at": "2024-02-06T08:44:49",
"updated_at": "2024-02-06T08:44:49",
"end_time": "20:00",
"repeat_type": "weekly",
"until": "2024/02/28",
"start_time": "06:00"
}
]
```
### 透過場地類別新增場地關閉
```
POST /field/category/[類別id]/close
```
- Body
```jsonld=
{
"date": "2024/01/06",
"repeat_type": "weekly",
"until": "2024/02/28",
"start_time": "06:00",
"end_time": "20:00",
"comment": "每個週六的06:00~20:00休息直到2024/02/28"
}
```
- Response
```
ok
```
### 透過場地類別刪除場地關閉
```
DELETE /field/category/[類別id]/close/[場地關閉id]
```
- Response
```
ok
```
## 場地預約相關
### 注意事項
- 系統這裡會控制可以預約的時間(`目前是3天`)
- 每個時段目前預設1個小時(有參數可以切換成半小時)
### 取得場地資訊(for預約)
```
GET /field/[場地id]
```
- Query Parameters
- mode: half 時段模式(不給的話是1小時一個時段,給half是半小時一個時段)
- date: 指定日期
- Response
```jsonld=
[
{
"date": "2024/02/07", // 日期
"blocks": [ // 時段列表
{
"available": false, // 可預約與否
"comment": "超時", // 無法預約的原因
"price": 1500, // 價格
"start_time": "00:00", // 時段開始時間
"end_time": "00:59" // 時段結束時間
},
{
"available": false,
"comment": "整修",
"price": 1500,
"start_time": "01:00",
"end_time": "01:59"
},
{
"available": false,
"comment": "超時",
"price": 1500,
"start_time": "02:00",
"end_time": "02:59"
},
{
"available": true,
"price": 1500,
"start_time": "03:00",
"end_time": "03:59"
},
{
"available": true,
"price": 1500,
"start_time": "04:00",
"end_time": "04:59"
},
{
"available": true,
"price": 1500,
"start_time": "05:00",
"end_time": "05:59"
},
{
"available": true,
"price": 1500,
"start_time": "06:00",
"end_time": "06:59"
},
{
"available": true,
"price": 1500,
"start_time": "07:00",
"end_time": "07:59"
},
{
"available": true,
"price": 1500,
"start_time": "08:00",
"end_time": "08:59"
},
{
"available": true,
"price": 1500,
"start_time": "09:00",
"end_time": "09:59"
},
{
"field": "3樓羽球場A", // 已預約的場地id
"available": false,
"price": 1500,
"start_time": "10:00",
"end_time": "10:59",
"occupied_by": "pos", // 從哪預約 pos/phone/app
"occupied_id": "+886972957297", // 預約會員電話(務必要用+886開頭)
"occupied_name": "Richard", // 預約會員姓名
"bgcolor": "#b37a1f", // 區塊背景顏色
"border_color": "#000000", // 區塊邊框顏色
"paid": true, // 已付款? true/false
"reservation_type": "normal", // 對應到上面的reservation_types api
"reservation_id": "1ed3fe67-18d5-4be3-b1e8-4774dea55047", // 預約的id可用來之後的操作,
"reservation": {
... // 格式請參考[搜尋預約記錄]
},
"order_info": { // 訂單相關內容
"order": 2024080100001, // 訂單編號
"invoice": "AA00000001", // 發票號碼,有開才會有
"created_at": "2024/08/01 07:00:00", // 預約時間,預約產生的時間
"paid_at": "2024/08/01 07:02:00", // 繳費時間,成功繳費的時間
"vat": "ooxx" // 統編,null的時候代表沒有或者已作廢折讓
}
},
{
"available": true,
"price": 1500,
"start_time": "11:00",
"end_time": "11:59"
},
{
"available": true,
"price": 1500,
"start_time": "12:00",
"end_time": "12:59"
},
...
]
},
...
]
```
### 預約
```
POST /reservation
```
- 注意事項
- ==批次預約是提供一個方便的介面,實際上是根據參數展開成數個時段!==
- Body
```jsonld=
{
"type": "normal", // 對應上面的reservation_types
"occupied_by": "pos", // 從哪預約 pos/phone/app (現場/電話/APP)
"occupied_id": "+886972957297", // 預約會員電話(務必要用+886開頭)
"occupied_name": "tester", // 要是沒有撈到會員資料時給這個欄位會自動建立使用者
"cost": 1000, //.實收金額 這個金額會在結帳時帶入
"comment": "備註", // 備註
"items": [
{
"field": "3樓羽球場A", // 場地id
"date": "2024/02/07", // 預約日期
"time": "10:00", // 預約時段
"duration": 60 // 預約的長度(單位是分鐘 預設是60 半小時模式是30)
},
{
"type": "expand", // 目前需要批次預約才會要用這個 其他情況下照上面的
"field": "3樓羽球場A",
"repeat_type": "weekly", // 與設定價格一樣的用法 不支援no_repeat!
"repeat_range": 1, // 指定重複的間距 ex: repeat_type=weekly repeat_range=1就是每個禮拜,2就是每兩個禮拜
"date": "2024/01/06", // 開始時間
"until": "2024/02/28", // 結束日期
"time": "10:00", // 預約時段
"duration": 60 // 預約的長度(單位是分鐘 預設是60 半小時模式是30)
}
]
}
```
- Response
- 200: ok
- 400: 與已預約場地衝突
### 搜尋預約記錄
```
GET /reservation/search
```
- Query Parameters
- phone: 會員電話(一定要是+886開頭的完整電話,可以透過上面的會員搜尋功能,拿到完整的電話號碼)
- paid: true/false 要包含已付款/未付款 (預設是false)
- Response
```jsonld=
[
{
"id": "1ed3fe67-18d5-4be3-b1e8-4774dea55047",
"status": "pending", // 狀態 pending/paid/cancel 待繳費/已繳費/已取消
"type": "normal", // 對應上面的reservation_types
"items": [
{
"id": "ecff976d-2ae5-4ddc-8f53-541331900ed7",
"date": "2024/02/07", // 預約日期
"time": "10:00", // 時段
"field_id": "3樓羽球場A", // 場地
"duration": 60, // 時長
"end_time": 1707274800, // 結束時間
"reservation_id": "1ed3fe67-18d5-4be3-b1e8-4774dea55047"
}
],
"deadline": 1707270600, // 最後繳費時間
"comment": null,
"occupied_by": "pos", // 預約方式 pos/phone/app
"occupied_id": "+886972957297", // 會員電話
"cost": 1000, // 應繳金額
"ext": null,
"inserted_at": "2024-02-06T17:48:51",
"updated_at": "2024-02-06T17:48:51"
},
{
"id": "78860f55-401f-4370-8215-25922ded2d2c",
"status": "pending",
"type": "normal",
"items": [
{
"id": "98131b49-196a-49a7-be6e-67d5bbee8a29",
"date": "2024/02/07",
"time": "12:00",
"field_id": "3樓羽球場A",
"duration": 60,
"end_time": 1707282000,
"reservation_id": "78860f55-401f-4370-8215-25922ded2d2c"
}
],
"deadline": 1707277779,
"comment": null,
"occupied_by": "pos",
"occupied_id": "+886972957297",
"cost": 1000,
"ext": null,
"inserted_at": "2024-02-07T03:39:39",
"updated_at": "2024-02-07T03:39:39"
}
]
```
### 搜尋預約記錄(透過場地類別)
```
GET /field/category/[類別id]/reservation/search
```
- Response
```jsonld=
[
{
"id": "1ed3fe67-18d5-4be3-b1e8-4774dea55047",
"status": "pending", // 狀態 pending/paid/cancel 待繳費/已繳費/已取消
"type": "normal", // 對應上面的reservation_types
"items": [
{
"id": "ecff976d-2ae5-4ddc-8f53-541331900ed7",
"date": "2024/02/07", // 預約日期
"time": "10:00", // 時段
"field_id": "3樓羽球場A", // 場地
"duration": 60, // 時長
"end_time": 1707274800, // 結束時間
"reservation_id": "1ed3fe67-18d5-4be3-b1e8-4774dea55047"
}
],
"deadline": 1707270600, // 最後繳費時間
"comment": null,
"occupied_by": "pos", // 預約方式 pos/phone/app
"occupied_id": "+886972957297", // 會員電話
"cost": 1000, // 應繳金額
"ext": null,
"inserted_at": "2024-02-06T17:48:51",
"updated_at": "2024-02-06T17:48:51"
},
{
"id": "78860f55-401f-4370-8215-25922ded2d2c",
"status": "pending",
"type": "normal",
"items": [
{
"id": "98131b49-196a-49a7-be6e-67d5bbee8a29",
"date": "2024/02/07",
"time": "12:00",
"field_id": "3樓羽球場A",
"duration": 60,
"end_time": 1707282000,
"reservation_id": "78860f55-401f-4370-8215-25922ded2d2c"
}
],
"deadline": 1707277779,
"comment": null,
"occupied_by": "pos",
"occupied_id": "+886972957297",
"cost": 1000,
"ext": null,
"inserted_at": "2024-02-07T03:39:39",
"updated_at": "2024-02-07T03:39:39"
}
]
```
### 重新預約(限定已取消且時段都還沒過期的)
```
PUT /reservation/[預約id]/redo
```
- Response
```
ok
```
### 取消預約(標記取消,不會刪除紀錄)
```
PUT /reservation/[預約id]/cancel
```
- Body
```jsonld=
{
"reason": "沒有理由"
}
```
- Response
```
ok
```
### 刪除預約紀錄(慎用)
```
DELETE /reservation/[預約id]
```
- Response
```
ok
```
### 查詢場地預約紀錄
```
GET /field/[場地id]/reservations
```
- Query Parameters ==用了start_date/end_date就不用date格式都是yyyy/MM/dd==
- date: 指定日期
- start_date: 開始日期 ==需與end_date一起否則忽略直接使用當天==
- end_date: 結束日期
- Response
```jsonld=
{
"count": 11, // 共有幾筆
"rows": [
{
"created_at": "2024/11/09 05:50:51", // 使用者預約日期及時間
"order_id": "", // 訂單編號
"invoice_number": "", // 發票號碼
"status": "未付款", // 交易狀態
"cancel_reason": "", // 取消原因
"cost": 300, // 金額
"range": "2024/11/11 06:00~06:59", // 場地被預約日期及時間
"created_from": "pos", // 結帳櫃檯
"created_by": "+886910814601", // 結帳人員
"cancel_from": "", // 取消櫃檯
"cancel_by": "", // 取消人員
"canceled_at": "" // 取消時間
},
...
]
}
```
---
## 卡片相關功能
### 建立敬老卡(沿用舊系統的建立員工卡加上參數)
```
POST /card2/[掃RFID拿到的卡號]
```
- Body
```jsonld=
{
"type": "elder",
"name": "ooxx", // 姓名
"profile": { // 裡面可以放資料如:警急聯絡人,電話等...key可以自己取
...
}
}
```
- Response
```
ok
```
### 拿敬老卡列表(沿用舊系統的員工卡列表加上參數)
```
GET /card2
```
- Query Parameters
-- type: elder/employee/monthly/app_monthly (elder: 敬老卡, employee: 員工卡, monthly: 月卡, app_monthly: APP月卡)
- Response
```jsonld=
{
"count": 1,
"rows": [
{
"id": "[卡號]",
"sn": "[卡號]",
"type": "elder",
"name": "ooxx",
"profile": {
...
}
},
...
],
"monthly_valids": { // 當type == "monthly" 的時候會出現,代表可以用的月卡數量
"fitness": 33,
"pool": 94
}
}
```
### 修改敬老卡(沿用舊系統的建立員工卡加上參數)
```
PUT /card2/[掃RFID拿到的卡號]
```
- Body
```jsonld=
{
"type": "elder",
"name": "ooxx", // 姓名
"profile": { // 裡面可以放資料如:警急聯絡人,電話等...key可以自己取
...
}
}
```
- Response
```
ok
```
### 建立月卡的操作
```
POST /monthly_operations
```
- Body
```jsonld=
{
"specific": "all", // default: "all" 指定的場地:all 全部 pool 游泳池 fitness 健身房
"date": "2025-03-20", // 指定什麼時候到期後的月卡
"extend_days": 1, // 延長幾天
"comment": "因為xxx所以xxx" // 備註
}
```
- Response
```jsonld=
{
"id": "bd28d94b-3bcd-4d12-a7fc-cb9e6a93a5a6",
"specific": "all", // 指定的場地
"status": "初始化", // 狀態
"date": "2025/03/20",
"comment": "因為xxx所以xxx",
"extend_days": 1,
"created_by": "722543ea-bdcc-48c4-aa9e-baf4e0f2fac4",
"executed_at": "",
"inserted_at": "2025/03/14 15:32:32",
"updated_at": "2025/03/14 15:32:32"
}
```
### 執行月卡的操作(已刪除)
```
PUT /monthly_operations/[monthly operation id]
```
- Response
```jsonld=
{
"id": "bd28d94b-3bcd-4d12-a7fc-cb9e6a93a5a6",
"specific": "all",
"status": "已完成",
"date": "2025/03/20",
"comment": "因為xxx所以xxx",
"extend_days": 1,
"created_by": "722543ea-bdcc-48c4-aa9e-baf4e0f2fac4",
"executed_at": "2025/03/14 15:35:07", // 執行時間
"inserted_at": "2025/03/14 15:32:32",
"updated_at": "2025/03/14 15:35:07"
}
```
### 刪除月卡的操作
```
DELETE /monthly_operations/[monthly operation id]
```
- Response
```
ok
```
### 取得月卡的操作列表
```
GET /monthly_operations
```
- Response
```jsonld=
{
"count": 1,
"rows": [
{
"id": "bd28d94b-3bcd-4d12-a7fc-cb9e6a93a5a6",
"specific": "all",
"status": "已完成",
"date": "2025/03/20",
"comment": "因為xxx所以xxx",
"inserted_at": "2025/03/14 15:32:32",
"updated_at": "2025/03/14 15:35:07",
"created_by": "722543ea-bdcc-48c4-aa9e-baf4e0f2fac4",
"executed_at": "2025/03/14 15:35:07",
"extend_days": 1
}
]
}
```
### 建立報表類別
```
POST /report_categories
```
- Body
```jsonld=
{
"code": "TestA", // code
"name": "NameA", // 名稱
"comment": "NameA", // 備註
"weight": 3, // 權重與排序有關(越大越前面)
"products": [ 1 ], // product id 的 array
"children": [],
"parent_id": "1" // 上一層類別的id(不給就是第一層)
}
```
- Response
```jsonld=
{
"id": "ooxxxxxx",
"code": "TestA",
"name": "NameA",
"comment": "NameA",
"weight": 3,
"products": [
1
],
"children": [],
"parent_id": "ooxxxxx"
}
```
### 修改報表類別
```
PUT /report_categories/[report category id]
```
- Body
```jsonld=
{
"code": "testB",
"name": "NameA_Update",
"comment": "NameA_Update",
"weight": 0,
"products": [ 2 ],
"children": [],
"parent_id": "2"
}
```
- Response
```
ok
```
### 刪除報表類別
```
DELETE /report_categories/[report category id]
```
- Response
```
ok
```
### 取得報表類別列表
```
GET /report_categories
```
- Response
```jsonld=
{
"count": 2,
"rows": [
{
"id": "ooxx",
"code": "TestA",
"name": "NameA",
"comment": "NameA",
"products": [
{
"id": 1,
"name": "體適能-全票",
"price": 50
}
],
"children": [],
"parent_id": null,
"weight": 3
},
{
"id": "xxoo",
"code": "TestB",
"name": "NameB",
"comment": "NameB",
"products": [
{
"id": 1,
"name": "體適能-全票",
"price": 50
}
],
"children": [],
"parent_id": "ooxx",
"weight": 0
}
]
}
```
---
---
## 固定電話驗證碼
### 建立固定驗證碼
```
POST /phonecodes
```
- Body
```jsonld=
{
"phone": "+886912345678",
"code": "123456" // 固定六位數字
}
```
- Response
```jsonld=
{
"phone": "+886912345678",
"code": "123456"
}
```
### 拿驗證碼列表
```
GET /phonecodes
```
- Response
```jsonld=
{
"count": 1,
"rows": [
{
"phone": "+886912345678",
"code": "123456"
},
...
]
}
```
### 刪除驗證碼
```
DELETE /phonecodes/[電話號碼(+886開頭)]
```
- Response
```
ok
```
### 修改固定驗證碼
```
PUT /phonecodes/[電話號碼(+886開頭)]
```
- Body
```jsonld=
{
"code": "123456" // 固定六位數字
}
```
- Response
```
ok
```
---
---
## 課程
### 課程欄位解說
* id: string 課程的id(客戶自己編)
* name: string 課程名稱
* type: string 課程類別的id
* teacher: string 老師的id
* classroom_type: string 教室類型("classroom", "field")
* classroom: string 當classroom_type=="classroom"時用教室id,當classroom_type=="field"時用場地id
* description: string 課程說明
* picture1: string url 照片1
* picture2: string url 照片2
* picture3: string url 照片3
* hide: true/false 封存?
* enable: true/false 啟動?
* app: true/false 開放app報名?
* begin: string yyyy/MM/dd 開始報名日期
* app_begin: string yyyy/MM/dd APP開始報名日期
* deadline: string yyyy/MM/dd 截止報名日期
* app_deadline: string yyyy/MM/dd APP截止報名日期
* open_threshold: integer 開課人數
* full: integer 滿班人數
* app_limit: integer 開放APP報名人數
* checkin_before: integer 開課前幾分鐘可報到
* checkin_after: integer 開課後幾分鐘可報到
* unit_price: integer 單堂價格
* total_price: integer 課程總價
* taste_price: integer 單次體驗價
* status_name: string 用在ui上的課程狀態
* enable_returning_student_discount: true/false 啟用舊生優惠?
* previous_course: string 關聯課程的id
* returning_student_threshold: integer 關聯課程需報名付款的堂數
* returning_student_after_discount_unit_price: integer 折扣後單堂價格
* returning_student_after_discount_total_price: integer 折扣後總價
* schedules: array 單堂資料(欄位下列)
* open_months: 開課年月
### 課程單堂欄位解說
* id: string 單堂的id(系統自動產生)
* date: string 日期yyyy/MM/dd
* start: string 時間HH:mm
* duration: integer 時長(分鐘)
* comment: string 該堂說明
### 新增課程
```
POST /courses
```
- Body
```jsonld=
{
..., //使用課程欄位解說所有欄位
"schedules": [
..., // 使用課程單堂欄位解說所有欄位
]
}
```
- Response
```jsonld=
{
... //使用上面所有欄位
}
```
### 取得課程列表
```
GET /courses
```
- Response
```jsonld=
{
"count": 1,
"rows": [
... //使用上面課程所有欄位
]
}
```
### 選課
```
POST /courses/[課程id]/takes
```
- Body
```jsonld=
{
"user": "[user的電話號碼+886開頭]",
"student": "[student id]", // student/user必須要選一個填
"schedules": [...] // 放schedule的id
}
```
- Response
```json
ok
```
### 取得選課資料(for繳費or點名)
```
GET /courses/[課程id]/takes
```
- Response
```jsonld=
{
"count": 1,
"rows": [
{
"id":"49055e94-6291-4e85-b39a-96158bddfb00", // 報名id
"course":"C001", // 課程id
"paid": false, // 是否繳費
"invoice": "AA00000001", // 發票號碼, 有繳費才會有
"attend":false, // 已報到
"isAbsent":false,
"isLeave":false,
"isShift":false,
"isTakeOff":false,
"schedule":"fffd2f91-b492-4d74-8499-02c6ec7f2bfa", // 課程單堂id
"student":"b9907b0a-7b54-48b6-933a-bc63cbe84915", // 報名學生id
"user":null, // 報名使用者電話
"name": "ooxx", //報名者名稱
"comment":null // 備註
},
...
]
}
```
### 取消選課(尚未繳費時用)
```
DELETE /courses/takes/[選課id]
```
- Response
```jsonld
ok
```
### 課程報名結帳(其他參數與一般結帳及場地預約結帳一樣只列出不同之處)
```
POST /sales
```
- Body
```jsonld=
{
"items": [
{
"type": "course",
"price": 金額(會照這個金額開發票),
"items": [...] // 報名id array
}
]
}
```
### 刪除課程(還未有人報名時)
```
DELETE /courses/[課程id]
```
- Response
```jsonld
ok
```
### 修改課程(還未有人報名時)
```
PUT /courses/[課程id]
```
- Body
```jsonld=
{
..., //使用課程欄位解說所有欄位,有帶的就會修改
"schedules": [ // 如有修改單堂資料請將所有課堂的資料都帶進來,如沒有修改請勿使用這個key(也不要用空array)
{
..., // 使用課程單堂欄位解說所有欄位(id除外)
}
]
}
```
- Response
```jsonld
ok
```
### 刪除單堂(還未有人報名時)
```
DELETE /courses/schedules/[單堂id]
```
- Response
```jsonld
ok
```
### 取得選課資料(for繳費)
```
GET /courses/takes
```
- Query Parameters ==下面兩個參數選一個就好==
- phone: 會員電話(+886開頭)
- student: student id
- Response
```jsonld=
{
"count": 3,
"rows": [
{
"id": "49055e94-6291-4e85-b39a-96158bddfb00", // 報名id用來帶到繳費api
"name": "student",
"comment": null,
"schedule": { // 報名的課堂資料
"id": "fffd2f91-b492-4d74-8499-02c6ec7f2bfa",
"start": "10:00",
"date": "2024/06/04",
"until": "11:00",
"comment": "1234",
"course": "C001",
"isTakeOff": false,
"isShift": false,
"duration": 60,
"weekday": "二"
},
"course": { // 報名的課程資料
"picture3": "https://cosmic-jaybird-regularly.ngrok-free.app/files/image/712d17dc6d95935019f226f54e676ce177551b190ce9ff75d5a06e28dbe970cb?t=19026",
"app_begin": "2024/06/04",
"checkin_after": 15,
"open_threshold": 10,
"picture2": "https://cosmic-jaybird-regularly.ngrok-free.app/files/image/712d17dc6d95935019f226f54e676ce177551b190ce9ff75d5a06e28dbe970cb?t=13680",
"type": "37776f6f-4729-41fb-b606-a6fdebd2b091",
"classroom_type": "classroom",
"app_intro": {
"schedule_count": 3,
"schedule_range": "2024/06/04 ~ 2024/06/08",
"take_range": "2024/06/04 ~ 2024/07/04",
"takes_count": 2,
"teacher": "teacher"
},
"unit_price": 100,
"deadline": "2024/07/04",
"begin": "2024/06/04",
"pictures": [
"https://cosmic-jaybird-regularly.ngrok-free.app/files/image/712d17dc6d95935019f226f54e676ce177551b190ce9ff75d5a06e28dbe970cb?t=78238",
"https://cosmic-jaybird-regularly.ngrok-free.app/files/image/712d17dc6d95935019f226f54e676ce177551b190ce9ff75d5a06e28dbe970cb?t=13680",
"https://cosmic-jaybird-regularly.ngrok-free.app/files/image/712d17dc6d95935019f226f54e676ce177551b190ce9ff75d5a06e28dbe970cb?t=19026"
],
"name": "測試課程",
"app_limit": 8,
"app_enable": true,
"classroom": "a9f2f48a-f825-4787-a78a-6c70e0112952",
"taste_price": 200,
"full": 10,
"type_name": "class_c",
"courseType": "37776f6f-4729-41fb-b606-a6fdebd2b091",
"enable": true,
"classroom_name": "舞蹈教室",
"status_name": "未知",
"total_price": 5000,
"description": "測試課程AAABBBCCCDDD",
"app_status": "報名進行中",
"id": "C001",
"app_deadline": "2024/07/04",
"schedules": [
{
"id": "fffd2f91-b492-4d74-8499-02c6ec7f2bfa",
"start": "10:00",
"date": "2024/06/04",
"until": "11:00",
"comment": "1234",
"course": "C001",
"isTakeOff": false,
"isShift": false,
"duration": 60,
"weekday": "二"
},
{
"id": "7283fa51-7910-47c9-85e7-3c73547c5218",
"start": "10:00",
"date": "2024/06/06",
"until": "11:00",
"comment": null,
"course": "C001",
"isTakeOff": false,
"isShift": false,
"duration": 60,
"weekday": "四"
},
{
"id": "5dc3b8c8-cd13-4bf3-892d-e7091033bf53",
"start": "10:00",
"date": "2024/06/08",
"until": "11:00",
"comment": null,
"course": "C001",
"isTakeOff": false,
"isShift": false,
"duration": 60,
"weekday": "六"
}
],
"hide": false,
"app": true,
"checkin_before": 15,
"picture1": "https://cosmic-jaybird-regularly.ngrok-free.app/files/image/712d17dc6d95935019f226f54e676ce177551b190ce9ff75d5a06e28dbe970cb?t=78238",
"teacher": "a82fbfed-7f8f-44c9-84d4-9e9965d6058a"
},
"attend": false,
"isTakeOff": false,
"isShift": false,
"isLeave": false,
"isAbsent": false,
"paid": false // 是否已繳費
},
...
]
}
```
### 透過QRCode課程報到
```
PUT /courses/take
```
- Body
```jsonld=
{
"code": "xxoo" // QRCode的內容
}
```
- Response
```jsonld=
{
"status": "報到成功", // 報到結果
"time": "2024/07/18 17:03:28", // 報到的時間
"schedule": "2024/07/18 17:00", // 報到的課堂時間
"course": "測試課程" // 課程名稱
}
```
### 確認有無符合舊生優惠
```
PUT /courses/[course_id]/discount
```
- Body
```jsonld=
{
"ref_id": "xxoo" // 學生id or 會員id
}
```
- Response
```jsonld=
{
"match_returning_student_discount": true/false // 有/無符合
}
```
---