④ 放款
产品定义:放款至授信环节已绑定的银行账号。承接 03-借款(提现申请单 applyStatus=C)。图例与服务名映射见 00-总览。
链路:审批回调loanApplyCallBack→(锁/防重/额度/建据)BeforePaymentLA.execute→laChannelPlutus→PlutusLoanApplyPublisher发 PMT → 通道 transfer → 回流激活。真实分支见下方「分支清单」。
时序
sequenceDiagram autonumber participant RISK as 风控审批回调(跨服务) participant FCS as FCS 账务 participant PFS as PFS 产品 participant PMT as PMT 支付 participant EXT as 外部三方(Paystack/Monnify) RISK->>FCS: IFinancialService.loanApplyCallBack(applyNo/custId/金额/productFeeId/卡/scene/H5) Note over FCS: 锁客户(lockCustByCustId) + 防重借据(checkDuplicateLoan by applyNo) FCS->>PFS: queryProductByProductFeeId + queryAcctType Note over FCS: checkCustLmt 客户额度校验 Note over FCS: 金额 < 产品 minAmt 则修正为 minAmt opt H5 复借 Note over FCS: 取上一笔成功放款订单的卡/银行(queryLastLASuccessOrder) end Note over FCS: getBeforePaymentProcess(LA) → BeforePaymentLA.execute 建账户/借据/计划/合同/放款订单 Note over FCS: laChannelPlutus:身份类型 BVN/NIN + 通道映射(plutusChannelMapping) FCS->>PMT: PlutusLoanApplyPublisher.sendMsg 放款事件 Note over FCS: 订单状态 channel=PLUTUS, orderStatus=P, paymentStatus=U Note over FCS: 放款派发失败 try-catch 仅 log(订单留 P/U) Note over PMT: routeChannel 选通道(业务线 + 身份 BVN/NIN/Goldman + 银行码 + Apollo 优先级 + 银行可用性矩阵) PMT->>EXT: IThirdPayment.transfer 放款到客户账户(选中通道, isAcceptOtherAccount=N) EXT-->>PMT: 放款结果回调 Note over PMT: 扣款 pending → 换下一优先级通道(容灾轮转, B26000PChannelChangePending) PMT->>FCS: IInnerPaymentService.paymentResult 回流 Note over FCS: afterpayment(credit) 借据激活/销账
分支清单(穷举放款全部分支)
出处 FinancialBusiness.loanApplyCallBack/laChannelPlutus、BeforePaymentLA。状态 ✓活跃 / △待确认。
| # | 分支 | 触发条件 | 处理 | 出处 | 状态 |
|---|---|---|---|---|---|
| 1 | 放款触发 | 审批通过回调 | loanApplyCallBack(跨服务调用方) | FinancialBusiness:392 | △ 调用方在仓库外(风控审批侧) |
| 2 | 锁客户 | 入口 | queryCustByCustId + lockCustByCustId(防并发) | :394 | ✓ |
| 3 | 防重借据 | 入口 | checkDuplicateLoan(by applyNo) | :397 | ✓ |
| 4 | 查产品 | — | getProductByProductFeeId + queryAcctType(PFS) | :403/456 | ✓ |
| 5 | 客户额度校验 | — | checkCustLmt | :411 | ✓ |
| 6 | 最小金额修正 | loanAmount < minAmt | 设为 minAmt | :414 | ✓ |
| 7 | H5 复借取卡 | H5=true | queryLastLASuccessOrder 取上次卡/银行 | :438 | ✓ |
| 8 | 建据 | — | BeforePaymentLA.execute:账户/借据/计划/合同/放款订单(TxnType LA) | :446 | ✓ |
| 9 | 身份类型 | verifyType NIN 前缀 | identityType=NIN / 否则 BVN | :497 | ✓ |
| 10 | 通道映射 | bizCode | plutusChannelMapping → businessChannel | :483 | ✓ |
| 11 | 不收其它账户 | — | isAcceptOtherAccount=N | :489 | ✓ |
| 12 | 放款派发 | 建据后 | PlutusLoanApplyPublisher.sendMsg(MessageModel) | :507 | ✓ |
| 13 | 订单状态机 | 派发后 | channel=PLUTUS, orderStatus=P, paymentStatus=U | :510 | ✓ |
| 14 | 派发失败 | laChannelPlutus 异常 | try-catch 仅 log,订单留 P/U(不抛/不回滚) | :451 | ✓ |
| 15 | 通道路由 | 放款前 | routeChannel:BVN→银行账户/NIN→电子钱包/Goldman→Goldman;Apollo 通道优先级 + 银行可用性矩阵 | PaymentManager:330 | ✓ |
| 15b | 放款执行 | 选中通道 | IThirdPayment.transfer(启用 transfer 类:Paystack/Monnify/Easypay/Palmpay/Aicapay;Flutterwave/Nibss 注释) | PMT ThirdPaymentFactory | ✓ |
| 15c | 通道容灾轮转 | 扣款 pending | paymentChannelCurrent→下一优先级通道 | PaymentManager:393、B26000 job | ✓ |
| 16 | 放款回调 | 通道完成 | PaystackCallbackBusiness/MonnifyPayCallbackBusiness | PMT | ✓ |
| 17 | 结果回流 | 回调后 | IInnerPaymentService.paymentResult | PMT→FCS | ✓ |
| 18 | 借据激活/销账 | 回流 | afterpayment(credit 类) | FCS | ✓ |
接口落地
| # | 业务步骤 | 服务 | 真实接口 | 现状 | 说明 |
|---|---|---|---|---|---|
| 1 | 放款触发(审批回调) | FCS | IFinancialService.loanApplyCallBack | △ | 端点在;调用方在风控审批回调侧(跨服务,归属 res 风控决策)。入参 LoanApplyCallBackReq:applyNo/customerId/loanAmount/productFeeId/bankAccNo/bankCode/scene/H5/couponId/uid/accountType/channel |
| 2 | 锁客户+防重借据 | FCS | lockCustByCustId + checkDuplicateLoan | ✓ | 防并发/防重放款 |
| 3 | 查产品/账户类型 | PFS | IProductClient.queryProductByProductFeeId/queryAcctType | ✓ | |
| 4 | 客户额度校验 | FCS | checkCustLmt | ✓ | |
| 5 | 建据 | FCS | BeforePaymentLA.execute → createAcct/createLoan/createSchedule/createContract/createDebitOrder | ✓ | 一次性建账户/借据/计划/合同/放款订单(TxnDirection.D) |
| 6 | 放款派发到 PMT | FCS→PMT | laChannelPlutus → PlutusLoanApplyPublisher.sendMsg | ✓ | 放款专用 publisher(还款用 BeforePaymentPlutusPublisher) |
| 7 | 通道路由 + 放款执行 | PMT→外部 | PaymentManager.routeChannel 选通道 → IThirdPayment.transfer | ✓ | 多通道路由(身份 BVN/NIN/Goldman + 银行码 + 优先级 + 可用性矩阵 + 容灾轮转);对接通道全集 Paystack/Monnify/Palmpay/Aicapay/Easypay/Goldman;实际启用通道+优先级在 Apollo(channel.avaliable.pay/bank.avaliable),代码取不到 |
| 8 | 放款回调 | 外部→PMT | PaystackCallbackBusiness/MonnifyPayCallbackBusiness | ✓ | 通道异步回调更新订单 |
| 9 | 结果回流 | PMT→FCS | IInnerPaymentService.paymentResult | ✓ | 回流通知账务 |
| 10 | 借据激活/销账 | FCS | afterpayment(credit 类) | ✓ | 放款成功激活借据 |
放款通道路由策略
放款不是单通道直发,而是多通道路由 + 容灾(
PaymentManager.routeChannel)。
- 身份类型分流:
- BVN → 银行账户路由
routeChannelBvn - NIN(或 custId 以 ID_CARD 前缀)→ 电子钱包路由
routeChannelNin - Goldman 银行 → 直发 Goldman 或
routeChannelBvnForGoldman(按goldmanPayOpen开关)
- BVN → 银行账户路由
- 选道算法:从 Apollo 通道优先级数组(
channel.avaliable.pay/.wallet/.goldman.pay)+ 通道-银行可用性矩阵(bank.avaliable)中,选首个「对该银行可用(Y)」的通道;bankCode 无专配则走others默认。 - 容灾轮转:扣款 pending 时按
paymentChannelCurrent取下一优先级通道重试(failover,B26000PChannelChangePendingjob 触发换道)。 - 通道处理器(ThirdPaymentFactory 实际启用 8 个):Paystack / PaystackWebpay / Monnify / MonnifyMandate / Easypay(NibssEasypay) / Palmpay / Aicapay;Flutterwave / FlutterwaveWebpay / Nibss(直接) 注释禁用。放款用 transfer 类(Paystack/Monnify/Easypay/Palmpay/Aicapay);Goldman 在路由分支但 ThirdPaymentFactory 无独立处理器(实际执行通道待确认)。
- 配套表:
PayChannelAvailableInfo(通道可用性)、BankChannelMapping(银行→通道映射)、B35020PPayChannelInfoSync(通道信息同步 job)。
现状边界:实际启用哪些通道 + 优先级 + 银行可用性矩阵全在 Apollo 配置,代码取不到——评估”当前用哪几家通道”必须查 Apollo,不能从代码断定。
缺口小结
- 放款链路完整:审批回调 →(锁/防重/额度/最小金额/H5卡)建据 → laChannelPlutus/PlutusLoanApplyPublisher 派发 PMT → 通道 transfer → 回流激活。fcs→pmt 走事件桥(放款
PlutusLoanApplyPublisher,还款BeforePaymentPlutusPublisher)。 - 入口校验链齐备(早期版未展开):客户锁定、重复借据校验(防重放款)、客户额度校验、最小金额修正、H5 复借取上次卡、身份类型 BVN/NIN、通道映射。
- 放款通道路由(多通道 + 容灾)详见上「放款通道路由策略」小节;缺口侧仅:实际启用通道清单在 Apollo、代码取不到。
- 放款派发失败仅 log 不抛(
laChannelPlutus外层 try-catch)——订单留 channel=PLUTUS/orderStatus=P/paymentStatus=U 态,失败重试机制待确认(疑靠 job 扫 P/U 订单重发,需进一步核实)。 - 唯一跨服务待确认:
loanApplyCallBack的调用方在风控审批回调侧(fund-control 外,归属 res 风控决策,见 02-授信)——“审批通过后谁回调 fcs 触发放款”取决于风控决策接入是否到位。入参契约可从LoanApplyCallBackReq反推(见接口落地 #1)。