US-202: 訂單狀態流轉
User Story
作為 店員/管理者 我想要 能夠變更訂單狀態並追蹤狀態流轉歷史 以便 掌握訂單進度並確保訂單按流程推進
驗收標準 (Acceptance Criteria)
Scenario 1: 確認訂單(待確認 → 已確認)
- Given 我是已登入的店員
- And 系統中有一筆「待確認」狀態的訂單
ABC-20251101-0001 - And 我已檢查訂單資訊無誤
- When 我在訂單詳情頁點擊「確認訂單」按鈕
- Then 系統應將訂單狀態變更為「已確認」
- And 系統應記錄狀態變更日誌(操作者、時間、狀態變更)
- And 系統應發送通知給客戶(「您的訂單已確認」)
- And 我應看到「訂單已確認」的成功訊息
- And 訂單應出現在「待分配設計師」列表中
Scenario 2: 分配設計師後自動流轉(已確認 → 設計中)
- Given 我是已登入的管理者
- And 系統中有一筆「已確認」狀態的訂單
ABC-20251101-0002 - When 我將訂單分配給設計師「王小花」
- Then 系統應自動將訂單狀態變更為「設計中」
- And 系統應記錄「分配設計師」操作日誌
- And 系統應發送通知給設計師「王小花」
- And 訂單應出現在設計師「王小花」的工作列表中
Scenario 3: 設計完成(設計中 → 待出貨)
- Given 我是已登入的設計師「王小花」
- And 我的工作列表中有一筆「設計中」狀態的訂單
ABC-20251101-0002 - And 我已完成商品設計
- When 我上傳作品照片(至少 1 張)
- And 我點擊「標記為完成」按鈕
- Then 系統應將訂單狀態變更為「待出貨」
- And 系統應記錄作品照片上傳與完成時間
- And 系統應發送通知給管理者與送貨員(「訂單已完成設計」)
- And 訂單應出現在「待分配送貨員」列表中
Scenario 4: 配送中(待出貨 → 配送中)
- Given 我是已登入的送貨員「李配送」
- And 系統中有一筆「待出貨」狀態的訂單
ABC-20251101-0003 - When 我從「待出貨」列表中接單
- And 我點擊「開始配送」按鈕
- Then 系統應將訂單狀態變更為「配送中」
- And 系統應記錄配送開始時間與送貨員資訊
- And 系統應發送通知給客戶(「訂單配送中,預計 {時段} 送達」)
- And 訂單應出現在我的「配送中」列表
Scenario 5: 簽收完成(配送中 → 已簽收)
- Given 我是已登入的送貨員「李配送」
- And 我的「配送中」列表中有一筆訂單
ABC-20251101-0003 - And 客戶已簽收商品
- When 我上傳簽收照片(至少 1 張)
- And 我點擊「確認簽收」按鈕
- Then 系統應將訂單狀態變更為「已簽收」
- And 系統應記錄簽收時間與照片
- And 系統應發送通知給客戶(「訂單已簽收,查看簽收照片」)
- And 系統應檢查支付狀態,若已支付則自動變更為「已完成」
Scenario 6: 訂單完成(已簽收 → 已完成)
- Given 系統中有一筆「已簽收」狀態的訂單
ABC-20251101-0003 - And 訂單支付狀態為「已支付」
- When 系統定期檢查訂單狀態(每 5 分鐘)
- Then 系統應自動將訂單狀態變更為「已完成」
- And 系統應記錄完成時間
- And 訂單應移至「已完成」列表
Scenario 7: 無效狀態流轉(錯誤場景)
- Given 我是已登入的店員
- And 系統中有一筆「設計中」狀態的訂單
ABC-20251101-0004 - When 我嘗試將訂單狀態變更為「待確認」(逆向流轉)
- Then 系統應拒絕此操作並顯示錯誤訊息「無效的狀態流轉」
- And 訂單狀態應保持為「設計中」
Scenario 8: 查看狀態流轉歷史
- Given 我是已登入的管理者
- And 系統中有一筆訂單
ABC-20251101-0001 - When 我在訂單詳情頁查看「狀態歷史」區塊
- Then 系統應顯示所有狀態變更記錄
- And 每筆記錄應包含:
- 變更時間(精確到秒)
- 原狀態 → 新狀態
- 操作者姓名與角色
- 操作說明(如「分配給設計師王小花」)
業務規則 (Business Rules)
-
狀態流轉規則(僅允許單向流轉)
待確認 → 已確認 → 設計中 → 待出貨 → 配送中 → 已簽收 → 已完成- 禁止逆向流轉(如「設計中」→「已確認」)
- 例外:任何狀態都可流轉至「已取消」(US-208 處理)
-
自動狀態流轉
- 已確認 → 設計中: 當分配設計師時自動流轉
- 待出貨 → 配送中: 當送貨員接單時自動流轉
- 已簽收 → 已完成: 當支付狀態為「已支付」時自動流轉(系統定期檢查)
-
手動狀態流轉
- 待確認 → 已確認: 店員/管理者手動確認
- 設計中 → 待出貨: 設計師上傳作品照片並標記完成
- 配送中 → 已簽收: 送貨員上傳簽收照片並確認
-
狀態流轉前置條件
- 設計中 → 待出貨: 必須上傳至少 1 張作品照片
- 配送中 → 已簽收: 必須上傳至少 1 張簽收照片
- 已簽收 → 已完成: 必須支付狀態為「已支付」
-
狀態歷史記錄
- 每次狀態變更都需記錄審計日誌
- 日誌包含:操作者、時間戳、原狀態、新狀態、操作說明
- 日誌不可修改或刪除
-
通知規則
- 每次狀態變更都應觸發相應的通知(整合 Epic 0 通知系統)
- 通知對象根據狀態不同而異(客戶、設計師、送貨員、管理者)
-
多租戶隔離
- 狀態流轉操作僅能針對當前租戶的訂單
- 員工選擇列表(設計師、送貨員)僅顯示當前租戶的員工
UI/UX 需求 (UI/UX Requirements)
訂單詳情頁 - 狀態流轉區塊
佈局
- 狀態進度條: 顯示訂單當前處於哪個階段(視覺化流程圖)
- 已完成的階段: 綠色勾選
- 當前階段: 藍色高亮
- 未完成階段: 灰色
- 操作按鈕區: 根據當前狀態與用戶角色動態顯示可執行操作
- 狀態歷史時間軸: 折疊式區塊,顯示所有狀態變更記錄
互動行為
1. 狀態進度條
[✓] 待確認 → [✓] 已確認 → [●] 設計中 → [ ] 待出貨 → [ ] 配送中 → [ ] 已簽收 → [ ] 已完成
- 點擊每個階段顯示該階段的操作記錄
2. 操作按鈕(根據狀態動態顯示)
| 當前狀態 | 可見按鈕(根據角色) | 操作結果 |
|---|---|---|
| 待確認 | 「確認訂單」(店員+) | → 已確認 |
| 已確認 | 「分配設計師」(管理者+) | → 設計中 |
| 設計中 | 「上傳作品照片」(設計師+) | 上傳照片 |
| 設計中 | 「標記為完成」(設計師+) | → 待出貨 |
| 待出貨 | 「分配送貨員」(管理者+) | 分配送貨員 |
| 待出貨 | 「開始配送」(送貨員+) | → 配送中 |
| 配送中 | 「上傳簽收照片」(送貨員+) | 上傳照片 |
| 配送中 | 「確認簽收」(送貨員+) | → 已簽收 |
3. 狀態歷史時間軸
- 預設折疊,點擊「查看狀態歷史」展開
- 顯示格式:
● 2025-11-01 14:30:25 設計中 → 待出貨
操作者: 王小花 (設計師)
說明: 上傳作品照片並標記完成
● 2025-11-01 10:15:00 已確認 → 設計中
操作者: 系統自動
說明: 分配給設計師王小花
● 2025-11-01 09:30:00 待確認 → 已確認
操作者: 張店員 (店員)
說明: 手動確認訂單
錯誤訊息
- 無效狀態流轉: 「無法執行此操作,當前狀態不允許此流轉」
- 缺少前置條件: 「請先上傳作品照片後再標記為完成」
- 權限不足: 「您沒有權限執行此操作」
成功反饋
- 狀態變更成功: Toast 通知「訂單狀態已更新為 {新狀態}」
- 通知發送成功: Toast 通知「已發送通知給 {通知對象}」
技術規格 (Technical Specifications)
API 端點
1. 變更訂單狀態
- 端點:
PUT /api/v1/orders/{orderId}/status - 權限要求: 根據目標狀態不同而異(見業務規則)
- 多租戶隔離: 自動檢查
tenantId
請求 Payload
interface UpdateOrderStatusRequest {
newStatus: OrderStatus; // 目標狀態(必填)
reason?: string; // 操作原因(可選,某些流轉需要)
assignedTo?: string; // 分配對象 ID(分配設計師/送貨員時必填)
photoUrls?: string[]; // 照片 URL(上傳作品/簽收照片時必填)
}
enum OrderStatus {
PENDING_CONFIRMATION = 'pending_confirmation',
CONFIRMED = 'confirmed',
IN_PRODUCTION = 'in_production',
READY_FOR_DELIVERY = 'ready_for_delivery',
OUT_FOR_DELIVERY = 'out_for_delivery',
DELIVERED = 'delivered',
COMPLETED = 'completed',
CANCELLED = 'cancelled',
DELIVERY_FAILED = 'delivery_failed'
}
響應範例
{
"orderId": "ABC-20251101-0001",
"oldStatus": "pending_confirmation",
"newStatus": "confirmed",
"updatedAt": "2025-11-01T09:30:00Z",
"updatedBy": {
"userId": "user-001",
"userName": "張店員",
"role": "ROLE_SALES"
},
"message": "訂單狀態已更新為「已確認」"
}
2. 查看狀態歷史
- 端點:
GET /api/v1/orders/{orderId}/status-history - 權限要求:
ROLE_STAFF或更高 - 多租戶隔離: 自動檢查
tenantId
響應範例
{
"orderId": "ABC-20251101-0001",
"history": [
{
"id": "history-001",
"timestamp": "2025-11-01T14:30:25Z",
"oldStatus": "in_production",
"newStatus": "ready_for_delivery",
"operator": {
"userId": "user-002",
"userName": "王小花",
"role": "ROLE_FLORIST"
},
"description": "上傳作品照片並標記完成",
"metadata": {
"photoCount": 3
}
},
{
"id": "history-002",
"timestamp": "2025-11-01T10:15:00Z",
"oldStatus": "confirmed",
"newStatus": "in_production",
"operator": {
"userId": "system",
"userName": "系統自動",
"role": "system"
},
"description": "分配給設計師王小花",
"metadata": {
"assignedTo": "user-002"
}
}
]
}
數據模型
OrderStatusHistory Entity
interface OrderStatusHistory {
id: string; // 歷史記錄 ID
orderId: string; // 訂單 ID(外鍵)
tenantId: string; // 租戶 ID
oldStatus: OrderStatus; // 原狀態
newStatus: OrderStatus; // 新狀態
timestamp: Date; // 變更時間
operatorId: string; // 操作者 ID
operatorName: string; // 操作者姓名(冗餘,方便查詢)
operatorRole: UserRole; // 操作者角色
description: string; // 操作描述
metadata?: Record<string, any>; // 額外資訊(如照片數量、分配對象)
createdAt: Date;
}
前端組件
-
使用框架組件:
@appfuse/appfuse-web的Button組件(操作按鈕)@appfuse/appfuse-web的Timeline組件(狀態歷史,若有)@appfuse/appfuse-web的Badge組件(狀態標籤)@appfuse/appfuse-web的ProgressSteps組件(狀態進度條,若有)
-
自定義組件:
OrderStatusFlow- 位於src/applets/order-applet/components/OrderStatusFlow.tsxOrderStatusHistory- 狀態歷史時間軸StatusProgressBar- 狀態進度條
狀態流轉驗證邏輯
// 狀態流轉規則映射表
const STATUS_TRANSITIONS: Record<OrderStatus, OrderStatus[]> = {
[OrderStatus.PENDING_CONFIRMATION]: [OrderStatus.CONFIRMED, OrderStatus.CANCELLED],
[OrderStatus.CONFIRMED]: [OrderStatus.IN_PRODUCTION, OrderStatus.CANCELLED],
[OrderStatus.IN_PRODUCTION]: [OrderStatus.READY_FOR_DELIVERY, OrderStatus.CANCELLED],
[OrderStatus.READY_FOR_DELIVERY]: [OrderStatus.OUT_FOR_DELIVERY, OrderStatus.CANCELLED],
[OrderStatus.OUT_FOR_DELIVERY]: [OrderStatus.DELIVERED, OrderStatus.DELIVERY_FAILED, OrderStatus.CANCELLED],
[OrderStatus.DELIVERED]: [OrderStatus.COMPLETED],
[OrderStatus.COMPLETED]: [],
[OrderStatus.CANCELLED]: [],
[OrderStatus.DELIVERY_FAILED]: [OrderStatus.OUT_FOR_DELIVERY, OrderStatus.CANCELLED]
};
// 驗證狀態流轉是否合法
function isValidTransition(currentStatus: OrderStatus, targetStatus: OrderStatus): boolean {
const allowedTransitions = STATUS_TRANSITIONS[currentStatus] || [];
return allowedTransitions.includes(targetStatus);
}
SBE 場景 (Specification by Example)
詳細的測試場景與範例數據:
估算 (Estimation)
- Story Points: 5 點
- 預估工時: 2-3 天
- 複雜度: 中等
工作拆分
-
後端開發 (1-1.5 天)
- 實作
PUT /api/v1/orders/{orderId}/statusAPI - 狀態流轉驗證邏輯
- 狀態歷史記錄(OrderStatusHistory Entity)
- GET 狀態歷史 API
- 自動狀態流轉邏輯(系統定期檢查)
- 通知觸發邏輯(整合 Epic 0)
- 實作
-
前端開發 (1-1.5 天)
- 創建
OrderStatusFlow組件 - 狀態進度條實作
- 操作按鈕動態顯示邏輯
- 狀態歷史時間軸組件
- 權限控制(根據角色顯示按鈕)
- 創建
-
整合與測試 (0.5 天)
- 整合測試(API + UI)
- E2E 測試(完整狀態流轉流程)
- Mock API 更新
依賴 (Dependencies)
前置條件
- US-201: 創建訂單 - 需要訂單資料
- Epic 0: 通知系統 - 狀態變更通知
- Epic 0: 審計日誌 - 記錄狀態變更
並行開發
- 可與 US-203(搜尋與過濾訂單)並行開發
外部依賴
- 通知系統 API(發送狀態變更通知)
- 員工管理 API(獲取設計師與送貨員列表)
測試策略 (Testing Strategy)
單元測試
- 測試狀態流轉驗證邏輯(
isValidTransition) - 測試自動狀態流轉邏輯(已簽收 → 已完成)
- 測試狀態歷史記錄生成
整合測試
- 測試
PUT /api/v1/orders/{orderId}/statusAPI 端點 - 測試狀態歷史記錄查詢 API
- 測試通知觸發邏輯
- 測試多租戶隔離(不同租戶的訂單狀態獨立)
E2E 測試
- 測試完整的訂單狀態流轉流程(待確認 → 已完成)
- 測試無效狀態流轉(錯誤場景)
- 測試權限控制(不同角色的操作權限)
手動測試
- 測試狀態進度條視覺化
- 測試操作按鈕動態顯示
- 測試狀態歷史時間軸展開/折疊
完成定義 (Definition of Done)
- 後端 API 實作完成並通過單元測試
- 前端 UI 實作完成並符合設計規範
- 狀態流轉驗證邏輯實作完成
- 狀態歷史記錄功能實作完成
- 整合測試通過(API + UI)
- E2E 測試通過(至少涵蓋完整流轉與錯誤場景)
- 單元測試覆蓋率 > 80%
- Code Review 通過
- API 文檔已更新(訂單 API 規格)
- Mock API 已更新(支援狀態流轉)
- 通知功能驗證通過
- 審計日誌記錄驗證通過
- 多租戶隔離驗證通過
- 產品經理驗收通過
備註 (Notes)
設計決策
為何禁止逆向流轉?
- 確保訂單流程的單向性與可追溯性
- 防止人為錯誤(如不小心將「已簽收」改回「設計中」)
- 若需要修正錯誤,應使用「取消訂單」並重新創建
為何需要狀態歷史?
- 滿足審計需求(追溯訂單處理過程)
- 幫助排查問題(如「為何訂單卡在設計中?」)
- 提升透明度(客戶可查看訂單進度)
未來優化
- 支援 WebSocket 即時推送狀態變更(目前使用輪詢)
- 支援狀態流轉通知偏好設定(客戶可選擇接收哪些通知)
- 支援批量狀態流轉(如批量確認訂單)
- 支援狀態流轉規則自定義(不同租戶可自定義流程)
最後更新: 2025-12-20