文件
hl-api-changelog/changelogs-v2/2026-09/17_7845_公司借款域全量上线-新增接口-管理后台.md
T
2026-09-17 10:50:57 +08:00

34 KiB
原始文件 Blame 文件历史

schema, ticket, title, consumer, author, change_type, backend_status, gateway_status, frontend_status, frontend_owner, frontend_ref, target_release, verified_at, status_note, updated_at, base
schema ticket title consumer author change_type backend_status gateway_status frontend_status frontend_owner frontend_ref target_release verified_at status_note updated_at base
hl-changelog/v2 finance-company-loan-module-onboarding 公司借款域全量上线(12 接口:登记/详情/借入到账/收回收银台/归还收银台/还款流水/操作流水 + 出纳 COMPANY_LOAN 新付款线) admin yst(GIT) 新增接口 deployed verified verified mmg 15e3d7dd906e5e738e70c279360caf8ac03e509d 2026-09-17 财务域公司借款模块首次整模块交付:双向 OUT 借出 / IN 借入,登记制四态(APPROVED 已登记 → PAID 已收付 → SETTLING 核销中 → SETTLED 已核销,无独立审批)。含登记、详情、借入到账确认、按单位聚合收回(OUT,支持部分收回)、整笔归还(IN)、还款流水分页、操作流水 12 个新端点;出纳侧新增 COMPANY_LOAN 付款类型(借出放款进待付款队列,金额锁死=借款金额)。后端 4 PR 已合并 dev-v3 并部署测试服,E2E 已真实跑通。前端此前无公司借款任何页面,按本文一次对接即可。 前端 hl-admin 2026-09-17 done:api 12 端点封装+公司借款页(列表/登记/详情/确认到账)+收回/归还收银台抽屉+出纳 COMPANY_LOAN 页签薄壳,ReviewLogPane 词表并集扩本域五码;菜单待后端 sys_menu 落地后可见。 2026-09-17 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

{
  "direction": "IN",
  "unitId": 8801,
  "handlerStaffId": 12,
  "amount": 50000.00,
  "dueDate": "2026-12-31",
  "purpose": "旺季房费周转",
  "loanDate": "2026-09-17",
  "feeRate": 0
}

响应:

{ "code": 0, "data": { "id": "1932700112233445567", "loanNo": "GS-202609170001" }, "msg": "" }

② 借入到账确认 POST /admin/finance/company-loans/1932700112233445567/confirm-inbound

{ "fundAccountId": 101, "actualAmount": 50000.00 }

响应 { "code": 0, "data": null };状态 APPROVED→PAID,落 CONFIRM_INBOUND 操作流水。

③ 归还收银台单位明细 GET /admin/finance/company-loans/repay-cashier/units/8801

{
  "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

{
  "unitId": 8801,
  "loanIds": [1932700112233445567],
  "fundAccountId": 101,
  "feeRate": 1,
  "voucherUrl": "https://oss.example.com/voucher/gh001.png"
}

响应(fee = 50000 × 1/1000 = 50,实付 50050):

{
  "code": 0,
  "data": {
    "totalAmount": 50000.00,
    "actualPayAmount": 50050.00,
    "fee": 50.00,
    "repayIds": ["1932700998877665544"],
    "settledLoanIds": ["1932700112233445567"]
  }
}

状态 PAID→SETTLED(一次还满直达终态)。

8.2 边界情况:OUT 借出部分收回 + 到账金额小于借款额 + 空流水

① 借入到账差额(到账手续费):借款 50000,实际到账 49800(差额 200 视为到账手续费,合法):

{ "fundAccountId": 101, "actualAmount": 49800.00 }

→ 200 OK,资金流水 IN 记 49800。

② OUT 单部分收回(借款 50000,先收 20000):POST /admin/finance/company-loans/recover/settle

{
  "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 无记录时返回空数组:

{ "code": 0, "data": [] }

(正常单据至少有 REGISTER 一条。)

④ 详情未收付前:fundAccountId=null / paidAt=null / repays=[] / approvalInstanceId=null。

8.3 业务失败:最小复现

① 方向不匹配(599310):对 OUT 借出单调借入到账:

POST /admin/finance/company-loans/{OUT单id}/confirm-inbound
Content-Type: application/json

{ "fundAccountId": 101, "actualAmount": 100.00 }
{ "code": 599310, "data": null, "msg": "借款单方向与该操作不匹配" }

② 收回超额(599309):余额 30000 的单填 30001:

{ "unitId": 8801, "items": [{ "loanId": 1932700112233445566, "amount": 30001.00 }], "fundAccountId": 101 }
{ "code": 599309, "data": null, "msg": "收/还金额超过借款剩余余额" }

③ 出纳放款金额未锁死(598610):借款 50000 的单按 49999 付款:

{ "bizType": "COMPANY_LOAN", "bizId": 1932700112233445566, "payAccountId": 101, "amount": 49999.00, "payDate": "2026-09-17" }
{ "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 字段,凭证在后续归还环节才登记。

十三、关联 / 联系人