# 📝【契约纠正·管理后台】对公转账不需要代收人 (#5120) > **变更性质**:现有接口契约澄清 + 历史文档示例纠错|**端类型**:管理后台|**更新日期**:2026-07-21 > > 本次没有发布新的后端字段、枚举或行为变更;下文说明接口已有的稳定契约。 ## 1. 接口背景 管理后台在“登记线下收款”中选择“对公转账”后仍显示“代收人”,与当前接口契约不一致。对公转账不由某位员工代收,只需填写转账流水号;代收人仅在“报账人收款”渠道下需要选择。 2026-07-10 的历史通知曾在示例中给 `BANK_TRANSFER.collectors` 放入“公司账户”对象,该示例与实际响应不符,本次一并纠正为空数组。 ## 2. 变更清单 | # | 方法 | 路径 | 通知类型 | 说明 | |---|---|---|---|---| | 1 | GET | `/v3/admin/order/{orderId}/payment/manual-receipt/options` | 契约澄清 | `BANK_TRANSFER.collectors` 始终为 `[]`;各渠道使用各自的候选项 | | 2 | POST | `/v3/admin/order/{orderId}/payment/manual-receipt` | 契约澄清 | `collectorStaffId` 仅对 `DRIVER_CASH` 条件必填;`BANK_TRANSFER` 条件必填 `transferRef` | | 3 | 文档 | `2026-07/10_4884_线下收款代收人-修改接口-管理后台.md` | 示例纠错 | 将对公转账的错误 `collectors` 对象改为 `[]` | ## 3. 接口详情 ### 3.1 查询线下收款选项 - **方法与路径**:`GET /v3/admin/order/{orderId}/payment/manual-receipt/options` - **使用场景**:打开登记线下收款表单时,查询当前订单可用的渠道、款项类型、代收人和收款方式。 - **认证**:需要管理后台 JWT。 - **幂等性**:幂等,只读查询。 - **限流**:无接口专属限流规则。 ### 3.2 登记线下收款 - **方法与路径**:`POST /v3/admin/order/{orderId}/payment/manual-receipt` - **使用场景**:按 options 当前返回的可用渠道和款项类型登记一笔线下收款。 - **认证**:需要管理后台 JWT。 - **幂等性**:非幂等,每次成功请求会新增一条收款记录。 - **限流**:无接口专属限流规则。 ## 4. 接口入参 ### 4.1 路径参数(两个接口通用) | 字段 | 位置 | 类型 | 必填 | 说明 | |---|---|---|---|---| | `orderId` | Path | String(Long) | 是 | 订单 ID,按字符串处理 | GET 接口无 Query 参数、无请求体。 ### 4.2 POST 请求体 | 字段 | 类型 | 必填 | 说明 | 校验规则 | |---|---|---|---|---| | `channel` | String | 是 | 收款渠道 | `DRIVER_CASH` / `BANK_TRANSFER` / `CONSULTANT_COLLECTION` | | `payType` | String | 是 | 款项类型 | 必须取 options 中当前渠道的 `allowedPayTypes` | | `amount` | Decimal | 是 | 收款金额 | 最小 `0.01`,不能超过当前可收余额 | | `receivedAt` | String(LocalDateTime) | 否 | 收款时间 | `yyyy-MM-dd'T'HH:mm:ss`;不传默认当前时间 | | `transferRef` | String | 条件必填 | 对公转账流水号 | `BANK_TRANSFER` 必填,其他渠道不使用 | | `receiptMethod` | String | 否 | 收款方式 | 取当前渠道 `receiptMethods[].value`;`BANK_TRANSFER` 为空 | | `collectorStaffId` | String(Long) | 条件必填 | 代收人 assignmentId | **仅 `DRIVER_CASH` 必填**,且必须取当前渠道 `collectors[].collectorId` | | `collectorType` | String | 否 | 实际代收人类型 | 不传时按 `channel` 推导;如传入,必须与渠道匹配 | | `voucherUrls` | Array | 否 | 凭证图片 URL 列表 | 可为空数组或不传 | | `remark` | String | 否 | 备注 | 最长 500 字 | ### 4.3 渠道联动必填矩阵 | `channel` | `collectorStaffId` | `collectorType` | `transferRef` | 代收人规则 | |---|---|---|---|---| | `BANK_TRANSFER` | 不需要;误传也不作为员工代收人处理 | 可不传;如传只能为 `COMPANY_ACCOUNT` | **必填** | 不选择任何员工,公司账户是收款归属而非代收人候选项 | | `CONSULTANT_COLLECTION` | 不需要 | 可不传;如传只能为 `CONSULTANT` | 不需要 | 使用订单定制师,不使用员工选择器 | | `DRIVER_CASH` | **必填** | 可不传;如传只能为 `ORDER_STAFF` | 不需要 | 仅能选当前订单 options 返回的有效报账人 | ## 5. 出参(响应) ### 5.1 通用响应包装 | 字段 | 类型 | 说明 | |---|---|---| | `code` | Integer | `200` 表示成功,其他值为业务错误码 | | `message` | String | 结果或错误说明 | | `data` | Object/null | 业务数据;失败时通常为 `null` | | `success` | Boolean | 是否成功 | ### 5.2 GET options 的 `data` | 字段 | 类型 | 说明 | |---|---|---| | `channels` | Array | 当前订单的线下收款渠道列表 | | `channels[].channel` | String | 渠道枚举值 | | `channels[].channelText` | String | 渠道展示文案 | | `channels[].allowedPayTypes` | Array | 当前订单状态下该渠道允许的款项类型;以本次响应为准 | | `channels[].disabled` | Boolean | `true` 表示当前不可提交该渠道 | | `channels[].disabledReason` | String/null | 禁用原因;可用时为 `null` | | `channels[].collectors` | Array | **该渠道自己的代收人候选列表**;`BANK_TRANSFER` 为 `[]` | | `channels[].receiptMethods` | Array | 该渠道可选收款方式;`BANK_TRANSFER` 为 `[]` | | `collectors[].collectorType` | String | 代收人类型 | | `collectors[].collectorId` | String(Long) | `ORDER_STAFF` 为 assignmentId,`CONSULTANT` 为管理员 ID | | `collectors[].collectorName` | String | 代收人姓名 | | `collectors[].collectorRole` | String | 代收人角色值 | | `collectors[].collectorRoleText` | String | 代收人角色文案 | | `collectors[].defaultSelected` | Boolean | 是否默认选中 | | `receiptMethods[].value` | String | 收款方式值 | | `receiptMethods[].label` | String | 收款方式文案 | | `receiptMethods[].defaultSelected` | Boolean | 是否默认选中 | ### 5.3 POST 的 `data` | 字段 | 类型 | 说明 | |---|---|---| | `id` | String(Long) | 收款凭据 ID | | `orderId` | String(Long) | 订单 ID | | `channel` / `channelLabel` | String | 收款渠道值 / 文案 | | `payType` / `payTypeLabel` | String | 款项类型值 / 文案 | | `amount` | Decimal | 本次收款金额 | | `receivedAt` | String(LocalDateTime) | 收款时间 | | `collectorStaffId` / `collectorStaffName` | String(Long)/String/null | 仅 `DRIVER_CASH` 有值 | | `collectorType` | String | 实际代收人类型 | | `collectorAdminId` | String(Long)/null | `CONSULTANT_COLLECTION` 为定制师管理员 ID | | `collectorName` / `collectorRole` | String | 代收归属快照名称 / 角色 | | `transferRef` | String/null | 对公转账流水号,仅 `BANK_TRANSFER` 有值 | | `receiptMethod` / `receiptMethodLabel` | String/null | 收款方式值 / 文案;`BANK_TRANSFER` 为空 | | `voucherUrls` | Array | 凭证图片 URL 列表 | | `remark` | String/null | 备注 | | `operatorName` | String | 登记人姓名 | | `createTime` | String(LocalDateTime) | 登记时间 | | `voided` | Boolean | 是否已撤销;新登记为 `false` | | `voidedByName` / `voidedAt` / `voidReason` | String/null | 撤销信息;新登记时为 `null` | | `paidAmountAfter` | Decimal | 登记后订单累计已付金额 | | `payStatusAfter` | String | 登记后订单支付状态 | ## 6. 枚举 / 数据字典 ### 6.1 `channel` **所属字段**:`channel` / `channels[].channel`|**类型**:String | 值 | 中文 | 说明 | |---|---|---| | `BANK_TRANSFER` | 对公转账 | 无员工代收人,必须填 `transferRef` | | `CONSULTANT_COLLECTION` | 定制师代收 | 使用订单定制师,不传 `collectorStaffId` | | `DRIVER_CASH` | 报账人收款 | 仅允许尾款,必须从本渠道 `collectors` 选择代收人 | ### 6.2 `payType` **所属字段**:`payType` / `channels[].allowedPayTypes[]`|**类型**:String | 值 | 中文 | 说明 | |---|---|---| | `DEPOSIT` | 订金 | 是否可登记以 options 当前返回为准 | | `FULL` | 全款 | 是否可登记以 options 当前返回为准 | | `BALANCE` | 尾款 | 是否可登记以 options 当前返回为准;`DRIVER_CASH` 只允许此值 | > `BANK_TRANSFER` 的通用契约可支持 `DEPOSIT` / `FULL` / `BALANCE`,但具体订单当次能提交哪些值,必须以 options 的 `allowedPayTypes` 为准,不要将某个实例的 `BALANCE` 硬编码为全局规则。 ### 6.3 `collectorType` **所属字段**:`collectorType` / `collectors[].collectorType`|**类型**:String | 值 | 中文 | 匹配渠道 | |---|---|---| | `COMPANY_ACCOUNT` | 公司账户 | `BANK_TRANSFER` | | `CONSULTANT` | 定制师 | `CONSULTANT_COLLECTION` | | `ORDER_STAFF` | 订单工作人员 | `DRIVER_CASH` | ### 6.4 `receiptMethod` **所属字段**:`receiptMethod` / `receiptMethods[].value`|**类型**:String | 值 | 中文 | 说明 | |---|---|---| | `WECHAT_TRANSFER` | 微信转账 | 人员代收渠道的当前默认字典值 | | `CASH` | 现金收款 | 人员代收渠道的当前默认字典值 | `BANK_TRANSFER.receiptMethods=[]`;该字典可扩展,实际可选值以 options 当次返回为准。 ### 6.5 `payStatusAfter` **所属字段**:POST 响应 `payStatusAfter`|**类型**:String | 值 | 中文 | 说明 | |---|---|---| | `UNPAID` | 未付款 | 尚未完成有效收款 | | `DEPOSIT_PAID` | 已付订金 | 订金已收 | | `FULLY_PAID` | 已付全款 | 应收金额已收齐 | ## 7. 错误码 | code | message / 含义 | 触发场景 | |---|---|---| | `520011` | 支付类型无效或与订单状态不匹配 | `payType` 不在当前 options 允许范围内 | | `520401` | 收款渠道非法 | `channel` 不在三个渠道枚举中 | | `520402` | 对公转账渠道必须填写转账流水号 | `BANK_TRANSFER` 未传 `transferRef` | | `520403` | 报账人收款渠道必须指定代收人 | `DRIVER_CASH` 未传 `collectorStaffId` | | `520404` | 代收人不属于本订单人员 | `collectorStaffId` 不是本订单有效人员 | | `520407` | 订单已取消,不允许登记线下收款 | 已取消订单提交 POST | | `520408` | 收款金额必须大于 0 | `amount < 0.01` | | `520409` | 线下收款代收人类型非法 | `collectorType` 与 `channel` 不匹配 | | `520410` | 报账人收款只能登记尾款 | `DRIVER_CASH` 提交 `DEPOSIT` 或 `FULL` | | `520411` | 报账人收款必须选择本订单报账人 | 选中的订单人员不是报账人 | | `520412` | 订单没有可用定制师,不能登记定制师代收 | `CONSULTANT_COLLECTION` 无可用定制师 | | `520413` | 本次收款金额超过当前可收余额 | `amount` 大于当前可收金额 | ## 8. 示例(典型 + 边界 + 异常) ### 8.1 典型:查询选项,对公转账无代收人 **请求**: ```http GET /v3/admin/order/2079454953641836546/payment/manual-receipt/options Authorization: Bearer 无请求体 ``` **响应**: ```json { "code": 200, "message": "操作成功", "data": { "channels": [ { "channel": "CONSULTANT_COLLECTION", "channelText": "定制师代收", "allowedPayTypes": ["BALANCE"], "disabled": false, "disabledReason": null, "collectors": [ { "collectorType": "CONSULTANT", "collectorId": "2037350531801993218", "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": [] }, { "channel": "DRIVER_CASH", "channelText": "报账人收款", "allowedPayTypes": [], "disabled": true, "disabledReason": "本订单暂无可代收报账人", "collectors": [], "receiptMethods": [ {"value": "WECHAT_TRANSFER", "label": "微信转账", "defaultSelected": true}, {"value": "CASH", "label": "现金收款", "defaultSelected": false} ] } ] }, "success": true } ``` ### 8.2 边界:对公转账不传代收人 **场景说明**:`collectorStaffId` 和 `collectorType` 都不传;仅提交 options 当前允许的款项类型与对公转账流水号。 **请求**: ```http POST /v3/admin/order/2079454953641836546/payment/manual-receipt Authorization: Bearer Content-Type: application/json { "channel": "BANK_TRANSFER", "payType": "BALANCE", "amount": 100.00, "transferRef": "BANK202607210001", "voucherUrls": [], "remark": "客户对公转账" } ``` **响应**: ```json { "code": 200, "message": "操作成功", "data": { "id": "2079600000000000001", "orderId": "2079454953641836546", "channel": "BANK_TRANSFER", "channelLabel": "对公转账", "payType": "BALANCE", "payTypeLabel": "尾款", "amount": 100.00, "receivedAt": "2026-07-21T15:30:00", "collectorStaffId": null, "collectorStaffName": null, "collectorType": "COMPANY_ACCOUNT", "collectorAdminId": null, "collectorName": "公司账户", "collectorRole": "COMPANY_ACCOUNT", "transferRef": "BANK202607210001", "receiptMethod": null, "receiptMethodLabel": null, "voucherUrls": [], "remark": "客户对公转账", "operatorName": "管理员", "createTime": "2026-07-21T15:30:00", "voided": false, "voidedByName": null, "voidedAt": null, "voidReason": null, "paidAmountAfter": 1600.00, "payStatusAfter": "DEPOSIT_PAID" }, "success": true } ``` ### 8.3 异常:报账人收款未选择代收人 **请求**: ```http POST /v3/admin/order/2079454953641836546/payment/manual-receipt Authorization: Bearer Content-Type: application/json { "channel": "DRIVER_CASH", "payType": "BALANCE", "amount": 100.00, "receiptMethod": "CASH" } ``` **响应**: ```json { "code": 520403, "message": "报账人收款渠道必须指定代收人", "data": null, "success": false } ``` ## 9. 业务边界 - `collectors` 是每个 channel 自己的候选列表,不是所有渠道共用的必选列表。 - `BANK_TRANSFER`:`collectors=[]`,不传 `collectorStaffId`,必须传 `transferRef`;即使误传 `collectorStaffId`,响应中员工代收人 ID 仍为空。 - `CONSULTANT_COLLECTION`:不要提交 `collectorStaffId`;当订单没有可用定制师时,渠道禁用。 - `DRIVER_CASH`:仅允许 `BALANCE`,必须传当前订单有效报账人的 assignmentId。 - options 的 `allowedPayTypes` 随订单状态和可收余额变化。待支付订单中,对公转账/定制师代收可返回 `DEPOSIT`、`FULL`;非待支付且仍有可收余额时可返回 `BALANCE`。 - 渠道 `disabled=true` 或 `allowedPayTypes=[]` 时,当前不可提交该渠道。 - 已取消订单、无可收余额的订单不能登记线下收款。 ## 10. 修改前后对比 > 本节对比的是“错误理解 / 错误文档示例”与“正确的现有契约”,不表示后端今日发布了新的接口变更。 | 项目 | 错误理解 / 历史错误示例 | 正确契约 | |---|---|---| | 对公转账的代收人候选 | `BANK_TRANSFER.collectors` 含“公司账户”对象 | `BANK_TRANSFER.collectors=[]` | | `collectorStaffId` 字段 | 所有渠道都要选代收人,或该字段已从后端删除 | 字段仍保留,**仅 `DRIVER_CASH` 条件必填** | | 对公转账必填项 | 代收人 | `transferRef` 转账流水号 | | 定制师代收 | 复用员工代收人选择器并传 `collectorStaffId` | 不要传 `collectorStaffId`,使用订单定制师 | | 对公转账款项类型 | 固定只能是某一种款项 | 以 options 当前返回的 `allowedPayTypes` 为准 | ## 11. 影响评估 / 回滚 ### 11.1 影响评估 - **是否破坏向后兼容**:否。后端字段、枚举和行为没有变更。 - **前端是否必须同步上线**:是。已有页面在 `BANK_TRANSFER` 下显示代收人,需要按正确契约纠正。 ### 11.2 回滚说明 - 本次仅修正通知文档,不涉及后端接口回滚。 - 若前端回滚渠道联动修正,对公转账将再次错误显示代收人。 ## 12. 注意事项 - 选中 `BANK_TRANSFER` 时,隐藏代收人选择器,并清空从其他渠道切换前残留的 `collectorStaffId`。 - 选中 `BANK_TRANSFER` 时,显示并校验 `transferRef`,不要根据统一响应结构中“存在 `collectors` 字段”就认定代收人必选。 - 仅 `DRIVER_CASH` 把 `collectorStaffId` 设为必填,候选项取当前 channel 的 `collectors`。 - `CONSULTANT_COLLECTION` 不要复用 `DRIVER_CASH` 的员工代收人校验。 - 不要把测试订单中 `BANK_TRANSFER.allowedPayTypes=["BALANCE"]` 固化为全局规则;每次均以 options 返回为准。 ## 13. 关联 / 联系人 ### 13.1 关联 - **Issue**:[#5120](https://git.1814.love:8443/wx/HL/issues/5120) - **后端 PR**:无(本次无后端代码变更) - **后端 commit**:无(本次无后端代码变更) ### 13.2 联系人 - **后端负责人**:腰苏图