28 KiB
schema, ticket, title, consumer, author, change_type, backend_status, gateway_status, frontend_status, frontend_owner, frontend_ref, target_release, verified_at, status_note, updated_at, base
| schema | ticket | title | consumer | author | change_type | backend_status | gateway_status | frontend_status | frontend_owner | frontend_ref | target_release | verified_at | status_note | updated_at | base |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| hl-changelog/v2 | 7100 | 团期退单户:提交退单申请 + 管理员审批(070 破坏性变更 + 072~075 新增) | admin | jw(GIT) | 修改接口 | deployed | verified | verified | mmg | 4bc8dd4d | 2026-09-05 | 已过网关真测(2026-09-05,admin 切 ADMIN 角色,5 端点全链路含提交/驳回/再提交/通过);含 #7126 预估口径修复后的复测 | 2026-09-05 | dev-v3 |
团期: 退单户改为「提交申请 + 管理员审批」
服务: hl-order-service-v3 PR: #7106 Issue: #7100 日期: 2026-09-04 影响范围: 管理后台团期详情「退单户」弹窗 + 新增退单审批中心
⚠️ 关键变化
POST .../sub-order/{orderId}/withdraw 是破坏性变更:调用它不再退款,只建一张待审申请单。
三条前端必读:
- 响应体由
Result<Void>变成对象。老前端只看code不读data的话不会崩,但提示语必须改—— 现在的语义是「已提交审核」,不是「已退款」。 - 金额要显示两个数:
paidAmount(已付)和estimatedRefundAmount(预计退)。 两者可以不相等,而且早期阶段常常不等——招募中 / 资源准备中退的是订金应付额, 与已付多少无关(TEST 实测:已付 ¥0、订金 ¥2000 的单,预计退与实退都是 ¥2000)。 不要自己调/v3/admin/order/{id}/cancel-preview算——那个接口恒按退改政策算, 与早期阶段的订金口径对不上。 - 审批中心是新界面:列表 → 详情 → 通过 / 取消退单(4 个新端点),入口按角色显隐,
仅
ADMIN/SUPER_ADMIN可见,其余角色调用返 589530。
一、背景
原来的退单户是「点一下就退款」:提交那一刻订单即 CANCELLED、团期名额当场释放、退款单自动建,
招募中/资源准备中甚至免审直退。但业务要的是可以取消退单,且取消后该户继续留在团期里走原流程——
订单都取消了、名额可能已被新客户占走,这事根本做不到。
故改为先挂申请单、批了才执行:PENDING 期间订单 / 名额 / 钱三项零变动,
该户照常提需求、排房排车;管理员通过才真正退团,驳回则全程无痕、可再次提交。
退款口径没有变:仍按团期状态选模式(招募中 / 资源准备中全退定金,物资准备中 / 待出发按退改政策阶梯扣)。 变的只是「什么时候执行」和「谁点头」。
二、变更接口清单
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|---|---|---|---|---|
| 1 | 退单户·提交退单申请 | POST | /v3/admin/order/group-batch/:groupBatchId/sub-order/:orderId/withdraw |
修改 | 破坏性:由「直接退款」改为「建待审申请单」,响应体 Void → 对象 |
| 2 | 退单审批分页列表 | GET | /v3/admin/order/group-batch/withdraw/page |
新增 | 审批中心列表,缺省只返待审 |
| 3 | 退单申请详情 | GET | /v3/admin/order/group-batch/withdraw/:approvalId |
新增 | 含「提交时预估」与「当前预估」两个金额 |
| 4 | 退单审核通过 | POST | /v3/admin/order/group-batch/withdraw/:approvalId/approve |
新增 | 此刻才执行退团:订单取消 + 名额回落 + 退款 |
| 5 | 取消退单(驳回) | POST | /v3/admin/order/group-batch/withdraw/:approvalId/reject |
新增 | 该户继续留在团期中走原流程 |
三、接口详情
1. 退单户·提交退单申请 POST /v3/admin/order/group-batch/:groupBatchId/sub-order/:orderId/withdraw
VO: WithdrawSubOrderReqVO / WithdrawSubOrderRespVO
使用场景
团期详情底部操作条点「退单户」→ 弹窗选一户(下拉数据仍用既有的
GET /v3/admin/order/group-batch/:groupBatchId/orders,后端没有另开候选接口)→ 填退团原因 →
点「提交退团审核」时调用。调完钱不动,等管理员在审批中心处理。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| groupBatchId | Path | Long | ✅ | - | 团期主订单 ID |
| orderId | Path | Long | ✅ | - | 要退的子订单 ID(= 一户) |
| reason | Body | String | ❌ | ≤512 字 | 退团原因;不传后端记「团期退团」。整个 body 可省略 |
出参 Result<WithdrawSubOrderRespVO>
| 字段 | 类型 | 说明 |
|---|---|---|
| approvalId | String | 退单审批单 ID(雪花,序列化为字符串),审批中心用它取详情 |
| paidAmount | BigDecimal | 该户已付款额,弹窗「已付 ¥5,000」取此列 |
| estimatedRefundAmount | BigDecimal | 预计退款额,弹窗「预计退 ¥3,500」取此列。FULL_DEPOSIT 时 = 订金应付额(与已付无关),POLICY 时 = 已付额按政策扣减后;实退以审批通过时重算为准 |
| refundMode | String | FULL_DEPOSIT=全退定金 / POLICY=按退改政策阶梯扣 |
| refundPolicy | Object | 退改政策明细,仅 POLICY 模式给(用于展示「距出发 6 天,扣 30%」),否则为 null |
| consultantName | String | 该户定制师姓名。信息项,不是审批人,前端不得暗示他要来点头 |
| warnings | String[] | 非阻断提示(如当前已满团,退单通过后将空出 1 户);无则为空数组 |
请求示例
{ "reason": "客户临时有事无法参团" }
响应示例
{
"code": 200,
"message": "成功",
"data": {
"approvalId": "1955009900112233",
"paidAmount": 5000.00,
"estimatedRefundAmount": 3500.00,
"refundMode": "POLICY",
"refundPolicy": { "policyName": "标准退改政策", "policyId": 12 },
"consultantName": "李雯",
"warnings": []
},
"success": true
}
空数据 / 降级响应
写操作,无空数据形态。refundPolicy 在 FULL_DEPOSIT 阶段恒为 null(退订金不看政策),
此时 estimatedRefundAmount 是订金应付额,与 paidAmount 无关,两者不等属正常:
{
"code": 200,
"data": {
"approvalId": "1955009900112234",
"paidAmount": 5000.00,
"estimatedRefundAmount": 2000.00,
"refundMode": "FULL_DEPOSIT",
"refundPolicy": null,
"warnings": []
},
"success": true
}
错误响应
{
"code": 589529,
"message": "该户已有退单审核在途,请勿重复提交",
"success": false,
"data": null
}
四类拒绝:
| code | 含义 |
|---|---|
| 589500 | 团期不存在 |
| 589501 | 团期状态不允许退团(出行中及以后,走售后退款) |
| 589512 | 子订单不属于该团期 |
| 589529 | 该户已有在途退单申请 |
业务边界
- 零副作用:本接口只 INSERT 一行审批单。订单状态、团期已报名人数/户数、退款单三项分文未动。
- 未付分文也能提交,但不等于退 0:
- 招募中 / 资源准备中(
FULL_DEPOSIT)退的是订金应付额,未付款的单照样会退订金并生成退款单—— 这是订单侧既有口径(D3 决策),不是本次引入;如果这不符合业务预期,需要在订单侧另开工单讨论。 - 物资准备中 / 待出发(
POLICY)以已付额为基数,未付则退 0、不生成退款单。 - 订金为 0 时
warnings会提示「该户订金为 0…」——这类单提交得进去但审批会被订单侧拒绝。
- 招募中 / 资源准备中(
- 出行后拒:出行中 / 核算中 / 已结算 / 已取消一律 589501,且在建单之前就拒,不会留下批不掉的单。
- 幂等:同一
groupBatchId + orderId5 秒窗口内重复提交只成功一次;顺序重复由 589529 兜底。 - 金额会漂移:
POLICY模式下「距出发天数」每天在变,本接口返回的是提交时的预估,仅供展示。 - 兼容:body 整体可省略;老前端不读
data也不会报错,但提示文案必须改。
2. 退单审批分页列表 GET /v3/admin/order/group-batch/withdraw/page
VO: WithdrawApprovalListReqVO / WithdrawApprovalItemRespVO
使用场景
退单审批中心的列表页。缺省只返待审单,管理员进来就是「待我处理」的视图。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| approvalStatus | Query | String | ❌ | PENDING/APPROVED/REJECTED/ALL | 缺省 PENDING;查全部传 ALL |
| groupBatchId | Query | Long | ❌ | - | 按团期筛选 |
| keyword | Query | String | ❌ | - | 客户姓名 / 订单号模糊匹配(两者取并集) |
| createdFrom | Query | String | ❌ | yyyy-MM-dd | 提交时间起;格式非法则忽略该条件 |
| createdTo | Query | String | ❌ | yyyy-MM-dd | 提交时间止,含当日 |
| pageNo | Query | Integer | ❌ | ≥1,默认 1 | 页码 |
| pageSize | Query | Integer | ❌ | ≤100,默认 20 | 每页条数,超 100 截断 |
出参 Result<PageResult<WithdrawApprovalItemRespVO>>
| 字段 | 类型 | 说明 |
|---|---|---|
| approvalId | String | 退单审批单 ID |
| groupBatchId | String | 团期 ID |
| batchNo | String | 团期号 |
| productName | String | 产品名称 |
| departDate | String | 出发日期 yyyy-MM-dd |
| orderId | String | 子订单 ID |
| orderNo | String | 订单号 |
| customerName | String | 客户姓名 |
| participantCount | Integer | 该户人数(成人+儿童+小童+婴儿) |
| paidAmount | BigDecimal | 已付款额(提交时快照) |
| estimatedRefundAmount | BigDecimal | 预计退款额(提交时快照) |
| refundMode | String | FULL_DEPOSIT / POLICY |
| reason | String | 退团原因 |
| applicantName | String | 提交人姓名 |
| approvalStatus | String | PENDING / APPROVED / REJECTED |
| createdAt | DateTime | 提交时间 |
请求示例
GET /v3/admin/order/group-batch/withdraw/page?approvalStatus=PENDING&pageNo=1&pageSize=20
响应示例
{
"code": 200,
"data": {
"records": [
{
"approvalId": "1955009900112233",
"batchNo": "GT-26-0007",
"productName": "小蒙马亲子团",
"departDate": "2026-10-01",
"orderNo": "GT-26-0099",
"customerName": "林婉清",
"participantCount": 2,
"paidAmount": 5000.00,
"estimatedRefundAmount": 3500.00,
"refundMode": "POLICY",
"reason": "临时有事无法参团",
"applicantName": "王磊",
"approvalStatus": "PENDING",
"createdAt": "2026-09-04 17:20:11"
}
],
"total": 1,
"page": 1,
"pageSize": 20
},
"success": true
}
空数据 / 降级响应
无待审单,或 keyword 未命中任何客户/订单号时返回空页(不是 null):
{ "code": 200, "data": { "records": [], "total": 0, "page": 1, "pageSize": 20 }, "success": true }
错误响应
{
"code": 589530,
"message": "仅管理员可处理退单审核",
"success": false,
"data": null
}
| code | 含义 |
|---|---|
| 589530 | 当前登录人不是管理员角色 |
业务边界
- 鉴权:仅
ADMIN/SUPER_ADMIN放行;定制师 / 财务 / 房务 / 车务一律 589530。前端入口应按角色显隐,不要靠调用失败来判断。 - 排序:按提交时间倒序。
- 性能:整页的团期与子订单各批量取一次,不随行数放大查询。
- 日期容错:
createdFrom/createdTo格式非法时忽略该条件并继续查询,不报错。
3. 退单申请详情 GET /v3/admin/order/group-batch/withdraw/:approvalId
VO: WithdrawApprovalDetailRespVO
使用场景
审批中心点进某一单。管理员在这里看清楚「退谁、退多少、现在退多少」再决定通过还是取消。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| approvalId | Path | Long | ✅ | - | 退单审批单 ID |
出参 Result<WithdrawApprovalDetailRespVO>
| 字段 | 类型 | 说明 |
|---|---|---|
| (列表行全部字段) | - | 见接口 2 的出参表 |
| currentEstimatedRefundAmount | BigDecimal | 当前预计退款额(实时重算)。审批通过时按它执行 |
| currentRefundMode | String | 当前退款模式;团期状态推进后可能与提交时不同 |
| refundPolicy | Object | 当前退改政策明细(POLICY 模式给) |
| actualRefundAmount | BigDecimal | 实际退款额,审批通过后回填;未通过为 null |
| consultantName | String | 该户定制师(信息项,非审批人) |
| approvedByName | String | 批复人姓名;未批复为 null |
| approvedAt | DateTime | 批复时间;未批复为 null |
| approveRemark | String | 批复备注 |
| refundApplicationId | String | 通过后生成的退款申请 ID |
请求示例
GET /v3/admin/order/group-batch/withdraw/1955009900112233
响应示例
{
"code": 200,
"data": {
"approvalId": "1955009900112233",
"orderNo": "GT-26-0099",
"customerName": "林婉清",
"participantCount": 2,
"paidAmount": 5000.00,
"estimatedRefundAmount": 3500.00,
"refundMode": "POLICY",
"currentEstimatedRefundAmount": 3200.00,
"currentRefundMode": "POLICY",
"consultantName": "李雯",
"approvalStatus": "PENDING",
"approvedByName": null,
"approvedAt": null,
"actualRefundAmount": null,
"refundApplicationId": null
},
"success": true
}
空数据 / 降级响应
团期已推进到不可退阶段(出行中及以后)时,当前预估取不到,currentEstimatedRefundAmount /
currentRefundMode 降级为 null,单子仍可查看——但点通过会被 589501 拦住:
{
"code": 200,
"data": {
"approvalId": "1955009900112233",
"estimatedRefundAmount": 3500.00,
"currentEstimatedRefundAmount": null,
"currentRefundMode": null
},
"success": true
}
refundApplicationId 目前恒为 null——退款单由订单取消事件异步建,取消响应里不带该 ID。
需要跳退款单请用 orderId 去退款工作台查。
错误响应
{
"code": 589531,
"message": "退单申请不存在",
"success": false,
"data": null
}
| code | 含义 |
|---|---|
| 589530 | 非管理员角色 |
| 589531 | 申请单不存在 / 已删除 |
业务边界
- 两个预估都要展示:
estimatedRefundAmount是提交时快照,currentEstimatedRefundAmount是当前值。POLICY下距出发天数每天在变,实退按当前值算,只给前者会误导审批人。 - 鉴权:同列表,仅管理员。
4. 退单审核通过 POST /v3/admin/order/group-batch/withdraw/:approvalId/approve
VO: ApproveWithdrawReqVO / WithdrawApprovalDetailRespVO
使用场景
审批中心详情页点「通过」。这一刻才真正退团:订单取消、团期名额回落、退款进实退链路。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| approvalId | Path | Long | ✅ | - | 退单审批单 ID |
| remark | Body | String | ❌ | ≤512 字 | 批复备注;body 可整体省略 |
出参 Result<WithdrawApprovalDetailRespVO>
| 字段 | 类型 | 说明 |
|---|---|---|
| (详情全部字段) | - | 见接口 3 |
| approvalStatus | String | 固定 APPROVED |
| actualRefundAmount | BigDecimal | 实际退款额(按批复时团期状态重算,可能与提交时快照不同) |
| approvedByName | String | 批复人(当前登录人) |
| approvedAt | DateTime | 批复时间 |
请求示例
{ "remark": "已与客户确认,同意退单" }
响应示例
{
"code": 200,
"data": {
"approvalId": "1955009900112233",
"approvalStatus": "APPROVED",
"refundMode": "POLICY",
"estimatedRefundAmount": 3500.00,
"actualRefundAmount": 3200.00,
"approvedByName": "刘涛",
"approvedAt": "2026-09-04 18:02:35"
},
"success": true
}
空数据 / 降级响应
写操作,无空数据形态。团期时间线写失败会降级(记 WARN)但不影响退团成功。
paidAmount = 0 的零元退单:订单照常取消,actualRefundAmount 为 0,不生成退款单:
{ "code": 200, "data": { "approvalStatus": "APPROVED", "actualRefundAmount": 0.00 }, "success": true }
错误响应
{
"code": 589532,
"message": "该退单申请已处理,不可重复操作",
"success": false,
"data": null
}
| code | 含义 |
|---|---|
| 589501 | 团期已推进到不可退阶段(出行中及以后) |
| 589512 | 子订单不属于该团期 |
| 589530 | 非管理员角色 |
| 589531 | 申请单不存在 |
| 589532 | 申请单已是终态(已通过 / 已取消) |
业务边界
- 钱以批复时为准:审批通过时重新按当时团期状态选模式、重算金额,不认提交时的快照。 典型场景:提交时团期还在资源准备中(全退 5000),批复时已进物资准备(按政策退 3200)→ 实退 3200。
- 一次到位:团期侧审批完即执行,退款不再进退款审批中心二次审。
- 名额回落:1 单 = 1 户 = 1 房,通过后该团期已报名 −1 户 / −N 人。
- 并发:按
approvalId加分布式锁 + 状态 CAS 双保险,两名管理员同时点通过只有一个成功,另一个 589532。 - 不可撤销:钱一旦进实退链路就撤不回来,要撤走售后退款。
5. 取消退单(驳回) POST /v3/admin/order/group-batch/withdraw/:approvalId/reject
VO: RejectWithdrawReqVO / WithdrawApprovalDetailRespVO
使用场景
审批中心详情页点「取消退单」。该户继续留在团期中走原流程,可以继续提需求、住房用车、正常出行。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| approvalId | Path | Long | ✅ | - | 退单审批单 ID |
| remark | Body | String | ✅ | 非空,≤512 字 | 驳回原因(合规要求必填),body 不可省略 |
出参 Result<WithdrawApprovalDetailRespVO>
| 字段 | 类型 | 说明 |
|---|---|---|
| (详情全部字段) | - | 见接口 3 |
| approvalStatus | String | 固定 REJECTED |
| approveRemark | String | 驳回原因 |
| approvedByName | String | 操作人 |
| approvedAt | DateTime | 操作时间 |
请求示例
{ "remark": "客户已改口,继续参团" }
响应示例
{
"code": 200,
"data": {
"approvalId": "1955009900112233",
"approvalStatus": "REJECTED",
"approveRemark": "客户已改口,继续参团",
"approvedByName": "刘涛",
"approvedAt": "2026-09-04 18:05:12"
},
"success": true
}
空数据 / 降级响应
写操作,无空数据形态。时间线写失败降级不阻断驳回。
错误响应
{
"code": 589532,
"message": "该退单申请已处理,不可重复操作",
"success": false,
"data": null
}
| code | 含义 |
|---|---|
| 589530 | 非管理员角色 |
| 589531 | 申请单不存在 |
| 589532 | 申请单已是终态 |
remark 为空时走参数校验,返回校验失败提示(非业务码)。
业务边界
- 零副作用:只改申请单状态。订单状态、团期名额、退款单三项分文未动。
- 可再次提交:驳回后该户可以再走一遍退单户流程(在途判重只拦
PENDING单)。 - 并发:同 approve,锁 + CAS 双保险。
四、契约约束与正确调用方式
✅ 正确 / ❌ 错误 payload 对照
// ✅ 提交退单:body 可省略,也可只带 reason
{ "reason": "客户临时有事无法参团" }
// ❌ 不要再期待「调完就退款了」——现在只是建了一张待审单
// ❌ 不要传 refundMode:退款模式由后端按团期状态定,前端无权指定
// ✅ 取消退单:remark 必填
{ "remark": "客户已改口,继续参团" }
// ❌ 取消退单不传 remark → 参数校验失败
{}
金额取哪个数
- 弹窗展示 → 提交接口返回的
paidAmount+estimatedRefundAmount - 审批详情展示 →
paidAmount+currentEstimatedRefundAmount(当前值才是实退依据) - 都不要调
/v3/admin/order/{id}/cancel-preview自己算,它恒按退改政策算,团期早期会少显示
五、数据库行为
- 提交时新增一条退单审批记录(待审),不改订单、不改团期计数、不建退款单。
- 审批通过时才发生:订单流转为已取消、团期已报名人数/户数回落、按金额生成退款申请并进实退链路 (金额为 0 时不生成退款申请)。
- 取消退单(驳回)只更新审批记录的状态与批复信息,其余数据零变动。
- 提交 / 通过 / 驳回各写一条团期时间线;写失败降级为 WARN,不影响主流程。
- 同一子订单同时只允许存在一条待审记录。
六、边界行为
- 出行中及以后不允许退单,提交与审批两处都拦(589501),走售后退款。
- 未付分文可以退单;早期阶段(全退订金)仍会按订金应付额退并生成退款单,后期阶段(按政策)才退 0 且不生成退款单。
- 已满团的团期提交退单会返回
warnings提示,不阻断。 - 审批期间该户完全正常:可提需求、可排房排车、可被派资源。
- 审批期间若该户又付了尾款,通过时按当前已付款额重算退款。
六.5、枚举 / 数据字典
审批状态(approvalStatus)
| 值 | 含义 | 可做的操作 |
|---|---|---|
| PENDING | 待审 | 通过 / 取消退单 |
| APPROVED | 已通过(已退团) | 无(终态) |
| REJECTED | 已取消退单 | 无(终态);该户可再次提交新申请 |
退款模式(refundMode)
| 值 | 含义 | 出现阶段 |
|---|---|---|
| FULL_DEPOSIT | 全额退订金应付额(与已付款额无关;订金为 0 时订单侧拒绝退款) | 招募中 / 资源准备中 |
| POLICY | 以已付款额为基数按退改政策阶梯扣减 | 物资准备中 / 待出发 |
六.6、修改前后对比
针对 POST /v3/admin/order/group-batch/:groupBatchId/sub-order/:orderId/withdraw:
| 维度 | 修改前 | 修改后 |
|---|---|---|
| 调用后果 | 立即退款:订单取消、名额释放、退款单自动建 | 只建待审申请单,三项零变动 |
| 招募中 / 资源准备中 | 免审直退,钱当场退 | 同样要管理员审批 |
| 物资准备中 / 待出发 | 退款单挂起等定制师审 | 团期侧审批通过后一次到位,不再二次审 |
| 响应体 | Result<Void>,data 为 null |
Result<WithdrawSubOrderRespVO>,含两个金额与审批单 ID |
| 能否反悔 | 不能,订单已取消 | 能,管理员可「取消退单」,该户继续留在团期 |
| 退款金额口径 | 按团期状态选模式 | 不变,仍按团期状态选模式 |
| 谁审批 | 定制师(且早期免审) | 管理员角色(ADMIN / SUPER_ADMIN) |
六.7、影响评估
- 前端必改:提交成功后的提示语(「已退款」→「已提交审核,待管理员确认后退款」); 弹窗金额改为两行展示;新增审批中心三个页面(列表 / 详情 / 通过与取消)。
- 不改也不会崩:响应体从 null 变对象是向后兼容的(老前端不读
data即可), 但业务语义会错——用户以为钱退了,实际还在等审批。属必须跟进项。 - 运营流程变化:招募期退款不再是秒退,需要管理员点一下;换来的是可撤销。
- 其他端:C 端、小程序、财务侧退款工作台均不受影响——退款单的建立与实退链路完全没动。
- 回滚:回滚本次发布即恢复旧行为;已建的待审申请单不会自动执行,需人工处理。
七、不影响范围
- 转订单
POST .../transfer-in(#7095)——两件事,各走各的,本次未动。 - 团期成团 / 取消成团 / 流团 / 调整容量 / 预支等其余团期动作端点。
- 子订单列表
GET /v3/admin/order/group-batch/:groupBatchId/orders——退单弹窗下拉仍用它,出参未变。 - 订单侧散客退改政策与
/v3/admin/order/{id}/cancel-preview,口径与实现均未动。 - 退款工作台的申请、审核、实退链路。
- C 端 / 小程序全部接口。
八、测试环境已验证
过网关真测已完成(2026-09-05,https://api.test.1814.love:9443,
admin 账号经 POST /admin/auth/login + POST /admin/auth/switch-role 切到 ADMIN 角色)。
测试数据:在团期 Q202610312089667212070612994(资源准备中)代下两单并全程验证后作废。
| # | 验证项 | 结果 |
|---|---|---|
| 1 | 角色门:ROOM_MANAGER 调审批列表 |
589530 拒绝 ✅ |
| 2 | 072 列表(ADMIN,缺省 PENDING / ALL) |
200,分页结构 records/total/page/pageSize ✅ |
| 3 | 073 详情:不存在的单 | 589531 ✅ |
| 4 | 070 提交:不存在的团期 | 589500 ✅ |
| 5 | 070 提交:真团期 + 不存在的子订单 | 581007 订单不存在 ✅ |
| 6 | 070 提交:真实子订单 | 200,返 approvalId + 两个金额 + 模式 ✅ |
| 7 | 提交后订单/名额零变动 | 订单仍 PENDING_PAY,enrolled 仍 2/1 ✅ |
| 8 | 072 列表出现该待审单 | total=1,字段齐 ✅ |
| 9 | 073 详情双预估 | 提交时预估与当前预估均返回 ✅ |
| 10 | 070 重复提交 | 589529 ✅ |
| 11 | 075 取消退单 | 200 → REJECTED ✅ |
| 12 | 驳回后该户仍在团里 | 订单仍 PENDING_PAY,enrolled 仍 2/1,三项零变动 ✅ |
| 13 | 已处理的单再驳 | 589532 ✅ |
| 14 | 驳回后可再次提交 | 200,新 approvalId ✅ |
| 15 | 074 审核通过 | 200 → APPROVED,回填批复人/实退额 ✅ |
| 16 | 通过后订单取消 + 名额回落 | 订单 CANCELLED,enrolled 2/1 → 0/0 ✅ |
| 17 | 已通过的单再批 | 589532 ✅ |
| 18 | 075 remark 为空 | 400「驳回原因不能为空」✅ |
| 19 | 预估 == 实退 | 预估 ¥2000 = 实退 ¥2000 ✅(见下方缺陷) |
实测暴露并已修复的缺陷
首轮实测发现:已付 ¥0 的单,弹窗显示「预计退 ¥0」,审批通过后实退 ¥2000——预估与实退不同源。
根因是订单侧 FULL_DEPOSIT 退的是订金应付额而非已付额,本模块的预估函数错用了已付额。
已由 PR #7126 修复(预估改用订金、订金为 0 时出 warning),重新部署后复测预估与实退一致。
两轮验证产生的退款单(2096027837650616321、2096029516789915650)均已置 REJECTED,
无实退记录,测试环境资金零变动。
部署记录
- 2026-09-04 19:39–19:40 首次部署(PR #7106)
- 2026-09-05 08:14–08:15 修复后重新部署(PR #7126)
两次均从 dev-v3 重新构建 hl-order-service-v3 并滚动重启,8186 / 8086 双实例先后健康。
本地测试
mvn -pl hl-order-service-v3 -am test 共 8175 例,Failures: 0、Errors: 7——
7 例全部是 Testcontainers 迁移测试因本机无 Docker 报 IllegalState,与本次改动无关。
GroupBatchWithdrawApprovalServiceTest 18 例(含 3 例订金口径回归)、
GroupBatchFinanceServiceTest 24 例、团期全域 553 例全绿;ArchUnit 架构规则全绿。
九、相关历史 PR
| PR | Issue | 说明 | 是否仍有效 |
|---|---|---|---|
| PR #7126 | #7100 | 实测暴露的预估口径修复(FULL_DEPOSIT 按订金算) | ✅ 最新 |
| PR #7106 | #7100 | 退单户改为申请 + 管理员审批,新增 072~075 | ✅ 有效 |
| #7103 | #7095 | 团期转订单(与本次并行开发,错误码与迁移号已错开) | ✅ 有效 |
十、相关文档
- 关联 Issue: wx/HL#7100
- 关联 PR: wx/HL#7106
- 后续计划: 流团审批复用同一套审批表(本次只做退单);已通过后的撤销走售后,不在本次范围
关联 / 联系人
链接
联系人
- 后端负责人: @jw