feat(changelog): 公司借款域全量上线——12 接口 + 出纳 COMPANY_LOAN 新付款线(#7845 / PR #7846 #7848 #7850 #7851)
changelog-filename-gate / validate (push) Failing after 2s
changelog-filename-gate / validate (push) Failing after 2s
这个提交包含在:
@@ -0,0 +1,705 @@
|
||||
---
|
||||
schema: "hl-changelog/v2"
|
||||
ticket: "finance-company-loan-module-onboarding"
|
||||
title: "公司借款域全量上线(12 接口:登记/详情/借入到账/收回收银台/归还收银台/还款流水/操作流水 + 出纳 COMPANY_LOAN 新付款线)"
|
||||
consumer: "admin"
|
||||
author: "yst(GIT)"
|
||||
change_type: "新增接口"
|
||||
backend_status: "deployed"
|
||||
gateway_status: "verified"
|
||||
frontend_status: "pending"
|
||||
frontend_owner: ""
|
||||
frontend_ref: ""
|
||||
target_release: ""
|
||||
verified_at: "2026-09-17"
|
||||
status_note: "财务域公司借款模块首次整模块交付:双向 OUT 借出 / IN 借入,登记制四态(APPROVED 已登记 → PAID 已收付 → SETTLING 核销中 → SETTLED 已核销,无独立审批)。含登记、详情、借入到账确认、按单位聚合收回(OUT,支持部分收回)、整笔归还(IN)、还款流水分页、操作流水 12 个新端点;出纳侧新增 COMPANY_LOAN 付款类型(借出放款进待付款队列,金额锁死=借款金额)。后端 4 PR 已合并 dev-v3 并部署测试服,E2E 已真实跑通。前端此前无公司借款任何页面,按本文一次对接即可。"
|
||||
updated_at: "2026-09-17"
|
||||
base: "dev-v3"
|
||||
---
|
||||
|
||||
# 公司借款域全量上线(管理后台)
|
||||
|
||||
> **服务**: hl-order-service-v3(hl-finance 模块)
|
||||
> **类型**: 🆕 整模块新增(本期新交付,前端首次对接)
|
||||
> **日期**: 2026-09-17
|
||||
> **影响范围**: 管理后台财务域「公司借款」菜单 + 出纳支付管理「公司借款」页签
|
||||
> **覆盖 Epic**: #7845(PR-1 #7846 地基+登记链 / PR-2 #7848 出纳放款+借入到账 / PR-3 #7850 收回·归还收银台 / PR-4 #7851 操作流水+文档)
|
||||
|
||||
---
|
||||
|
||||
## 一、接口背景
|
||||
|
||||
公司借款 = **公司与外部往来单位(本期恒为供应商)之间的资金拆借**。两个方向:
|
||||
|
||||
- **OUT 借出**:公司把钱借给单位 → 出纳放款 → 到期按单位聚合**收回**(可部分多次)
|
||||
- **IN 借入**:公司向单位借钱 → 财务确认**借入到账** → 到期按单位**整笔归还**(勾选即还欠还全额)
|
||||
|
||||
业务闭环(登记制,**无独立审批**,登记即生效 APPROVED):
|
||||
|
||||
```
|
||||
登记 POST /admin/finance/company-loans ──▶ APPROVED(已登记)
|
||||
│
|
||||
├─ OUT 借出:出纳支付管理队列放款 POST /admin/finance/cashier/pay (bizType=COMPANY_LOAN)
|
||||
│ APPROVED → PAID(落 CASHIER_PAY 操作流水 + 资金流水 OUT)
|
||||
└─ IN 借入:借款详情页确认到账 POST /{id}/confirm-inbound
|
||||
APPROVED → PAID(落 CONFIRM_INBOUND 操作流水 + 资金流水 IN)
|
||||
│
|
||||
├─ OUT 收回:收回收银台 单位聚合 → 勾选填额 → POST /recover/settle(支持部分收回)
|
||||
└─ IN 归还:归还收银台 单位聚合 → 勾选整笔 → POST /repay-cashier/settle(每笔还欠还全额)
|
||||
│
|
||||
按 SUM(repay) 现算状态:0 < 已收/还 < 借款金额 → SETTLING(核销中)
|
||||
已收/还 ≥ 借款金额 → SETTLED(已核销,终态)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 二、变更清单
|
||||
|
||||
| # | 变更 | 类型 | 说明 |
|
||||
|---|------|------|------|
|
||||
| 1 | `GET /admin/finance/company-loans/page` | ✨ 新增 | 公司借款分页(状态/方向/单位/关键字筛选) |
|
||||
| 2 | `POST /admin/finance/company-loans` | ✨ 新增 | 登记借款(登记即 APPROVED) |
|
||||
| 3 | `GET /admin/finance/company-loans/{id}` | ✨ 新增 | 借款单详情(全字段 + 还款流水 + 余额现算) |
|
||||
| 4 | `POST /admin/finance/company-loans/{id}/confirm-inbound` | ✨ 新增 | 借入到账确认(仅 IN 单) |
|
||||
| 5 | `GET /admin/finance/company-loans/{id}/review-logs` | ✨ 新增 | 操作流水(登记/到账/放款/收回/归还留痕) |
|
||||
| 6 | `GET /admin/finance/company-loans/recover/units` | ✨ 新增 | 收回收银台-单位聚合(OUT) |
|
||||
| 7 | `GET /admin/finance/company-loans/recover/units/{unitId}` | ✨ 新增 | 收回收银台-单位待收回明细 |
|
||||
| 8 | `POST /admin/finance/company-loans/recover/settle` | ✨ 新增 | 合并收款(收回,仅 OUT,支持部分) |
|
||||
| 9 | `GET /admin/finance/company-loans/repay-cashier/units` | ✨ 新增 | 归还收银台-单位聚合(IN) |
|
||||
| 10 | `GET /admin/finance/company-loans/repay-cashier/units/{unitId}` | ✨ 新增 | 归还收银台-单位待归还明细 |
|
||||
| 11 | `POST /admin/finance/company-loans/repay-cashier/settle` | ✨ 新增 | 整笔归还(仅 IN,每笔还欠还全额) |
|
||||
| 12 | `GET /admin/finance/company-loans/repays/page` | ✨ 新增 | 还款流水分页(收回/归还共用) |
|
||||
| 13 | `GET /admin/finance/cashier/queue?payType=COMPANY_LOAN` | 🔧 修改 | 出纳待付款队列新增 COMPANY_LOAN 付款类型(仅 OUT 借出且 APPROVED 单进队列) |
|
||||
| 14 | `POST /admin/finance/cashier/pay`(bizType=COMPANY_LOAN) | 🔧 修改 | 出纳登记付款新增公司借款借出放款业务线,金额锁死=借款金额 |
|
||||
| 15 | 资金流水 `bizType` 枚举 | ✨ 新增值 | 新增 `COMPANY_LOAN`(资金流水按 bizType=COMPANY_LOAN&bizId 可串联借款单) |
|
||||
|
||||
---
|
||||
|
||||
## 三、接口详情
|
||||
|
||||
| 项 | 说明 |
|
||||
|---|---|
|
||||
| 使用场景 | 管理后台财务域「公司借款」模块(列表/详情/登记/收银台)+ 出纳支付管理「公司借款」页签 |
|
||||
| 认证 | 管理后台 JWT(网关统一鉴权),需财务域菜单权限 |
|
||||
| 幂等性 | 登记/收付/收回/归还均**非幂等写**:重复提交由状态机守卫拦截——登记靠单号 uk 撞号重试;收付后状态已非 APPROVED,重试被 599302 拦;收回/归还对 SETTLED 单重试被 599308 拦、超额被 599309 拦(锁内现算余额,整体回滚不留半截) |
|
||||
| 限流 | 走网关统一限流,无模块特殊限流 |
|
||||
| 单号规则 | 借款单号 `GS-` + yyyyMMdd + 4 位序号(OUT/IN **共用前缀**,靠 `direction` 徽标区分);还款流水号 `GH-` + yyyyMMdd + 4 位序号 |
|
||||
| ID 序列化 | 所有 Long 型 ID(id / unitId / handlerStaffId / fundAccountId / repayIds 等)序列化为 **String**,防 JS 精度丢失 |
|
||||
|
||||
---
|
||||
|
||||
## 四、接口入参
|
||||
|
||||
### 4.1 `GET /admin/finance/company-loans/page` 公司借款分页
|
||||
|
||||
Query 入参(继承 PageParam:`pageNo` / `pageSize` 必填):
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| `status` | String | 否 | 单据状态单值:APPROVED / PAID / SETTLING / SETTLED;空=全部 |
|
||||
| `statuses` | String[] | 否 | 状态多值 IN 查询(如 `statuses=APPROVED&statuses=PAID`);非空时优先于 status |
|
||||
| `direction` | String | 否 | 方向:OUT 借出 / IN 借入;空=不限 |
|
||||
| `unitId` | Long | 否 | 往来单位ID 精确;空=不限 |
|
||||
| `keyword` | String | 否 | 关键字(借款单号 / 往来单位名称模糊);空=不限 |
|
||||
|
||||
### 4.2 `POST /admin/finance/company-loans` 登记借款
|
||||
|
||||
请求体 `CompanyLoanCreateReqVO`:
|
||||
|
||||
| 字段 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| `direction` | String | ✅ | 方向:OUT 借出 / IN 借入(其他值 → 599302) |
|
||||
| `unitType` | String | 否 | 往来单位类型(字典 fin_unit_type;本期恒 SUPPLIER,空按 SUPPLIER 处理,其他值 → 599304) |
|
||||
| `unitId` | Long | ✅ | 往来单位ID(供应商;后端反查可付款性并落全称快照,查不到/不可选 → 599304) |
|
||||
| `unitName` | String | 否 | **契约兼容字段,服务端反查覆盖,前端传值不生效**(≤200 字) |
|
||||
| `handlerStaffId` | Long | ✅ | 经办人 adminId(后端反查 wechatName 落姓名快照;查不到/无真名/用户域降级 → 599305) |
|
||||
| `handlerStaffName` | String | 否 | **契约兼容字段,服务端反查覆盖,前端传值不生效**(≤64 字) |
|
||||
| `amount` | BigDecimal | ✅ | 借款金额(>0,否则 599303;不计息) |
|
||||
| `feeRate` | BigDecimal | 否 | 手续费率‰(登记参考值,空按 0;实际手续费在收付环节定) |
|
||||
| `loanDate` | Date | 否 | 借款日期(yyyy-MM-dd) |
|
||||
| `dueDate` | Date | ✅ | 约定归还日期(yyyy-MM-dd) |
|
||||
| `purpose` | String | ✅ | 借款用途(≤200 字) |
|
||||
|
||||
### 4.3 `GET /admin/finance/company-loans/{id}` 借款单详情
|
||||
|
||||
路径参数:`id`(Long,借款单ID,必填)。不存在(含已软删)→ 599301。
|
||||
|
||||
### 4.4 `POST /admin/finance/company-loans/{id}/confirm-inbound` 借入到账确认
|
||||
|
||||
路径参数:`id`(必填)。**仅 direction=IN 单可调**(OUT 单 → 599310);状态须 APPROVED(否则 599302)。
|
||||
|
||||
请求体 `CompanyLoanInboundConfirmReqVO`:
|
||||
|
||||
| 字段 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| `fundAccountId` | Long | ✅ | 入账资金账户ID(fin_fund_account;不存在 595001 / 已停用 595006) |
|
||||
| `actualAmount` | BigDecimal | ✅ | 实际到账金额(>0 且 ≤ 借款金额,否则 599311;与借款金额差额 = 到账手续费) |
|
||||
|
||||
> 本端点**不收**到账凭证影像(契约无 voucherUrl)。
|
||||
|
||||
### 4.5 `GET /admin/finance/company-loans/{id}/review-logs` 操作流水
|
||||
|
||||
路径参数:`id`(必填,不存在 → 599301)。无 Query 入参。按操作发生时间**升序**返回,无记录返回空数组 `[]`。
|
||||
|
||||
### 4.6 `GET /admin/finance/company-loans/recover/units` 收回收银台-单位聚合
|
||||
|
||||
Query 入参:
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| `unitName` | String | 否 | 单位名模糊;空=全部 |
|
||||
|
||||
只聚合 direction=OUT 且状态 PAID/SETTLING(未核销)的借出单。
|
||||
|
||||
### 4.7 `GET /admin/finance/company-loans/recover/units/{unitId}` 单位待收回明细
|
||||
|
||||
路径参数:`unitId`(Long,必填)。返回该单位名下全部未核销借出单(余额现算 + 逾期标记),供勾选合并收款。
|
||||
|
||||
### 4.8 `POST /admin/finance/company-loans/recover/settle` 合并收款(收回)
|
||||
|
||||
请求体 `CompanyLoanRecoverSettleReqVO`:
|
||||
|
||||
| 字段 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| `unitId` | Long | ✅ | 往来单位ID(勾选单须全部属该单位,否则 599312 整体回滚) |
|
||||
| `items` | Item[] | ✅ | 勾选明细(≥1 条) |
|
||||
| `items[].loanId` | Long | ✅ | 借款单ID |
|
||||
| `items[].amount` | BigDecimal | ✅ | 本次收回金额(>0 且 ≤ 该单余额,超额 → 599309 整体回滚) |
|
||||
| `fundAccountId` | Long | ✅ | 入账资金账户ID(595001/595006) |
|
||||
| `feeRate` | BigDecimal | 否 | 手续费率‰(默认 0,负值 → 599303) |
|
||||
| `voucherUrl` | String | 否 | 收款凭证影像URL |
|
||||
|
||||
金额口径:**fee = Σ勾选填额 × feeRate / 1000;实收 = Σ − fee**。资金流水合并**单笔 IN**(amount=实收,biz_id=首笔还款流水ID)。
|
||||
|
||||
### 4.9 `GET /admin/finance/company-loans/repay-cashier/units` 归还收银台-单位聚合
|
||||
|
||||
Query 入参同 4.6(`unitName` 模糊,可空)。只聚合 direction=IN 且 PAID/SETTLING 的借入单。
|
||||
|
||||
### 4.10 `GET /admin/finance/company-loans/repay-cashier/units/{unitId}` 单位待归还明细
|
||||
|
||||
路径参数:`unitId`(必填)。返回该单位名下未核销借入单,**勾选即整笔还 outstandingAmount 全额**(不支持部分归还)。
|
||||
|
||||
### 4.11 `POST /admin/finance/company-loans/repay-cashier/settle` 整笔归还
|
||||
|
||||
请求体 `CompanyLoanRepaySettleReqVO`:
|
||||
|
||||
| 字段 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| `unitId` | Long | ✅ | 往来单位ID(勾选单须全部属该单位,否则 599312) |
|
||||
| `loanIds` | Long[] | ✅ | 勾选整笔归还的借入单ID列表(≥1;**每笔还其欠还全额**,不填金额) |
|
||||
| `fundAccountId` | Long | ✅ | 出账资金账户ID(595001/595006;余额不足透支闸 595103) |
|
||||
| `feeRate` | BigDecimal | 否 | 手续费率‰(默认 0,负值 → 599303) |
|
||||
| `voucherUrl` | String | 否 | 付款凭证影像URL |
|
||||
|
||||
金额口径:**fee = Σ欠还全额 × feeRate / 1000;实付 = Σ + fee**(注意:归还侧手续费是**外加**,与收回侧**内扣**相反)。资金流水合并**单笔 OUT**(结存 −Σ−fee)。
|
||||
|
||||
### 4.12 `GET /admin/finance/company-loans/repays/page` 还款流水分页
|
||||
|
||||
Query 入参(继承 PageParam:`pageNo` / `pageSize` 必填):
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|---|---|---|---|
|
||||
| `loanId` | Long | 否 | 借款单ID 精确;空=不限 |
|
||||
| `unitId` | Long | 否 | 往来单位ID;空=不限 |
|
||||
| `direction` | String | 否 | OUT 借出(行=收回)/ IN 借入(行=归还);空=不限 |
|
||||
| `repaidAtStart` | Date | 否 | 收/还日期起(含,yyyy-MM-dd) |
|
||||
| `repaidAtEnd` | Date | 否 | 收/还日期止(含,yyyy-MM-dd) |
|
||||
|
||||
### 4.13 出纳既有接口(COMPANY_LOAN 调用方式)
|
||||
|
||||
**队列**:`GET /admin/finance/cashier/queue?payType=COMPANY_LOAN&pageNo=1&pageSize=10`(出参结构不变,见 §五.13)。
|
||||
|
||||
**放款**:`POST /admin/finance/cashier/pay`,请求体 `CashierPayReqVO`(既有结构):
|
||||
|
||||
| 字段 | 必填 | 公司借款场景取值 |
|
||||
|---|---|---|
|
||||
| `bizType` | ✅ | 固定 `COMPANY_LOAN` |
|
||||
| `bizId` | ✅ | 借款单ID(仅 direction=OUT 且 status=APPROVED;IN 单 → 599310) |
|
||||
| `payAccountId` | ✅ | 出账公司账户ID |
|
||||
| `payMethod` | 否 | 字典 fin_pay_way:CASH / BANK / THIRD_PARTY |
|
||||
| `payChannel` | 否 | WXPAY / ALIPAY(仅 payMethod=THIRD_PARTY 时传) |
|
||||
| `amount` | ✅ | **金额锁死 = 借款金额**,不等 → 598610 |
|
||||
| `fee` | 否 | 手续费(≥0,挂出账流水) |
|
||||
| `voucherNo` / `voucherUrl` | 否 | 付款凭证号 / 凭证影像 URL |
|
||||
| `payDate` | ✅ | 付款日期(yyyy-MM-dd,可回溯补录) |
|
||||
| `operatorName` | 否 | 后端忽略,统一取当前登录人快照 |
|
||||
|
||||
---
|
||||
|
||||
## 五、出参字段
|
||||
|
||||
### 5.1 分页行 `CompanyLoanRowRespVO`(接口 1,`Result<PageResult<行>>`)
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|---|---|---|
|
||||
| `id` | String | 借款单ID |
|
||||
| `loanNo` | String | 借款单号(GS- 前缀) |
|
||||
| `direction` | String | OUT 借出 / IN 借入 |
|
||||
| `unitType` | String | 往来单位类型(本期恒 SUPPLIER) |
|
||||
| `unitId` | String | 往来单位ID |
|
||||
| `unitName` | String | 往来单位名称快照 |
|
||||
| `handlerStaffId` | String | 经办人 adminId |
|
||||
| `handlerStaffName` | String | 经办人姓名快照 |
|
||||
| `amount` | BigDecimal | 借款金额 |
|
||||
| `repaidAmount` | BigDecimal | 已收/还金额(repay 汇总现算) |
|
||||
| `outstandingAmount` | BigDecimal | 待收/还余额 = amount − repaidAmount |
|
||||
| `purpose` | String | 借款用途 |
|
||||
| `loanDate` | Date | 借款日期 |
|
||||
| `dueDate` | Date | 约定归还日期 |
|
||||
| `status` | String | APPROVED / PAID / SETTLING / SETTLED |
|
||||
| `operatorId` | String | 登记人 adminId(created_by 反查) |
|
||||
| `operatorName` | String | 登记人真名(反查降级可为 null,仅展示) |
|
||||
| `createTime` | DateTime | 创建时间 |
|
||||
|
||||
### 5.2 登记响应 `CompanyLoanCreateRespVO`(接口 2)
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|---|---|---|
|
||||
| `id` | String | 新借款单ID(状态 APPROVED) |
|
||||
| `loanNo` | String | 借款单号(GS-) |
|
||||
|
||||
### 5.3 详情 `CompanyLoanDetailRespVO`(接口 3)
|
||||
|
||||
在 5.1 全部字段基础上增加:
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|---|---|---|
|
||||
| `feeRate` | BigDecimal | 手续费率‰(登记参考值) |
|
||||
| `fundAccountId` | String | 出/入账资金账户ID(**仅 PAID 及之后有值**) |
|
||||
| `paidAt` | DateTime | 收付讫业务时间(**仅 PAID 及之后有值**) |
|
||||
| `approvalInstanceId` | String | 审批实例ID(登记制无审批,恒 null) |
|
||||
| `repays` | RepayItem[] | 还款流水(按收/还时间**倒序**;未发生收还前空数组) |
|
||||
|
||||
`repays[]` 子项 `CompanyLoanRepayItem`:
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|---|---|---|
|
||||
| `id` | String | 还款流水ID |
|
||||
| `repayNo` | String | 还款单号(GH- 前缀) |
|
||||
| `direction` | String | 随主单:OUT(本行=收回)/ IN(本行=归还) |
|
||||
| `amount` | BigDecimal | 本次收/还金额 |
|
||||
| `fundAccountId` | String | 收/付资金账户ID |
|
||||
| `voucherUrl` | String | 收/还凭证影像URL |
|
||||
| `repaidAt` | DateTime | 收/还时间 |
|
||||
|
||||
### 5.4 借入到账确认(接口 4)
|
||||
|
||||
`Result<Void>`,成功无返回体(`data=null`)。
|
||||
|
||||
### 5.5 操作流水行 `FinReviewLogRespVO`(接口 5,`Result<List<行>>`,升序)
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|---|---|---|
|
||||
| `logId` | String | 流水ID |
|
||||
| `action` | String | 操作动作:**REGISTER 登记 / CONFIRM_INBOUND 借入到账 / CASHIER_PAY 出纳放款 / RECOVER 收回 / REPAY 归还**(公司借款词表,与 #7801 六域审核词表 APPROVE/REJECT/RETURN/UN_APPROVE 不同) |
|
||||
| `operatorId` | String | 操作人ID(无登录上下文快照可为空) |
|
||||
| `operatorName` | String | 操作人姓名快照 |
|
||||
| `opinion` | String | 操作意见/备注(可空) |
|
||||
| `fromStatus` | String | 操作前状态(登记 REGISTER 时为 null) |
|
||||
| `toStatus` | String | 操作后状态 |
|
||||
| `createTime` | DateTime | 操作发生时间 |
|
||||
|
||||
### 5.6 收回单位聚合行 `CompanyLoanRecoverUnitRespVO`(接口 6,`Result<List<行>>`)
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|---|---|---|
|
||||
| `unitId` | String | 往来单位ID |
|
||||
| `unitName` | String | 往来单位名称快照 |
|
||||
| `loanCount` | Integer | 未核销借出单笔数 |
|
||||
| `totalOutstanding` | BigDecimal | 待收回余额合计 |
|
||||
| `nearestDueDate` | Date | 最近到期日(MIN(due_date)) |
|
||||
|
||||
### 5.7 单位待收回明细行 `CompanyLoanRecoverItemRespVO`(接口 7)
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|---|---|---|
|
||||
| `loanId` | String | 借款单ID |
|
||||
| `loanNo` | String | 借款单号 |
|
||||
| `amount` | BigDecimal | 借款金额 |
|
||||
| `repaidAmount` | BigDecimal | 已收回合计(现算) |
|
||||
| `outstandingAmount` | BigDecimal | 待收回余额(填额上限) |
|
||||
| `dueDate` | Date | 约定归还日期 |
|
||||
| `overdue` | Boolean | 是否已逾期(dueDate < 今日且未核销) |
|
||||
|
||||
### 5.8 合并收款响应 `CompanyLoanRecoverSettleRespVO`(接口 8)
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|---|---|---|
|
||||
| `totalAmount` | BigDecimal | 本次收回合计(Σ 勾选填额) |
|
||||
| `actualAmount` | BigDecimal | 实收 = totalAmount − fee |
|
||||
| `fee` | BigDecimal | 手续费(= totalAmount × feeRate/1000) |
|
||||
| `repayIds` | String[] | 生成的还款流水ID(逐笔) |
|
||||
| `settledLoanIds` | String[] | 本次余额归零转 SETTLED 的借款单ID(前端可据此局部刷新行状态) |
|
||||
|
||||
### 5.9 归还单位聚合行 `CompanyLoanRepayUnitRespVO`(接口 9)
|
||||
|
||||
字段与 5.6 完全对称(unitId / unitName / loanCount / totalOutstanding / nearestDueDate),仅语义为「待归还」。
|
||||
|
||||
### 5.10 单位待归还明细行 `CompanyLoanRepayCashierItemRespVO`(接口 10)
|
||||
|
||||
字段与 5.7 完全对称(loanId / loanNo / amount / repaidAmount / outstandingAmount / dueDate / overdue);`outstandingAmount` = 勾选后整笔还的全额。
|
||||
|
||||
### 5.11 整笔归还响应 `CompanyLoanRepaySettleRespVO`(接口 11)
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|---|---|---|
|
||||
| `totalAmount` | BigDecimal | 本次归还合计(Σ 勾选单欠还全额) |
|
||||
| `actualPayAmount` | BigDecimal | 实付 = totalAmount + fee(手续费外加) |
|
||||
| `fee` | BigDecimal | 手续费(= totalAmount × feeRate/1000) |
|
||||
| `repayIds` | String[] | 生成的还款流水ID(逐笔) |
|
||||
| `settledLoanIds` | String[] | 余额归零转 SETTLED 的借款单ID |
|
||||
|
||||
### 5.12 还款流水行 `CompanyLoanRepayRowRespVO`(接口 12,`Result<PageResult<行>>`)
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|---|---|---|
|
||||
| `id` | String | 还款流水ID |
|
||||
| `repayNo` | String | 归还/收回单号(GH- 前缀) |
|
||||
| `loanId` | String | 关联借款单ID |
|
||||
| `loanNo` | String | 关联借款单号 |
|
||||
| `direction` | String | 随主单:OUT(本行=收回)/ IN(本行=归还) |
|
||||
| `unitName` | String | 往来单位名称快照 |
|
||||
| `amount` | BigDecimal | 本次归还/收回金额 |
|
||||
| `fundAccountId` | String | 收/付资金账户ID |
|
||||
| `repaidAt` | DateTime | 归还/收回时间 |
|
||||
| `voucherUrl` | String | 凭证影像URL |
|
||||
|
||||
### 5.13 出纳队列行 `CashierQueueRowRespVO`(接口 13,既有结构)
|
||||
|
||||
COMPANY_LOAN 行的关键取值(其余字段沿用既有定义):
|
||||
|
||||
| 字段 | COMPANY_LOAN 取值 |
|
||||
|---|---|
|
||||
| `id` / `bizNo` | 借款单ID / 借款单号(GS-) |
|
||||
| `payType` | `COMPANY_LOAN` |
|
||||
| `payTypeName` | `公司借款` |
|
||||
| `unitId` / `unitName` | 往来单位ID / 名称快照 |
|
||||
| `category` | 固定值 `公司借款` |
|
||||
| `categoryName` | 同 category(`公司借款`) |
|
||||
| `amount` | 借款金额(放款金额锁死基准) |
|
||||
| `fee` | 0(放款手续费在 pay 时登记) |
|
||||
| `actualAmount` | = amount − fee |
|
||||
| `operatorName` | 经办人姓名快照 |
|
||||
| `status` | 队列内恒 `APPROVED` |
|
||||
| `occurDate` / `remark` | 借款日期 / 借款用途 |
|
||||
|
||||
---
|
||||
|
||||
## 六、枚举 / 数据字典
|
||||
|
||||
### 6.1 方向 `direction`
|
||||
|
||||
| 值 | 中文 | 说明 |
|
||||
|---|---|---|
|
||||
| `OUT` | 借出 | 公司借钱给单位;出纳队列放款;收回走 recover 收银台 |
|
||||
| `IN` | 借入 | 公司向单位借钱;confirm-inbound 确认到账;归还走 repay-cashier 收银台 |
|
||||
|
||||
### 6.2 单据状态 `status`(四态,登记制无审批)
|
||||
|
||||
| 值 | 中文 | 进入条件 |
|
||||
|---|---|---|
|
||||
| `APPROVED` | 已登记 | 登记成功即此态(无独立审批) |
|
||||
| `PAID` | 已收付 | OUT=出纳放款完成 / IN=借入到账确认完成 |
|
||||
| `SETTLING` | 核销中 | 0 < SUM(repay) < amount(部分收/还) |
|
||||
| `SETTLED` | 已核销 | SUM(repay) ≥ amount(终态,一次还满则 PAID→SETTLED 直达) |
|
||||
|
||||
### 6.3 操作流水动作 `action`(公司借款词表)
|
||||
|
||||
| 值 | 中文 | fromStatus → toStatus |
|
||||
|---|---|---|
|
||||
| `REGISTER` | 登记 | null → APPROVED |
|
||||
| `CONFIRM_INBOUND` | 借入到账 | APPROVED → PAID(仅 IN) |
|
||||
| `CASHIER_PAY` | 出纳放款 | APPROVED → PAID(仅 OUT) |
|
||||
| `RECOVER` | 收回 | PAID/SETTLING → SETTLING/SETTLED(仅 OUT) |
|
||||
| `REPAY` | 归还 | PAID/SETTLING → SETTLING/SETTLED(仅 IN) |
|
||||
|
||||
### 6.4 出纳付款类型 `FinCashierPayTypeEnum`(本次新增值)
|
||||
|
||||
| 值 | 中文 | 单号前缀 | 进付款队列 |
|
||||
|---|---|---|---|
|
||||
| `COMPANY_LOAN` 🆕 | 公司借款 | GS- | ✅(仅 direction=OUT 且 APPROVED 单) |
|
||||
|
||||
(既有值 NONBIZ / EXPENSE / PAYMENT / PREPAY / STAFF_LOAN / REIMBURSE / ADVANCE 不变;ADVANCE 仍 queueVisible=false 不进队列。)
|
||||
|
||||
### 6.5 资金流水 `bizType` 新增值
|
||||
|
||||
`COMPANY_LOAN` —— 公司借款相关的全部真金白银落点(放款 OUT / 到账 IN / 收回 IN / 归还 OUT)均以此 bizType + bizId 串联,资金流水列表可按 bizType=COMPANY_LOAN 过滤。
|
||||
|
||||
### 6.6 数据字典
|
||||
|
||||
| 字典 | 用途 |
|
||||
|---|---|
|
||||
| `fin_unit_type` | 往来单位类型(本期恒 SUPPLIER 供应商) |
|
||||
| `fin_pay_way` | 付款方式(出纳 pay:CASH / BANK / THIRD_PARTY) |
|
||||
|
||||
---
|
||||
|
||||
## 七、错误码
|
||||
|
||||
### 7.1 公司借款新段位 599301-599312(owner=hl-finance)
|
||||
|
||||
| 码 | 常量 | 消息 | 触发场景 |
|
||||
|---|---|---|---|
|
||||
| 599301 | COMPANY_LOAN_NOT_FOUND | 借款单不存在 | 详情/流水/收付/收回/归还操作的借款单不存在(含已软删) |
|
||||
| 599302 | COMPANY_LOAN_STATUS_ILLEGAL | 借款单状态或方向不允许此操作 | 状态机守卫:如对 PAID 单再次 confirm-inbound、对 APPROVED 单收回 |
|
||||
| 599303 | COMPANY_LOAN_AMOUNT_INVALID | 借款金额无效(须大于0) | 登记 amount≤0;settle feeRate 为负 |
|
||||
| 599304 | COMPANY_LOAN_UNIT_INVALID | 往来单位不存在或不可选 | unitId 查不到/不可付款/资源域降级/unitType 非 SUPPLIER |
|
||||
| 599305 | COMPANY_LOAN_HANDLER_INVALID | 经办人非法(不存在或未登记真名) | handlerStaffId 查不到/wechatName 空/用户域降级 |
|
||||
| 599306 | COMPANY_LOAN_NO_CONFLICT | 借款单号生成冲突,请重试 | GS- 取号撞号重试 3 次耗尽 |
|
||||
| 599307 | COMPANY_LOAN_REPAY_NO_CONFLICT | 还款单号生成冲突,请重试 | GH- 取号撞号重试 3 次耗尽 |
|
||||
| 599308 | COMPANY_LOAN_ALREADY_SETTLED | 借款单已核销,不允许再收/还 | 对 SETTLED 终态单收回/归还 |
|
||||
| 599309 | COMPANY_LOAN_REPAY_EXCEED | 收/还金额超过借款剩余余额 | 收回填额 > 该单锁内现算余额(整体回滚,不静默截断) |
|
||||
| 599310 | COMPANY_LOAN_DIRECTION_ILLEGAL | 借款单方向与该操作不匹配 | IN 单走出纳放款 / OUT 单 confirm-inbound / IN 单收回 / OUT 单归还 |
|
||||
| 599311 | COMPANY_LOAN_INBOUND_AMOUNT_INVALID | 到账金额须大于0且不超过借款金额 | confirm-inbound actualAmount 越界 |
|
||||
| 599312 | COMPANY_LOAN_UNIT_MISMATCH | 勾选借款单与所选单位不一致 | settle 勾选单含其他单位的单(整体回滚) |
|
||||
|
||||
### 7.2 复用既有码
|
||||
|
||||
| 码 | 消息 | 触发场景 |
|
||||
|---|---|---|
|
||||
| 598601 | 业务单不存在 | 出纳 pay 的 bizId 查不到借款单 |
|
||||
| 598602 | 业务单状态非已批准,不可付款 | 出纳 pay 时单据已非 APPROVED(含并发推进) |
|
||||
| 598604 | 账户余额不足且不允许透支 | 出纳放款出账账户余额不足(595103 在出纳域边界的翻译) |
|
||||
| 598610 | 付款金额与单据应付金额不一致(出纳付款须严格按审批应付金额,不得修改) | 出纳 pay amount ≠ 借款金额(金额锁死) |
|
||||
| 595001 | 账户不存在 | fundAccountId/payAccountId 查不到 |
|
||||
| 595006 | 账户已停用 | 资金账户状态非 ACTIVE |
|
||||
| 595103 | 账户余额不足且不允许透支 | 归还 settle 出账账户余额不足(本域直接透出,不翻译) |
|
||||
|
||||
---
|
||||
|
||||
## 八、示例
|
||||
|
||||
### 8.1 典型成功:IN 借入全链路(登记 → 到账 → 整笔归还)
|
||||
|
||||
**① 登记** `POST /admin/finance/company-loans`
|
||||
|
||||
```json
|
||||
{
|
||||
"direction": "IN",
|
||||
"unitId": 8801,
|
||||
"handlerStaffId": 12,
|
||||
"amount": 50000.00,
|
||||
"dueDate": "2026-12-31",
|
||||
"purpose": "旺季房费周转",
|
||||
"loanDate": "2026-09-17",
|
||||
"feeRate": 0
|
||||
}
|
||||
```
|
||||
|
||||
响应:
|
||||
|
||||
```json
|
||||
{ "code": 0, "data": { "id": "1932700112233445567", "loanNo": "GS-202609170001" }, "msg": "" }
|
||||
```
|
||||
|
||||
**② 借入到账确认** `POST /admin/finance/company-loans/1932700112233445567/confirm-inbound`
|
||||
|
||||
```json
|
||||
{ "fundAccountId": 101, "actualAmount": 50000.00 }
|
||||
```
|
||||
|
||||
响应 `{ "code": 0, "data": null }`;状态 APPROVED→PAID,落 CONFIRM_INBOUND 操作流水。
|
||||
|
||||
**③ 归还收银台单位明细** `GET /admin/finance/company-loans/repay-cashier/units/8801`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"data": [
|
||||
{
|
||||
"loanId": "1932700112233445567",
|
||||
"loanNo": "GS-202609170001",
|
||||
"amount": 50000.00,
|
||||
"repaidAmount": 0.00,
|
||||
"outstandingAmount": 50000.00,
|
||||
"dueDate": "2026-12-31",
|
||||
"overdue": false
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
**④ 整笔归还** `POST /admin/finance/company-loans/repay-cashier/settle`
|
||||
|
||||
```json
|
||||
{
|
||||
"unitId": 8801,
|
||||
"loanIds": [1932700112233445567],
|
||||
"fundAccountId": 101,
|
||||
"feeRate": 1,
|
||||
"voucherUrl": "https://oss.example.com/voucher/gh001.png"
|
||||
}
|
||||
```
|
||||
|
||||
响应(fee = 50000 × 1/1000 = 50,实付 50050):
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"data": {
|
||||
"totalAmount": 50000.00,
|
||||
"actualPayAmount": 50050.00,
|
||||
"fee": 50.00,
|
||||
"repayIds": ["1932700998877665544"],
|
||||
"settledLoanIds": ["1932700112233445567"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
状态 PAID→SETTLED(一次还满直达终态)。
|
||||
|
||||
### 8.2 边界情况:OUT 借出部分收回 + 到账金额小于借款额 + 空流水
|
||||
|
||||
**① 借入到账差额(到账手续费)**:借款 50000,实际到账 49800(差额 200 视为到账手续费,合法):
|
||||
|
||||
```json
|
||||
{ "fundAccountId": 101, "actualAmount": 49800.00 }
|
||||
```
|
||||
|
||||
→ 200 OK,资金流水 IN 记 49800。
|
||||
|
||||
**② OUT 单部分收回**(借款 50000,先收 20000):`POST /admin/finance/company-loans/recover/settle`
|
||||
|
||||
```json
|
||||
{
|
||||
"unitId": 8801,
|
||||
"items": [{ "loanId": 1932700112233445566, "amount": 20000.00 }],
|
||||
"fundAccountId": 101,
|
||||
"feeRate": 0
|
||||
}
|
||||
```
|
||||
|
||||
响应:`totalAmount=20000 / actualAmount=20000 / fee=0 / settledLoanIds=[]`,状态 PAID→**SETTLING**(余额 30000 未清)。
|
||||
|
||||
**③ 无操作流水**(异常空态):`GET /admin/finance/company-loans/{id}/review-logs` 无记录时返回空数组:
|
||||
|
||||
```json
|
||||
{ "code": 0, "data": [] }
|
||||
```
|
||||
|
||||
(正常单据至少有 REGISTER 一条。)
|
||||
|
||||
**④ 详情未收付前**:`fundAccountId=null / paidAt=null / repays=[] / approvalInstanceId=null`。
|
||||
|
||||
### 8.3 业务失败:最小复现
|
||||
|
||||
**① 方向不匹配(599310)**:对 OUT 借出单调借入到账:
|
||||
|
||||
```http
|
||||
POST /admin/finance/company-loans/{OUT单id}/confirm-inbound
|
||||
Content-Type: application/json
|
||||
|
||||
{ "fundAccountId": 101, "actualAmount": 100.00 }
|
||||
```
|
||||
|
||||
```json
|
||||
{ "code": 599310, "data": null, "msg": "借款单方向与该操作不匹配" }
|
||||
```
|
||||
|
||||
**② 收回超额(599309)**:余额 30000 的单填 30001:
|
||||
|
||||
```json
|
||||
{ "unitId": 8801, "items": [{ "loanId": 1932700112233445566, "amount": 30001.00 }], "fundAccountId": 101 }
|
||||
```
|
||||
|
||||
```json
|
||||
{ "code": 599309, "data": null, "msg": "收/还金额超过借款剩余余额" }
|
||||
```
|
||||
|
||||
**③ 出纳放款金额未锁死(598610)**:借款 50000 的单按 49999 付款:
|
||||
|
||||
```json
|
||||
{ "bizType": "COMPANY_LOAN", "bizId": 1932700112233445566, "payAccountId": 101, "amount": 49999.00, "payDate": "2026-09-17" }
|
||||
```
|
||||
|
||||
```json
|
||||
{ "code": 598610, "data": null, "msg": "付款金额与单据应付金额不一致(出纳付款须严格按审批应付金额,不得修改)" }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 九、业务边界
|
||||
|
||||
### 适用场景
|
||||
|
||||
- 公司与**供应商**之间的资金拆借登记与核销(借出收回 / 借入归还)
|
||||
- 收回支持**部分多次**(同一单位多笔单可合并一次收款,逐笔填额)
|
||||
- 归还为**整笔**(勾选即还该单欠还全额,不支持部分归还——这是产品设计,非缺陷)
|
||||
|
||||
### 不适用场景
|
||||
|
||||
- 员工个人借款 → 走「员工借款」模块(fin_staff_loan,接口前缀 `/admin/finance/staff-loans`),不要混用
|
||||
- 需要审批流的借款 → 本域登记制**无审批**,登记即生效
|
||||
- 跨单位合并结算 → 一次 settle 只能勾同一 unitId 的单(599312)
|
||||
|
||||
### 特殊边界
|
||||
|
||||
- **SETTLED 为终态**:已核销单不再出现在收回/归还收银台(聚合与明细接口都只出 PAID/SETTLING 单)
|
||||
- **一次还满直达 SETTLED**:PAID 单一次收/还满额时状态 PAID→SETTLED,不经 SETTLING
|
||||
- **方向锁死动作**:OUT 单只进出纳付款队列 + recover 收银台;IN 单只走 confirm-inbound + repay-cashier 收银台,交叉一律 599310
|
||||
- **逾期仅展示**:overdue=true 不阻断收回/归还,仅列表标记
|
||||
- **余额现算不存列**:repaidAmount/outstandingAmount 由 fin_company_loan_repay 实时 SUM,页面刷新即最新
|
||||
|
||||
---
|
||||
|
||||
## 十、修改前后对比(出纳既有接口)
|
||||
|
||||
### 10.1 `GET /admin/finance/cashier/queue` 出参变化
|
||||
|
||||
| 项 | 原来 | 现在 |
|
||||
|---|---|---|
|
||||
| `payType` 枚举值 | NONBIZ / EXPENSE / PAYMENT / PREPAY / STAFF_LOAN / REIMBURSE / ADVANCE(预留) | 新增 **COMPANY_LOAN**(公司借款,queueVisible=true) |
|
||||
| `category` 固定值映射 | PREPAY=「预付款」/ STAFF_LOAN=「员工借款」/ REIMBURSE=「报账款」 | 新增 COMPANY_LOAN=固定值「**公司借款**」 |
|
||||
| 队列数据源 | 6 条已接通业务线 | +1 条:fin_company_loan(direction=OUT 且 status=APPROVED) |
|
||||
|
||||
字段**零增删**,仅枚举值扩充——前端按 payType 建字典/页签的需补 COMPANY_LOAN 一项。
|
||||
|
||||
### 10.2 `POST /admin/finance/cashier/pay` 行为变化
|
||||
|
||||
| 项 | 原来 | 现在 |
|
||||
|---|---|---|
|
||||
| `bizType` 可选值 | NONBIZ / EXPENSE / PAYMENT / PREPAY / STAFF_LOAN / REIMBURSE | +**COMPANY_LOAN** |
|
||||
| COMPANY_LOAN 金额基准 | ——(不存在) | **锁死 = 借款金额 amount**(不等 → 598610) |
|
||||
| COMPANY_LOAN 方向红线 | —— | 仅 direction=OUT;IN 单 → 599310(借入到账走本域 confirm-inbound,不进出纳) |
|
||||
|
||||
### 10.3 资金流水 `bizType` 枚举
|
||||
|
||||
| 原来 | 现在 |
|
||||
|---|---|
|
||||
| NONBIZ / EXPENSE / PAYMENT / PREPAY / STAFF_LOAN / REIMBURSE 等 | +**COMPANY_LOAN**(放款/到账/收回/归还四种资金动作共用) |
|
||||
|
||||
---
|
||||
|
||||
## 十一、影响评估 / 回滚
|
||||
|
||||
| 项 | 评估 |
|
||||
|---|---|
|
||||
| 破坏兼容 | **否**。12 个端点全部新增;出纳侧仅枚举值扩充 + 新路由分支,既有 payType 行为零变化 |
|
||||
| 前端同步上线 | 无需同步——前端无公司借款页面时不影响任何既有功能;新页面按本文对接后上线即可 |
|
||||
| 数据库 | 新建 3 表(fin_company_loan / fin_company_loan_repay / fin_company_loan_review_log),无存量表/存量数据变更,Flyway `V20260917_108` 部署自动执行 |
|
||||
| 菜单配置 | 后端需配 sys_menu:财务域「公司借款」页 + 出纳支付管理「公司借款」页签(以后端菜单 SQL 落地为准) |
|
||||
| 回滚方案 | 代码回滚到 PR-1 前即可(新端点 404、队列不再出 COMPANY_LOAN 行);3 张新表为增量,无存量依赖时可 `DROP TABLE fin_company_loan_review_log, fin_company_loan_repay, fin_company_loan;` 并清理 flyway_schema_history 对应行(需 DBA 操作,正常不需要) |
|
||||
|
||||
---
|
||||
|
||||
## 十二、注意事项
|
||||
|
||||
1. **unitName / handlerStaffName 前端传值不生效**:登记时服务端按 unitId / handlerStaffId 反查覆盖快照(防乱传),前端只需传 ID;展示用快照名,单位/人员改名不追溯。
|
||||
2. **收回与归还手续费方向相反**:收回 fee 内扣(实收=合计−fee);归还 fee 外加(实付=合计+fee)。前端金额预览区不要套错公式。
|
||||
3. **action 词表勿复用六域审核字典**:公司借款操作流水是 REGISTER/CONFIRM_INBOUND/CASHIER_PAY/RECOVER/REPAY,与 #7801 六域(APPROVE/REJECT/RETURN/UN_APPROVE)是两套词表,VO 虽同为 FinReviewLogRespVO,action 展示字典要分开。
|
||||
4. **GS- 单号 OUT/IN 共用**:列表/详情必须用 direction 徽标区分方向,不能只凭单号前缀判断。
|
||||
5. **Long ID 全部 String 序列化**:前端按字符串处理,勿转 Number(精度丢失)。
|
||||
6. **金额锁死**:出纳放款 amount 必须等于借款金额,前端付款弹窗金额框应只读回填队列行 amount。
|
||||
7. **settledLoanIds 局部刷新**:settle 响应已给出本次转 SETTLED 的单ID,收银台明细列表可据此直接移除对应行,不必整表重查。
|
||||
8. **confirm-inbound 不收凭证**:借入到账确认无 voucherUrl 字段,凭证在后续归还环节才登记。
|
||||
|
||||
---
|
||||
|
||||
## 十三、关联 / 联系人
|
||||
|
||||
- **父 Issue**: https://git.1814.love:8443/wx/HL/issues/7845
|
||||
- **PR-1 地基+登记链**: https://git.1814.love:8443/wx/HL/pulls/7846 | commit https://git.1814.love:8443/wx/HL/commit/f2ed775962
|
||||
- **PR-2 出纳放款+借入到账**: https://git.1814.love:8443/wx/HL/pulls/7848 | commit https://git.1814.love:8443/wx/HL/commit/c5c0c0672e
|
||||
- **PR-3 收回/归还收银台**: https://git.1814.love:8443/wx/HL/pulls/7850 | commit https://git.1814.love:8443/wx/HL/commit/7e238c211f
|
||||
- **PR-4 操作流水+文档**: https://git.1814.love:8443/wx/HL/pulls/7851 | commit https://git.1814.love:8443/wx/HL/commit/d2fbfd0846
|
||||
- **后端负责人**: 腰苏图(yst)
|
||||
在新工单中引用
屏蔽一个用户