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
8597
退团房清空免费退改期限:截止时刻与提醒天数保留原值(订正 #8491 交接件三处表述),异常检查补回源单已取消的退团房待办
admin
wx(GIT)
修改接口
deployed
not_required
not_required
PR #8599(提交 ff68637542)已合入 dev-v3;测试服 hl-order-service-v3 运行提交 d57498d38、BEHIND 0/N、STATE ok、2026-09-30 05:32:57,ff68637542 是 d57498d381 的祖先。两个端点的路径与方法均未变,网关 /v3/admin/** 路由块已通配,零网关改动。
2026-09-30
dev-v3
房务控制台: 退团房期限清空口径订正 + 异常检查退团房待办补全
存放目录 : 二期 → changelogs-v2/2026-09/
服务 : hl-order-service-v3
Issue : #8597
PR : #8599
日期 : 2026-09-30
影响范围 : 管理后台「房务控制台」的「退团房」页签(设期限弹窗)与「异常检查」页签(待办列表)
⚠️ 关键变化(非必须,本版与上版行为不同 / 纠错 / 撤销时必写)
🔴 订正 #8491 交接件的三处表述 : PUT .../room-transfers/{id}/deadline 传 cancelDays: null 清除期限时,只有 cancelDays 变成 null,cancelCutoff 与 remindDays 保留该行原值,不会被置空 。changelogs-v2/2026-09/30_8491_房务控制台接口-新增接口-管理后台.md 的第 746、747 行(入参表)、第 787 行(空数据 / 降级响应)、第 1623 行(显式 SET NULL 说明)写的「三列一并清空 / 本字段被忽略、一并清空」与实际行为不符,以本条为准;该文件第 1847 行的测试环境读数(cancel_cutoff / remind_days 保留原值)才是正确的那一条。
🔴 判「这一行有没有设免费退改期限」只能看 cancelDays === null 或 risk === "NO_DEADLINE" ,不能看 cancelCutoff / remindDays 是否为 null——清空后这两个字段仍有值(该行从未设过期限时是建表默认的 "18:00" 与 1)。
清除期限从「必定失败」改为成功 :本次改动前,cancelDays: null 的请求 100% 返回 808932 「房务状态已被并发修改,请刷新后重试」(并非真的并发冲突),现在返回 code=200 并给出更新后的整行。
异常检查 tasks[] 的 TRANSFER_PENDING 条目不再漏行 :待处理退团房行的窗口归属改为只看源团期 / 源订单的出发日 ,不看源单状态 ;源单查不到、或源单出发日为空时同样列出。取消订单恰恰是产生退团房最常见的原因,订正前这些待办在控制台唯一的待办载体上看不到。同一窗口下本端点返回的 tasks 行数会比订正前多。
一、背景(选填)
退团房行有两处独立缺陷,都发生在「房务控制台」已交付的端点上:
清期限走的乐观锁写口,其入参守卫要求截止时刻与提醒天数非空(两列在库中是 NOT NULL);旧代码在 cancelDays 为 null 时把这两项也一起传 null,守卫直接返回「影响行数 0」,上层把 0 当成版本冲突抛 808932。表现是「清除期限」按钮永远失败,而错误文案指向刷新重试,看不出是入参问题。
异常检查的退团房待办原先用「窗口内的团期集合 / 散单集合」判归属,这两个集合按占用口径排除了已取消的单,于是「订单取消 → 释放房间 → 待转出」这条最常见的链路产出的待办从不出现。
二、变更接口清单
#
接口
方法
路径
变更类型
说明
1
设置 / 清除退团房免费退改期限
PUT
/v3/admin/order/house-console/room-transfers/{id}/deadline
修改
清除期限由必定失败改为成功;cancelCutoff / remindDays 保留原值(订正交接件表述)
2
房务异常检查
GET
/v3/admin/order/house-console/audit
修改
tasks[] 的 TRANSFER_PENDING 按源单出发日归属、不看源单状态,补回源单已取消的行
三、接口详情
1. 设置 / 清除退团房免费退改期限 PUT /v3/admin/order/house-console/room-transfers/{id}/deadline
VO : HouseRoomTransferDeadlineSaveReqVO → HouseRoomTransferRespVO
使用场景
「退团房」页签某一行点「设期限」,录入酒店给的免费取消规则(入住前几天、当天几点前)与提前几天提醒;也用于把已设的期限清掉。清掉后该行的风险分档变为 NO_DEADLINE,前端应按 cancelDays 是否为 null 渲染「未设免费取消期」,而不是按 cancelCutoff / remindDays 是否有值判断。
入参
字段
位置
类型
必填
约束
说明
id
Path
Long
✅
必须是退团房父行 (子行是转出明细,不可改期限);不存在或已删返 808320
退团房行 ID
cancelDays
Body
Integer
❌
0~60,越界返 808328;传 null 表示清除期限
入住前几天可免费取消
cancelCutoff
Body
String
❌
HH:mm 24 小时制(00:00~23:59),格式不符返 808328;cancelDays 非空而本字段为空 / 空白时取 18:00;cancelDays 为 null 时本字段被忽略,该行原值保留
截止当天的时刻
remindDays
Body
Integer
❌
0~30,越界返 808328;cancelDays 非空而本字段为空时取 1;cancelDays 为 null 时本字段被忽略,该行原值保留
提前几天提醒
出参 Result<HouseRoomTransferRespVO>
字段
类型
说明
(整行)
HouseRoomTransferRespVO
更新后的该退团房父行,字段与退团房分页 records[] 同构
cancelDays
Integer
入住前几天免费取消;清除期限后为 null
cancelCutoff
String
截止当天的时刻 HH:mm;清除期限后仍是该行原值(从未设过则是 "18:00"),不会变成 null
remindDays
Integer
提前几天提醒;清除期限后仍是该行原值(从未设过则是 1),不会变成 null
deadlineAt
LocalDateTime
免费取消截止时刻 = 入住晚 − cancelDays 天的 cancelCutoff;cancelDays 为 null 或缺入住晚时为 null
risk
String
风险码 OVERDUE / NEAR / NO_DEADLINE / NORMAL;仅 PENDING 行有值,其余为 null
riskLabel
String
风险中文;NO_DEADLINE 对应「未设免费取消期」
status / statusLabel
String
行状态 PENDING / TRANSFERRED / CANCELLED 与中文;本端点只对 PENDING 行成功
id / sourceOrderId / sourceGroupBatchId / hotelId / roomTypeId
Long(String)
雪花 ID,JSON 中为字符串
teamNo
String
源订单团号(批量读订单主表团号);取不到为 null
stayDate
LocalDate
入住晚
roomCount / remainingCount
Integer
原始间数 / 剩余待处理间数
readOnly / readOnlyReason
Boolean / String
对当前操作人是否只读(源单由他人处理)与理由
请求示例
响应示例
空数据 / 降级响应
本端点恒返回整行,没有空响应形态。
清除期限(cancelDays: null)是正常成功路径:data.cancelDays = null、data.deadlineAt = null、data.risk = "NO_DEADLINE"、data.riskLabel = "未设免费取消期",而 data.cancelCutoff 与 data.remindDays 仍是该行原值。
源单(订单需求 / 团期)读不到时,只影响「谁是源单处理人」的判定,不影响本端点的写入结果;非源单处理人且非超管一律返 808326。
错误响应
code
message
触发
808090
未登录或非房务角色,无权操作
非房务角色
808320
转房记录不存在
id 不存在、已删、或不是父行
808321
该房间已处理
行已不是 PENDING(已转出 / 已取消)
808326
只有原单处理人可以处理退团房间
非源单处理人且非超管
808328
退改期限参数不合法
cancelDays 超 060、remindDays 超 030、cancelCutoff 不是 HH:mm
808932
房务状态已被并发修改,请刷新后重试
真并发写冲突(行版本在锁定读与写之间被改)。订正前 cancelDays: null 会恒定命中这一条,订正后不再出现这种假冲突
100502
修改处理中,请勿重复提交
3 秒幂等窗口内重复提交同一请求
业务边界
入参不走 Bean Validation,范围与格式错误统一以 808328 返回,HTTP 状态仍是 200,不是 400。
清除期限只清 cancelDays 这一项语义;cancelCutoff / remindDays 是「下次设期限时的默认值」,保留它们不影响「有没有期限」的判定,因为 deadlineAt 与 risk 都只在 cancelDays 非空时才成立。
该行处于 PENDING 才可改期限;TRANSFERRED / CANCELLED 返 808321。
只有源单处理人或超管可改;源订单来源看该需求的持有人,团期来源看该团期的房务认领人。
同一行的改期限、转房、向酒店取消共用一把行级锁,前端不必自己串行化。
2. 房务异常检查 GET /v3/admin/order/house-console/audit
VO : HouseConsoleAuditReqVO → HouseConsoleAuditRespVO
使用场景
「异常检查」页签:按出发日期区间一次列出数据对不上的问题(issues)和还没办完的事(tasks)。本次订正只影响 tasks 里 TRANSFER_PENDING(退团房未结清)这一类条目的取行范围 ,字段结构未变;前端按 refId 跳转退团房处理页的逻辑不变。
入参
字段
位置
类型
必填
约束
说明
scope
Query
String
❌
mine / all,默认 mine;其他取值返 400
只作用于 tasks: mine 只留当前登录人是处理人的条目;issues 不受它影响
departDateFrom
Query
LocalDate
❌
yyyy-MM-dd,默认今天
出发日期区间起(含)
departDateTo
Query
LocalDate
❌
yyyy-MM-dd,默认起始日 +30 天;早于起始日或跨度超 92 天返 808313
出发日期区间止(含)
出参 Result<HouseConsoleAuditRespVO>
字段
类型
说明
issues
Array
数据不一致问题,不归属处理人,不受 scope 影响;无则空数组
tasks
Array
待处理事项,受 scope 过滤;无则空数组
issues[].code / tasks[].code
String
问题码 / 待办码,取值见「六.5、枚举」
tasks[].taskCode
String
待办码(仅 tasks 有值),与 code 同值
issues[].codeLabel / tasks[].codeLabel
String
中文标签,后端给出直接展示;TRANSFER_PENDING 为「退团房未结清」
tasks[].orderId
Long(String)
源订单 ID;退团房条目取该行的源订单
tasks[].teamNo
String
源订单团号;取不到为 null
tasks[].groupBatchId / tasks[].batchNo
Long(String) / String
源团期 ID 与批次号;散单来源为 null
tasks[].stayDate
LocalDate
入住晚
tasks[].hotelId / hotelName / roomTypeId / roomTypeName
Long(String) / String
酒店与房型
tasks[].refId
Long(String)
关联单据 ID,TRANSFER_PENDING 为退团房父行 ID,前端据此跳转
tasks[].detail
String
说明文案,TRANSFER_PENDING 为「剩余 N 间待转出或向酒店取消」
请求示例
响应示例
空数据 / 降级响应
issues 与 tasks 恒为数组,不会是 null。
退团房条目的源单读不到(源订单或源团期查不到、或出发日为空)时,该条目仍然列出 ,teamNo / batchNo 可能为 null;口径是「宁可多报一条,也不让待办从唯一载体上消失」。
STOCK_LEDGER_MISMATCH(库存账不平)只在资源侧全局库存追踪开关打开时检查,开关关闭时不产出该问题码。
错误响应
code
message
触发
400
scope 取值非法
scope 不是 mine / all
808090
未登录或非房务角色,无权操作
非房务角色
808313
日期跨度不能超过 {0} 天
出发日期区间跨度超 92 天,或止日早于起日
业务边界
TRANSFER_PENDING 的归属判据是源团期 / 源订单的出发日落在窗口内 ,与源单当前状态(含已取消)无关;这是本次订正的点。
只列 PENDING 的退团房父行;已转出、已取消的行不是待办。
scope=mine 的「我的」按源单处理人判:散单来源看该需求持有人,团期来源看该团期房务认领人;源单读不到时该条目在 mine 下不会出现(无法判定处理人)。
窗口跨度上限 92 天,与控房表查询的 62 天不是同一个上限,别复用。
纯读接口,不写数据。
四、契约约束与正确调用方式(接口类必写)
✅ 正确 / ❌ 错误 payload 对照
场景
payload / 判断
✅ 设期限
{ "cancelDays": 3, "cancelCutoff": "18:00", "remindDays": 1 }
✅ 设期限只给天数
{ "cancelDays": 3 } → 截止时刻取 18:00、提醒天数取 1
✅ 清除期限
{ "cancelDays": null }(或整个 body 只有 {})→ 200,cancelCutoff / remindDays 保留原值
✅ 判「未设期限」
data.cancelDays === null,或 data.risk === "NO_DEADLINE"
❌ 判「未设期限」
data.cancelCutoff === null && data.remindDays === null——清除期限后这两项仍有值,该判断恒为 false
❌ 清除期限时显式传空
{ "cancelDays": null, "cancelCutoff": "", "remindDays": null } 能成功,但 cancelCutoff / remindDays 一样被忽略,不要指望用它们清值
❌ 期限天数越界
{ "cancelDays": 61 } → 808328(不是 400)
切换状态时的必要动作
清除期限成功后,前端应以返回的整行直接替换列表行,不要只把 cancelDays 置空——risk / riskLabel / deadlineAt 都由后端重算,本地推算会与「退团房分页」的汇总读数对不上。
「异常检查」页签的待办条数在订正后可能增加;若页面上有与之对照的徽标计数,改为直接用本端点返回的 tasks.length,不要沿用按订单状态自行过滤后的口径。
五、数据库行为(涉及写操作时必写)
写操作
外部可观察行为
设期限(cancelDays 非空)
该行的免费退改天数、截止时刻、提醒天数三项按入参(含默认值)整体更新;行版本 +1;写一条订单级操作日志「退团房 {入住晚} {酒店名} 免费退改期限改为入住前 N 天 HH:mm」
清除期限(cancelDays 为 null)
只有免费退改天数被清空 ;截止时刻与提醒天数保持该行原值;行版本 +1;写一条订单级操作日志「…免费退改期限改为未设」
并发保护
行级分布式锁 + 行版本比对;版本在锁定读与写之间被改则整笔回滚并返 808932
两个写路径都不产生跨服务调用,不发消息。
「异常检查」端点是纯读,不写任何数据。
六、边界行为
清除期限后再次设期限,若只传 cancelDays,截止时刻与提醒天数会被重新按默认值 18:00 / 1 覆盖 (不是沿用清除前保留下来的那两个值);要沿用旧值必须显式回传。
从未设过期限的新行,其截止时刻与提醒天数是建表默认的 "18:00" 与 1,所以「一行从没设过期限」与「设过又被清掉」在这两个字段上不可区分;唯一区分点是操作日志。
风险分档 NEAR 按「日」比较(今天 ≥ 截止日 − 提醒天数),同一天上午和下午不会给出不同分档。
退团房待办的取行只设窗口下限(入住晚不早于窗口起日),不设上限:待处理池量级小,多读回的行由源单出发日过滤掉。
scope=all 时任何房务都能看到全部待办条目,但看得见不等于能写;改期限仍按源单处理人校验(808326)。
六.5、枚举 / 数据字典(接口出现枚举时必写)
risk(退团房风险分档)
值
中文(riskLabel)
判据
OVERDUE
已过免费取消期
现在已过截止时刻
NEAR
临近免费取消期
今天 ≥ 截止日 − 提醒天数
NO_DEADLINE
未设免费取消期
cancelDays 为空(或该行缺入住晚)
NORMAL
正常
其余
仅 status = PENDING 的行有值,其余行 risk / riskLabel 均为 null。
status(退团房行状态)
值
中文(statusLabel)
说明
PENDING
待处理
还有剩余间数待转出或向酒店取消;只有这一状态能改期限
TRANSFERRED
已转出
全部间数已转给别的订单 / 团期
CANCELLED
已取消
已向酒店取消
taskCode / code(异常检查待办码,tasks[])
值
中文(codeLabel)
说明
TRANSFER_PENDING
退团房未结清
本次订正影响的就是这一类的取行范围
HOTEL_CANCEL_PENDING
原酒店待取消
改配留下的原订尚未确认取消
INQUIRY_PENDING
新订 / 变更待确认
—
STAY_UNARRANGED
住宿待落实
—
issues[] 的 code 取值域是另一组(STOCK_OVERBOOKED / STOCK_LEDGER_MISMATCH / STOCK_ROW_MISSING / TRANSFER_TARGET_GONE / PLAN_COUNT_MISMATCH),本次未变。
六.6、修改前后对比(修改/删除类接口必写,新增跳过)
字段级对比
字段
之前交接件写的
现在的实际行为
data.cancelCutoff(清除期限后)
被一并置空为 null
保留该行原值 (从未设过则为 "18:00")
data.remindDays(清除期限后)
被一并置空为 null
保留该行原值 (从未设过则为 1)
data.cancelDays(清除期限后)
null
null(不变)
data.deadlineAt(清除期限后)
null
null(不变)
data.risk / riskLabel(清除期限后)
NO_DEADLINE / 「未设免费取消期」
同(不变)
异常检查 tasks[] 结构
—
字段与类型均未变
行为级对比
行为
之前
现在
PUT .../deadline 传 cancelDays: null
恒定返回 808932「房务状态已被并发修改,请刷新后重试」,期限清不掉
返回 200 并给出更新后的整行
PUT .../deadline 传 cancelDays 非空
成功
成功(口径不变)
GET .../audit 的 TRANSFER_PENDING
源订单 / 源团期已取消的退团房行不出现在 tasks 里
按源单出发日归属、不看源单状态,这些行会出现
GET .../audit 的 TRANSFER_PENDING(源单查不到 / 出发日为空)
不出现
出现(宁可多报一条)
GET .../audit 的 issues[]
—
口径不变
六.7、影响评估(修改/删除类必写)
项
评估
需要前端改代码
是(1 处必改) :凡按 cancelCutoff / remindDays 是否为 null 判「有没有设期限」的地方,改为按 cancelDays === null 或 risk === "NO_DEADLINE" 判。
需要前端改代码
可能(1 处) :「异常检查」页签若自行按订单状态过滤过待办条目,去掉该过滤,直接用后端返回的 tasks。
兼容性
无字段增删、无类型变化、无路径与方法变化;只有取值与取行范围变化。
「清除期限」功能
从不可用变为可用,前端原有的 808932 报错提示分支在该场景不再触发(真并发冲突仍会返回它,不要删该分支)。
读数变化
同一出发日窗口下「异常检查」的待办行数只会增加或不变,不会减少。
其他消费方
退团房分页、转房、向酒店取消三个端点的契约未变;本次不涉及小程序端。
七、不影响范围(显式声明, 帮前端/QA 缩小排查面)
退团房分页 GET /v3/admin/order/house-console/room-transfers、转入候选 GET .../room-transfers/{id}/candidates、转房 POST .../room-transfers/{id}/transfer、向酒店取消 POST .../room-transfers/{id}/cancel-hotel:字段与口径均未变。
控房表(查询 / 调房量 / 调价 / 导出)、住宿模板、批量认领、改配取消确认、团期转交:未触及。
issues[] 的五类问题码及其判据未变。
房务只读标识 readOnly / readOnlyReason 的口径未变(其口径见 #8491 的两份交接件)。
通知、消息模板、跳转链接未变。
无数据库结构变更,无新增 Flyway 脚本,无网关路由改动。
八、测试环境已验证
项
读数
依据
hl-order-service-v3 运行的提交
d57498d38,BEHIND 0/N,STATE ok,时间 2026-09-30 05:32:57
测试服部署登记脚本 /opt/hulalv/scripts/deploy-status.sh,2026-09-30 本次读取
本次改动在运行的字节里
是
git merge-base --is-ancestor ff68637542 origin/dev-v3 返回 0;origin/dev-v3 头为 d57498d381
清除期限
cancelDays=null → code=200;库里免费退改天数为 NULL,截止时刻 / 提醒天数保留原值;risk=NO_DEADLINE
取证提交 ff6863754,读数原文记在 changelogs-v2/2026-09/30_8491_房务控制台接口-新增接口-管理后台.md 第 1847 行
设期限(回归)
cancelDays=3 → code=200、该行 risk=OVERDUE;cancelDays=0 + remindDays=1 → code=200、risk=NEAR
同上文件第 1845、1846 行,复测提交 ff6863754
退团房待办含源单已取消的行
源订单已取消 + 退团房行 PENDING + 窗口覆盖出发日 → code=200,tasks 含 TRANSFER_PENDING「退团房未结清」
同上文件第 1861 行,取证提交 ff6863754
用例覆盖
HouseRoomTransferManagerTest#updateDeadline_nullCancelDays_keepsRowCutoffAndRemind;HouseRoomTransferMapperMysqlTest#casUpdateDeadline_nullCancelDaysWithRowValues_writesNullAndKeepsCutoffRemind;HouseConsoleAuditManagerTest#audit_pendingTransferSourceOrderCancelledInWindow_listed / #audit_pendingTransferSourceBatchCancelledInWindow_listed / #audit_pendingTransferSourceOrderMissing_listed / #audit_pendingTransferSourceOrderDepartOutsideWindow_notListed
随 ff68637542 新增
九、相关历史 PR(纠错 / 功能演进时必写)
PR / 提交
内容
与本条的关系
PR #8564( 7c21cf0e40)
房务控制台整套(#8491),首次引入本文两个端点
被订正的表述出自它的交接件
PR #8599( ff68637542)
本条的两处修复(#8597)
本条正文描述的就是它合入后的行为
十、相关文档
本条 Issue: #8597( PR #8599)
被订正的交接件:changelogs-v2/2026-09/30_8491_房务控制台接口-新增接口-管理后台.md(接口 8 与接口 12)
只读标识口径:changelogs-v2/2026-09/30_8491_房务配房接口字段与口径调整-修改接口-管理后台.md
关联 / 联系人
链接
Issue: #8597
PR: #8599
分支基线: dev-v3
联系人