docs(changelog): #8181 线下收款废除报账人代收DRIVER_CASH渠道——options出参channels移除DRIVER_CASH+register新增520417(尾款收款模型重构PR-1,修改接口-管理后台)
changelog-filename-gate / validate (push) Failing after 2s
changelog-filename-gate / validate (push) Failing after 2s
这个提交包含在:
@@ -0,0 +1,369 @@
|
||||
---
|
||||
schema: "hl-changelog/v2"
|
||||
ticket: "8181"
|
||||
title: "线下收款废除报账人代收 DRIVER_CASH 渠道(尾款收款模型重构 PR-1)"
|
||||
consumer: "admin"
|
||||
author: "yst(GIT)"
|
||||
change_type: "修改接口"
|
||||
backend_status: "merged"
|
||||
gateway_status: "not_required"
|
||||
frontend_status: "pending"
|
||||
frontend_owner: ""
|
||||
frontend_ref: ""
|
||||
target_release: "v2.1"
|
||||
verified_at: ""
|
||||
status_note: "backend_status: merged - 已合 dev-v3(PR #8183,merge commit a1fb7bc5ef),未部署测试服; gateway_status: not_required - 零网关改动,/v3/admin/order/** 走 hl-gateway 既有通配路由; frontend_status: pending - 前端适配情况未知,需排查 options 消费方是否硬编码 DRIVER_CASH"
|
||||
updated_at: "2026-09-22"
|
||||
base: "dev-v3"
|
||||
---
|
||||
|
||||
# 线下收款废除「报账人代收 DRIVER_CASH」渠道(尾款收款模型重构 PR-1,#8181)
|
||||
|
||||
> 订单线下收款登记的「报账人收款(DRIVER_CASH)」渠道下线:登记选项接口不再返回该渠道,登记接口传 DRIVER_CASH 直接报新错误码 520417。历史 DRIVER_CASH 收款记录的查询、撤销不受影响。
|
||||
|
||||
## ① 接口背景
|
||||
|
||||
此前管理后台给订单补录线下收款时有三个渠道:定制师代收、对公转账、报账人收款(司机/导游等报账人手持现金收尾款)。「报账人代收尾款」模式资金不入公账、对账困难,尾款收款模型重构(Epic #8181)将其废除,改为「确认行程时指定主报账人,尾款挂其代收债务」的新链路(后续 PR 上线)。
|
||||
|
||||
本 PR 是该重构的第 1 步:只下线 DRIVER_CASH 的**登记入口**,存量数据完全兼容。
|
||||
|
||||
## ② 变更清单
|
||||
|
||||
| 类型 | 接口 | 变更 |
|
||||
|---|---|---|
|
||||
| 修改(出参结构收缩) | `GET /v3/admin/order/{orderId}/payment/manual-receipt/options` | 出参 `channels[]` 从 3 项变 2 项,**移除 DRIVER_CASH 渠道项** |
|
||||
| 修改(行为变更 + 新错误码) | `POST /v3/admin/order/{orderId}/payment/manual-receipt` | `channel=DRIVER_CASH` 不再可登记,返回 **520417**(此前可正常登记尾款) |
|
||||
| 不变 | `GET /v3/admin/order/{orderId}/payment/manual-receipt` 列表 | 历史 DRIVER_CASH 记录照常返回 |
|
||||
| 不变 | `DELETE /v3/admin/order/{orderId}/payment/manual-receipt/{receiptId}` 撤销 | 历史 DRIVER_CASH 记录照常可撤销 |
|
||||
|
||||
## ③ 接口详情
|
||||
|
||||
### 3.1 查询线下收款登记选项
|
||||
|
||||
```
|
||||
GET /v3/admin/order/{orderId}/payment/manual-receipt/options
|
||||
```
|
||||
|
||||
- 使用场景:订单详情「登记线下收款」弹窗打开时拉取,渲染渠道 tabs + 各渠道可选款项/代收人/收款方式
|
||||
- 认证:管理后台 JWT(hl-gateway 统一鉴权)
|
||||
- 权限:订单归属校验(订单顾问/财务相关角色可读),车务管理员(VEHICLE_MANAGER)可读;房源角色(HOUSE)禁止
|
||||
- 幂等性:只读接口,天然幂等
|
||||
- 限流:走网关默认限流,无单独配额
|
||||
|
||||
### 3.2 登记线下收款
|
||||
|
||||
```
|
||||
POST /v3/admin/order/{orderId}/payment/manual-receipt
|
||||
```
|
||||
|
||||
- 使用场景:线下收到款项后补录(对公转账到账、定制师代收款),同事务推进订单 `paid_amount` / `pay_status`
|
||||
- 认证:管理后台 JWT
|
||||
- 权限:需线下收款写权限(结算写守卫)
|
||||
- 幂等性:非幂等,每次成功调用新增一条收款凭据并累加已付金额;**重复提交会重复收款**,前端须防连击
|
||||
- 事务:凭据落库与订单已付金额累加在同一事务,不会出现半成功状态
|
||||
|
||||
## ④ 入参
|
||||
|
||||
### 4.1 选项接口入参
|
||||
|
||||
| 参数 | 位置 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|---|
|
||||
| `orderId` | path | Long | 是 | 订单 ID |
|
||||
|
||||
无 query / body 参数。
|
||||
|
||||
### 4.2 登记接口请求体
|
||||
|
||||
| 字段 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| `channel` | string | 是 | 收款渠道:`CONSULTANT_COLLECTION`(定制师代收)/ `BANK_TRANSFER`(对公转账)。⚠️ `DRIVER_CASH` 已下线,传了返回 520417 |
|
||||
| `payType` | string | 是 | 款项类型:`DEPOSIT`(订金)/ `BALANCE`(尾款)/ `FULL`(全款) |
|
||||
| `amount` | number | 是 | 收款金额,必须 > 0,不能超过当前可收余额 |
|
||||
| `receivedAt` | string(datetime) | 否 | 收款时间,可补录过去时间;不传默认当前时间 |
|
||||
| `transferRef` | string | 条件必填 | 对公转账流水号,`BANK_TRANSFER` 渠道必填 |
|
||||
| `receiptMethod` | string | 否 | 收款方式(字典 `manual_receipt_method`),`BANK_TRANSFER` 为空 |
|
||||
| `collectorStaffId` | Long | 否 | 代收人 assignmentId。原为 DRIVER_CASH 必填,该渠道下线后登记链路不再使用 |
|
||||
| `collectorType` | string | 否 | 实际代收人类型 `ORDER_STAFF`/`CONSULTANT`/`COMPANY_ACCOUNT`;不传按 channel 兼容推导 |
|
||||
| `voucherUrls` | string[] | 否 | 凭证图片 URL 列表 |
|
||||
| `remark` | string | 否 | 备注,最长 500 字 |
|
||||
|
||||
## ⑤ 出参
|
||||
|
||||
### 5.1 选项接口出参 `ManualReceiptOptionsVO`
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|---|---|---|
|
||||
| `channels` | array | 收款渠道选项。**本次变更后固定 2 项:`CONSULTANT_COLLECTION`、`BANK_TRANSFER`**(顺序即此顺序) |
|
||||
|
||||
`channels[]` 元素 `ChannelOption`:
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|---|---|---|
|
||||
| `channel` | string | 渠道值 |
|
||||
| `channelText` | string | 渠道显示文案(「定制师代收」/「对公转账」) |
|
||||
| `allowedPayTypes` | string[] | 当前订单状态下允许的款项类型,空数组 = 该渠道不可用 |
|
||||
| `disabled` | boolean | 是否禁用,true 时前端置灰 |
|
||||
| `disabledReason` | string | 禁用原因,`disabled=true` 时有值 |
|
||||
| `collectors` | array | 该渠道可选代收人(见下表);`BANK_TRANSFER` 恒为空 |
|
||||
| `receiptMethods` | array | 该渠道可选收款方式(见下表);`BANK_TRANSFER` 恒为空 |
|
||||
|
||||
`collectors[]` 元素 `CollectorOption`:
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|---|---|---|
|
||||
| `collectorType` | string | `ORDER_STAFF` / `CONSULTANT` / `COMPANY_ACCOUNT` |
|
||||
| `collectorId` | Long(string) | 代收人 ID:`CONSULTANT` 为 adminId |
|
||||
| `collectorName` | string | 代收人姓名 |
|
||||
| `collectorRole` | string | 代收人角色 |
|
||||
| `collectorRoleText` | string | 角色显示文案 |
|
||||
| `defaultSelected` | boolean | 是否默认选中 |
|
||||
|
||||
`receiptMethods[]` 元素 `OptionItem`:
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|---|---|---|
|
||||
| `value` | string | 选项值(字典 `manual_receipt_method`) |
|
||||
| `label` | string | 显示文案 |
|
||||
| `defaultSelected` | boolean | 是否默认选中(首项为 true) |
|
||||
|
||||
### 5.2 登记接口出参 `ManualReceiptVO`
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|---|---|---|
|
||||
| `id` | Long(string) | 收款凭据 ID(雪花,String 防 JS 精度丢失) |
|
||||
| `orderId` | Long(string) | 订单 ID |
|
||||
| `channel` | string | 收款渠道值 |
|
||||
| `channelLabel` | string | 渠道显示标签 |
|
||||
| `payType` | string | 款项类型值 |
|
||||
| `payTypeLabel` | string | 款项类型显示标签 |
|
||||
| `amount` | number | 收款金额 |
|
||||
| `receivedAt` | string(datetime) | 收款时间 |
|
||||
| `collectorStaffId` | Long(string) | 代收人 assignmentId(历史 DRIVER_CASH 行才有值) |
|
||||
| `collectorStaffName` | string | 代收人姓名(历史 DRIVER_CASH 行才有值) |
|
||||
| `collectorType` | string | 实际代收人类型 |
|
||||
| `collectorAdminId` | Long(string) | 定制师/管理员代收人 ID |
|
||||
| `collectorName` | string | 通用代收人姓名快照 |
|
||||
| `collectorRole` | string | 通用代收人角色快照 |
|
||||
| `transferRef` | string | 对公转账流水号(BANK_TRANSFER) |
|
||||
| `receiptMethod` | string | 收款方式值 |
|
||||
| `receiptMethodLabel` | string | 收款方式显示标签 |
|
||||
| `voucherUrls` | string[] | 凭证图片 URL 列表 |
|
||||
| `remark` | string | 备注 |
|
||||
| `operatorName` | string | 登记人姓名 |
|
||||
| `createTime` | string(datetime) | 登记时间 |
|
||||
| `voided` | boolean | 是否已撤销 |
|
||||
| `voidedByName` | string | 撤销人姓名 |
|
||||
| `voidedAt` | string(datetime) | 撤销时间 |
|
||||
| `voidReason` | string | 撤销原因 |
|
||||
| `paidAmountAfter` | number | 登记/撤销后订单累计已付金额(仅登记/撤销响应有值,列表查询为 null) |
|
||||
| `payStatusAfter` | string | 登记/撤销后订单支付状态(同上) |
|
||||
|
||||
## ⑥ 枚举 / 数据字典
|
||||
|
||||
**收款渠道 `channel`**:
|
||||
|
||||
| 值 | 含义 | 本次变化 |
|
||||
|---|---|---|
|
||||
| `CONSULTANT_COLLECTION` | 定制师代收 | 不变 |
|
||||
| `BANK_TRANSFER` | 对公转账 | 不变 |
|
||||
| `DRIVER_CASH` | 报账人收款 | **已下线**:options 不再返回、register 拒绝(520417)。⚠️ 但列表接口的历史数据仍可能出现该值(channelLabel=「报账人收款」),渲染映射不能删 |
|
||||
|
||||
**款项类型 `payType`**:`DEPOSIT` 订金 / `BALANCE` 尾款 / `FULL` 全款(不变)。
|
||||
|
||||
**代收人类型 `collectorType`**:`ORDER_STAFF` / `CONSULTANT` / `COMPANY_ACCOUNT`(不变)。
|
||||
|
||||
**收款方式 `receiptMethod`**:走数据字典 `manual_receipt_method`(如 `WECHAT_TRANSFER` 微信转账、`CASH` 现金收款),以 options 接口实际返回为准。
|
||||
|
||||
## ⑦ 错误码
|
||||
|
||||
| 码 | 语义 | 触发场景 |
|
||||
|---|---|---|
|
||||
| **520417** | 报账人代收尾款已下线,请通过确认行程挂账主报账人代收 | **本次新增**:register 传 `channel=DRIVER_CASH` |
|
||||
| 520401 | 收款渠道非法: {0} | register 传了枚举外的渠道值 |
|
||||
| 520402 | 对公转账渠道必须填写转账流水号 | BANK_TRANSFER 缺 `transferRef` |
|
||||
| 520407 | 订单已取消,不允许登记线下收款 | 订单状态 CANCELLED |
|
||||
| 520412 | 订单没有可用定制师,不能登记定制师代收 | CONSULTANT_COLLECTION 但订单无定制师 |
|
||||
| 520413 | 本次收款金额超过当前可收余额 | 金额超可收余额 |
|
||||
| 520415 | 收款方式不能为空 | 渠道要求 receiptMethod 但未传 |
|
||||
| 520416 | 收款方式非法: {0} | receiptMethod 不在字典内 |
|
||||
| 520405 | 线下收款凭据不存在 | 撤销时 receiptId 无效或不属本单 |
|
||||
| 520406 | 该收款凭据已撤销,无法重复操作 | 重复撤销 |
|
||||
| 520414 | 当前订单状态禁止撤销收款 | 当前订单/流程状态不允许撤销 |
|
||||
|
||||
> 注:原 DRIVER_CASH 专属错误码 520403(缺代收人)/ 520404(代收人不属本单)/ 520410(只能登尾款)/ 520411(必须选报账人)因入口下线在 register 链路不再可达,前端无需再处理这几个码(保留兼容无害)。
|
||||
|
||||
## ⑧ 示例
|
||||
|
||||
### 8.1 典型:options 返回 2 个渠道 + BANK_TRANSFER 登记成功
|
||||
|
||||
请求 `GET /v3/admin/order/2100123456789012345/payment/manual-receipt/options`(订单状态非待支付、尾款未收齐):
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"success": true,
|
||||
"data": {
|
||||
"channels": [
|
||||
{
|
||||
"channel": "CONSULTANT_COLLECTION",
|
||||
"channelText": "定制师代收",
|
||||
"allowedPayTypes": ["BALANCE"],
|
||||
"disabled": false,
|
||||
"disabledReason": null,
|
||||
"collectors": [
|
||||
{
|
||||
"collectorType": "CONSULTANT",
|
||||
"collectorId": "2090001111222233334",
|
||||
"collectorName": "王定制",
|
||||
"collectorRole": "CONSULTANT",
|
||||
"collectorRoleText": "定制师",
|
||||
"defaultSelected": true
|
||||
}
|
||||
],
|
||||
"receiptMethods": [
|
||||
{ "value": "WECHAT_TRANSFER", "label": "微信转账", "defaultSelected": true },
|
||||
{ "value": "CASH", "label": "现金收款", "defaultSelected": false }
|
||||
]
|
||||
},
|
||||
{
|
||||
"channel": "BANK_TRANSFER",
|
||||
"channelText": "对公转账",
|
||||
"allowedPayTypes": ["BALANCE"],
|
||||
"disabled": false,
|
||||
"disabledReason": null,
|
||||
"collectors": [],
|
||||
"receiptMethods": []
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
请求 `POST /v3/admin/order/2100123456789012345/payment/manual-receipt`:
|
||||
|
||||
```json
|
||||
{
|
||||
"channel": "BANK_TRANSFER",
|
||||
"payType": "BALANCE",
|
||||
"amount": 3000.00,
|
||||
"transferRef": "GZL20260922001",
|
||||
"remark": "客户对公转账尾款"
|
||||
}
|
||||
```
|
||||
|
||||
响应:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 200,
|
||||
"success": true,
|
||||
"data": {
|
||||
"id": "2102999888777666555",
|
||||
"orderId": "2100123456789012345",
|
||||
"channel": "BANK_TRANSFER",
|
||||
"channelLabel": "对公转账",
|
||||
"payType": "BALANCE",
|
||||
"payTypeLabel": "尾款",
|
||||
"amount": 3000.00,
|
||||
"receivedAt": "2026-09-22T17:00:00",
|
||||
"transferRef": "GZL20260922001",
|
||||
"collectorType": "COMPANY_ACCOUNT",
|
||||
"voided": false,
|
||||
"paidAmountAfter": 8800.00,
|
||||
"payStatusAfter": "FULLY_PAID"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 8.2 边界:订单无定制师 → 定制师代收渠道置灰
|
||||
|
||||
订单无定制师快照时,`CONSULTANT_COLLECTION` 渠道 `collectors` 为空且禁用:
|
||||
|
||||
```json
|
||||
{
|
||||
"channel": "CONSULTANT_COLLECTION",
|
||||
"channelText": "定制师代收",
|
||||
"allowedPayTypes": [],
|
||||
"disabled": true,
|
||||
"disabledReason": "订单没有可用定制师",
|
||||
"collectors": [],
|
||||
"receiptMethods": [
|
||||
{ "value": "WECHAT_TRANSFER", "label": "微信转账", "defaultSelected": true },
|
||||
{ "value": "CASH", "label": "现金收款", "defaultSelected": false }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
尾款已收齐时各渠道 `allowedPayTypes=[]`、`disabled=true`、`disabledReason="尾款已收齐,无可收余额"`;订单已取消时 `disabledReason="订单已取消,不能登记收款"`。
|
||||
|
||||
### 8.3 业务失败:DRIVER_CASH 登记被拒(520417)
|
||||
|
||||
请求:
|
||||
|
||||
```json
|
||||
{
|
||||
"channel": "DRIVER_CASH",
|
||||
"payType": "BALANCE",
|
||||
"amount": 2000.00,
|
||||
"collectorStaffId": "2099888777666555444",
|
||||
"receiptMethod": "CASH"
|
||||
}
|
||||
```
|
||||
|
||||
响应:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 520417,
|
||||
"success": false,
|
||||
"message": "报账人代收尾款已下线,请通过确认行程挂账主报账人代收"
|
||||
}
|
||||
```
|
||||
|
||||
不会落库任何收款记录,订单金额无变化。
|
||||
|
||||
## ⑨ 业务边界
|
||||
|
||||
- **适用**:订单收到线下款项后补录(订金/全款仅限待支付状态,尾款在非待支付、非已取消状态);定制师代收、对公转账两种渠道照常可用。
|
||||
- **不适用**:报账人(司机/导游)手持现金收尾款的场景——此入口已废除,改走「确认行程挂账主报账人代收」链路(后续 PR 上线,前端关注后续 changelog)。
|
||||
- **存量兼容**:历史已登记的 DRIVER_CASH 收款记录正常返回在列表接口、正常可撤销,撤销后 `paid_amount` 精确回退,行为与旧版一致。
|
||||
- **可收余额**:`amount` 不能超过订单当前可收余额(520413);可收余额 ≤ 0 时各渠道 `allowedPayTypes` 为空且置灰。
|
||||
- **登记接口非幂等**:重复点击会产生重复收款记录,前端须做按钮防重。
|
||||
|
||||
## ⑩ 修改前后对比
|
||||
|
||||
### 字段/结构级
|
||||
|
||||
| 项 | 修改前 | 修改后 |
|
||||
|---|---|---|
|
||||
| options 出参 `channels[]` | `[CONSULTANT_COLLECTION, BANK_TRANSFER, DRIVER_CASH]`(3 项,DRIVER_CASH 项内含本单报账人候选 collectors) | `[CONSULTANT_COLLECTION, BANK_TRANSFER]`(2 项,**DRIVER_CASH 项整体移除**) |
|
||||
| register 入参 `channel=DRIVER_CASH` | 合法值,可登记尾款(仅 BALANCE,需 collectorStaffId 属本单报账人) | 非法值,一律返回 520417,不落库 |
|
||||
|
||||
### 行为级
|
||||
|
||||
| 项 | 修改前 | 修改后 |
|
||||
|---|---|---|
|
||||
| 报账人代收尾款登记 | 可在订单详情登记 | 入口下线,需走确认行程挂账主报账人代收(后续 PR) |
|
||||
| 历史 DRIVER_CASH 记录查询/撤销 | 可查可撤 | 不变,仍可查可撤 |
|
||||
| 订金/全款/尾款的定制师代收、对公转账补录 | 可用 | 不变,照常可用 |
|
||||
|
||||
## ⑪ 影响评估 / 回滚
|
||||
|
||||
- **破坏兼容**:是。options 出参结构收缩(少一个渠道项)+ register 对 DRIVER_CASH 的行为从成功变为报错。
|
||||
- **前端同步上线要求**:前端必须先排查并适配(见 ⑫),否则若按旧 channels 结构硬编码索引/枚举映射,渠道 tabs 渲染或默认值逻辑可能异常;若仍向用户展示 DRIVER_CASH 入口,登记会收到 520417。
|
||||
- **后端兼容**:已合 dev-v3,未部署测试服;列表/撤销接口对历史数据完全兼容。
|
||||
- **回滚方案**:代码回滚至本 PR 前版本即恢复 DRIVER_CASH 渠道;下线期间不会产生新 DRIVER_CASH 数据,回滚无数据迁移负担。
|
||||
|
||||
## ⑫ 注意事项
|
||||
|
||||
1. **前端排查 options 消费方是否硬编码 DRIVER_CASH**:检查渠道 tabs 渲染、渠道枚举映射、默认渠道选中逻辑、channel 文案映射表(`DRIVER_CASH → 报账人收款`)等位置。options 不再返回该渠道,任何按「必有 3 项 / 必有 DRIVER_CASH」假设的代码都要清理。
|
||||
2. **列表接口渲染映射不能删 DRIVER_CASH**:历史收款记录仍可能返回 `channel=DRIVER_CASH`、`channelLabel=报账人收款`,列表/详情的展示映射需保留该值,否则历史行显示异常。
|
||||
3. 新错误码 520417 的 message 可直接透出给用户(文案即操作指引)。
|
||||
4. 原 DRIVER_CASH 专属错误码 520403/520404/520410/520411 在 register 链路不再可达,前端可不再处理。
|
||||
|
||||
## ⑬ 关联 / 联系人
|
||||
|
||||
- Issue:https://git.1814.love:8443/wx/HL/issues/8181
|
||||
- PR:https://git.1814.love:8443/wx/HL/pulls/8183
|
||||
- Commit:https://git.1814.love:8443/wx/HL/commit/a1fb7bc5ef6befa409696fdba7c1d98b840a7c4a
|
||||
- 后端负责人:yst
|
||||
在新工单中引用
屏蔽一个用户