[REFACTOR] 統一訂單同步 API 錯誤回應與修正 Linter 警告

This commit is contained in:
2026-03-19 14:07:32 +08:00
parent e3ceedc579
commit 0b4aeacb55
15 changed files with 1173 additions and 108 deletions

View File

@@ -14,7 +14,61 @@ Star ERP 系統提供外部整合 API (Integration API) 供電商前台、POS
---
## 1. 品資料同步 (Upsert Product)
## 1. 品資料讀取 (Product Retrieval)
此 API 用於讓外部系統(如 POS依據關鍵字、分類或最後更新時間從 ERP 中批量抓取商品資料。支援分頁與增量同步。
- **Endpoint**: `/products`
- **Method**: `GET`
### Query Parameters
| 參數名稱 | 類型 | 必填 | 說明 |
| :--- | :--- | :---: | :--- |
| `product_id` | Integer| 否 | 依 ERP 商品 ID (`products.id`) 精準篩選 |
| `external_pos_id` | String | 否 | 依外部 POS 端的唯一識別碼 (`external_pos_id`) 精準篩選 |
| `barcode` | String | 否 | 依商品條碼 (Barcode) 精準篩選 |
| `code` | String | 否 | 依商品代碼 (Code) 精準篩選 |
| `category` | String | 否 | 分類名稱精準過濾 |
| `updated_after` | String | 否 | 增量同步機制。僅回傳該時間點之後有異動的商品 (格式: `YYYY-MM-DD HH:mm:ss`) |
| `per_page` | Integer| 否 | 每頁筆數 (預設 50, 最大 100) |
| `page` | Integer| 否 | 分頁頁碼 (預設 1) |
### Response
**Success (HTTP 200)**
僅開放公開價格 `price`,隱藏敏感成本與會員價。
```json
{
"status": "success",
"data": [
{
"id": 12,
"code": "PROD-001",
"barcode": "4710001",
"name": "可口可樂 600ml",
"external_pos_id": "POS-P-001",
"category_name": "飲品",
"brand": "可口可樂",
"specification": "600ml",
"unit_name": "瓶",
"price": 25.0,
"is_active": true,
"updated_at": "2026-03-19 09:30:00"
}
],
"meta": {
"current_page": 1,
"last_page": 5,
"per_page": 50,
"total": 240
}
}
```
---
## 2. 商品資料同步 (Upsert Product)
此 API 用於將第三方系統(如 POS的產品資料單向同步至 ERP。採用 Upsert 邏輯:若 `external_pos_id` 存在則更新資料,不存在則新增產品。
@@ -23,14 +77,15 @@ Star ERP 系統提供外部整合 API (Integration API) 供電商前台、POS
### Request Body (JSON)
| 欄位名稱 | 類型 | 必填 | 說明 |
| 參數名稱 | 類型 | 必填 | 說明 |
| :--- | :--- | :---: | :--- |
| `external_pos_id` | String | **是** | 在 POS 系統中的唯一商品 ID (Primary Key) |
| `name` | String | **是** | 商品名稱 (最大 255 字元) |
| `category` | String | **是** | 商品分類名稱。若系統中不存在則自動建立 (最大 100 字元) |
| `unit` | String | **是** | 商品單位 (例如:個、杯、件)。若不存在則自動建立 (最大 100 字元) |
| `code` | String | 否 | 商品代碼。若未提供將由 ERP 自動產生 (最大 100 字元) |
| `price` | Decimal | 否 | 商品售價 (預設 0) |
| `barcode` | String | 否 | 商品條碼 (最大 100 字元) |
| `category` | String | 否 | 商品分類名稱。若系統中不存在,會自動建立 (最大 100 字元) |
| `unit` | String | 否 | 商品單位 (例如:個、杯、件)。若不存在會自動建立 (最大 100 字元) |
| `barcode` | String | 否 | 商品條碼 (最大 100 字元)。若未提供將由 ERP 自動產生 |
| `brand` | String | 否 | 商品品牌名稱 (最大 100 字元) |
| `specification` | String | 否 | 商品規格描述 (最大 255 字元) |
| `cost_price` | Decimal | 否 | 成本價 (預設 0) |
@@ -44,10 +99,10 @@ Star ERP 系統提供外部整合 API (Integration API) 供電商前台、POS
{
"external_pos_id": "POS-PROD-9001",
"name": "特級冷壓初榨橄欖油 500ml",
"price": 380.00,
"barcode": "4711234567890",
"category": "調味料",
"unit": "瓶",
"price": 380.00,
"barcode": "4711234567890",
"brand": "健康王",
"specification": "500ml / 玻璃瓶裝",
"cost_price": 250.00,
@@ -58,22 +113,34 @@ Star ERP 系統提供外部整合 API (Integration API) 供電商前台、POS
}
```
> [!TIP]
> **自動編碼與分類機制**
> - **必填項**`category``unit` 為必填。若 ERP 中無對應名稱,將會依據傳入值自動建立。
> - **自動編碼**:若未提供 `code` (商品代碼),將由 ERP 自動產生 8 位隨機代碼。
> - **自動條碼**:若未提供 `barcode` (條碼),將由 ERP 自動產生 13 位隨機數字條碼。
> - 建議在同步後儲存回傳的 `id``code``barcode`,以利後續精確對接。
### Response
**Success (HTTP 200)**
回傳 ERP 端的完整商品主檔資訊,供外部系統回存 ID 或代碼。
### 回傳範例 (Success)
- **Status Code**: `200 OK`
```json
{
"message": "Product synced successfully",
"data": {
"id": 15,
"external_pos_id": "POS-ITEM-001"
"id": 1,
"external_pos_id": "POS-P-999",
"code": "A1B2C3D4",
"barcode": "4710009990001"
}
}
```
---
## 2. 門市庫存查詢 (Query Inventory)
## 3. 門市庫存查詢 (Query Inventory)
此 API 用於讓外部系統(如 POS依據特定的「倉庫代碼」查詢該倉庫目前所有商品的庫存餘額。
**注意**:此 API 會回傳該倉庫內的所有商品數量,不論該商品是否已綁定外部 POS ID。
@@ -87,25 +154,53 @@ Star ERP 系統提供外部整合 API (Integration API) 供電商前台、POS
| :--- | :--- | :---: | :--- |
| `warehouse_code` | String | **是** | 要查詢的倉庫代碼 (例如:`STORE-001`,測試可使用預設建立之 `api-test-01`) |
### Query Parameters (選填)
| 參數名稱 | 類型 | 說明 |
| :--- | :--- | :--- |
| `product_id` | String | 依 ERP 商品 ID (`products.id`) 篩選。 |
| `external_pos_id` | String | 依外部 POS 端的唯一識別碼 (`external_pos_id`) 篩選。 |
| `barcode` | String | 依商品條碼 (Barcode) 篩選商品。 |
| `code` | String | 依商品代碼 (Code) 篩選商品。 |
若不帶任何參數,將回傳該倉庫下所有商品的庫存餘額。
### Response
**Success (HTTP 200)**
回傳該倉庫內所有的商品目前庫存總數。若商品未建置 `external_pos_id`,該欄位將顯示為 `null`
回傳該倉庫內所有的商品目前庫存總數及詳細資訊。若商品未建置 `external_pos_id`,該欄位將顯示為 `null`
```json
{
"status": "success",
"warehouse_code": "api-test-01",
"data": [
{
"external_pos_id": "POS-ITEM-001",
"product_id": 1,
"external_pos_id": "PROD-001",
"product_code": "PROD-A001",
"product_name": "特級冷壓初榨橄欖油 500ml",
"barcode": "4710123456789",
"category_name": "調味料",
"unit_name": "瓶",
"price": 450.00,
"brand": "奧利塔",
"specification": "500ml/瓶",
"batch_number": "PROD-A001-TW-20231026-01",
"expiry_date": "2025-10-26",
"quantity": 15
},
{
"external_pos_id": null,
"product_code": "MAT-001",
"product_name": "未包裝干貝醬原料",
"barcode": null,
"category_name": "原料",
"unit_name": "kg",
"price": 0.00,
"brand": null,
"specification": null,
"batch_number": "MAT-001-TW-20231020-01",
"expiry_date": "2024-04-20",
"quantity": 2.5
}
]
@@ -123,10 +218,10 @@ Star ERP 系統提供外部整合 API (Integration API) 供電商前台、POS
---
## 3. 訂單資料寫入與扣庫 (Create Order)
## 4. 訂單資料寫入與扣庫 (Create Order)
此 API 用於讓第三方系統(如 POS 結帳後)將「已成交」的訂單推送到 ERP。
**重要提醒**:寫入訂單的同ERP 會自動且**強制**扣除對應倉庫的庫存(允許扣至負數,以利後續盤點或補單)
**重要提醒**寫入訂單時ERP 會無條件扣除庫存。若指定的「批號」庫存不足,系統會自動轉向 `NO-BATCH` 庫存項目扣除;若最終仍不足,則會在 `NO-BATCH` 產生負數庫存
- **Endpoint**: `/orders`
- **Method**: `POST`
@@ -145,27 +240,26 @@ Star ERP 系統提供外部整合 API (Integration API) 供電商前台、POS
| 欄位名稱 | 型態 | 必填 | 說明 |
| :--- | :--- | :---: | :--- |
| `pos_product_id` | String | **是** | 對應產品的 `external_pos_id`。**注意:商品必須先透過產品同步 API 建立至 ERP 中。** |
| `product_id` | Integer | **是** | **ERP 內部的商品 ID (`id`)**。請優先使用商品同步 API 取得此 ID |
| `batch_number` | String | 否 | **商品批號**。若提供,將優先扣除該批號庫存;若該批號無剩餘或找不到,將自動 fallback 至 `NO-BATCH` 扣除 |
| `qty` | Number | **是** | 銷售數量 (必須 > 0) |
| `price` | Number | **是** | 銷售單價 |
**注意**:請確保傳入正確的 `product_id` 以便 ERP 準確識別商品與扣除庫存。
**請求範例:**
```json
{
"external_order_id": "ORD-20231026-0001",
"external_order_id": "ORD-20240320-0001",
"warehouse_code": "api-test-01",
"payment_method": "credit_card",
"sold_at": "2023-10-26 14:30:00",
"sold_at": "2024-03-20 14:30:00",
"items": [
{
"pos_product_id": "POS-ITEM-001",
"product_id": 15,
"batch_number": "BATCH-2024-A1",
"qty": 2,
"price": 450
},
{
"pos_product_id": "POS-ITEM-005",
"qty": 1,
"price": 120
"price": 500
}
]
}
@@ -181,17 +275,9 @@ Star ERP 系統提供外部整合 API (Integration API) 供電商前台、POS
}
```
**Error: Product Not Found (HTTP 400)**
`items` 內傳入了未曾同步過的 `pos_product_id`,會導致寫入失敗。
```json
{
"message": "Sync failed: Product not found for POS ID: POS-ITEM-999. Please sync product first."
}
```
#### 錯誤回應 (HTTP 422 Unprocessable Entity - 驗證失敗)
當傳入資料格式有誤、商品編號不存在,或是該訂單正在處理中被系統鎖定時返回。
當傳入資料格式有誤、商品 ID 於系統中不存在(如 `items` 內傳入了無法辨識的商品 ID或是倉庫代碼無效時返回。
- **`message`** (字串): 錯誤摘要。
- **`errors`** (物件): 具體的錯誤明細列表,能一次性回報多個商品不存在或其它欄位錯誤。
@@ -201,10 +287,10 @@ Star ERP 系統提供外部整合 API (Integration API) 供電商前台、POS
"message": "Validation failed",
"errors": {
"items": [
"The following products are not found: POS-999, POS-888. Please sync products first."
"The following product IDs are not found: 15, 22. Please ensure these products exist in the system."
],
"external_order_id": [
"The order ORD-01 is currently being processed by another transaction. Please try again later."
"warehouse_code": [
"Warehouse with code STORE-999 not found."
]
}
}