19 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 | 8401 | 房务配房台账联动:确认缺团号拒绝、清空/改价审计应付行 | admin | wx(GIT) | 修改接口 | deployed | verified | not_required | PR #8402 已合入 dev-v3(合并提交 57199b539);2026-09-27 部署测试环境并经网关实测 AC-1 至 AC-4;pre-flight 核对部署 COMMIT=57199b539 STATE=ok【2026-09-27 mmg】前端判 not_required(零代码):808188/599602 grep 前端零引用无错误码字典;五个配房写口全走标准 http 封装无 silentError,消费方三 composable catch 均由 request.js 拦截器统一弹 message(该拦截器对 4xxxxx/5xxxxx 全业务码透 body.message);改价/删除改前本就抛 599600/599601 前端零按码处理,599xxx 同路;§6.7 自述「前端 100% 透明」与实证一致,建议文案「请先完成收款/联系财务解冻」是 UX 建议非契约,后端 message 已可达因。 | 2026-09-27 | dev-v3 |
房务配房台账联动:确认前置关卡、改价/清空应付行审计
服务: hl-order-service-v3 PR: #8402 | Issue: #8401 | 合并提交:
57199b539影响范围: 管理后台「房务配房工作台 → 配房确认、改价、删除、清空」、应付款台账行联动
⚠️ 关键变化
确认配房前新增团号检查;改价、删除、清空配房时对应付款台账行作同事务作废与冻结校验。
三类场景导致配房行 CONFIRMED 但缺应付台账行或行被占用:
| 场景 | 原行为 | 新行为 |
|---|---|---|
| 确认配房时团号未生成(收款前) | 200 成功但不推台账 | 拒绝,新错误码 808188 |
| 改价/删除该行时其无台账 | 改前 599601、删前 599601 | 改后 200(只改价不补推);删后 200(正常软删) |
| 改价/删除/清空时台账被占用 | 各自独立校验 | 统一 599602「应付款台账行已锁定」 |
契约边界:改价只是数值标度不同(265 vs 265.00)不再视作改价,应付行不作废。
一、背景
房务配房成立应付款「该付供应商的钱」的凭据,必须在确认时同事务落应付款台账行。多轮测试发现三处漏洞:
- 无团号可确认:订单未收款时 team_no 为空,确认应该被拒,原实现放行确认但不推台账,留下「CONFIRMED 但无台账」。
- 改价/删除无审计:已确认配房改结算价、删除或清空时,假设被操作行原本就有应付台账,实际可能无行(存量或异常路径产生),改前的"有台账才改"假设不再成立。
- 应付行被占用时整体锁定:付款草稿(PENDING)、已付款(applied > 0)的应付行应该阻止对应配房的清空,整笔清空拒绝、一条都不删。
二、变更接口清单
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|---|---|---|---|---|
| 1 | 单日确认配房 | POST | /v3/admin/order/hotel-requirements/{requirementId}/assignments/days/{dayNumber}/confirm |
行为变更 | 订单 team_no 为空时拒绝,新错误码 808188;配房行保持 INQUIRING,不生成应付台账 |
| 2 | 修改单条配房 | PUT | /v3/admin/order/assignments/{id} |
副作用变更 | 改结算价时,原无应付台账行的只改价不补推;原有台账行的作废旧行按新价重推;只是标度不同不视作改价 |
| 3 | 删除配房 | DELETE | /v3/admin/order/assignments/{id} |
副作用变更 | 已确认但无应付台账行的配房删除不再报 599601,正常 200 软删 |
| 4 | 清空整需求配房 | DELETE | /v3/admin/order/hotel-requirements/{requirementId}/assignments |
校验变更 | 清空时同步作废已确认配房的应付台账行;台账行被占用时整体拒绝 599602 |
| 5 | 清空某天配房 | DELETE | /v3/admin/order/hotel-requirements/{requirementId}/assignments/days/{dayNumber} |
校验变更 | 同接口 4,按日分流 |
三、接口详情
1. 单日确认配房 POST /v3/admin/order/hotel-requirements/{requirementId}/assignments/days/{dayNumber}/confirm
VO: AssignmentDayConfirmReqVO
使用场景
房务配房工作台选择该天候选配房后点「确认」,调用该接口保留选中行、软删落选行、推送应付款台账。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
requirementId |
Path | Long | ✅ | — | 房型需求 id |
dayNumber |
Path | Integer | ✅ | ≥1 | 第几晚(从 1 开始) |
keepAssignmentIds |
Body | List<Long> | ❌ | 非空时每个 id 须属于该天候选 | 要保留确认的配房行 id;缺省为空(保留全部) |
出参 Result<Void>
| 字段 | 类型 | 说明 |
|---|---|---|
data |
Null | 无返回体 |
请求示例
{
"keepAssignmentIds": [2104045881147965442]
}
响应示例
确认成功:
{
"code": 200,
"message": "成功",
"success": true,
"data": null
}
空数据 / 降级响应
入参 keepAssignmentIds 为空时视为保留该天全部候选,该天无候选时返回 808118:
{
"code": 808118,
"message": "该天无可确认的询房中候选, 请先配房再确认",
"success": false,
"data": null
}
错误响应
新增错误码 808188:订单团号未生成(收款前)时拒绝确认:
{
"code": 808188,
"message": "订单团号未生成(收款后生成),暂不能确认配房",
"success": false,
"data": null
}
保留的配房行不属于该天候选时 fail-fast 拒绝:
{
"code": 808123,
"message": "保留的配房行不属于该天询房中候选(可能配房已更新), 请刷新后重试",
"success": false,
"data": null
}
业务边界
- 团号检查:CORE 订单检查
order_main.team_no非空;GROUP 订单检查班期batch_no(列定义 NOT NULL,实际打不到) - 台账推送时点:确认成功后即事务内推送应付款 NORMAL 行,金额 =
settlementPrice × roomCount,团号为键 - 并发场景:后到的确认请求仍可能收到 599601(两个请求并发取消同一行时)
- 幂等性:同 (requirementId, dayNumber) 3 秒内重复确认拒绝
- 存量一致性:确认不改变 SQL 求交逻辑,该天无 INQUIRING 候选照旧报 808118
2. 修改单条配房 PUT /v3/admin/order/assignments/{id}
VO: AssignmentUpdateReqVO
使用场景
房务工作台配房行改价/备注/支付方式时调用;路径参数、出参结构、签名、权限均未变。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
id |
Path | Long | ✅ | — | 配房行 id(house_hotel_assignment.id) |
protoPrice |
Body | BigDecimal | ❌ | ≥0 | 原始供应商报价 |
settlementPrice |
Body | BigDecimal | ❌ | ≥0 | 结算价(现在改后作废旧台账行) |
settlementMethod |
Body | String | ❌ | 枚举值 | 支付方式 |
remark |
Body | String | ❌ | — | 备注 |
出参 Result<Void>
| 字段 | 类型 | 说明 |
|---|---|---|
data |
Null | 无返回体 |
请求示例
改结算价:
{
"settlementPrice": "380.00",
"remark": "协议优惠"
}
响应示例
改价成功(原无应付台账行,只改价不补推):
{
"code": 200,
"message": "成功",
"success": true,
"data": null
}
空数据 / 降级响应
无特殊空数据;行不存在或权限不足时返回对应业务码。
错误响应
应付款台账行已被占用(付款申请占用或已付款):
{
"code": 599602,
"message": "应付款台账行已锁定",
"success": false,
"data": null
}
业务边界
- 改价判定:值的数值部分不同才视作改价(
265.00与265.000视同不改),例如380.00→390.00才作废旧台账 - 无台账行的改价:仅改配房行,不补推台账行(存量中部分 CONFIRMED 配房原本就无台账)
- 有台账行的改价:作废旧 NORMAL 行 + 按新价重推新行(仅限该配房对应的台账)
- 新价校验:若新价导致
settlementPrice × roomCount ≤ 0,重推 fail-fast 报 599600(与改前逻辑一致) - 并发场景:改价与删除/清空并发时,清空可能因台账被占用而拒,改价则进行中
3. 删除配房 DELETE /v3/admin/order/assignments/{id}
VO: StaffAssignmentVO
使用场景
房务工作台删除单条配房行;路径参数、出参结构、签名、权限均未变。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
id |
Path | Long | ✅ | — | 配房行 id |
出参 Result<Void>
| 字段 | 类型 | 说明 |
|---|---|---|
data |
Null | 无返回体 |
请求示例
DELETE /v3/admin/order/assignments/2100873375659266050
响应示例
删除成功:
{
"code": 200,
"message": "成功",
"success": true,
"data": null
}
空数据 / 降级响应
行不存在或权限不足时返回 808120 或 808110。
错误响应
应付款台账行已被占用:
{
"code": 599602,
"message": "应付款台账行已锁定",
"success": false,
"data": null
}
业务边界
- 已确认无台账的删除:改前报 599601,改后正常 200 软删(存量或异常路径产生的 CONFIRMED 无台账行)
- 已确认有台账的删除:行被占用时报 599602,阻止删除;未被占用时正常软删并同步作废应付行
- 幂等性:同一行删除后重删报 808120(行已软删、再读不到)
- 与清空互斥:单行删除与整需求/整天清空互斥,串行化执行
4. 清空整需求配房 DELETE /v3/admin/order/hotel-requirements/{requirementId}/assignments
VO: AssignmentClearRespVO
使用场景
房务工作台清空整个住宿需求下全部配房行,调用该接口一次性清空、同步作废应付台账。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
requirementId |
Path | Long | ✅ | — | 房型需求 id |
出参 Result<AssignmentClearRespVO>
| 字段 | 类型 | 说明 |
|---|---|---|
clearedCount |
Integer | 清空行数 |
请求示例
DELETE /v3/admin/order/hotel-requirements/2104045736624820226/assignments
响应示例
清空成功:
{
"code": 200,
"message": "成功",
"success": true,
"data": {
"clearedCount": 2
}
}
空数据 / 降级响应
需求无配房行时 clearedCount=0,接口仍 200:
{
"code": 200,
"message": "成功",
"success": true,
"data": {
"clearedCount": 0
}
}
错误响应
清空范围内任一配房的应付台账行被付款申请占用或已付款,整体拒绝(一条都不删):
{
"code": 599602,
"message": "应付款台账行已锁定",
"success": false,
"data": null
}
业务边界
- 整体性:检查待清空全部 CONFIRMED 行的应付台账,任一被占用则整笔拒绝(失败时零行被删)
- 应付行同步作废:清空成功后同事务作废该需求对应的全部 NORMAL 台账行(无论是否被占用)
- 不动抢单:清空仅删配房,不释放抢单人、不回抢单池
- 幂等性:同需求 3 秒内重复清空拒绝
- 部分被占用的场景:假设需求 2 个 CONFIRMED 行,其中 1 个台账被占用,整批拒、2 行都保留
5. 清空某天配房 DELETE /v3/admin/order/hotel-requirements/{requirementId}/assignments/days/{dayNumber}
VO: AssignmentClearRespVO
使用场景
房务工作台行程日行内「清空」按钮,调用该接口清空该天全部配房,无关其他天。
入参
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
requirementId |
Path | Long | ✅ | — | 房型需求 id |
dayNumber |
Path | Integer | ✅ | ≥1 | 第几晚(从 1 开始) |
出参 Result<AssignmentClearRespVO>
| 字段 | 类型 | 说明 |
|---|---|---|
clearedCount |
Integer | 清空行数 |
请求示例
DELETE /v3/admin/order/hotel-requirements/2104045736624820226/assignments/days/1
响应示例
清空成功:
{
"code": 200,
"message": "成功",
"success": true,
"data": {
"clearedCount": 1
}
}
空数据 / 降级响应
该天无配房行时 clearedCount=0,接口仍 200:
{
"code": 200,
"message": "成功",
"success": true,
"data": {
"clearedCount": 0
}
}
错误响应
该天清空范围内任一配房的应付台账行被占用,整体拒绝:
{
"code": 599602,
"message": "应付款台账行已锁定",
"success": false,
"data": null
}
业务边界
- 按日分流:仅清空该天配房,不影响其他晚次
- 应付行同步:清空成功后同事务作废该天对应的应付台账行
- 台账冻结:该天任一台账被占用,整天清空拒绝
- 幂等性:同 (requirementId, dayNumber) 3 秒内重复清空拒绝
- 与单行删除互斥:整天清空与单行删除由同一分布式锁保护
四、契约约束与正确调用方式
- 团号时点:收款后(manual-receipt 或 transition 路径产生团号),确认前 team_no 必须非空
- 应付台账键:落库应付行时以 team_no 为业务键,确认失败时台账行零行存在
- 改价与标度:小数点后补零(
265→265.00)不视作改价,应付行不变;需财务的驳回或重新定价时前端提示「联系财务调整」 - 台账被占用判定:
fin_payable_line.applied > 0(付款申请已占用)或支付单已删除但applied未清零时视作被占用 - 清空原子性:清空失败为原子操作,检查与删除在同一事务内,失败时零行被删
- 权限一致性:全部接口遵循现有权限校验规则,本单无权限变更
五、数据库行为
无 DDL、无迁移、无新增列。行为变化:
| 表 | 列 | 变化 |
|---|---|---|
house_hotel_assignment |
confirm_status |
确认拒绝 808188 时保持 INQUIRING(不翻态) |
fin_payable_line |
— | 改价/删除/清空时按新规则作废旧行(deleted_at = 当前时刻) |
fin_payable_line |
applied |
作废时 applied 不清零,保留历史记录 |
| 其他表 | — | 无变化 |
���、边界行为
- 确认前团号为空 → 808188,拒绝,配房行保持 INQUIRING,台账零行
- 改价无台账行 → 200,只改配房行
- 改价有台账行 → 200,作废旧行按新价重推
- 改价新价非法 → 599600,与改前一致
- 删除无台账行 → 200,正常软删
- 删除有台账被占用 → 599602,拒绝
- 清空全部被占用 → 599602,整批拒
- 清空部分被占用 → 599602,整批拒(一条都不删)
六.5、枚举 / 数据字典
本次新增错误码 808188 HOUSE_TEAM_NO_MISSING:「订单团号未生成(收款后生成),暂不能确认配房」。
统一使用错误码 599602 PAYABLE_LINE_LOCKED 表示应付台账行被占用(原为单行改价/删除场景,改后扩展到清空场景)。
六.6、修改前后对比
| 项 | 变更前 | 变更后 |
|---|---|---|
| 无团号确认 | 200 成功但不推台账 | 808188 拒绝 |
| 无台账改价 | 599601 回滚 | 200 成功(只改价) |
| 无台账删除 | 599601 回滚 | 200 成功(正常删除) |
| 有台账改价 | 599601 / 200 异常组合 | 200 成功(作废旧+新推) |
| 清空整需求 | 无台账冻结校验 | 任一被占用则整体拒 |
| 清空按天 | 无台账冻结校验 | 该天任一被占用则整天拒 |
| 台账占用拒绝码 | 599602(单行)/ 零(清空) | 统一 599602 |
| 路径、入参、出参结构 | — | 全部不变 |
六.7、影响评估
| 维度 | 评估 |
|---|---|
| 兼容性 | 对前端 100% 透明。路径、入参、出参结构、HTTP 方法均未变;行为变更仅增加拒绝场景(无团号确认、台账被占用),不破坏现有成功调用 |
| 前端 | 无需改动。错误码 808188 交付时前端应已配置提示「请先完成收款」,599602 提示沿用「联系财务解冻」 |
| 数据 | 无 DDL、无迁移、无回填 |
| 性能 | 改价、删除、清空时新增应付行查询与冻结校验,单次 O(n)(n=配房行数,通常 <10) |
| 回滚 | git revert,单一 PR,无数据侧残留 |
| 风险 | 低。前置检查只能降低風险、不会升高;应付行作废改为同事务内原子操作,消除中间态 |
七、不影响范围
- 零影响:所有接口的路径、HTTP 方法、入参结构
- 零影响:出参结构(均为 Result 或 Result)
- 零影响:权限校验、鉴权闸口
- 零影响:库存扣减逻辑(确认失败不改库存,改价/删除不再动库存)
- 零影响:房型快照、房型冻结逻辑
- 零影响:与定制师的交互(改期、驳回等)
- 零影响:订单状态机推进(resource_ready / confirm 等)
八、测试环境已验证
✅ 2026-09-27 于测试环境网关实测,真实鉴权(房务端)。
- 网关
https://api.test.1814.love,分支dev-v3,部署提交57199b539 - pre-flight:
ssh -p 2220 root@192.168.100.236 bash /opt/hulalv/scripts/deploy-status.sh确认 COMMIT=57199b539 STATE=ok
| # | 用例 | 期望 | 实测 |
|---|---|---|---|
| AC-1 | 无台账行改价 / 删除 | 200,无台账新增 | ✅ 改价 0→0;删除 0→0(夹具:2 条存量行) |
| AC-2 | 确认后删除、清空、改价 | 200,应付行同步作废 | ✅ confirmed→deleted_at(SQL 验证) |
| AC-3 | 清空时付款草稿占用 | 599602,0 行被删 | ✅ 整天拒,deleted_at 仍 NULL |
| AC-4 | team_no 为空确认 | 808188 拒绝 | ✅ INQUIRING 未翻态,fin_payable_line COUNT=0 |
观察:部署后服务无重启,双实例持续 running,日志最近 200 行 ERROR / Exception 命中 0 条。
存量数据:测试环境所造数据一律 AC-* 前缀,验证后已物理删除,残留合计 0 条。
十、相关文档
- 房务配房 API 规范:
docs/apis/house/assignments/(dev-v3 分支) - 应付款台账设计:
docs/finance/payable-lines.md - 团号生成规则:
docs/order/team-no-generation.md
关联 / 联系人
- Issue: #8401
- PR: #8402(合并提交
57199b539)