12 KiB
12 KiB
🔧 出行人批量编辑:资料完整度与完成统计统一为订单级手机号语义(#5203)
PR: #5210 Issue: #5203 日期: 2026-07-24 消费端: 一期小程序 MP BFF 接口:
POST /mp/v3/order/{id}/traveler/batch-edit
1. 变更背景
出行人资料完整度与订单签约、确认门禁此前存在两套手机号口径:逐人完成状态可能要求每名成人都有手机号,但订单门禁只要求整单至少一名出行人有手机号。
本次统一为:
- 单名出行人的资料完整度只检查
name、gender、birthday、idType、idNo五项; phone不再影响该出行人的完成状态;- 订单整体仍必须至少有一名出行人填写手机号;
- 接口字段名、类型和层级不变,但
completedCount、pendingCount、allCompleted的统计结果可能变化。
2. 变更接口
| 接口 | 方法 | 路径 | 变更类型 |
|---|---|---|---|
| 客户批量补全出行人 | POST | /mp/v3/order/{id}/traveler/batch-edit |
响应字段语义修改 |
3. 完整接口契约
3.1 调用约束
| 项目 | 契约 |
|---|---|
| 认证 | 需要小程序登录态 |
| 可编辑订单状态 | PENDING_PAY(待支付)、CUSTOMIZING(定制中) |
| 订单归属 | 只能编辑当前登录用户自己的订单 |
| 幂等 | 同一订单 3 秒内重复提交返回 100502 |
| 批量上限 | 每次 1~30 名出行人 |
| 写入语义 | id=null 为新增,id 非空为更新;未出现在数组中的已有出行人不会被删除 |
3.2 路径参数
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
id |
Long | 是 | 订单 ID;建议以字符串形式传递,避免大整数精度丢失 |
3.3 请求体
请求类型:TravelerBatchEditReqVO
| 字段 | 类型 | 必填 | 约束与语义 |
|---|---|---|---|
travelers |
TravelerEditItem[] |
是 | 1~30 项 |
travelers[].id |
Long / null | 否 | null 表示新增;非空表示更新,且必须属于路径中的订单 |
travelers[].name |
String / null | 条件必填 | 新增项的 name、idType、idNo 至少一项非空;有值时长度 2~30,只允许中文、英文、中点 ·、连字符 -、空格 |
travelers[].gender |
String / null | 否 | 0、1、2;该字段为空时资料状态为 PENDING |
travelers[].birthday |
String | 是 | yyyy-MM-dd,不得晚于当天;用于派生出行人类型 |
travelers[].idType |
String / null | 条件必填 | 取值见第 4 节;与 idNo 配套 |
travelers[].idNo |
String / null | 条件必填 | ID_CARD 为 18 位数字或末位 X/x;其他证件为 5~30 位字母、数字或连字符 |
travelers[].nationality |
String / null | 否 | 允许不传或传 null,不允许显式传空字符串 |
travelers[].race |
String / null | 否 | 允许不传或传 null,不允许显式传空字符串 |
travelers[].phone |
String / null | 否 | 有值时必须为 11 位数字;更新时 null 表示保留原值,空字符串表示清空 |
travelers[].emergencyContact |
String / null | 否 | 出行人级紧急联系人姓名 |
travelers[].emergencyPhone |
String / null | 否 | 有值时必须为 11 位数字 |
travelers[].roomGroupNo |
Integer / null | 否 | 最小为 1,最大不超过订单声明总人数 |
更新已有出行人时,除必填的 birthday 外,其他可选字段传 null 表示保留原值。
3.4 响应
响应类型:Result<TravelerBatchEditRespVO>
统一响应字段:
| 字段 | 类型 | 说明 |
|---|---|---|
code |
Integer | 200 表示成功,其他值见第 5 节 |
message |
String | 响应文案 |
data |
Object / null | 成功时为批量编辑统计,失败时通常为 null |
traceId |
String / null | 链路追踪 ID,可能为空 |
success |
Boolean | code == 200 时为 true |
data 字段:
| 字段 | 类型 | 说明 |
|---|---|---|
createdCount |
Integer | 本次请求中 id=null 的新增数量 |
updatedCount |
Integer | 本次请求中 id 非空的更新数量 |
completedCount |
Integer | 操作完成后,订单内五项资料均完整的出行人总数 |
pendingCount |
Integer | 操作完成后,订单内五项资料仍有缺失的出行人总数 |
allCompleted |
Boolean | 同时满足“订单声明人数大于 0、实际人数等于声明人数、pendingCount=0、整单至少一名出行人有手机号”时为 true |
五项资料指:name、gender、birthday、idType、idNo。手机号不计入单名出行人的完成状态,但仍计入 allCompleted 的订单级门禁。
4. 枚举与数据字典
4.1 gender
| 值 | 中文 | 完整度语义 |
|---|---|---|
0 |
未知 | 有值,满足 gender 完整度 |
1 |
男 | 有值,满足 gender 完整度 |
2 |
女 | 有值,满足 gender 完整度 |
4.2 资料完成状态
该状态不单独出现在本接口响应中,但直接决定 completedCount 和 pendingCount。
| 值 | 中文 | 判定 |
|---|---|---|
COMPLETED |
已完善 | name/gender/birthday/idType/idNo 五项全部非空 |
PENDING |
待完善 | 上述五项任一为空 |
4.3 idType
| 值 | 中文 |
|---|---|
ID_CARD |
身份证 |
PASSPORT |
护照 |
HK_MACAU_PASS |
港澳通行证 |
HONGKONG_RESIDENT_PASS |
回乡证 |
TAIWAN_PASS |
台湾通行证 |
MILITARY_ID |
军官证 |
OTHER |
其他 |
4.4 出行人类型
出行人类型不由请求体传入,而是根据 birthday 自动派生,并用于校验订单各类型人数配额。
| 年龄 | 值 | 中文 |
|---|---|---|
| 未满 2 周岁 | BABY |
幼童 |
| 2~6 周岁 | YOUNG_CHILD |
小童 |
| 7~17 周岁 | CHILD |
儿童 |
| 18 周岁及以上 | ADULT |
成人 |
5. 错误码
| code | message / 含义 | 触发场景 |
|---|---|---|
401 |
未认证 | 未携带有效小程序登录态 |
500 |
出行人服务不可用,请稍后重试 | BFF 无法调用出行人服务 |
100001 |
参数非法 | travelers 为空、超过 30 项、缺少 birthday、日期格式错误等请求校验失败 |
100502 |
出行人补全处理中,请勿重复提交 | 同一订单 3 秒内重复提交 |
100503 |
资源被占用,请稍后重试 | 同一订单存在并发写入且未能取得操作权 |
100701 |
姓名长度异常(2-30字符) | 非空姓名长度不在 2~30 字符 |
100702 |
姓名含非法字符 | 姓名包含允许字符集之外的内容 |
100703 |
姓名含敏感词 | 姓名命中敏感词 |
100704 |
姓名格式不正确 | 同一字符连续重复 5 次及以上 |
581101 |
12301 必报字段缺失(国籍 / 民族不能为空字符串) | nationality 或 race 显式传空字符串 |
581102 |
订单不存在,无法编辑出行人 | 处理过程中订单不存在 |
581103 |
性别编码不合法(应为 1=男/2=女/0=未知) | 非空 gender 不在 0/1/2 |
581104 |
同住分组号超出订单家庭数上限 | roomGroupNo < 1 或超过订单声明总人数 |
581110 |
出行人 ID 不属于该订单 | 更新项的 id 不属于路径订单 |
581111 |
已签电子合同后禁止修改证件号 | 已签约记录尝试修改 idNo |
581112 |
证件号格式不合法,请检查证件类型与号码是否匹配 | idType 非法或 idNo 格式不匹配 |
581113 |
手机号格式非法(应为 11 位数字) | 非空 phone 或 emergencyPhone 不是 11 位数字 |
581114 |
出生日期不能晚于今天 | birthday 为未来日期 |
581118 |
新增出行人缺少必填字段 | 新增项的 name/idType/idNo 全部为空 |
581119 |
出行人证件号重复 | 同一请求或订单内出现重复证件号 |
581122 |
订单不属于当前用户 | 订单不存在或不属于当前登录用户 |
581145 |
订单已确认,出行人信息不可再经小程序修改,如需变更请联系定制师 | 订单状态不在 PENDING_PAY/CUSTOMIZING 白名单 |
581149 |
出行人类型人数超出订单人数配置 | 根据生日派生后的某类出行人数超过订单声明配额 |
6. 示例
6.1 典型成功:两人五项完整,仅一人有手机号
请求
POST /mp/v3/order/2079576729147338754/traveler/batch-edit
Authorization: Bearer <mp-token>
Content-Type: application/json
{
"travelers": [
{
"id": "2079576729147338801",
"name": "张三",
"gender": "1",
"birthday": "1990-01-01",
"idType": "PASSPORT",
"idNo": "P1234567",
"nationality": "中国",
"race": "汉族",
"phone": "13800138000",
"emergencyContact": null,
"emergencyPhone": null,
"roomGroupNo": 1
},
{
"id": "2079576729147338802",
"name": "李四",
"gender": "2",
"birthday": "1992-02-02",
"idType": "PASSPORT",
"idNo": "P7654321",
"nationality": "中国",
"race": "汉族",
"phone": "",
"emergencyContact": null,
"emergencyPhone": null,
"roomGroupNo": 1
}
]
}
响应
{
"code": 200,
"message": "成功",
"data": {
"createdCount": 0,
"updatedCount": 2,
"completedCount": 2,
"pendingCount": 0,
"allCompleted": true
},
"traceId": "a1b2c3d4-e5f6-7890",
"success": true
}
6.2 边界成功:五项全部完整,但整单没有手机号
假设订单声明人数和实际人数均为 2,且请求将最后一部手机号清空。
请求
POST /mp/v3/order/2079576729147338754/traveler/batch-edit
Authorization: Bearer <mp-token>
Content-Type: application/json
{
"travelers": [
{
"id": "2079576729147338801",
"name": "张三",
"gender": "1",
"birthday": "1990-01-01",
"idType": "PASSPORT",
"idNo": "P1234567",
"phone": ""
},
{
"id": "2079576729147338802",
"name": "李四",
"gender": "2",
"birthday": "1992-02-02",
"idType": "PASSPORT",
"idNo": "P7654321",
"phone": ""
}
]
}
响应
{
"code": 200,
"message": "成功",
"data": {
"createdCount": 0,
"updatedCount": 2,
"completedCount": 2,
"pendingCount": 0,
"allCompleted": false
},
"traceId": "a1b2c3d4-e5f6-7890",
"success": true
}
这里 completedCount=2 表示两人的五项资料都完整;allCompleted=false 表示订单级“至少一名出行人有手机号”门禁未满足。
6.3 业务失败:订单已确认
请求
POST /mp/v3/order/2079576729147338754/traveler/batch-edit
Authorization: Bearer <mp-token>
Content-Type: application/json
{
"travelers": [
{
"id": "2079576729147338801",
"name": "张三",
"gender": "1",
"birthday": "1990-01-01",
"idType": "PASSPORT",
"idNo": "P1234567",
"phone": "13800138000"
}
]
}
响应
{
"code": 581145,
"message": "订单已确认,出行人信息不可再经小程序修改,如需变更请联系定制师",
"data": null,
"traceId": "a1b2c3d4-e5f6-7890",
"success": false
}
7. 修改前后对比
| 场景 | 修改前 | 修改后 |
|---|---|---|
| 单名成人五项完整但本人无手机号 | 可能计入 pendingCount |
计入 completedCount |
| 同行人已有手机号 | 仍可能要求每名成人各自填写 | 整单手机号门禁已满足 |
| 五项完整且整单无手机号 | 逐人完成状态与手机号门禁混合 | completedCount 可等于实际人数,但 allCompleted=false |
| 请求 / 响应结构 | 现有字段 | 不变 |
8. 消费注意事项
- 不要按“每名成人必须有手机号”在本地重算资料完成状态。
completedCount和pendingCount是操作后订单内的总量,不是本次请求中发生状态变化的行数。- 判断本接口是否已满足整单补全条件,以响应
allCompleted为准;它已同时包含人数、五项资料和订单级手机号门禁。 phone=null在更新场景表示保留原值;需要清空手机号时传空字符串。
9. 关联
- Issue: #5203
- PR: #5210
- Merge commit: 88d0aec8375b56b5b8141984645a6998f8a42609