18 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 | 8517 | 预支审批中心列表与审批 / 驳回只放行财务与管理员(585008),撤回只放行申请人本人与管理员(585009),带 nacos 回滚开关 | admin | jw(GIT) | 修改接口 | deployed | verified | not_required | 已合并 dev-v3(e51832e8d)并部署 TEST,自签 token 经网关实测:列表 11 角色矩阵、不存在 advanceId 的三个写接口、真实预支的审批 / 驳回 / 撤回正反路径、nacos 开关关闭→还原往返(md5 逐字节还原)与服务端 ADVANCE_ACL_DENY 日志正反两面。前端判 not_required:审批中心菜单与通过 / 驳回按钮本来只授超管 / 管理员 / 财务;新错误码由 request.js 拦截器统一弹 message;撤回按钮对非申请人仍显示,点了会提示 585009,出参里没有申请人 id 供前端判断显隐(本单不改出参)。 | 2026-09-29 | dev-v3 |
order-v3: 预支审批中心列表与审批 / 驳回 / 撤回补角色守卫
服务: hl-order-service-v3
PR: #8531(已合入 dev-v3,合并提交 e51832e8d)
Issue: #8517
⚠️ 关键变化
🔴 审批中心列表、审批通过、驳回:只放行超管、管理员、财务,其余角色返回 585008。 改前任意后台账号都能看全公司预支、能审批(订单级预支审批通过会生成出纳待付款),只有团期管理员被挡。
🔴 撤回:只放行申请人本人和超管、管理员,其余返回 585009。 财务也不能撤别人的预支,要拦应走驳回并填原因。
🟢 四个接口的入参、出参、成功码全部不变。 有权限的调用方行为与改前一致。
一、背景
预支按设计由财务审批:管理后台「预支审批」菜单和通过 / 驳回按钮只授给超管、管理员、财务。但这四个接口此前只拒团期管理员,界面上进不去的角色直接调接口就能审批、查看全量预支、撤掉别人待审批的预支。本单补上接口层的判权。
二、变更接口清单
| # | 接口 | 方法 | 路径 | 变更类型 | 说明 |
|---|---|---|---|---|---|
| 1 | 预支审批列表 | GET | /v3/admin/order/advance-approvals/page |
修改 | 新增判权:只放行 SUPER_ADMIN / ADMIN / FINANCE,其余 585008;出参不变 |
| 2 | 预支审批通过 | PUT | /v3/admin/order/advance/:advanceId/approve |
修改 | 新增判权:同上,其余 585008;出参不变 |
| 3 | 预支审批驳回 | PUT | /v3/admin/order/advance/:advanceId/reject |
修改 | 新增判权:同上,其余 585008;出参不变 |
| 4 | 撤回待审批预支 | DELETE | /v3/admin/order/advance/:advanceId |
修改 | 新增判权:只放行申请人本人与 SUPER_ADMIN / ADMIN,其余 585009;出参不变 |
三、接口详情
1. 预支审批列表 GET /v3/admin/order/advance-approvals/page
VO: AdvanceApprovalPageReqVO → Result<PageResult<AdvanceApprovalPageItemRespVO>>
使用场景
管理后台「财务管理 → 预支审批」页的列表。本单起只有超管、管理员、财务能查。
入参字段表
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| page | Query | Integer | ❌ | ≥1 | 页码。行为不变 |
| pageSize | Query | Integer | ❌ | ≥1 | 每页条数。行为不变 |
| status | Query | String | ❌ | SUBMITTED / APPROVED / REJECTED / PAID |
缺省 SUBMITTED。行为不变 |
| 其余筛选项 | Query | — | ❌ | — | orderId / keyword / scope / payeeName / createdByName / 提交时间区间。行为不变 |
出参字段表
| 字段 | 类型 | 说明 |
|---|---|---|
| data | PageResult<AdvanceApprovalPageItemRespVO> |
结构完全不变(records / total / page / pageSize) |
请求示例
GET /v3/admin/order/advance-approvals/page?page=1&pageSize=20&status=SUBMITTED HTTP/1.1
Authorization: Bearer <财务账号 token>
响应示例
{
"code": 200,
"message": "成功",
"data": {
"records": [],
"total": 0,
"page": 1,
"pageSize": 20
},
"success": true
}
空数据 / 降级响应
无数据时 records 为空数组、total 为 0(行为不变)。降级:nacos advance.acl.enforce.role-guard 置 false 时回到改前行为(任意后台角色可查),但服务端每次仍留一条 ADVANCE_ACL_DENY 日志(enforced=false)。开关默认 true。
错误响应
| 码 | 符号 | 触发 | 本单 |
|---|---|---|---|
| 585008 | ADVANCE_APPROVAL_FORBIDDEN |
当前角色不是超管 / 管理员 / 财务(含缺角色的 token) | 🆕 新增 |
| 585005 | ADVANCE_STATUS_ILLEGAL |
status 不是合法取值 |
不变 |
585008 实打响应体(TEST,2026-09-29,定制师):
{
"code": 585008,
"message": "仅财务或管理员可查看预支审批、审批或驳回预支",
"data": null,
"success": false
}
业务边界
- 判权在查询之前,被拒时不返回任何数据。
- 团期管理员也返回
585008(本接口改前对它不设防)。
2. 预支审批通过 PUT /v3/admin/order/advance/:advanceId/approve
VO: OrderAdvanceRespVO(无请求体,出参 Result<OrderAdvanceRespVO>)
使用场景
预支审批页「通过」按钮:待审批(SUBMITTED)→ 已审批(APPROVED);订单级预支同时生成出纳待付款。本单起只有超管、管理员、财务能批。
入参字段表
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| advanceId | Path | Long | ✅ | 预支 ID | 行为不变 |
出参字段表
| 字段 | 类型 | 说明 |
|---|---|---|
| data | OrderAdvanceRespVO |
结构完全不变;status=APPROVED,approvedBy 为审批人姓名 |
请求示例
PUT /v3/admin/order/advance/2104861625016287233/approve HTTP/1.1
Authorization: Bearer <财务账号 token>
响应示例
{
"code": 200,
"message": "成功",
"data": {
"id": "2104861625016287233",
"status": "APPROVED",
"approvedBy": "jw",
"rejectReason": null
},
"success": true
}
空数据 / 降级响应
无空数据语义。降级:nacos 开关置 false 时回到改前行为(除团期管理员外任意后台角色可批),仍留 ADVANCE_ACL_DENY 日志。团期管理员的 581008 不读该开关,关掉也照拒。
错误响应
| 码 | 符号 | 触发 | 本单 |
|---|---|---|---|
| 585008 | ADVANCE_APPROVAL_FORBIDDEN |
当前角色不是超管 / 管理员 / 财务。先于预支存在性校验,预支不存在也返回本码 | 🆕 新增 |
| 581008 | ORDER_VIEW_FORBIDDEN |
团期管理员(排在最前) | 不变 |
| 585000 | ADVANCE_NOT_FOUND |
有权角色操作不存在的预支 | 不变 |
| 585005 | ADVANCE_STATUS_ILLEGAL |
预支不是待审批 | 不变 |
{
"code": 585008,
"message": "仅财务或管理员可查看预支审批、审批或驳回预支",
"data": null,
"success": false
}
业务边界
- 被拒时零写入:预支状态不变,也不会生成出纳待付款。
- 定制师审批自己申请的预支同样返回
585008。 - 本单不限制「管理员 / 财务审批自己申请的预支」(职责分离不在本单范围)。
3. 预支审批驳回 PUT /v3/admin/order/advance/:advanceId/reject
VO: RejectAdvanceReqVO → Result<OrderAdvanceRespVO>
使用场景
预支审批页「驳回」按钮:待审批(SUBMITTED)→ 已驳回(REJECTED),须填驳回原因。本单起只有超管、管理员、财务能驳。
入参字段表
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| advanceId | Path | Long | ✅ | 预支 ID | 行为不变 |
| reason | Body | String | ✅ | 非空 | 驳回原因。行为不变 |
出参字段表
| 字段 | 类型 | 说明 |
|---|---|---|
| data | OrderAdvanceRespVO |
结构完全不变;status=REJECTED,rejectReason 为驳回原因 |
请求示例
PUT /v3/admin/order/advance/2104861622562627585/reject HTTP/1.1
Authorization: Bearer <财务账号 token>
Content-Type: application/json
{"reason": "门票已由地接社统一采购,无需个人垫付"}
响应示例
{
"code": 200,
"message": "成功",
"data": {
"id": "2104861622562627585",
"status": "REJECTED",
"approvedBy": "jw",
"rejectReason": "门票已由地接社统一采购,无需个人垫付"
},
"success": true
}
空数据 / 降级响应
无空数据语义。降级口径同「审批通过」。
错误响应
| 码 | 符号 | 触发 | 本单 |
|---|---|---|---|
| 585008 | ADVANCE_APPROVAL_FORBIDDEN |
当前角色不是超管 / 管理员 / 财务;先于存在性校验 | 🆕 新增 |
| 581008 | ORDER_VIEW_FORBIDDEN |
团期管理员 | 不变 |
| 585000 / 585005 | — | 预支不存在 / 不是待审批 | 不变 |
{
"code": 585008,
"message": "仅财务或管理员可查看预支审批、审批或驳回预支",
"data": null,
"success": false
}
业务边界
- 被拒时零写入:状态与驳回原因都不变。
4. 撤回待审批预支 DELETE /v3/admin/order/advance/:advanceId
VO: Result<Void>(无请求体)
使用场景
订单详情「预支」弹窗、团期详情「财务」页签里的「撤回」按钮:撤掉一笔还没审批的预支。本单起只有申请人本人和超管、管理员能撤。
入参字段表
| 字段 | 位置 | 类型 | 必填 | 约束 | 说明 |
|---|---|---|---|---|---|
| advanceId | Path | Long | ✅ | 预支 ID | 行为不变 |
出参字段表
| 字段 | 类型 | 说明 |
|---|---|---|
| data | null |
不变 |
请求示例
DELETE /v3/admin/order/advance/2104861626131980289 HTTP/1.1
Authorization: Bearer <申请人本人 token>
响应示例
{
"code": 200,
"message": "成功",
"data": null,
"success": true
}
空数据 / 降级响应
无空数据语义。降级:nacos 开关置 false 时回到改前行为(除团期管理员外任意后台角色可撤),仍留日志。
错误响应
| 码 | 符号 | 触发 | 本单 |
|---|---|---|---|
| 585009 | ADVANCE_REVOKE_FORBIDDEN |
既不是这笔预支的申请人,也不是超管 / 管理员(财务也返回本码)。非管理员撤不存在的预支也返回本码 | 🆕 新增 |
| 581008 | ORDER_VIEW_FORBIDDEN |
团期管理员 | 不变 |
| 585000 | ADVANCE_NOT_FOUND |
超管 / 管理员撤不存在的预支 | 不变 |
| 585005 | ADVANCE_STATUS_ILLEGAL |
预支已审批 / 已驳回 | 不变 |
{
"code": 585009,
"message": "仅申请人本人或管理员可撤回该预支",
"data": null,
"success": false
}
业务边界
- 「申请人」指提交这笔预支的后台账号,按账号 ID 判定,不按姓名。
- 被拒时零写入:预支不删。
- 期初结转等没有申请人记录的存量预支,只有超管、管理员能撤。
四、契约约束与正确调用方式
- 新错误码
585008/585009直接透出message即可。 - 撤回按钮目前对所有能看到待审批预支的人显示;非申请人点击会收到
585009。出参里没有申请人账号 ID,本单不改出参,按钮显隐暂不能按申请人精确控制。 - 同时挂财务与其它角色的账号,要切到财务角色才能进审批中心(后端按当前角色判定)。
五、数据库行为
- 零 DDL、零数据迁移。
- 撤回的「申请人」取预支记录既有的创建人字段(提交预支时自动写入);TEST 现存预支该字段全部有值。
- 被拒绝的请求不写库。
六、边界行为
- 有权限的调用方:与改前完全一致。
- 缺角色的 token:列表 / 审批 / 驳回返回
585008;撤回只要是申请人本人仍可撤。 - 系统内部调用(定时任务、消息消费等无请求的场景)不受限制。
- 团期管理员:审批 / 驳回 / 撤回仍先返回
581008;列表返回585008。
六.6、修改前后对比
| 角色 | 列表 | 审批 / 驳回 | 撤回别人的预支 | 撤回自己的预支 |
|---|---|---|---|---|
SUPER_ADMIN / ADMIN |
正常 → 正常 | 正常 → 正常 | 正常 → 正常 | 正常 → 正常 |
FINANCE |
正常 → 正常 | 正常 → 正常 | 正常 → 585009 | 正常 → 正常 |
CUSTOMIZER |
正常 → 585008 | 正常 → 585008 | 正常 → 585009 | 正常 → 正常 |
| 车务 / 房务 / 房务组长 / 运营 / 客服 | 正常 → 585008 | 正常 → 585008 | 正常 → 585009 | 正常 → 正常 |
GROUP_BATCH_MANAGER |
正常 → 585008 | 581008 → 不变 | 581008 → 不变 | 581008 → 不变 |
六.7、影响评估
- 是否破坏向后兼容:对有权限的调用方否;对无权限的调用方,原来能成功的请求改为返回新错误码。
- 前端是否必须同步上线:否。
- 回滚:nacos
advance.acl.enforce.role-guard置false,TEST 实测 5.6 秒内生效,不需重发服务。
七、不影响范围
- 创建预支
POST /v3/admin/order/:orderId/advance、借款对象候选、本单预支列表GET /v3/admin/order/:orderId/advances:判权不变。 - 团期发起预支、团期财务页签的预支列表:判权不变。
- 财务出纳付款:本单未改。
- 小程序端:无影响。
八、测试环境已验证
环境:TEST(https://api.test.1814.love) 验证时间:2026-09-29 17:08~17:15
构建身份:order-v3 部署 dev-v3 @ e51832e8d(本单合并提交),17:08 完成。零写入判据:旧字节里定制师查审批列表返回 200 和数据,新字节才会返回 585008;部署后连打 6 次全部 585008,同时管理员 200。
身份:自签 token 直打网关,未只用超管;TEST 上没有持财务角色的账号,财务身份用 role=FINANCE 的自签 token。
8.1 列表角色矩阵
| 角色 | 结果 |
|---|---|
| SUPER_ADMIN / ADMIN / FINANCE | 200,status=PAID 返回 2 条 |
| CUSTOMIZER / VEHICLE_MANAGER / ROOM_MANAGER / house_keeper_lead / GROUP_BATCH_MANAGER / OPERATOR / CUSTOMER_SERVICE / 缺角色 | 585008,data 为 null |
8.2 不存在的预支 ID(零写入)
| 角色 | 审批 | 驳回 | 撤回 |
|---|---|---|---|
| CUSTOMIZER / VEHICLE_MANAGER | 585008 | 585008 | 585009 |
| FINANCE | 585000(过守卫) | 585000(过守卫) | 585009 |
| ADMIN | 585000 | 585000 | 585000 |
| GROUP_BATCH_MANAGER | 581008 | 581008 | 581008 |
前后预支表、出纳执行单表行数不变。
8.3 真实预支的正反路径
在待出发订单 HL20260918082629372 上以定制师身份提交 4 笔预支(门票 380、餐费 260、门票 150、餐费 120):
| 操作 | 结果 |
|---|---|
| 其他定制师 / 车务管理员 / 申请人本人审批 380 那笔 | 均 585008,仍待审批,出纳执行单 0 行 |
| 其他定制师驳回 | 585008,驳回原因为空 |
| 财务、其他定制师撤回 | 均 585009,未删除 |
| 财务驳回 | 200,已驳回,出纳执行单 0 行 |
| 其他定制师审批 260 那笔 | 585008;随后财务审批 200,已审批,出纳执行单 1 行 |
| 申请人本人撤回 150 那笔 | 200,已软删 |
| 管理员撤回 120 那笔(别人申请的) | 200,已软删 |
8.4 nacos 回滚开关往返
配置 hl-order-service-v3-test.yml(tenant=test)原本不含 advance.* 键,即默认 true。
| 态 | 配置 | 定制师查列表 | 定制师审批不存在的预支 | 定制师撤不存在的预支 | 团期管理员审批 |
|---|---|---|---|---|---|
| A | 无键(默认 true) |
585008 |
585008 |
585009 |
581008 |
| B | 追加 role-guard: false |
200(5.6 秒内生效) |
585000(回到改前) |
585000(回到改前) |
581008(不受开关影响) |
| C | 逐字节还原 | 585008(9.3 秒内生效) |
— | — | — |
- 发布带
casMd5,还原写在finally里;还原后 md5 与原值同为c2206934960057f70b7173159046dc54。 - 服务端日志(两个实例合计):
ADVANCE_ACL_DENY ... enforced=false只出现在 B 态的 17:14:37~43,共 9 条,与 B 态调用次数一致;A、C 两态只有enforced=true。
本地证据
| 项 | 读数 |
|---|---|
| 新增 4 个测试类 | 51 例全绿(守卫 29、绑定器 6、Controller 7、撤回 9) |
| 预支包 + ArchTest + 错误码门禁 + 切片清单 | 249/0/0/0 |
| order-v3 全量(有 Docker) | 14519 例,9F / 8E;红的 7 个类在基底 48e66bd06 上逐类、逐用例名一致,本单零新增失败 |
| 变异 | 删掉审批端点守卫 → 1 例红;开关判定上提到方法头 → 12 例红;已还原 |
十、相关文档
- Issue
#8517;PR#8531 docs/finance/api/API-SPEC-FINANCE-V1.0.html§2.4.4(补判权口径)docs/group/团期模块接口文档-v2.0.html§0B.9、docs/group/数据模型.html§A.11.12、docs/group/实施单/11-财务与预支.html(错误码表补 585008 / 585009)
关联 / 联系人
链接
联系人
- 后端负责人: @jw