docs(v3-order): 按代码事实修订 §1/§2 changelog(fix issue #1 + 补充 5 项)

回复 hl-api-changelog#1 前端反馈的 5 处契约不明 / 冲突,并同步补足 4 处文档与代码不一致:

§1 订单核心模块(15 处修改):
- §3.1/§3.2/§3.3/§3.14 示例值:orderStatus/flowStatus 全部从中文标签改为英文枚举值
  (后端 OrderInfo.orderStatus/flowStatus 直接透传 DB 列的英文枚举字符串)
- §3.3 OrderMainVO 字段表:
  * customerName/customerPhone (admin 明文) → customerName + customerPhoneMasked(admin 也脱敏)
  * exceptionBadges/progressStepper 标注「运行时暂返 null,OrderInfoConverter 派生逻辑待 Issue 接通」
  * 新增 6 个 Tab 状态徽标字段(contractStatus/insuranceStatus/refundStatus/hasRefund/hasServiceStandard/hasFinanceDetail)
  * subStatus 枚举补 NOT_APPLICABLE + 列示 ASSIGN_PARALLEL 子项结构
  * 主聚合示例 transportPlanIds 改用真实雪花 ID(19 位)String
- §3.11 取消预览业务边界:粗状态集改英文枚举 + 说明 v3 已删「已确认」
- §3.14 transition:eventCode 入参表内联 9 个值,便于前端跳读
- §6.2 orderStatus:全表替换为 10 个英文枚举(PENDING_PAY/PENDING_COMPLETE/CUSTOMIZING/PENDING_DEPARTURE/PENDING_BALANCE/TRAVELLING/REVIEWING/SETTLED/REFUNDING/CANCELLED)
- §6.3 flowStatus:全表替换为 13 个英文枚举(AWAITING_DEPOSIT/.../CANCELLED_BEFORE_PAY)
- §6.4 consultantSource:补 SHARED + ROUND_ROBIN,说明 user-service 透传规则
- §6.17 加后端 enum 路径备注

§2 traveler 模块(9 处修改):
- §3.1 出行人列表:每条 17 字段 → 16 字段(off-by-one 笔误)
- §3.1/§3.3 curl 示例:路径 /travelers → /traveler/list 和 /traveler/add(对齐字段表与代码 @PostMapping)
- §3.1 transportPlanIds:补全局 Long→String 序列化规则脚注 + 示例值改真实雪花 ID
- §3.4 错误码段位让位:581119 → 581106(已签合同禁删),581120 → 581107(最后成人禁删)
  (DB 段位 581119/581120 已分别被 TRAVELER_ID_CARD_DUPLICATE / TRANSPORT_PLAN_NOT_FOUND 占用)
- §3.9 smart-parse 错误码段位让位:581120/581121/581122/581123 → 581131/581132/100501/581134
  (581122 限流走 HL 全局 CommonErrorCode.RATE_LIMITED)
- §12 注意事项同步删人错误码

关联:
- Issue: #1
- 验证代码 commit: HL@dev-v3 47d24228
- 验证报告: HL/.claude/tmp-changelog/issue1-analysis.md(仅本地)
这个提交包含在:
yaosutu 2026-05-19 10:28:11 +08:00
父节点 fa843a7ba8
当前提交 89a1938cb9
共有 2 个文件被更改,包括 91 次插入69 次删除

查看文件

@ -86,8 +86,8 @@
| `id` | String | 订单主键 |
| `orderNo` | String | 订单号,格式 `HL{yyyyMMddHHmmss}{3 位序号}` |
| `displayOrderNo` | String | 展示订单号 = `orderNo + teamNo``teamNo` 为空时等同 `orderNo` |
| `orderStatus` | String | 创单后固定 `待支付`(枚举见 §6.2 |
| `flowStatus` | String | 创单后固定 `待支付订金`(枚举见 §6.3 |
| `orderStatus` | String | 创单后固定 `PENDING_PAY`(枚举见 §6.2 |
| `flowStatus` | String | 创单后固定 `AWAITING_DEPOSIT`(枚举见 §6.3 |
| `consultantId` | String | 实际绑定的定制师 ID |
| `consultantSource` | String | 定制师来源(枚举见 §6.4 |
| `tags` | List\<String\> | 标签列表(含入参 tags + 系统自动标签) |
@ -164,8 +164,8 @@ Content-Type: application/json
"id": "60123456789012",
"orderNo": "HL20260518220000001",
"displayOrderNo": "HL20260518220000001",
"orderStatus": "待支付",
"flowStatus": "待支付订金",
"orderStatus": "PENDING_PAY",
"flowStatus": "AWAITING_DEPOSIT",
"consultantId": "50001234567890",
"consultantSource": "DEFAULT_ASSIGNED",
"tags": ["VIP 客户", "含儿童"],
@ -209,8 +209,8 @@ Content-Type: application/json
|------|------|:----:|------|
| `page` | Integer | ❌ | 页码,默认 1 |
| `pageSize` | Integer | ❌ | 每页条数,默认 10 |
| `orderStatus` | String | ❌ | 粗状态过滤(多值用逗号) |
| `flowStatus` | String | ❌ | 细状态过滤 |
| `orderStatus` | String | ❌ | 粗状态过滤(传英文枚举值,多值用逗号,见 §6.2 |
| `flowStatus` | String | ❌ | 细状态过滤(传英文枚举值,见 §6.3 |
| `tagNames` | List\<String\> | ❌ | 按标签过滤(多标签为 AND |
| `keyword` | String | ❌ | 关键字LIKE 团号 / 客户姓名 / 产品名 / 订单号 任一) |
| `departureDateFrom` | LocalDate | ❌ | 出发日期范围起始 |
@ -261,7 +261,7 @@ Content-Type: application/json
**典型 - 请求**
```http
GET /v3/admin/order?page=1&pageSize=10&orderStatus=待出行&tagNames=VIP%20%E5%AE%A2%E6%88%B7
GET /v3/admin/order?page=1&pageSize=10&orderStatus=PENDING_DEPARTURE&tagNames=VIP%20%E5%AE%A2%E6%88%B7
Authorization: Bearer {admin_jwt}
```
@ -284,8 +284,8 @@ Authorization: Bearer {admin_jwt}
"peopleSummary": "2 大 1 小",
"departureDate": "2026-06-01",
"tripDays": 3,
"orderStatus": "待出行",
"flowStatus": "待出行",
"orderStatus": "PENDING_DEPARTURE",
"flowStatus": "CONFIRMED_PENDING_DEPARTURE",
"totalAmount": 8580.00,
"paidAmount": 8580.00,
"balanceAmount": 0.00,
@ -339,18 +339,25 @@ Authorization: Bearer {admin_jwt}
| `departureDate` / `returnDate` | LocalDate | 出发日 / 返团日 |
| `tripDays` / `tripNights` | Integer | 行程天数 / 晚数 |
| `adultCount` / `childCount` / `youngChildCount` / `babyCount` | Integer | 4 类人数 |
| `customerName` / `customerPhone` | String | 客户姓名 / 手机admin 明文) |
| `customerName` | String | 客户姓名 |
| `customerPhoneMasked` | String | 客户手机admin 也脱敏,如 138****2046 |
| `consultantName` | String | 定制师姓名 |
| `confirmedAt` | LocalDateTime? | 确认锁单时间 |
| `exceptionBadges` | Object | 异常态横条 9 类标识(见下方) |
| `progressStepper` | Object | 步骤进度条(见下方) |
| `exceptionBadges` | Map<String, Boolean> | 异常态横条 9 类标识(见下方)⚠️ 运行时**暂返 null**,OrderInfoConverter 派生逻辑待 Issue 接通子表后实现 |
| `progressStepper` | Object | 步骤进度条(见下方)⚠️ 运行时**暂返 null**,OrderInfoConverter 派生逻辑待 Issue 接通子表后实现 |
| `contractStatus` | String? | [Tab 状态] 合同状态枚举:`NONE/GENERATING/GENERATED/SIGNED/VOIDED/RESIGNING`,直接读主表 contract_status |
| `insuranceStatus` | String? | [Tab 状态] 保险状态枚举:`NONE/ISSUING/ISSUED/CANCELLED/FAILED`,直接读主表 insurance_status |
| `refundStatus` | String | [Tab 状态] 退款汇总状态枚举:`NONE/PROCESSING/COMPLETED`(派生,见 OrderMainRefundStatus |
| `hasRefund` | Boolean | [Tab 状态] 是否存在退款记录refundedAmount > 0 |
| `hasServiceStandard` | Boolean | [Tab 状态] 是否存在服务标准快照EXISTS order_product_snapshot |
| `hasFinanceDetail` | Boolean | [Tab 状态] 是否有财务明细discountAmount > 0 OR surchargeAmount > 0,派生无 SQL |
**`exceptionBadges`** 9 类布尔字段(全 false 表示无异常):`contractFail` / `insuranceFail` / `refundAbnormal` / `grabTimeout` / `hotelPending` / `vehiclePending` / `travelerIncomplete` / `longUnpaid` / `awaitingCustomerConfirm`
**`progressStepper`**`currentStage` (String) + `nodes` 数组,每节点 `{key, label, status, subItems?}`
- 节点 key 枚举:`INFO_COMPLETE` / `ASSIGN_PARALLEL` / `CONFIRM` / `DEPARTED` / `RETURNED` / `REVIEW` / `SETTLED`
- 节点 status`DONE` / `ACTIVE` / `PENDING`
- `ASSIGN_PARALLEL``subItems``HOTEL` / `VEHICLE` / `LEADER` / `PHOTOGRAPHER` 子项
- 节点 status`DONE` / `ACTIVE` / `PENDING` / `NOT_APPLICABLE`
- `ASSIGN_PARALLEL``subItems``HOTEL` / `VEHICLE` / `LEADER` / `PHOTOGRAPHER` 子项,每子项 {key, label, subStatus, applicable};subStatus 枚举同节点 statusDONE / ACTIVE / PENDING / NOT_APPLICABLE
`TagVO``name` / `type`(枚举见 §6.15 / `color`
@ -399,8 +406,8 @@ Authorization: Bearer {admin_jwt}
"displayOrderNo": "HL20260510143025001-T20260601A",
"productName": "长白山天池3日深度游",
"tierName": "经典档",
"orderStatus": "待出行",
"flowStatus": "待出行",
"orderStatus": "PENDING_DEPARTURE",
"flowStatus": "CONFIRMED_PENDING_DEPARTURE",
"totalAmount": 8580.00,
"paidAmount": 8580.00,
"balanceAmount": 0.00,
@ -413,7 +420,7 @@ Authorization: Bearer {admin_jwt}
"youngChildCount": 0,
"babyCount": 0,
"customerName": "张三",
"customerPhone": "13800002046",
"customerPhoneMasked": "138****2046",
"consultantName": "李定制",
"confirmedAt": "2026-05-12T10:25:00",
"exceptionBadges": {
@ -461,7 +468,7 @@ Authorization: Bearer {admin_jwt}
"emergencyPhone": "13900008888",
"roomGroupNo": 1,
"profileStatus": "COMPLETED",
"transportPlanIds": ["80012345"]
"transportPlanIds": ["80012345678901234"]
}
],
"customerRemark": "希望住朝阳房",
@ -1046,7 +1053,7 @@ Content-Type: application/json
#### 业务边界
- ✅ **适用**:订单粗状态 ∈ {待支付, 待完善, 定制中, 已确认, 待出行}
- ✅ **适用**:订单粗状态 ∈ {PENDING_PAY, PENDING_COMPLETE, CUSTOMIZING, PENDING_DEPARTURE}v3 状态机已删除「已确认」,由 CONFIRM event 直接迁到 PENDING_DEPARTURE
- ❌ **拒绝**:已取消 / 已完成 / 退款中 → `581050`
- ⚠️ **`daysToDeparture` 负数**:已过出发日,前端应引导走 §3.13 出行中取消on-trip而非本接口预览
@ -1238,7 +1245,7 @@ Content-Type: application/json
| 字段 | 类型 | 必填 | 说明 | 校验规则 |
|------|------|:----:|------|----------|
| `eventCode` | String | ✅ | 状态机事件代码(枚举见 §6.17 | `@NotBlank` |
| `eventCode` | String | ✅ | 状态机事件代码,9 个PAY_DEPOSIT / PAY_FULL / CANCEL / CONFIRM / INITIATE_REFUND / SET_PENDING_BALANCE / SET_PENDING_DEPARTURE / DEPART / FINISH含义见 §6.17 | `@NotBlank` |
| `reason` | String | ❌ | 操作原因(按 event 强制要求时必填) | — |
| `payload` | Map\<String, Object\> | ❌ | 事件相关额外数据(不同 event 含义不同) | — |
@ -1293,10 +1300,10 @@ Content-Type: application/json
"code": 200,
"data": {
"success": true,
"oldStatus": "定制中",
"newStatus": "待出行",
"oldFlowStatus": "待确认",
"newFlowStatus": "待出行",
"oldStatus": "CUSTOMIZING",
"newStatus": "PENDING_DEPARTURE",
"oldFlowStatus": "PENDING_CONFIRM",
"newFlowStatus": "CONFIRMED_PENDING_DEPARTURE",
"triggeredEvents": ["ASYNC_CONTRACT_GENERATE", "ASYNC_INSURANCE_ISSUE"]
},
"msg": "success"
@ -1476,47 +1483,58 @@ Authorization: Bearer {admin_jwt}
**使用字段**§3.1 出参 / §3.2 出参 / §3.3 main / §3.2 入参过滤
| 值 | 说明 |
|----|------|
| `待支付` | 创单后默认 |
| `待完善` | 订金到账后进入 |
| `定制中` | 出行人 + 房车齐后 |
| `已确认` | — |
| `出行中` | — |
| `已完成` | — |
| `已取消` | — |
> 后端 enum`com.hulalv.order.core.enums.OrderStatus`,共 10 个值。**API 传/返均为英文枚举值DB 存什么前端拿什么,前端自己映射中文标签)**。
| 值 | 中文标签 | 说明 |
|----|------|------|
| `PENDING_PAY` | 待支付 | 创单后默认 |
| `PENDING_COMPLETE` | 待完善 | 订金到账后进入 |
| `CUSTOMIZING` | 定制中 | 出行人 + 房车齐前 |
| `PENDING_DEPARTURE` | 待出行 | 确认锁单后 |
| `PENDING_BALANCE` | 待付尾款 | 切到「待支付尾款」细状态时归此粗态(状态机粗态目标) |
| `TRAVELLING` | 出行中 | 已发车 |
| `REVIEWING` | 核单中 | 出行结束待财务核算 |
| `SETTLED` | 已结算 | 财务核算完成 |
| `REFUNDING` | 退款中 | 退款流程进行中(状态机粗态目标) |
| `CANCELLED` | 已取消 | — |
### 6.3 flowStatus订单细状态
**使用字段**§3.1 出参 / §3.2 出参 / §3.3 main / §3.2 入参过滤
| 值 | 说明 |
|----|------|
| `待支付订金` | 创单后默认细状态 |
| `待支付尾款` | — |
| `待补全信息` | 订金到账后 |
| `待提交房型` | — |
| `待抢房` | — |
| `配房中` | — |
| `待提交用车` | — |
| `车控处理中` | — |
| `待确认` | 房车齐后 |
| `待出行` | 确认锁单后 |
| `出行中` | — |
| `已完成` | — |
| `已取消` | — |
> 后端 enum`com.hulalv.order.core.enums.OrderFlowStatus`,共 13 个值。flow_status 列只承载流程细节,不喂状态机;粗态见 §6.2。
> 完整 flowStatus 枚举见订单状态机文档§1C 推送时补全)。
| 值 | 中文标签 | 说明 |
|----|------|------|
| `AWAITING_DEPOSIT` | 待支付订金 | 创单默认细状态 |
| `DEPOSIT_PAID_PENDING_CONFIRM` | 已付订金待确认 | — |
| `FULLY_PAID_PENDING_CONFIRM` | 已全款待确认 | — |
| `PENDING_CONFIRM` | 待确认 | — |
| `CONFIRMED_PENDING_HOTEL` | 已确认配房中 | — |
| `CONFIRMED_PENDING_VEHICLE` | 已确认配车中 | — |
| `CONFIRMED_PENDING_DEPARTURE` | 已确认待出行 | 确认锁单后默认细状态 |
| `DEPOSIT_PAID` | 已付订金 | — |
| `FULLY_PAID` | 已全款 | — |
| `REFUNDED` | 已退款 | — |
| `COMPLETED` | 已完成 | — |
| `TRAVELER_INCOMPLETE` | 出行人待完善 | — |
| `CANCELLED_BEFORE_PAY` | 未付款取消 | 取消时未支付任何金额走此值 |
### 6.4 consultantSource定制师分配来源
**使用字段**§3.1 出参 / §3.3 main
> 该字段为字符串而非强枚举类admin 端硬编码 `MANUAL`;C 端分享下单硬编码 `SHARED`;C 端兜底默认定制师时透传 hl-user-service 派生值(如 `DEFAULT_ASSIGNED` / `ROUND_ROBIN`,由 user-service 决定)。
| 值 | 说明 |
|----|------|
| `DEFAULT_ASSIGNED` | 系统默认分配(轮询) |
| `LINK_BOUND` | 链接绑定(客户扫定制师专属码) |
| `MANUAL` | 手动指定 |
| `MANUAL` | admin 端代下单JWT adminId 即定制师) |
| `SHARED` | C 端客户扫定制师专属分享码下单 |
| `DEFAULT_ASSIGNED` | C 端兜底hl-user-service 派发默认定制师 |
| `ROUND_ROBIN` | C 端兜底hl-user-service 轮询派发(未来扩展) |
| `LINK_BOUND` | DB comment 保留,当前代码路径未实际写入) |
> ⚠️ 因 user-service 可能新增 source 值,前端**严禁**对该字段穷举判断;展示时未知值兜底为 `MANUAL` 的中文标签即可。
### 6.5 paymentMode支付模式
@ -1646,6 +1664,8 @@ Authorization: Bearer {admin_jwt}
**使用字段**§3.14 入参 `eventCode`
> 后端 enum`com.hulalv.order.core.enums.OrderEvent`,共 9 个值。状态机由 `OrderStateMachineConfig` 16 条 transition 规则驱动。
| 值 | 说明 |
|----|------|
| `PAY_DEPOSIT` | 客户支付订金 |

查看文件

@ -69,7 +69,7 @@
`id` (path, Long) — 订单 ID
#### 出参(`Result<List<TravelerVO>>`,每条 17 字段)
#### 出参(`Result<List<TravelerVO>>`,每条 16 字段)
| 字段 | 类型 | 说明 |
|------|------|------|
@ -90,6 +90,8 @@
| `profileStatus` | String | 枚举见 §6.4PENDING / COMPLETED |
| `transportPlanIds` | List\<Long\> | 关联的大交通批次 ID 列表 |
> ⚠️ **transportPlanIds 序列化规则**:后端字段类型 `List<Long>`,但 HL 全局 Jackson `NumberSerializer` 会自动把超过 JS 安全整数2^53-1的 Long 转 String 输出。大交通批次 ID 是雪花 ID19 位),**实际响应中一定是 String 数组**;下面示例值 `80012345`8 位短整数)仅为可读性目的,**生产值类似 `"80012345678901234"`**。前端按 String 数组接收。
#### 错误码
| code | 含义 |
@ -102,7 +104,7 @@
**典型 - 请求**
```http
GET /v3/admin/order/60123456789012/travelers
GET /v3/admin/order/60123456789012/traveler/list
Authorization: Bearer {admin_jwt}
```
@ -128,7 +130,7 @@ Authorization: Bearer {admin_jwt}
"emergencyPhone": "13900008888",
"roomGroupNo": 1,
"profileStatus": "COMPLETED",
"transportPlanIds": [80012345, 80012346]
"transportPlanIds": ["80012345678901234", "80012345678901235"]
},
{
"id": "70123456789013",
@ -317,7 +319,7 @@ Content-Type: application/json
**典型 - 请求**
```http
POST /v3/admin/order/60123456789012/travelers
POST /v3/admin/order/60123456789012/traveler/add
Authorization: Bearer {admin_jwt}
Content-Type: application/json
@ -392,15 +394,15 @@ Content-Type: application/json
|------|------|
| `581020` | 订单不存在 |
| `581110` | 出行人不属于该订单 |
| `581119` | 已签电子合同,禁止删除出行人 |
| `581120` | 出行人是订单最后 1 位成人,禁止删除 |
| `581106` | 已签电子合同,禁止删除出行人DB 段位让位581119 已被 `TRAVELER_ID_CARD_DUPLICATE` 占用,文档原 581119 让位至此) |
| `581107` | 出行人是订单最后 1 位成人,禁止删除DB 段位让位581120 已被 `TRANSPORT_PLAN_NOT_FOUND` 占用,文档原 581120 让位至此) |
#### 业务边界
- ✅ **软删**UPDATE `order_traveler.deleted=1`,不真删
- ✅ **级联解除桥接**UPDATE `order_transport_plan_traveler.deleted=1`
- ❌ **已签合同禁删**:合同强约束 → `581119`
- ❌ **最后成人禁删**:保留至少 1 位成人 → `581120`
- ❌ **已签合同禁删**:合同强约束 → `581106`
- ❌ **最后成人禁删**:保留至少 1 位成人 → `581107`
#### 示例
@ -417,10 +419,10 @@ Authorization: Bearer {admin_jwt}
{ "code": 200, "data": true, "msg": "success" }
```
**异常(已签合同 581119 - 响应**
**异常(已签合同 581106 - 响应**
```json
{ "code": 581119, "data": null, "msg": "订单已签电子合同,禁止删除出行人" }
{ "code": 581106, "data": null, "msg": "订单已签电子合同,禁止删除出行人" }
```
---
@ -774,10 +776,10 @@ Authorization: Bearer {admin_jwt}
| code | 含义 |
|------|------|
| `581120` | 原文超长(> 20000 字符 |
| `581121` | 原文为空或全行无法解析 |
| `581122` | 限流触发10 次/分钟) |
| `581123` | 订单状态不允许批量导入(已结算 / 已取消) |
| `581131` | 原文超长(> 20000 字符DB 段位让位:原文档 581120 已被 `TRANSPORT_PLAN_NOT_FOUND` 占用 |
| `581132` | 原文为空或全行无法解析DB 段位让位:原文档 581121 改至此) |
| `100501` | 限流触发10 次/分钟)—— 走 HL 全局 `CommonErrorCode.RATE_LIMITED`,不在 traveler 段位 |
| `581134` | 订单状态不允许批量导入(已结算 / 已取消DB 段位让位:原文档 581123 改至此 |
#### 业务边界 + 审计安全
@ -822,10 +824,10 @@ Content-Type: application/json
}
```
**异常(限流 581122 - 响应**
**异常(限流 100501 - 响应**
```json
{ "code": 581122, "data": null, "msg": "智能导入解析过于频繁,请稍后再试" }
{ "code": 100501, "data": null, "msg": "请求过于频繁,请稍后再试" }
```
---
@ -1018,7 +1020,7 @@ Authorization: Bearer {admin_jwt}
- **§2.8 smart-parse 待 wx 新建Issue [#2526](https://git.1814.love:8443/wx/HL/issues/2526)**:前端可先按本文字段对接 UI,wx 实现完接口立即可调;接口字段已确定不会变
- **敏感字段明文返回**§2.1 / §2.3 / §2.8 / §2.9 admin 接口返回 `idNo` / `phone` / `emergencyPhone` 明文,前端拿到后**不要**写本地 log / 不要塞 URL query;§2.9 `incompleteList[].name` 已脱敏
- **桥接表约束**§3.6 / §3.7 大交通批次新增/编辑时同方向同一出行人只能在 1 个 plan错则 `581143`
- **删人合同强约束**§3.4 已签电子合同后禁止删人 → `581119`
- **删人合同强约束**§3.4 已签电子合同后禁止删人 → `581106`
- **`/v3/admin/**` 公司隔离**:所有 admin 接口均带跨公司隔离校验,跨公司访问返 `581021`,前端无需自行过滤
---