# 订单内部流程 ProcessStatus V2 重构（Cola 状态机 + 清单确认 + 申请开票）

**日期**: 2026-04-23
**PR**: #1318 (dev)
**Issue**: #1310
**类型**: refactor
**服务**: hl-order-service-v2

---

## 摘要

订单内部流程状态 `ProcessStatus` 彻底重构：线性 switch → Cola 状态机；新增"清单确认"节点统一改尾款；新增"申请开票"C 端入口；房差/车差自动写入优惠/增项。

## 新流程

```
PENDING_TRAVELER_INFO → PENDING_ROOM_CONFIG → PENDING_VEHICLE_CONFIG
  → PENDING_CHECKLIST_CONFIRM → READY → PENDING_INVOICE
```

## 枚举值变化（字典 order_process_status）

### 删除（老值软删）
- PENDING_INFO / PENDING_ROOM / PENDING_VEHICLE / PENDING_FINANCE
- PENDING_INSURANCE / PENDING_CONTRACT / INTERNAL_CONFIRMED

### 新增（6 个）
| value | label | 业务含义 |
|-------|-------|---------|
| `PENDING_TRAVELER_INFO` | 待补全出行人信息 | 支付订金/全款后初始态 |
| `PENDING_ROOM_CONFIG` | 配置房子 | 出行人齐全后 |
| `PENDING_VEHICLE_CONFIG` | 配置车辆 | 房型分配后 |
| `PENDING_CHECKLIST_CONFIRM` | 确认清单 | 车辆分配后,确认前 |
| `READY` | 已就绪 | 清单确认通过,保险/合同异步触发 |
| `PENDING_INVOICE` | 待开票 | 尾款付清后用户主动申请开票 |

## 接口变化（管理端 + C 端）

### 新增接口

#### 1. `POST /admin/order/{orderId}/checklist-confirm`
**管理员确认清单**（把所有未确认优惠/增项批量锁定 → 推进到 READY → 触发保险/合同自动化）
- **权限**: Admin
- **幂等**: `@Idempotent(60s)` · key = `orderId + operatorId`
- **校验**:
  - `processStatus == PENDING_CHECKLIST_CONFIRM`
  - 尾款计算 `totalPrice - SUM(confirmedDiscount) + SUM(confirmedSurcharge) - paidAmount >= 0`（含即将 confirmed=true 的条目）
  - `checklist_confirmed != true`（幂等双保险）
- **响应**: `Result<Void>`
- **失败**: `确认后尾款为负(¥-xxx),请调整优惠/增项` / `流程状态不正确` / `清单已确认`

#### 2. `POST /mp/orders/{orderId}/checklist/confirm`
**用户端确认清单**（架构预留,本次 PR 未上线 MP Controller,待下个 PR）

### 修改接口

#### 3. `POST /mp/invoices/apply`（既有 `OrderInvoiceService.applyInvoice` 升级）
**申请开票**
- **幂等**: `@Idempotent(300s)` · key = `userId + orderId`
- **新增 Guard**:
  - `processStatus == READY`
  - OrderStatus NOT IN `{CANCELLED, REFUNDED, REFUNDING}`
  - `paidAmount >= totalPrice`（原只检查 `paidAmount > 0`）
- **保留**: 原 countValidByOrderId 判重兜底
- **失败**:
  - `流程状态不允许开票,请先完成确认清单`
  - `订单已取消或退款,无法开票`
  - `尾款未结清,无法开票`

### VO 字段变化

#### `OrderDiscountVO` / `OrderSurchargeVO`（新增 3 字段）
```json
{
  "confirmed": true,        // false=未确认不影响尾款,true=已确认
  "sourceType": "ROOM_ASSIGN",  // MANUAL / ROOM_ASSIGN / VEHICLE_ASSIGN
  "sourceRefId": 12345      // 来源主键(如 hotel_assignment_id)
}
```

#### `OrderVO` / `OrderDetailVO`
- `待确认差价`（`pendingUpgradeAmount`）字段过渡期保留,返回值恒为 0（T+2 周清理 PR 硬删）
- `processStatus` / `processStatusLabel` 返回新 6 个枚举值(字典自动下发 label)

## 保险/合同触发时机变化（⚠️ 重要）

- **旧**: 订单 CONFIRMED 时立即自动投保/签约（`OrderConfirmedEvent`）
- **新**: **清单确认时**触发（`ChecklistConfirmedEvent`）→ 避免出行人/房型未定就投保导致的退保重投
- 失败处理: 业务失败 → 创建 `OrderTodo` 人工补救；5xx/超时 → LocalEvent 兜底
- ProcessStatus 保持 READY 不变（即使保险或合同失败）

## 追加优惠/增项自动 REOPEN

- 订单 `process_status ∈ {READY, PENDING_INVOICE}` + `checklist_confirmed = true` 时
- 调用 `addDiscount` / `addSurcharge` 会自动触发 `PROC_CHECKLIST_REOPENED`
- 订单回退到 `PENDING_CHECKLIST_CONFIRM`,`checklist_confirmed=false`
- **已完成的保险/合同不反向取消**（业务硬规则）
- 新追加的条目 `confirmed=false`,需要再次"确认清单"

## 前端影响（前端 AI 必读）

1. 订单详情页的 `待确认差价` 字段**过渡期保留值为 0**,**不要**继续读此字段做展示；改读 `discounts[]` / `surcharges[]` 数组 + 按 `confirmed` 字段分组展示
2. 流程状态标签 6 个新中文（字典自动下发）
3. Admin 端**新增"确认清单"按钮**,调 `POST /admin/order/{orderId}/checklist-confirm`
4. Admin 端 `addDiscount` / `addSurcharge` 在订单已 READY/PENDING_INVOICE 时会**自动 REOPEN**,前端需要刷新订单状态
5. C 端新增"申请开票"入口,调 `POST /mp/invoices/apply`(需订单 processStatus = READY + 尾款已付清)

## 文档

- 需求单 V2: `docs/tasks/order-process-v2-statemachine-20260423.md`
- 架构详设: `docs/tasks/order-process-v2-arch-design-20260423.md`
- 评审报告: `docs/tasks/order-process-v2-review-v2-20260423.md`
- CR 报告: `docs/tasks/order-process-v2-cr-20260423.md`
