--- schema: "hl-changelog/v2" ticket: "7003" title: "资金互转(发起 + 分页,双边成对记账)" consumer: "admin" author: "yst" change_type: "新增接口" backend_status: "deployed" gateway_status: "verified" frontend_status: "verified" frontend_owner: "mmg" frontend_ref: "21540997" target_release: "" verified_at: "2026-09-09" status_note: "后端已合 dev-v3(account 资金账户域)并部署测试服。双边成对记账(一转出一入账);幂等键防重复提交;不收转入金额(转出净减 amount+fee、转入净加 amount)。" updated_at: "2026-09-09" base: "dev-v3" --- # 资金互转 ## 1. 接口背景 财务域「资金互转」:公司各资金账户间划转(银行取现、现金存银行、三方提现、账户互转等)。一次互转双边成对记账(转出户一笔 OUT、转入户一笔 IN,共享 transferGroupId)。 ## 2. 变更清单 | 类型 | 接口 | 说明 | |---|---|---| | 新增 | GET `/admin/finance/fund-transfers/page` | 互转记录分页(按 transferGroupId 成对聚合) | | 新增 | POST `/admin/finance/fund-transfers` | 发起互转(幂等) | ## 3. 接口详情 ### 3.1 分页 GET /page 入参(Query + 分页,均可选):`fromAccountId` / `toAccountId` / `mode` / `operatorName`(精确)/ `flowAtStart` / `flowAtEnd`(按 transferDate 过滤)/ pageNo / pageSize。 出参行(FundTransferRowRespVO,一转出一入账聚合成一行,Long ID 序列化为 String): | 字段 | 类型 | 说明 | |---|---|---| | transferGroupId | String | 互转组ID | | mode | String | 存取方式 | | fromAccountId / fromAccountName | String | 转出账户 | | toAccountId / toAccountName | String | 转入账户 | | transferDate | String | 业务日期(yyyy-MM-dd,可回溯补录) | | amount | BigDecimal | 转出金额(转入实收同额) | | fee | BigDecimal | 手续费(挂转出行) | | outFlowId / inFlowId | String | 转出/入账流水ID | | voucherUrl | String | 佐证影像 | | flowAt | String | 落账时刻 | | handlerName / operatorName | String | 经手人 / 经办人 | | status | String | 恒 COMPLETED(本期无审批/撤销) | ### 3.2 发起互转 POST / **幂等**:`@Idempotent`,key=`fromAccountId:toAccountId:amount`,5 秒内重复提交返回「互转提交处理中,请勿重复提交」。 入参(FundTransferReqVO): | 字段 | 必填 | 说明 | |---|---|---| | mode | 是 | 存取方式(见枚举) | | fromAccountId | 是 | 转出账户ID | | toAccountId | 是 | 转入账户ID(不得与转出相同) | | amount | 是 | 转出金额(>0) | | fee | 否 | 手续费(≥0,默认 0,挂转出行) | | transferDate | 是 | 业务日期(可回溯补录) | | handlerName | 否 | 经手人(≤50) | | voucherUrl | 否 | 佐证影像(≤500) | | remark | 否 | 备注(≤200) | **口径**:不收转入金额——转出户净减 `amount+fee`、转入户净加 `amount`。 出参(FundTransferRespVO):`transferGroupId` / `outFlowId` / `inFlowId` / `fromBalanceAfter` / `toBalanceAfter`。 ## 4. 枚举 / 数据字典 | 字段 | 取值 | |---|---| | mode | BANK2CASH 银行取现金 / CASH2BANK 现金存银行 / THIRD2BANK 三方提现到银行 / BANK2THIRD 银行转三方 / BANK2BANK 银行转银行 / CASH2CASH 现金转现金 | | status | COMPLETED(恒值,本期无审批/撤销) | ## 5. 错误码 | 码 | 含义 | |---|---| | 595001 | 账户不存在 | | 595004 | 互转两方账户不能相同 | | 595006 | 账户已停用 | | 595008 | 取现出账账户须为基本户 | | 595009 | 存取方式无效 | | 595010 | 存取方式与转出/转入账户类型不匹配 | | 595102 | 金额无效(须大于0) | | 595103 | 余额不足且不允许透支 | | 595104 | 资金写入并发冲突,请重试 | ## 6. 示例 **银行取现** ``` POST /admin/finance/fund-transfers {"mode":"BANK2CASH","fromAccountId":"2097...","toAccountId":"2098...","amount":5000.00,"transferDate":"2026-09-09","handlerName":"李四"} → 200 {"transferGroupId":"...","outFlowId":"...","inFlowId":"...","fromBalanceAfter":...,"toBalanceAfter":...} ``` **两方同账户(异常)** ``` POST /admin/finance/fund-transfers {"mode":"BANK2BANK","fromAccountId":"X","toAccountId":"X","amount":100,"transferDate":"2026-09-09"} → 595004 互转两方账户不能相同 ``` **5 秒内重复提交(幂等拦截)** ``` (同 fromAccountId:toAccountId:amount 再次 POST) → 互转提交处理中,请勿重复提交 ``` ## 7. 注意事项 - 互转即付即完成(status 恒 COMPLETED),无审批/撤销。 - 银行取现(BANK2CASH)出账账户须为基本户(595008)。 - 手续费 fee 只挂转出行,转入户实收=amount。 - 长整型 ID 序列化为字符串。 ## 8. 关联 / 联系人 - Issue:https://git.1814.love:8443/wx/HL/issues/7003 - Commit:https://git.1814.love:8443/wx/HL/commit/b46269a4d4 - 负责人:腰苏图(yst)