# 订单状态流转 — 测试指南 > 本文档面向测试人员和项目经理,描述订单系统在状态重构后的全部业务行为。 > 如有疑问请对照 `specs/006-orderstate/spec.md` 原始需求文档。 --- ## 一、背景 系统支持三种订单类型,每种类型有不同的参与角色和完成方式: | 订单类型 | 谁送餐 | 谁付钱 | 谁完成订单 | |---------|--------|--------|-----------| | **外送** (type=0) | 骑手配送 | 在线支付 / 到付 | 骑手点"已送达" | | **自取** (type=1) | 用户到店取 | 现金(线下收款) | 商家点"完成" 或 用户确认取餐 | | **堂食** (type=2) | 商家端上 | 现金(线下收款) | 商家点"完成" | --- ## 二、状态字段说明 订单有 4 个独立的状态字段,各自跟踪不同的关注点: ### 2.1 订单状态 (state) — 订单的生命周期 | 值 | 状态名 | 含义 | |----|--------|------| | 0 | 待处理 | 订单刚创建,等待商家接单 | | 1 | 已接单 | 商家已接单,正在备餐 | | 2 | 已出餐 | 商家备餐完成 | | 3 | 已完成 | 订单结束(外送=骑手送达,自取=用户取餐,堂食=备餐完成) | | 4 | 已取消 | 订单被取消 | ### 2.2 支付状态 (payStatus) | 值 | 状态名 | 含义 | |----|--------|------| | 0 | 未支付 | 等待付款 | | 1 | 已支付 | 付款完成 | | 2 | 已退款 | 退款完成 | **关键规则:** - 外送到付订单:下单时直接标记为"已支付"(1),骑手送货时收现金 - 自取/堂食现金订单:下单时为"未支付"(0),商家收款+点完成时才改为"已支付"(1) - 在线支付订单:下单时为"未支付"(0),支付成功后改为"已支付"(1) ### 2.3 配送状态 (deliveryStatus) — 仅外送订单 | 值 | 状态名 | 含义 | |----|--------|------| | null | 不适用 | 自取/堂食订单没有配送状态 | | 0 | 待接单 | 等待骑手接单 | | 1 | 骑手已接单 | 骑手已接单,还没取餐 | | 2 | 配送中 | 骑手已取餐,正在送 | | 3 | 已送达 | 骑手已送到 | ### 2.4 售后状态 (afterSaleStatus) | 值 | 状态名 | 含义 | |----|--------|------| | 0 | 无售后 | 正常订单 | | 1 | 申请中 | 用户申请退款,等商家处理 | | 2 | 退款中 | 商家同意,退款正在处理 | | 3 | 已退款 | 退款完成 | | 4 | 退款拒绝 | 商家拒绝退款 | | 5 | 客服介入 | 客服正在处理 | | 6 | 售后完成 | 售后流程结束 | > **本次不实现售后/退款流程**。afterSaleStatus 字段已预留,但退款相关操作(申请退款、同意退款、拒绝退款、客服介入等)暂未开发。 --- ## 三、状态流转场景 ### 3.1 外送 — 在线支付 ``` 用户下单 → 用户付款 → 商家接单 → 商家出餐 → 骑手接单 → 骑手取餐 → 骑手送达 state: 0 0 1 2 2 2 3 pay: 0 → 1 1 1 1 1 1 delivery: null null null 0 1 2 3 ``` | 步骤 | 操作者 | 操作 | state | payStatus | deliveryStatus | |------|--------|------|-------|-----------|----------------| | 1 | 系统 | 创建订单 | 0 | 0 | null | | 2 | 用户 | 在线支付 | 0 | **0→1** | null | | 3 | 商家 | 接单 | **0→1** | 1 | null | | 4 | 商家 | 出餐 | **1→2** | 1 | **0** | | 5 | 骑手 | 接单 | 2 | 1 | **0→1** | | 6 | 骑手 | 取餐出发 | 2 | 1 | **1→2** | | 7 | 骑手 | 送达 | **2→3** | 1 | **2→3** | ### 3.2 外送 — 到付 ``` 与在线支付基本相同,唯一区别:下单时 payStatus 直接设为 1(已支付) ``` | 步骤 | 操作者 | 操作 | state | payStatus | deliveryStatus | |------|--------|------|-------|-----------|----------------| | 1 | 系统 | 创建订单 | 0 | **1**(直接已支付) | null | | 2 | 商家 | 接单 | **0→1** | 1 | null | | 3 | 商家 | 出餐 | **1→2** | 1 | **0** | | 4 | 骑手 | 接单→取餐→送达 | 2→2→3 | 1 | 0→1→2→3 | ### 3.3 自取 — 现金 ``` 用户下单 → 商家接单 → 商家出餐 → 商家收款+完成(或用户确认取餐) state: 0 1 2 3 pay: 0 0 0 1(商家收款时设为1) delivery: 无 无 无 无 ``` | 步骤 | 操作者 | 操作 | state | payStatus | |------|--------|------|-------|-----------| | 1 | 系统 | 创建订单 | 0 | 0 | | 2 | 商家 | 接单 | **0→1** | 0 | | 3 | 商家 | 出餐 | **1→2** | 0 | | 4a | 商家 | 完成(收款+完成) | **2→3** | **0→1** | | 4b | 用户 | 确认取餐(仅已支付时可用) | **2→3** | 1(不变) | > **重要规则**:用户"确认取餐"仅对已支付(payStatus=1)的自取订单有效。现金订单(payStatus=0)的用户无法自己确认取餐,只能等商家点"完成"。 ### 3.4 堂食 — 现金 与自取流程完全一致,只是 type=2。 --- ## 四、取消订单场景 ### 4.1 用户取消 | 条件 | state | 结果 | |------|-------|------| | 商家未接单 | state=0 | state→4(已取消) | | 商家已接单 | state=1 或更高 | **不允许取消**(需走退款流程) | **测试步骤:** 1. 用户下单(state=0) 2. 用户点击"取消订单" 3. 预期:订单变为"已取消"(state=4) ### 4.2 商家取消 | 条件 | state | 结果 | |------|-------|------| | 待处理或已接单 | state=0 或 1 | state→4(已取消) | | 已出餐或之后 | state=2 或更高 | **不允许取消** | ### 4.3 系统自动取消 | 场景 | 条件 | 结果 | |------|------|------| | 超时未接单 | 商家在规定时间内未接单 | state→4 | | 超时未完成 | 商家出餐后长时间未完成 | state→3(自动完成) | --- ## 五、各端订单列表测试 ### 5.1 用户端 接口:`GET /system/userOrder/orderList` | Tab 名称 | tab 参数 | 应出现的订单 | 不应出现的订单 | |----------|---------|-------------|---------------| | 待付款 | `unpaid` | 外送未支付订单(payStatus=0, type=0) | 自取/堂食的未支付订单、已支付的外送订单 | | 进行中 | `active` | 所有正在进行的订单 | 已完成、已取消、有售后的订单 | | 已完成 | `completed` | state=3 的订单 | 其他状态的订单 | | 已取消 | `cancelled` | state=4 且无售后的订单 | 有售后的已取消订单 | | 退款/售后 | `refund` | afterSaleStatus>0 的订单 | 正常订单 | **重点测试用例:** | # | 场景 | 预期结果 | |---|------|---------| | 1 | 自取订单(type=1)刚创建,payStatus=0 | 应出现在"进行中"Tab,**不应**出现在"待付款"Tab | | 2 | 堂食订单(type=2)刚创建,payStatus=0 | 同上,出现在"进行中",不在"待付款" | | 3 | 外送订单(type=0)未支付 | 应出现在"待付款"Tab | | 4 | 外送到付订单刚创建,payStatus=1 | 应出现在"进行中"Tab | | 5 | 传入 type=1 筛选 | 只显示自取订单 | | 6 | 不传 type | 显示所有类型的订单 | ### 5.2 商家端 接口:`GET /system/orderShOprate/orderList` | Tab 名称 | tab 参数 | 应出现的订单 | |----------|---------|-------------| | 待受理 | `pending` | state=0 且(已支付 OR 自取/堂食) | | 待出餐 | `preparing` | state=1 | | 已出餐 | `ready` | state=2 且无售后 | | 已完成 | `completed` | state=3 且无售后 | | 已取消 | `cancelled` | state=4 且无售后 | | 退款/售后 | `refund` | 有售后记录的订单 | **重点测试用例:** | # | 场景 | 预期结果 | |---|------|---------| | 1 | 外送未支付订单(state=0, payStatus=0) | **不应**出现在"待受理"(用户还没付款) | | 2 | 自取订单刚创建(state=0, payStatus=0) | **应**出现在"待受理"(现金线下收) | | 3 | 外送到付订单(state=0, payStatus=1) | 应出现在"待受理" | | 4 | 外送在线支付成功(state=0, payStatus=1) | 应出现在"待受理" | | 5 | 商家接单后 | 订单从"待受理"移到"待出餐" | | 6 | 商家出餐后 | 订单从"待出餐"移到"已出餐" | ### 5.3 骑手端 接口:`GET /system/orderQsOprate/orderList` | Tab 名称 | tab 参数 | 应出现的订单 | |----------|---------|-------------| | 新任务 | `newTask` | 外送订单(type=0)、已出餐(state=2)、等待骑手(deliveryStatus=0)、无售后 | | 待取货 | `toPickup` | 当前骑手已接单(deliveryStatus=1)、无售后 | | 配送中 | `delivering` | 当前骑手正在配送(deliveryStatus=2)、无售后 | | 已完成 | `completed` | 当前骑手已完成的订单 | | 已取消 | `cancelled` | 当前骑手关联的已取消订单 | | 退款/售后 | `refund` | 当前骑手关联的有售后的订单 | **重点测试用例:** | # | 场景 | 预期结果 | |---|------|---------| | 1 | 商家还没出餐(state=1)的外送订单 | **不应**出现在"新任务"Tab | | 2 | 自取订单(type=1) | **不应**出现在骑手端任何Tab | | 3 | 新任务列表排序 | 按距离从近到远排列(需要传入经纬度参数) | | 4 | 其他骑手已接单的订单 | **不应**出现在当前骑手的"新任务"中 | --- ## 六、用户端操作测试 ### 6.1 确认取餐 接口:`POST /system/userOrder/confirmPickup` | # | 前置条件 | 操作 | 预期结果 | |---|---------|------|---------| | 1 | 自取订单、已出餐(state=2)、已支付(payStatus=1) | 点击确认取餐 | 成功,state→3 | | 2 | 自取订单、已出餐(state=2)、未支付(payStatus=0) | 点击确认取餐 | 失败,提示"订单未支付" | | 3 | 外送订单(type=0) | 点击确认取餐 | 失败,提示"仅自取订单可确认取餐" | | 4 | 堂食订单(type=2) | 点击确认取餐 | 失败,提示"仅自取订单可确认取餐" | | 5 | 自取订单、待处理(state=0) | 点击确认取餐 | 失败,提示"当前订单状态不可确认取餐" | | 6 | 自取订单、已接单(state=1) | 点击确认取餐 | 失败,提示"当前订单状态不可确认取餐" | | 7 | 自取订单、已完成(state=3) | 点击确认取餐 | 失败,提示"当前订单状态不可确认取餐" | | 8 | 别人的订单 | 点击确认取餐 | 失败,提示"订单不存在" | ### 6.2 取消订单 接口:`POST /system/userOrder/cancelOrder` | # | 前置条件 | 操作 | 预期结果 | |---|---------|------|---------| | 1 | 任何类型、待处理(state=0) | 点击取消订单 | 成功,state→4 | | 2 | 任何类型、已接单(state=1) | 点击取消订单 | 失败,提示"仅待处理状态的订单可取消" | | 3 | 任何类型、已出餐(state=2) | 点击取消订单 | 失败,同上 | | 4 | 别人的订单 | 点击取消订单 | 失败,提示"订单不存在" | | 5 | 自取订单(state=0) | 点击取消 | 成功 | | 6 | 堂食订单(state=0) | 点击取消 | 成功 | | 7 | 外送订单(state=0) | 点击取消 | 成功 | --- ## 七、商家端操作测试 | 操作 | 接口 | 前置条件 | 预期结果 | |------|------|---------|---------| | 接单 | `POST /system/orderShOprate/acceptOrder` | state=0 | state→1 | | 出餐 | `GET /system/orderShOprate/dispatchOrder` | state=1 | state→2;外送额外设 deliveryStatus=0 | | 完成(自取/堂食) | `POST /system/orderShOprate/completeOrder` | type=1或2,state=2 | state→3,payStatus→1 | | 取消 | `POST /system/orderShOprate/cancelOrder` | state=0或1 | state→4 | **重点测试用例:** | # | 场景 | 预期结果 | |---|------|---------| | 1 | 商家对外送订单出餐 | state→2,**同时 deliveryStatus=0**(等待骑手) | | 2 | 商家对自取订单出餐 | state→2,deliveryStatus 保持 null | | 3 | 商家对自取订单点"完成" | state→3,payStatus→1(收款+完成一步到位) | | 4 | 商家对外送订单点"完成" | **不允许**(外送订单由骑手完成) | | 5 | 商家对已出餐(state=2)的订单接单 | **不允许**(只能对 state=0 的订单接单) | --- ## 八、骑手端操作测试 | 操作 | 接口 | 前置条件 | 预期结果 | |------|------|---------|---------| | 接单 | `POST /system/orderQsOprate/acceptOrder` | type=0, deliveryStatus=0, afterSaleStatus=0 | deliveryStatus→1,绑定骑手ID | | 取餐出发 | `POST /system/orderQsOprate/pickupOrder` | deliveryStatus=1, afterSaleStatus=0 | deliveryStatus→2 | | 送达 | `POST /system/orderQsOprate/deliverOrder` | deliveryStatus=2 | deliveryStatus→3,**state→3** | **重点测试用例:** | # | 场景 | 预期结果 | |---|------|---------| | 1 | 骑手对自取订单(type=1)接单 | **不允许**(只有外送订单需要骑手) | | 2 | 骑手对已有人接的订单接单 | **不允许**(防止重复接单) | | 3 | 骑手送达后 | state=3, deliveryStatus=3,订单在骑手端移到"已完成"Tab | | 4 | 骑手接单时有活跃退款(afterSaleStatus>0) | 允许操作但需提示 | --- ## 九、用户看到的文字 用户端页面不直接显示 state 数字,而是根据状态组合显示中文文字。 ### 9.1 外送订单 (type=0) 用户看到的 | 用户看到 | 对应的订单状态 | |---------|--------------| | 待支付 | 还没付款(payStatus=0) | | 商家已接单 | 已付款,等商家处理(state=0或1) | | 配送中 | 商家出餐,骑手在送(state=2, deliveryStatus=0/1/2) | | 已送达 | 骑手送到(state=2, deliveryStatus=3) | | 已完成 | 订单结束(state=3) | | 已取消 | 订单取消(state=4) | | 退款中/已退款 | 有退款处理(afterSaleStatus>0) | ### 9.2 自取订单 (type=1) 用户看到的 | 用户看到 | 对应的订单状态 | |---------|--------------| | 待支付 | 还没付款(payStatus=0) | | 商家已接单 | 等商家处理(state=0或1) | | 待取餐 | 商家出餐了,等用户去取(state=2) | | 已完成 | 订单结束(state=3) | | 已取消 | 订单取消(state=4) | ### 9.3 堂食订单 (type=2) 用户看到的 | 用户看到 | 对应的订单状态 | |---------|--------------| | 待支付 | 还没付款(payStatus=0) | | 商家已接单 | 等商家处理(state=0或1) | | 备餐完成 | 商家出餐了(state=2) | | 已完成 | 订单结束(state=3) | | 已取消 | 订单取消(state=4) | ### 9.4 商家端订单卡片显示 **外送订单:** | 条件 | 显示 | 颜色建议 | |------|------|---------| | state=0, payStatus=0 | 待支付 | 灰色 | | state=0, payStatus=1 | 待接单 | 橙色 | | state=1 | 制作中 | 蓝色 | | state=2, deliveryStatus=0/1 | 待骑手取餐 | 蓝色 | | state=2, deliveryStatus=2 | 配送中 | 蓝色 | | state=2, deliveryStatus=3 | 已送达 | 绿色 | | state=3 | 已完成 | 灰色 | | state=4 | 已取消 | 红色 | **自取/堂食订单:** | 条件 | 显示 | 颜色建议 | |------|------|---------| | state=0 | 待接单 | 橙色 | | state=1 | 制作中 | 蓝色 | | state=2 | 备餐完成 | 橙色 | | state=3 | 已完成 | 灰色 | | state=4 | 已取消 | 红色 | **售后状态覆盖规则**:当 afterSaleStatus>0 时,不管上面的规则,统一显示售后状态文字(退款申请中/退款中/已退款/退款已拒绝),优先级最高。 --- ## 十、边界场景和注意事项 | # | 场景 | 说明 | |---|------|------| | 1 | 已取消的订单应出现在哪个Tab | 三个端都有独立的"已取消"Tab 承接 | | 2 | 自取/堂食订单的 deliveryStatus | 始终为 null,不应出现在骑手端 | | 3 | 外送订单商家出餐后 | deliveryStatus 应自动设为 0(等待骑手),不是 null | | 4 | 现金自取订单的支付 | 下单时 payStatus=0,只有商家点"完成"时才变为 1 | | 5 | 到付外送订单的支付 | 下单时 payStatus=1(直接确认支付方式) | | 6 | 用户确认取餐前提 | 必须是自取(type=1) + 已支付(payStatus=1) + 已出餐(state=2) | | 7 | 退款流程 | **本次不实现**,afterSaleStatus 字段已预留但无操作入口 | | 8 | 旧接口 | 旧的订单列表接口保留不删,但不再维护,前端应切换到新接口 | | 9 | 平台管理端 | 订单列表页需从单状态下拉改为四个独立下拉筛选(state/payStatus/deliveryStatus/afterSaleStatus) | | 10 | 定时任务 | 商家出餐后超时未完成的订单,系统自动设为已完成(state=3) | --- ## 十一、实现状态总览 | 功能 | 状态 | 说明 | |------|------|------| | 订单创建(四字段初始化) | ✅ 已实现 | UserOrderController.createOrder | | 用户端订单列表 | ✅ 已实现 | UserOrderController.orderList | | 商家端订单列表 | ✅ 已实现 | PosOrderShOprateController.orderList | | 骑手端订单列表 | ✅ 已实现 | PosOrderQsOprateController.orderList | | 用户确认取餐 | ✅ 已实现 | UserOrderController.confirmPickup | | 用户取消订单(新) | ✅ 已实现 | UserOrderController.cancelOrder | | 用户取消订单(旧) | ⚠️ 已废弃 | OrderAppealController.userCancelpOrder 已注释 | | 商家接单/出餐/完成/取消 | ✅ 已实现 | PosOrderShOprateController | | 骑手接单/取餐/送达 | ✅ 已实现 | PosOrderQsOprateController | | 支付回调更新 payStatus | ✅ 已实现 | PayController | | 定时任务自动完成 | 待确认 | TestTask.java | | 用户申请退款 | ❌ 未实现 | 留待接入在线支付后开发 | | 商家同意/拒绝退款 | ❌ 未实现 | 留待接入在线支付后开发 | | 客服介入 | ❌ 未实现 | 留待接入在线支付后开发 | | 平台管理端四字段筛选 | ❌ 未实现 | foodie-admin-vue 待改造 |