hl-api-changelog/changelogs-v2/2026-08/04_5477_核单其他收入字段收口-修改接口-管理后台.md
Mimingguang 7a54feb25d
一些检查失败了
changelog-filename-gate / validate (push) Failing after 1s
chore(changelog): 更新 #5477 前端交付引用
修改原因:其他收支日期控件与列宽在联调反馈后继续收敛,需要让 source 指向最新完整交付。

修改内容:将 #5477 frontend_ref 更新为 hl-admin@9f46fa040a77cd899bbc9c21b9b8304a518499e2。

实际验证:日期控件提交通过定向 Vitest,列宽调整通过 pnpm checkpoint 和生产构建,业务提交已推送 origin/v2.1。
2026-08-04 17:04:32 +08:00

21 KiB

schema, ticket, title, consumer, change_type, author, backend_status, gateway_status, frontend_status, frontend_owner, frontend_ref, target_release, verified_at, status_note, updated_at, base
schema ticket title consumer change_type author backend_status gateway_status frontend_status frontend_owner frontend_ref target_release verified_at status_note updated_at base
hl-changelog/v2 5477 核单其他收入移除项目类别与票种规格字段 admin 修改接口 yaosutu(GIT) deployed verified implemented pi-main-session hl-admin@9f46fa040a77cd899bbc9c21b9b8304a518499e2 2026-08-04 PR #5488 已合并 dev-v3;测试服真实网关已验证 POST 无旧字段成功、PUT 多传旧字段被忽略、GET/POST/PUT 响应均不含 projectCategory/projectCategoryName/specification。前端需删除项目类别与票种规格控件及相关字段读写。 2026-08-04 dev-v3

⚠️ 修改接口·管理后台】核单其他收入移除项目类别与票种规格字段(#5477

PR: #5488 | 服务: hl-order-service-v3 | 更新时间: 2026-08-04 16:30

1. 接口背景

“其他收入”页签本身已表达项目类型,继续要求填写“项目类别”属于重复信息;“票种/规格”也不适用于其他收入。此次统一收口新增、修改和查询契约,前端应删除这两个控件及相关字段读写。

2. 变更清单

# 接口 方法 路径 变更类型 前端动作
1 查询其他收入核单明细及增减费汇总 GET /v3/admin/order/{orderId}/settlement/other-incomes 删除出参字段 停止读取 projectCategoryprojectCategoryNamespecification
2 新增其他收入并原子创建订单增费 POST /v3/admin/order/{orderId}/settlement/other-incomes 删除入参、出参字段 删除项目类别与票种规格控件;停止传两个旧入参
3 修改其他收入 PUT /v3/admin/order/{orderId}/settlement/other-incomes/{incomeId} 删除入参、出参字段 删除项目类别与票种规格控件;停止传两个旧入参

DELETE 接口签名与返回结构未变化,不属于本次契约变更。

3. 接口详情

3.1 查询其他收入核单明细及增减费汇总

  • 方法/路径GET /v3/admin/order/{orderId}/settlement/other-incomes
  • 使用场景:进入其他收入页签,以及新增、修改、删除后刷新明细和汇总。
  • 认证:需要管理后台登录态;配房角色不可访问。
  • 幂等性:只读接口,可安全重复调用。
  • 限流:未声明接口专属限流。

路径参数

字段 类型 必填 说明 校验
orderId String(Long) 订单 ID 必须大于 0

请求体:无。

成功响应 data

字段 类型 可空 说明
items OtherIncomeItem[] 其他收入明细;无数据返回 []
deductions Deduction[] 只读减费明细;无数据返回 []
summary Summary 当前有效增减费汇总

OtherIncomeItem 完整字段:

字段 类型 可空 说明
id String(Long) 其他收入 ID
requestId String 手工新增幂等请求 ID;自动投影时为空
incomeDate LocalDate 收入日期,YYYY-MM-DD
projectName String 项目名称
quantity Decimal 数量
unitPrice Decimal 核算单价
settlementAmount Decimal 核算金额
paymentMethod String 付款类型,见 §6.1
paymentMethodName String 付款类型中文名
voucherUrls String[] 凭证 URL 列表
settlementConfirmStatus String 确认状态,见 §6.2
settlementConfirmStatusName String 确认状态中文名
remark String 备注
sourceType String 来源类型,见 §6.3
sourceTypeName String 来源类型中文名
sourceId String(Long) 来源附加费 ID

Deduction 完整字段:

字段 类型 可空 说明
id String(Long) 减费 ID
discountName String 减费名称
discountAmount Decimal 减费金额
sourceType String 来源类型
sourceId String(Long) 来源业务 ID
createdAt LocalDateTime 创建时间

Summary 完整字段:

字段 类型 说明
surchargeAmount Decimal 有效增费合计
discountAmount Decimal 有效减费合计
netAdjustmentAmount Decimal 净调整额,即增费减去减费

本接口错误码与业务边界:见 §7、§9;查询不允许再依赖三个已删除字段。

典型成功示例

GET /v3/admin/order/2084000000000002978/settlement/other-incomes
Authorization: Bearer <token>
{
  "code": 200,
  "message": "success",
  "data": {
    "items": [{
      "id": "2084000000000004978",
      "requestId": "oi-5477-0001",
      "incomeDate": "2026-08-04",
      "projectName": "酒店升级补差",
      "quantity": 2,
      "unitPrice": 12.34,
      "settlementAmount": 24.68,
      "paymentMethod": "COMPANY_PAID",
      "paymentMethodName": "公司付款",
      "voucherUrls": [],
      "settlementConfirmStatus": "UNCONFIRMED",
      "settlementConfirmStatusName": "未确认",
      "remark": null,
      "sourceType": "MANUAL",
      "sourceTypeName": "手工",
      "sourceId": "2084000000000004979"
    }],
    "deductions": [],
    "summary": {
      "surchargeAmount": 24.68,
      "discountAmount": 0,
      "netAdjustmentAmount": 24.68
    }
  },
  "success": true
}

边界示例(空列表)

GET /v3/admin/order/2084000000000002978/settlement/other-incomes
Authorization: Bearer <token>
{
  "code": 200,
  "message": "success",
  "data": {
    "items": [],
    "deductions": [],
    "summary": {"surchargeAmount": 0, "discountAmount": 0, "netAdjustmentAmount": 0}
  },
  "success": true
}

异常示例(非法订单 ID

GET /v3/admin/order/0/settlement/other-incomes
Authorization: Bearer <token>
{"code": 400, "message": "订单 ID 必须大于 0", "data": null, "success": false}

3.2 新增其他收入并原子创建订单增费

  • 方法/路径POST /v3/admin/order/{orderId}/settlement/other-incomes
  • 使用场景:核单人员新增一条手工其他收入。
  • 认证:需要管理后台登录态;仅超级管理员、管理员或财务可写。
  • 幂等性requestId 是同一订单内永久唯一的稳定幂等键;同一 requestId 与相同载荷重试返回同一结果,不同载荷冲突返回 584087
  • 限流:未声明接口专属限流。

路径参数orderId,String(Long),必填且必须大于 0。

请求体完整字段

字段 类型 必填 校验与说明
requestId String 最长 64;同订单内永久唯一
incomeDate LocalDate YYYY-MM-DD
projectName String 非空,最长 100
quantity Decimal ≥0,最多 8 位整数、4 位小数
unitPrice Decimal ≥0,最多 8 位整数、2 位小数
settlementAmount Decimal ≥0.01,最多 8 位整数、2 位小数;必须等于 quantity × unitPrice 四舍五入到 2 位
paymentMethod String 见 §6.1
settlementConfirmStatus String 新增只能为 UNCONFIRMED
voucherUrls String[] 最多 9 项;每项最长 1024,必须为 http/https URL
remark String 最长 500

成功响应data 为 §3.1 的完整 OtherIncomeItem;不含 projectCategoryprojectCategoryNamespecification

典型成功请求与响应

POST /v3/admin/order/2084000000000002978/settlement/other-incomes
Authorization: Bearer <token>
Content-Type: application/json
{
  "requestId": "oi-5477-0001",
  "incomeDate": "2026-08-04",
  "projectName": "酒店升级补差",
  "quantity": 2,
  "unitPrice": 12.34,
  "settlementAmount": 24.68,
  "paymentMethod": "COMPANY_PAID",
  "settlementConfirmStatus": "UNCONFIRMED",
  "voucherUrls": [],
  "remark": null
}
{
  "code": 200,
  "message": "success",
  "data": {
    "id": "2084000000000004978",
    "requestId": "oi-5477-0001",
    "incomeDate": "2026-08-04",
    "projectName": "酒店升级补差",
    "quantity": 2,
    "unitPrice": 12.34,
    "settlementAmount": 24.68,
    "paymentMethod": "COMPANY_PAID",
    "paymentMethodName": "公司付款",
    "voucherUrls": [],
    "settlementConfirmStatus": "UNCONFIRMED",
    "settlementConfirmStatusName": "未确认",
    "remark": null,
    "sourceType": "MANUAL",
    "sourceTypeName": "手工",
    "sourceId": "2084000000000004979"
  },
  "success": true
}

边界请求与响应(旧字段仍被旧客户端多传)

{
  "requestId": "oi-5477-legacy-0001",
  "incomeDate": "2026-08-04",
  "projectName": "历史客户端补差",
  "projectCategory": "HOTEL",
  "specification": "VIP",
  "quantity": 1,
  "unitPrice": 0.01,
  "settlementAmount": 0.01,
  "paymentMethod": "CASH_PAID",
  "settlementConfirmStatus": "UNCONFIRMED",
  "voucherUrls": []
}
{
  "code": 200,
  "message": "success",
  "data": {
    "id": "2084000000000004980",
    "requestId": "oi-5477-legacy-0001",
    "incomeDate": "2026-08-04",
    "projectName": "历史客户端补差",
    "quantity": 1,
    "unitPrice": 0.01,
    "settlementAmount": 0.01,
    "paymentMethod": "CASH_PAID",
    "paymentMethodName": "现付",
    "voucherUrls": [],
    "settlementConfirmStatus": "UNCONFIRMED",
    "settlementConfirmStatusName": "未确认",
    "remark": null,
    "sourceType": "MANUAL",
    "sourceTypeName": "手工",
    "sourceId": "2084000000000004981"
  },
  "success": true
}

旧字段会被忽略,响应不会回显。该兼容仅用于过渡;前端仍必须停止发送。

异常请求与响应(缺少确认状态)

{
  "requestId": "oi-5477-invalid-0001",
  "incomeDate": "2026-08-04",
  "projectName": "无确认状态",
  "quantity": 1,
  "unitPrice": 10,
  "settlementAmount": 10,
  "paymentMethod": "CASH_PAID"
}
{"code": 400, "message": "确认状态不能为空", "data": null, "success": false}

3.3 修改其他收入

  • 方法/路径PUT /v3/admin/order/{orderId}/settlement/other-incomes/{incomeId}
  • 使用场景:修改已有其他收入的公开业务字段。
  • 认证:需要管理后台登录态;仅超级管理员、管理员或财务可写。
  • 幂等性:无单独幂等键;重复提交相同最终载荷不会改变公开结果。调用方不得依赖并发请求顺序。
  • 限流:未声明接口专属限流。

路径参数

字段 类型 必填 说明 校验
orderId String(Long) 订单 ID 必须大于 0
incomeId String(Long) 其他收入 ID 必须大于 0,且必须属于该订单

请求体完整字段:与 POST 相同,但没有 requestIdsettlementConfirmStatus 可为 UNCONFIRMEDCONFIRMED。字段长度、金额一致性、凭证约束均与 §3.2 相同。

成功响应data 为 §3.1 的完整 OtherIncomeItem;不含 projectCategoryprojectCategoryNamespecification

典型成功请求与响应

PUT /v3/admin/order/2084000000000002978/settlement/other-incomes/2084000000000004978
Authorization: Bearer <token>
Content-Type: application/json
{
  "incomeDate": "2026-08-04",
  "projectName": "酒店升级补差-已更新",
  "quantity": 3,
  "unitPrice": 15.00,
  "settlementAmount": 45.00,
  "paymentMethod": "CASH_PAID",
  "settlementConfirmStatus": "UNCONFIRMED",
  "voucherUrls": [],
  "remark": "金额已核对"
}
{
  "code": 200,
  "message": "success",
  "data": {
    "id": "2084000000000004978",
    "requestId": "oi-5477-0001",
    "incomeDate": "2026-08-04",
    "projectName": "酒店升级补差-已更新",
    "quantity": 3,
    "unitPrice": 15,
    "settlementAmount": 45,
    "paymentMethod": "CASH_PAID",
    "paymentMethodName": "现付",
    "voucherUrls": [],
    "settlementConfirmStatus": "UNCONFIRMED",
    "settlementConfirmStatusName": "未确认",
    "remark": "金额已核对",
    "sourceType": "MANUAL",
    "sourceTypeName": "手工",
    "sourceId": "2084000000000004982"
  },
  "success": true
}

边界请求与响应(夹带旧字段):请求可额外包含 projectCategoryspecification,服务端会忽略,仍按上述公开字段更新,响应不会出现三个旧字段。

{
  "incomeDate": "2026-08-04",
  "projectName": "酒店升级补差-兼容请求",
  "projectCategory": "OLD_JSON_CATEGORY_SHOULD_BE_IGNORED",
  "specification": "OLD_JSON_SPEC_SHOULD_BE_IGNORED",
  "quantity": 3,
  "unitPrice": 15,
  "settlementAmount": 45,
  "paymentMethod": "CASH_PAID",
  "settlementConfirmStatus": "UNCONFIRMED",
  "voucherUrls": []
}
{
  "code": 200,
  "message": "success",
  "data": {
    "id": "2084000000000004978",
    "requestId": "oi-5477-0001",
    "incomeDate": "2026-08-04",
    "projectName": "酒店升级补差-兼容请求",
    "quantity": 3,
    "unitPrice": 15,
    "settlementAmount": 45,
    "paymentMethod": "CASH_PAID",
    "paymentMethodName": "现付",
    "voucherUrls": [],
    "settlementConfirmStatus": "UNCONFIRMED",
    "settlementConfirmStatusName": "未确认",
    "remark": null,
    "sourceType": "MANUAL",
    "sourceTypeName": "手工",
    "sourceId": "2084000000000004982"
  },
  "success": true
}

异常请求与响应(金额不一致)

{
  "incomeDate": "2026-08-04",
  "projectName": "金额错误",
  "quantity": 3,
  "unitPrice": 15,
  "settlementAmount": 44,
  "paymentMethod": "CASH_PAID",
  "settlementConfirmStatus": "UNCONFIRMED"
}
{"code": 584076, "message": "其他收入核算金额必须等于数量乘以核算单价", "data": null, "success": false}

4. 接口入参汇总

接口 路径参数 请求体差异 已删除字段
GET orderId 无入参;响应删除三个字段
POST orderId 比 PUT 多必填 requestId;新增必须从 UNCONFIRMED 开始 projectCategoryspecification
PUT orderIdincomeId requestId;确认状态可为两种合法值 projectCategoryspecification

完整字段、类型和校验均已在 §3 对应接口内列出。

5. 出参字段汇总

POST、PUT 返回单个 OtherIncomeItem;GET 返回 items[] + deductions[] + summaryOtherIncomeItem 的完整当前字段见 §3.1,三种接口均不再返回:

已删除字段 原类型 当前替代
projectCategory String 无;前端删除对应状态与控件
projectCategoryName String 无;前端删除对应展示读取
specification String 无;前端删除对应状态与控件

6. 枚举 / 数据字典

6.1 paymentMethod(付款类型)

所属字段POST/PUT 入参、OtherIncomeItem.paymentMethod | 类型String | 必填:是

中文 说明
CASH_PAID 现付 已现场支付
COMPANY_PAID 公司付款 由公司付款
SIGNED 签单 签单结算

6.2 settlementConfirmStatus(确认状态)

所属字段POST/PUT 入参、OtherIncomeItem.settlementConfirmStatus | 类型String | 必填:是

中文 说明
UNCONFIRMED 未确认 POST 新增时唯一允许的初始值
CONFIRMED 已确认 仅对已有明细通过 PUT 更新使用

6.3 sourceType(公开来源类型)

所属字段OtherIncomeItem.sourceType | 类型String | 必填:响应必有

中文 说明
MANUAL 手工 管理后台手工新增
SYSTEM 系统 系统投影来源

projectCategory 对应的数据字典不再属于其他收入接口契约;前端应删除该字典请求和映射逻辑。

7. 错误码

code 含义 触发场景
400 参数校验失败 缺必填字段、长度/格式超限、非法枚举、订单 ID 非正数等
401 未登录或登录态失效 缺少有效管理后台凭证
584073 其他收入不存在或不属于当前订单 PUT 的 incomeId 不存在或订单归属不符
584074 当前核单状态不允许修改其他收入 订单核单状态不是待核单或核单中
584075 其他收入关联的附加费来源无效 关联来源无法建立或已失效
584076 核算金额不等于数量乘以单价 quantity × unitPrice 四舍五入到 2 位后与金额不一致
584086 无权修改核单资金数据 写接口调用角色不是超级管理员、管理员或财务
584087 requestId 已用于另一笔其他收入 POST 重用幂等键但载荷不同
584088 核单凭证数据损坏 历史凭证数据无法读取
584089 核单或结算已完成,资金数据不可修改 对完成后的资金事实调用 POST/PUT
584106 确认状态非法 UNCONFIRMED/CONFIRMED
584107 手工新增必须先保存为未确认 POST 直接传 CONFIRMED

旧错误码 584103(项目类别非法)、584104(规格非法)、584105(相关字典不可用)不再由这三个接口触发。

8. 示例索引

三类示例均已与接口放在一起,避免跨节拼接:

接口 典型成功 边界 业务失败
GET §3.1 有明细 §3.1 空列表 §3.1 非法 orderId
POST §3.2 不传旧字段创建 §3.2 旧请求多传字段被忽略 §3.2 缺确认状态
PUT §3.3 正常更新 §3.3 夹带旧字段被忽略 §3.3 金额不一致

9. 业务边界

  • GET 用于读取当前其他收入、减费与汇总;空数据稳定返回空数组。
  • POST/PUT 仅适用于核单资金仍可修改的订单,且调用角色必须具备资金写权限。
  • POST 必须携带稳定 requestId,并以 UNCONFIRMED 创建;后续可通过 PUT 改为 CONFIRMED
  • settlementAmount 必须等于 quantity × unitPrice 四舍五入到 2 位。
  • ⚠️ 旧客户端继续多传 projectCategory/specification 时,新接口会忽略;这不是继续保留控件的理由。
  • 核单或结算完成后禁止 POST/PUT;不存在或跨订单的 incomeId 禁止更新。
  • 前端不得从其他字段猜测、拼装或恢复已删除的项目类别与票种规格。

10. 修改前后对比

10.1 字段级对比

接口字段 原来 现在
POST/PUT projectCategory 必填 String,受项目类别字典校验 已从契约删除;旧 JSON 多传会被忽略
POST/PUT specification 可选 String,受规格字典校验 已从契约删除;旧 JSON 多传会被忽略
GET/POST/PUT projectCategory 响应返回 不再返回
GET/POST/PUT projectCategoryName 响应返回中文名 不再返回
GET/POST/PUT specification 响应返回 不再返回

10.2 行为级对比

行为 原来 现在
新增/修改表单 必须维护项目类别,可选维护票种规格 两个控件都删除,只提交当前公开字段
旧客户端多传旧字段 参与校验和保存 被忽略,且响应不回显
查询展示 可读取类别、类别名称和规格 三个字段不存在,禁止继续读取或设置默认值
相关字典异常 可能阻断写入 不再属于其他收入接口错误面

11. 影响评估 / 回滚

11.1 影响评估

  • 是否破坏向后兼容:响应字段删除属于破坏性变化;但旧前端继续多传两个旧请求字段时,新接口会忽略,因此后端先上线兼容旧请求。
  • 前端是否必须同步上线:必须。删除项目类别与票种规格控件、请求字段、响应读取和相关字典依赖。
  • 上线顺序边界:允许“新后端 → 旧前端”短暂过渡;不允许“新前端 → 旧后端”,因为旧后端仍要求 projectCategory

11.2 回滚方案

  • 若接口契约回滚到旧版本,必须同步恢复前端 projectCategory 必填提交,否则旧接口会拒绝新增/修改。
  • 仅回滚前端到旧版本不会阻断新接口写入,但旧页面读取不到三个已删除响应字段,类别/规格区域会为空,因此不建议长期维持。

12. 注意事项

  • 删除项目类别控件、票种规格控件及其表单校验。
  • 停止在 POST/PUT 请求中传 projectCategoryspecification
  • 停止读取 GET/POST/PUT 响应中的 projectCategoryprojectCategoryNamespecification
  • 删除其他收入页面对项目类别字典、票种规格字典的加载与映射。
  • Long ID 继续按 String 消费;空明细继续按 [] 处理。

13. 关联 / 联系人

13.1 链接

13.2 联系人

  • 后端负责人: @yaosutu
  • QA 验证: Issue #5477 接口验收已完成管理后台真实网关,TARGETED_FALLBACK