# Tasks: 订单状态四字段分离

**Input**: Design documents from `/specs/test/`
**Prerequisites**: plan.md, spec.md, research.md, data-model.md, contracts/

**Tests**: 无自动化测试要求，通过手动接口测试验证。

**Organization**: 按功能模块（用户故事）分组，每个阶段可独立验证。

## Format: `[ID] [P?] [Story] Description`

- **[P]**: 可并行（不同文件，无依赖）
- **[Story]**: 所属用户故事（US1-US9）
- 包含具体文件路径

## Path Conventions

- 后端源码: `ruoyi-system/src/main/java/com/ruoyi/system/`、`ruoyi-admin/src/main/java/com/ruoyi/app/order/`
- MyBatis XML: `ruoyi-system/src/main/resources/mapper/system/`
- SQL: `updatesql/sql.md`
- 前端: `E:\QtwCode\foodie\foodie-admin-vue\src\`

---

## Phase 1: Setup（数据库 & 实体层）

**Purpose**: 添加新字段到数据库和实体类，是所有后续任务的基础。

- [x] T001 在 `updatesql/sql.md` 末尾追加 ALTER TABLE 语句：添加 `delivery_status`（BIGINT DEFAULT NULL）、`pay_status`（BIGINT DEFAULT 0）、`after_sale_status`（BIGINT DEFAULT 0）三列到 pos_order 表
- [x] T002 [P] 在 `ruoyi-system/src/main/java/com/ruoyi/system/domain/PosOrder.java` 新增三个字段：`deliveryStatus`(Long)、`payStatus`(Long)、`afterSaleStatus`(Long)，添加对应 getter/setter
- [x] T003 在 `ruoyi-system/src/main/resources/mapper/system/PosOrderMapper.xml` 的 resultMap 中添加三个字段映射（delivery_status→deliveryStatus, pay_status→payStatus, after_sale_status→afterSaleStatus）
- [x] T004 在 `ruoyi-system/src/main/resources/mapper/system/PosOrderMapper.xml` 的 insertPosOrder 语句中添加三个新字段
- [x] T005 在 `ruoyi-system/src/main/resources/mapper/system/PosOrderMapper.xml` 的 updatePosOrder 语句中添加三个新字段

**Checkpoint**: 数据库 ALTER TABLE 执行完毕，PosOrder 实体和 Mapper 包含新字段，项目编译通过

---

## Phase 2: Foundational（订单创建 & 支付回调）

**Purpose**: 确保新订单创建时正确初始化四字段，支付回调正确更新 payStatus。

- [x] T006 改造 `ruoyi-admin/src/main/java/com/ruoyi/app/order/UserOrderController.java` 的 `createOrder()` 方法：创建订单时设置 state=0、afterSaleStatus=0、deliveryStatus=NULL；根据类型和支付方式设置 payStatus（外送到付→1，其他→0）
- [x] T007 [P] 找到支付回调处理代码（搜索 payUrl 或支付回调相关类），在支付成功后添加 `payStatus` 从 0 改为 1 的逻辑

**Checkpoint**: 创建外送/自取/堂食订单后，数据库中四个新字段值正确初始化。模拟支付回调后 payStatus 正确更新为 1。

---

## Phase 3: User Story 1 — 商家操作改造（接单/出餐/完成）

**Goal**: 商家可以对新状态体系的订单执行接单、出餐、完成操作。

**Independent Test**: 创建订单→商家接单(state=1)→商家出餐(state=2, 外送deliveryStatus=0)→自取/堂食完成(state=3, payStatus=1)

### Implementation for User Story 1

- [x] T008 改造 `ruoyi-admin/src/main/java/com/ruoyi/app/order/PosOrderShOprateController.java` 的接单方法：将 state 从 0 改为 1（替换旧逻辑）
- [x] T009 改造 `ruoyi-admin/src/main/java/com/ruoyi/app/order/PosOrderShOprateController.java` 的 `dispatchOrder()` 出餐方法：将 state 从 1 改为 2；外送订单(type=0)额外设置 deliveryStatus=0；自取/堂食只改 state=2
- [x] T010 新增完成方法：在 `ruoyi-admin/src/main/java/com/ruoyi/app/order/PosOrderShOprateController.java` 中新增"完成"接口，仅限 type=1(自取)或 type=2(堂食)且 state=2 的订单，将 state 改为 3 同时 payStatus 改为 1

**Checkpoint**: 商家端接单→出餐→完成流程走通，state/deliveryStatus/payStatus 值符合预期

---

## Phase 4: User Story 2 — 骑手操作改造

**Goal**: 骑手可以对已出餐的外送订单执行接单、取餐、送达操作。

**Independent Test**: 商家出餐后(deliveryStatus=0)→骑手接单(deliveryStatus=1)→取餐(deliveryStatus=2)→送达(deliveryStatus=3, state=3)

### Implementation for User Story 2

- [x] T011 改造 `ruoyi-admin/src/main/java/com/ruoyi/app/order/PosOrderQsOprateController.java` 的 `acceptOrder()`：校验 type=0 且 afterSaleStatus=0，设置 deliveryStatus=1（替换旧 state 逻辑）
- [x] T012 [P] 改造 `ruoyi-admin/src/main/java/com/ruoyi/app/order/PosOrderQsOprateController.java` 的 `pickupOrder()`：校验 type=0 且 afterSaleStatus=0，设置 deliveryStatus=2（替换旧 state 逻辑）
- [x] T013 改造 `ruoyi-admin/src/main/java/com/ruoyi/app/order/PosOrderQsOprateController.java` 的 `deliverOrder()`：设置 deliveryStatus=3，同时设置 state=3（替换旧 state 逻辑）
- [x] T014 改造骑手约束逻辑：在骑手接单防重复逻辑中，原来查 `state IN (3,4)` 改为查 `deliveryStatus IN (1,2)`；更新 `ruoyi-system/src/main/java/com/ruoyi/system/mapper/RiderPositionMapper.java` 和对应的 XML 排除条件

**Checkpoint**: 骑手端接单→取餐→送达流程走通，deliveryStatus 和 state 值正确流转

---

## Phase 5: User Story 3 — 订单取消

**Goal**: 用户和商家可以在未接单前取消订单，state 设为 4。

**Independent Test**: 创建订单→用户/商家取消→state=4, afterSaleStatus=0

### Implementation for User Story 3

- [x] T015 改造 `ruoyi-admin/src/main/java/com/ruoyi/app/order/OrderAppealController.java` 的 `userCancelpOrder()`：取消订单时设 state=4, afterSaleStatus 保持 0（替换旧 state=10 逻辑）
- [x] T016 [P] 在商家端 `ruoyi-admin/src/main/java/com/ruoyi/app/order/PosOrderShOprateController.java` 新增商家取消订单接口：校验 state IN (0,1)，设 state=4

**Checkpoint**: 用户取消和商家取消都正确设 state=4

---

## Phase 6: User Story 4 — 定时任务改造

**Goal**: 定时任务使用新字段条件执行超时取消和自动完成。

**Independent Test**: 超时未支付订单自动 state=4；超时未完成订单自动 state=3

### Implementation for User Story 4

- [x] T017 改造 `ruoyi-admin/src/main/java/com/ruoyi/app/order/TestTask.java` 的 `testTiming()`（未支付超时取消）：查 payStatus=0 AND state=0 且超时，设 state=4（替换旧 state=0→10 逻辑）
- [x] T018 改造 `ruoyi-admin/src/main/java/com/ruoyi/app/order/TestTask.java` 的 `zidwancheng()`（自动完成兜底）：查 state=2 AND afterSaleStatus=0 且超时，设 state=3（外送同时设 deliveryStatus=3，自取/堂食同时设 payStatus=1）
- [x] T019 改造 `ruoyi-admin/src/main/java/com/ruoyi/app/order/TestTask.java` 中作废逻辑：原来设 state=10 改为设 state=4

**Checkpoint**: 模拟超时场景，确认定时任务正确更新 state 和关联字段

---

## Phase 7: User Story 5 — 新列表接口（三端）

**Goal**: 用户端、商家端、骑手端各有独立的 Tab 分页列表接口。

**Independent Test**: 各端各 Tab 返回正确的订单列表，分页格式 {records, total, page, size}

### Implementation for User Story 5

- [x] T020 在 `ruoyi-admin/src/main/java/com/ruoyi/app/order/UserOrderController.java` 新增 `orderList()` 方法：GET /system/userOrder/orderList，支持 tab（unpaid/active/completed/cancelled/refund）、page、size、type 参数，使用 LambdaQueryWrapper 查询，返回 PosOrder 全字段 + 关联数据（shanghu/store/shaddress/user/food/parentRemarks）
- [x] T021 [P] 在 `ruoyi-admin/src/main/java/com/ruoyi/app/order/PosOrderShOprateController.java` 新增 `orderList()` 方法：GET /system/orderShOprate/orderList，支持 tab（pending/preparing/ready/completed/cancelled/refund）、page、size、mdId、type 参数，使用 LambdaQueryWrapper 查询
- [x] T022 [P] 在 `ruoyi-admin/src/main/java/com/ruoyi/app/order/PosOrderQsOprateController.java` 新增 `orderList()` 方法：GET /system/orderQsOprate/orderList，支持 tab（newTask/toPickup/delivering/completed/cancelled/refund）、page、size、longitude、latitude 参数，newTask Tab 使用 ST_Distance_Sphere 距离排序

**Checkpoint**: 三端列表接口各 Tab 返回正确数据，分页 total 准确，骑手端 newTask 距离排序正确

---

## Phase 8: User Story 6 — 平台管理端前端改造

**Goal**: foodie-admin-vue 订单列表页支持四字段筛选和多 Tag 状态展示。

**Independent Test**: 平台管理端可按 state/payStatus/deliveryStatus/afterSaleStatus 筛选，状态列显示多 Tag 组合

### Implementation for User Story 6

- [x] T023 改造 `E:\QtwCode\foodie\foodie-admin-vue\src\views\system\order\index.vue` 筛选区域：将旧 state 单下拉框替换为四个独立下拉框（state/payStatus/deliveryStatus/afterSaleStatus），选项前端硬编码
- [x] T024 改造 `E:\QtwCode\foodie\foodie-admin-vue\src\views\system\order\index.vue` 状态列：从单个 el-tag 改为主 Tag（state）+ 副 Tag（deliveryStatus/payStatus/afterSaleStatus）组合展示
- [x] T025 改造 `E:\QtwCode\foodie\foodie-admin-vue\src\views\system\order\index.vue` 订单详情弹窗：进度条从 7 步改为 4 步（0-3），新增支付状态/配送状态/售后状态信息行；修改订单弹窗的 state 下拉改为 0-4
- [x] T026 改造后端 `/system/order/list` 接口（PosOrderController）：支持 state/payStatus/deliveryStatus/afterSaleStatus 查询参数，多个条件 AND 关系，deliveryStatus 支持 NULL 筛选

**Checkpoint**: 平台管理端订单列表页筛选、状态展示、详情弹窗均正常工作

---

## Phase 9: Polish & Cross-Cutting

**Purpose**: 推送通知更新和最终验证。

- [x] T027 更新推送通知代码中的 state 值映射：根据 type + state + deliveryStatus + afterSaleStatus 组合发送不同推送内容
- [x] T028 [P] 清理旧代码中的注释：在 PosOrder.java 中为废弃字段（diningStatus、isAccepted）添加 @Deprecated 注解
- [ ] T029 完整流程验证：外送在线支付全流程→外送到付全流程→自取现金全流程→堂食现金全流程→取消订单→定时任务触发

## Phase 10：自取配送费与专属出餐推送（2026-08-24 增量）

- [ ] T030 为三个有效下单入口补充回归测试：自取订单忽略客户端配送费并保存为 `0D`，非自取订单保持原值
- [ ] T031 在用户聚合下单、商家端下单和 `/system/order/addorder` 中统一强制自取订单配送费为 `0D`
- [ ] T032 为自取出餐推送补充文案分流测试，验证专属 key 携带当前 `pickUpNum`，其他订单继续使用通用 key
- [ ] T033 增加五套后端 i18n 自取出餐文案，并接入现有用户 App 推送与 `push_message` 入库链路
- [ ] T034 运行定向测试、`ruoyi-admin` 模块构建并记录未执行的完整回归项
- [x] T035 补充骑手先接单、支付后开放及商家操作门槛的回归测试
- [x] T036 调整用户聚合下单和旧 `/system/order/addorder`，初始化外送配送状态并按到付/在线支付控制开放时机
- [x] T037 调整骑手新任务查询和接单状态机，仅允许已支付且商家未接单的外送订单由骑手接单
- [x] T038 调整商家接单和出餐校验，要求骑手已分配并在出餐时保留配送状态
- [x] T039 接入到付、LINE Pay 和 OMG 支付成功后的可接单骑手推送
- [x] T040 调整骑手接单、商家出餐和订单取消推送，并解除取消订单对骑手可接单资格的占用
- [x] T041 使用 JDK 21 完成验证：定向测试 52/52 通过，`ruoyi-admin` 模块构建通过；完整回归 272 个用例中 269 个通过，3 个原有 `OrderListPaymentFilterTest` 因缺少 `MessageUtils/SpringUtils` 测试上下文报空指针

---

## Dependencies & Execution Order

### Phase Dependencies

- **Phase 1 (Setup)**: 无依赖，立即开始
- **Phase 2 (Foundational)**: 依赖 Phase 1 — BLOCKS 所有后续
- **Phase 3 (商家操作)**: 依赖 Phase 2
- **Phase 4 (骑手操作)**: 依赖 Phase 2
- **Phase 5 (订单取消)**: 依赖 Phase 2
- **Phase 6 (定时任务)**: 依赖 Phase 2
- **Phase 7 (列表接口)**: 依赖 Phase 2（可与 Phase 3-6 并行）
- **Phase 8 (前端改造)**: 依赖 Phase 7（后端接口就绪）
- **Phase 9 (Polish)**: 依赖所有其他 Phase

### User Story Dependencies

- **US1 (商家操作)**: Phase 2 完成后可开始，独立
- **US2 (骑手操作)**: Phase 2 完成后可开始，独立，与 US1 并行
- **US3 (订单取消)**: Phase 2 完成后可开始，独立
- **US4 (定时任务)**: Phase 2 完成后可开始，独立
- **US5 (列表接口)**: Phase 2 完成后可开始，独立，与 US1-US4 并行
- **US6 (前端改造)**: 依赖 US5（后端接口就绪）

### Parallel Opportunities

- Phase 1: T002 可与 T003-T005 并行
- Phase 3-6: T008-T019 中不同 Phase 的任务可并行
- Phase 7: T020、T021、T022 可完全并行（三个不同 Controller）

---

## Parallel Example: Phase 7（列表接口三端并行）

```bash
# 三个列表接口互不依赖，可同时开发：
Task T020: "用户端 UserOrderController.orderList()"
Task T021: "商家端 PosOrderShOprateController.orderList()"
Task T022: "骑手端 PosOrderQsOprateController.orderList()"
```

---

## Implementation Strategy

### MVP First (Phase 1-3 + Phase 7 用户端)

1. Phase 1: 数据库 & 实体层
2. Phase 2: 订单创建改造
3. Phase 3: 商家操作改造
4. Phase 7: 用户端列表接口
5. **STOP and VALIDATE**: 商家可以接单→出餐→完成，用户可以查看订单列表

### Full Delivery

1. Phase 1-2 → 基础就绪
2. + Phase 3 → 商家端可用
3. + Phase 4 → 骑手端可用
4. + Phase 5 → 取消功能可用
5. + Phase 6 → 定时任务就绪
6. + Phase 7 → 三端列表就绪
7. + Phase 8 → 平台管理端就绪
8. + Phase 9 → 完整验证通过

---

## Notes

- [P] 任务 = 不同文件，无依赖，可并行
- 每个任务完成后确认编译通过
- Phase 1 完成后需手动执行 SQL（updatesql/sql.md）
- 前端文件编辑需用 Python 脚本处理 CRLF 换行符问题
- 旧方法（PosOrderController 中旧列表查询）保留不删
