主要變更: - 實作 POS 與販賣機訂單同步邏輯,支援多租戶與 Sanctum 驗證。 - 修正多租戶識別中間件與 Sanctum 驗證順序問題。 - 切換快取驅動至 Redis 以支援 Tenancy 標籤功能。 - 新增商品同步 API (Upsert) 及相關單元測試。 - 新增手動測試腳本 tests/manual/test_integration_api.sh。 - 前端新增銷售訂單來源篩選與欄位顯示。
7.0 KiB
7.0 KiB
第三方系統 API 對接手冊
Star ERP 系統提供外部整合 API (Integration API) 供電商前台、POS 機或其他第三方系統串接。 所有的整合 API 均受到 Laravel Sanctum Token 與多租戶 (Multi-tenant) Middleware 保護。
基礎連線資訊
- API Base URL:
https://[租戶網域]/api/v1/integration(依實際部署網址為準,單機開發為http://localhost/api/v1/integration) - Headers 要求:
Accept: application/jsonContent-Type: application/jsonAuthorization: Bearer {YOUR_API_TOKEN}(由 ERP 系統管理員核發的 Sanctum Token)
- 速率限制:每位使用者每分鐘最多 60 次請求。超過時會回傳
429 Too Many Requests。
1. 產品資料同步 (Upsert Product)
此 API 用於將第三方系統(如 POS)的產品資料單向同步至 ERP。採用 Upsert 邏輯:若 external_pos_id 存在則更新資料,不存在則新增產品。
- Endpoint:
/products/upsert - Method:
POST
Request Body (JSON)
| 欄位名稱 | 類型 | 必填 | 說明 |
|---|---|---|---|
external_pos_id |
String | 是 | 在 POS 系統中的唯一商品 ID (Primary Key) |
name |
String | 是 | 商品名稱 (最大 255 字元) |
price |
Decimal | 否 | 商品售價 (預設 0) |
barcode |
String | 否 | 商品條碼 (最大 100 字元) |
category |
String | 否 | 商品分類名稱。若系統中不存在,會自動建立 (最大 100 字元) |
unit |
String | 否 | 商品單位 (例如:個、杯、件)。若不存在會自動建立 (最大 100 字元) |
brand |
String | 否 | 商品品牌名稱 (最大 100 字元) |
specification |
String | 否 | 商品規格描述 (最大 255 字元) |
cost_price |
Decimal | 否 | 成本價 (預設 0) |
member_price |
Decimal | 否 | 會員價 (預設 0) |
wholesale_price |
Decimal | 否 | 批發價 (預設 0) |
is_active |
Boolean | 否 | 是否上架/啟用 (預設 true) |
updated_at |
String | 否 | POS 端的最後更新時間 (格式: YYYY-MM-DD HH:mm:ss) |
請求範例:
{
"external_pos_id": "POS-PROD-9001",
"name": "特級冷壓初榨橄欖油 500ml",
"price": 380.00,
"barcode": "4711234567890",
"category": "調味料",
"unit": "瓶",
"brand": "健康王",
"specification": "500ml / 玻璃瓶裝",
"cost_price": 250.00,
"member_price": 350.00,
"wholesale_price": 300.00,
"is_active": true,
"updated_at": "2024-03-15 14:30:00"
}
Response
Success (HTTP 200)
{
"message": "Product synced successfully",
"data": {
"id": 15,
"external_pos_id": "POS-ITEM-001"
}
}
2. 訂單資料寫入與扣庫 (Create Order)
此 API 用於讓第三方系統(如 POS 結帳後)將「已成交」的訂單推送到 ERP。 重要提醒:寫入訂單的同時,ERP 會自動且強制扣除對應倉庫的庫存(允許扣至負數,以利後續盤點或補單)。
- Endpoint:
/orders - Method:
POST
Request Body (JSON)
| 欄位名稱 | 型態 | 必填 | 說明 |
|---|---|---|---|
external_order_id |
String | 是 | 第三方系統中的唯一訂單編號,不可重複 (Unique) |
warehouse_id |
Integer | 否 | 指定出貨倉庫的系統 ID (若已知) |
warehouse |
String | 否 | 指定出貨倉庫名稱。若 warehouse_id 與此欄皆未傳,系統將預設寫入並建立「銷售倉庫」 |
payment_method |
String | 否 | 付款方式,僅接受:cash, credit_card, line_pay, ecpay, transfer, other。預設為 cash |
sold_at |
String(Date) | 否 | 交易發生時間,預設為當下時間 (格式: YYYY-MM-DD HH:mm:ss) |
items |
Array | 是 | 訂單明細陣列,至少需包含一筆商品 |
items 陣列欄位說明:
| 欄位名稱 | 型態 | 必填 | 說明 |
|---|---|---|---|
pos_product_id |
String | 是 | 對應產品的 external_pos_id。注意:商品必須先透過產品同步 API 建立至 ERP 中。 |
qty |
Number | 是 | 銷售數量 (必須 > 0) |
price |
Number | 是 | 銷售單價 |
請求範例:
{
"external_order_id": "ORD-20231026-0001",
"warehouse": "台北大安門市",
"payment_method": "credit_card",
"sold_at": "2023-10-26 14:30:00",
"items": [
{
"pos_product_id": "POS-ITEM-001",
"qty": 2,
"price": 450
},
{
"pos_product_id": "POS-ITEM-005",
"qty": 1,
"price": 120
}
]
}
Response
Success (HTTP 201)
{
"message": "Order synced and stock deducted successfully",
"order_id": 42
}
Error: Product Not Found (HTTP 400)
若 items 內傳入了未曾同步過的 pos_product_id,會導致寫入失敗。
{
"message": "Sync failed: Product not found for POS ID: POS-ITEM-999. Please sync product first."
}
錯誤回應 (HTTP 422 Unprocessable Entity - 驗證失敗)
當傳入資料格式有誤、商品編號不存在,或是該訂單正在處理中被系統鎖定時返回。
message(字串): 錯誤摘要。errors(物件): 具體的錯誤明細列表,能一次性回報多個商品不存在或其它欄位錯誤。
{
"message": "Validation failed",
"errors": {
"items": [
"The following products are not found: POS-999, POS-888. Please sync products first."
],
"external_order_id": [
"The order ORD-01 is currently being processed by another transaction. Please try again later."
]
}
}
錯誤回應 (HTTP 500 Internal Server Error - 伺服器異常)
當系統發生預期外的錯誤(如資料庫連線失敗)時返回。
{
"message": "Sync failed: An unexpected error occurred."
}
幂等性說明 (Idempotency)
訂單 API 支援幂等性處理:若傳入已存在的 external_order_id,系統不會報錯,而是回傳該訂單的資訊:
{
"message": "Order already exists",
"order_id": 42
}
這讓第三方系統在網路問題導致重送時,不會產生重複訂單或重複扣庫。
常見問題與除錯 (FAQ)
-
收到
401 Unauthorized錯誤?- 請檢查請求標頭 (Header) 是否有正確攜帶
Authorization: Bearer {Token}。 - 確認該 Token 尚未過期或被撤銷。
- 請檢查請求標頭 (Header) 是否有正確攜帶
-
收到
422 Unprocessable Entity錯誤?- 代表傳送的 JSON 欄位不符合格式要求,例如必填欄位遺漏、數量為負數、或
payment_method不在允許的值中。Laravel 會在回應的errors物件中詳細說明哪個欄位驗證失敗。
- 代表傳送的 JSON 欄位不符合格式要求,例如必填欄位遺漏、數量為負數、或
-
收到
429 Too Many Requests錯誤?- 代表已超過速率限制(每分鐘 60 次),請稍後再試。
-
庫存扣除邏輯
- POS 訂單寫入視為「已發生之事實」,系統會無條件扣除庫存。若該產品在指定倉庫原先庫存為 0,訂單寫入後庫存將變為負數,提醒門市人員需進行調撥補貨。