③ 借款(首借 / 复借)
产品定义:首借(快捷/试算/绑卡/合同)、复借(常规/还款并复借/试算/绑卡/合同)。首借 vs 复借同一套
loanApply/loanCalculate,靠isFirstLoan分支。图例与服务名映射见 00-总览。
边界:本阶段终点是生成提现申请单(落 bns 本地表 applyStatus=C);建据与打钱见 04-放款。真实分支见下方「分支清单」(读ApplyBusiness/LoanBusiness/BankBusiness核实)。
时序
sequenceDiagram autonumber actor C as 客户 participant App as 客户端 H5 participant GW as 业务网关 participant BNS as BNS 业务编排 participant FCS as FCS 账务 participant PFS as PFS 产品 participant FDS as FDS 反欺诈 participant IMS as IMS 绑卡 participant EXT as 外部三方(支付通道) participant MISS as 大数据(注释·未接) Note over C,MISS: ① 试算(loanCalculate) C->>App: 选金额/期限 App->>GW: POST /bns/apply/loanCalculate BNS->>FCS: IFcsNonfinancialClient.loanCalculate(费用/利息/到账/应还) Note over C,MISS: ② 绑卡(routeRedirect, bindCardType=API/H5) opt 需绑卡 App->>GW: POST /bns/bank/routeRedirect BNS->>IMS: imsServiceClient.routeRedirect(cardType 卡/账户) IMS-->>BNS: bindCardType + redirectUrl alt bindCardType=H5 Note over BNS: 落 BnsCardboundOrder(processLink=Plutus, status=pending) App->>EXT: 跳转 Plutus/IMS 托管页绑卡 else bindCardType=API(默认) Note over App: 原生直绑(卡走 token, 账户走 Direct Debit+OTP) end EXT-->>IMS: 通道回调(paystackWebPayCallback 等) IMS->>BNS: POST /bns/bindCardCallBack(落卡/账户) end Note over C,MISS: ③ 提现申请(loanApply→loanApplyDeal) C->>App: 确认提交 App->>GW: POST /bns/apply/loanApply BNS->>FDS: queryAccountIsFreeze(冻结校验) ✓ BNS->>FCS: isFirstLoan 首借/复借判定 opt 首借且 ischeckCard Note over BNS: checkCard:无有效卡→NOT_BANK_CARD,有效期<3月→NOT_THREE_MONTHS_BANK_CARD end BNS->>PFS: queryProductByProductFeeId(fixProductInfo) Note over BNS: checkLoanAmt 产品额度校验 Note over BNS: Redisson 防重锁(LOAN_APPLY_PREFIX+custId) BNS->>FCS: fcsFinancialClient.checkLoanApply 提现校验 Note over BNS: 账户类型分流 钱包(WALLET)/银行(BANK_ACCOUNT) BNS->>MISS: iBigdataClient.applyExclusionRule 大数据互斥 Note over MISS: ✗ 整段注释禁用(含提额 extraAmount 逻辑), 互斥恒 0 alt 互斥命中(mutuallyExclusive != -1) Note over BNS: 拦截返回(applyStatus=N) else 未命中(-1, 注释下恒此路) Note over BNS: genApplyLoan 落 BnsApplyMainLoan applyStatus=C end Note over BNS: sendKafka 通知 agg 算变量 ✗ 已注释
分支清单(穷举借款全部分支)
出处 ApplyBusiness / LoanBusiness / BankBusiness。状态 ✓活跃 / ✗注释 / △外部。
| # | 分支 | 触发条件 | 处理 | 出处 | 状态 |
|---|---|---|---|---|---|
| 1 | 试算-未登录/参数 | uid 无/参数无效 | NOT_LOGIN / PARAMETER_ERR | ApplyBusiness:307/311 | ✓ |
| 2 | 试算 | 合法 | nonfinancialClient.loanCalculate(FCS) | :318 | ✓ |
| 3 | 绑卡-取地址 | 需绑卡 | routeRedirect → IMS 返回 bindCardType | BankBusiness:221 | ✓ |
| 4 | 绑卡-H5 类型 | bindCardType=H5 | 落 BnsCardboundOrder(Plutus 托管页, pending) | BankBusiness:252 | ✓ |
| 5 | 绑卡-API 类型 | bindCardType=API(默认) | 原生直绑 | BankBusiness:249 | ✓ |
| 6 | 卡 vs 账户 | cardType | 银行卡走 token / 银行账户走 Direct Debit+OTP | routeRedirect:243 | ✓ |
| 7 | 绑卡回调 | 通道完成 | bindCardCallBack 落卡/账户 | IInnerService | ✓ |
| 8 | 提现-未登录/参数 | uid 无/参数账户校验 | NOT_LOGIN / PARAMETER_ERR | ApplyBusiness:257/263 | ✓ |
| 9 | 冻结校验 | loanApply 入口 | queryAccountIsFreeze, freeze→拦截 | :268 | ✓ |
| 10 | 首借/复借 | isFirstLoan | firstLoanFlag 分支 | :280 | ✓ |
| 11 | 首借卡校验 | ischeckCard && isFirstLoan | checkCard:无卡 NOT_BANK_CARD / 有效期<3月 NOT_THREE_MONTHS_BANK_CARD | :283、checkCard:329 | ✓ |
| 12 | 查产品 | — | fixProductInfo(queryProductByProductFeeId) | :289 | ✓ |
| 13 | 产品额度校验 | — | checkLoanAmt | :291 | ✓ |
| 14 | 防重锁 | loanApplyDeal | Redisson tryLock(LOAN_APPLY_PREFIX+custId) | LoanBusiness:74 | ✓ |
| 15 | 提现校验 | 锁内 | fcsFinancialClient.checkLoanApply(FCS) | LoanBusiness:79 | ✓ |
| 16 | 账户类型分流 | walletAccountNumber 有/无 | accountType=WALLET / BANK_ACCOUNT | LoanBusiness:113 | ✓ |
| 17 | 大数据互斥 | applyExclusionRule | iBigdataClient.applyExclusionRule(含提额 extraAmount) | LoanBusiness:133 | ✗ 整段注释 |
| 18 | 互斥结果分流 | mutuallyExclusive | != -1 拦截返回(N) / 注释下恒 0→applyStatus=C | LoanBusiness:83/142 | ✓(逻辑在, 互斥断) |
| 19 | 生成提现单 | 通过 | genApplyLoan/saveApplyLoan 落 BnsApplyMainLoan(applyStatus=C) | LoanBusiness:146/193 | ✓ |
| 20 | 通知 agg 变量 | — | sendKafka | LoanBusiness:87 | ✗ 注释 |
接口落地
| # | 业务步骤 | 服务 | 真实接口 | 类型 | 现状 | 说明 |
|---|---|---|---|---|---|---|
| 1 | 提现试算 | FCS | IApplyService.loanCalculate → IFcsNonfinancialClient.loanCalculate | 端点+下游 | ✓ | FCS 内部算费用/利息/到账/应还 |
| 2 | 取绑卡地址 | IMS | IBankService.routeRedirect → IImsServiceClient.routeRedirect | 端点+下游 | ✓ | 返回 bindCardType(API/H5) + redirectUrl;H5 类型落 Plutus 订单 |
| 3 | 跳转完成绑定 | IMS 子系统/通道 | IMS tokenSave/accountInfoBind/accountOtpSend;通道回调 paystackWebPayCallback | 子系统 | ✓ | 绑卡实质在 IMS 托管页+通道侧;卡走 token,账户走 Direct Debit+OTP |
| 4 | 绑卡结果回调 | BNS | IInnerService.bindCardCallBack | 端点 | ✓ | IMS 回调 bns,落客户卡/账户 |
| 5 | 冻结校验 | FDS | queryAccountIsFreeze → IFdsServiceClient | 下游 | ✓ | loanApply 入口校验 |
| 6 | 首借/复借判定 | FCS | IFcsNonfinancialClient.isFirstLoan | 下游 | ✓ | 决定首借卡校验等分支 |
| 7 | 首借卡校验 | BNS | checkCard(本地查 BnsCustBankInfo) | 内部 | ✓ | 无卡/有效期<3月 拦截(仅 BVN 客户) |
| 8 | 查产品/费用 | PFS | IPfsServiceClient.queryProductByProductFeeId | 下游 | ✓ | fixProductInfo |
| 9 | 产品额度校验 | BNS | checkLoanAmt | 内部 | ✓ | 校验提现金额在产品额度内 |
| 10 | 提现校验 | FCS | IFcsFinancialClient.checkLoanApply | 下游 | ✓ | Redisson 锁内调用 |
| 11 | 大数据互斥/排除规则 | 大数据 | IBigdataClient.applyExclusionRule | 下游 | ✗ | LoanBusiness.applyExclusionRule 整段注释,互斥恒 0 |
| 12 | 生成提现申请单 | BNS | genApplyLoan → saveApplyLoan | 内部 | ✓ | 落 BnsApplyMainLoan(applyStatus=C) |
| 13 | 通知 agg 算变量 | (未发) | sendKafka | 事件 | ✗ | 注释,借款不触发 agg 变量计算 |
缺口小结
- 借款链路本地齐备:试算(FCS)、查产品(PFS)、产品额度校验、首借卡校验、提现校验(FCS)、冻结校验(FDS)、绑卡(IMS+通道)、防重锁、落申请单(bns)均可跑。
- 绑卡两路 bindCardType=API/H5(13 早期版误标为”卡/账户”):H5 类型跳 Plutus 托管页并落 BnsCardboundOrder;卡/账户是另一维度 cardType(卡走 token,账户走 Direct Debit+OTP)。与前端 03-借款提现 的绑卡跳转一致。
- 账户类型分流:钱包(WALLET) / 银行账户(BANK_ACCOUNT)——早期版未提。
- applyStatus N/C 逻辑在但互斥已断:互斥命中应拦截(N),但
applyExclusionRule整段注释(含提额 extraAmount 逻辑)→ 恒 0 → applyStatus=C。 - 缺口仍在风控/变量:大数据互斥
applyExclusionRule注释(不执行)、sendKafka通知 agg 注释——与授信风控决策缺失一脉相承,指向 大数据/agg/res 未接通。 - 终点是 bns 提现申请单(applyStatus=C),放款建据见 04-放款。