---
schema: "hl-changelog/v2"
ticket: "5456"
title: "派单创建 holdMode 双流 500 修复与失败重试幂等释放"
consumer: "admin"
author: "wx(GIT)"
change_type: "修改接口"
backend_status: "deployed"
gateway_status: "verified"
frontend_status: "not_required"
frontend_owner: ""
frontend_ref: ""
target_release: ""
verified_at: ""
status_note: ""
updated_at: "2026-08-04"
base: "dev-v3"
---

# 车务派单创建: holdMode=0/1 创建 500 修复 + 失败后同 requestId 可重试

> **存放目录**: `changelogs-v2/2026-08/`
> **服务**: hl-fleet-service
> **PR**: #5467
> **Issue**: #5456 / #5461 / #5451
> **日期**: 2026-08-04
> **影响范围**: 管理后台「派单弹窗」创建派单（直接派定 holdMode=0 / 排车锁定 holdMode=1）

---

## ⚠️ 关键变化

前一版（#5444 Step2 机制合并后）`POST /admin/fleet/assignments` 对任意 unassigned 订单创建派单必返 500：
- holdMode=0（直接派定）：`code=500 服务器内部错误[IllegalStateException]: DAILY_V3 snapshot invalid: daily rows do not cover declared topology`
- holdMode=1（排车锁定）：`code=500 服务器内部错误[IllegalStateException]: 派车组身份不完整或已失效，拒绝签发行程单 token`

本次修复后两者均正常返回 200；同时修复业务校验失败（如 `605036 司机与车辆不是常驻组合`）后同 requestId 立即重试被 `100502 派单创建处理中，请勿重复提交` 卡死的问题——失败后幂等键释放，同 requestId 可立即重试。

## 变更接口

| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|------|------|------|----------|------|
| 1 | 创建派单 | POST | `/admin/fleet/assignments` | 行为修复 | holdMode=0/1 创建不再 500；业务失败后同 requestId 可立即重试 |

接口请求/响应字段无任何变化，仅行为修复。

## 二、接口契约变化

### POST /admin/fleet/assignments（创建派单）

**使用场景**：车务在派单弹窗选定车辆/司机后创建派单。`holdMode=1` → 落 holding 并发 HOLD 通知；`holdMode=0` → 落 assigned 直接派定。

**入参**（无变化）：`orderId / requirementId / vehicleId / driverId / startDate / endDate / holdMode(0|1) / headcount / requestId / confirmCrossResident / messageTemplateId / customBody / pickupAt / dropoffAt`。

**出参**（无变化）：成功返回 `assignmentStatus=holding|assigned` 的派单写结果。

**行为变化**：

| 场景 | 原来 → 现在 |
|------|-------------|
| holdMode=0 对 unassigned 订单创建 | 500 内部错误（DAILY_V3 快照拓扑校验失败，事务回滚）→ 200 创建成功返回 assigned |
| holdMode=1 对 Step2 建槽订单创建 | 500 内部错误（HOLD 通知签发行程单短链时组行未冻结）→ 200 创建成功返回 holding，HOLD 通知正常生成 |
| 业务校验失败（如 605036 非跨常驻未确认）后同 requestId 重试 | 100502 派单创建处理中，请勿重复提交（幂等键残留至 TTL 300s）→ 幂等键释放，同 requestId 可立即重试并得到与首次一致的结果 |
| HOLD 通知短信中的行程链接 | 失败无法发送 → 短信正常发送，行程链接占位文案「行程确认后发送」，司机最终确认（assigned）后行程短信携带真实链接 |

**错误码**（无变化）：`605001/605003/605005/605006/605008/605013/605014/605036/605041/100502`。

## 三、典型示例

### 成功（holdMode=0 直接派定）

请求：

```http
POST /admin/fleet/assignments
Authorization: Bearer <token>
Content-Type: application/json

{
  "orderId": "2084276690049007618",
  "requirementId": "2084276690049007619",
  "vehicleId": "2079857985848320002",
  "driverId": "2065272150012444674",
  "startDate": "2026-08-03",
  "endDate": "2026-08-05",
  "holdMode": 0,
  "headcount": 2,
  "confirmCrossResident": true,
  "requestId": "qa-5456-direct-001"
}
```

响应（200）：

```json
{
  "code": 200,
  "message": "成功",
  "data": {
    "assignmentStatus": "assigned",
    "confirmedAt": "2026-08-04T12:00:00"
  }
}
```

### 业务失败后同 requestId 重试

第一次请求（不传 confirmCrossResident，非跨常驻组合）→ `605036 司机与车辆不是常驻组合，请确认跨常驻车派单后重试`；补 `confirmCrossResident: true` 后**同 requestId** 立即重试 → 正常进入业务处理（不再 100502）。

## 四、前端需要做什么

无需修改。前端如遇 100502 且确认首次请求已失败，可直接同 requestId 重试；HOLD 通知短信内行程链接在司机确认前为占位文案。

## 验证证据

- hl-common/hl-starter-protection verify 31 例全过；hl-fleet-service verify 3060 例（2 个基线环境失败与本改动无关）
- 回归测试：IdempotentAspect 失败释放/成功保留；HOLD 快照降级短链；DIRECT 快照事件发布前冻结断言
- TEST 部署与网关验证见工单 #5456/#5461/#5451

## 关联 / 联系人

### 链接

- **Issue**: [#5456](https://git.1814.love:8443/wx/HL/issues/5456) / [#5461](https://git.1814.love:8443/wx/HL/issues/5461) / [#5451](https://git.1814.love:8443/wx/HL/issues/5451)
- **PR**: [#5467](https://git.1814.love:8443/wx/HL/pulls/5467)
- **Merge commit**: [ad3f3684c602](https://git.1814.love:8443/wx/HL/commit/ad3f3684c602)

### 联系人

- **后端负责人**: @wx
