支付域 — 开发设计(开发就绪样板)
本文是支付域改造点的实现级设计,目标是开发照此即可动手:改什么、怎么改、内外依赖、配置、异常。规划级范围见 03-支付域。
标注:✓ 代码实证(payment-middle 源码)/ ⚠ 待确认(需后端架构讲解人确认,不臆造)。
1. 现状关键结构(实证)
| 层 | 实现 | 说明 |
|---|---|---|
| 入口契约 | IInnerPaymentService(Feign HTTP,/pmt/innerPayment) | paymentOrderPush(放款)、paymentResult、repayOrderPush/repayOrderBatchPush(还款)、repayResult、repayOrderForH5/repayTypeForH5、commonRepayGateway、vitualAccountRepay |
| 通道路由 | ThirdPaymentFactory.getThirdPayment(PaymentChannel) | switch 路由;已启用 Paystack / PaystackWebpay / Monnify / MonnifyMandate / NibssEasypay |
| 通道抽象 | IThirdPayment | payment / transfer(放款) / repayment / batchRepayment / queryPayment / queryRepayment / queryTransfer / queryBalance |
| 通道出口 | PaystackOuting / MonnifyOutgoing | 调三方 HTTP,URL + 密钥从 Apollo 注入 |
| 回调 | PaystackCallbackBusiness(transfer/charge)、MonnifyPayCallbackBusiness(disburse)、MonnifyRepayCallbackBusiness(collection) | |
| 数据 | PmtPaymentOrder / PmtPaymentFlow / PmtOrderOriginal;MonnifyMandateRecord/Result;账务侧 fcs_order_txn(含 merchant_name) | |
| 异步对账/补偿 Job | QueryTransferResult / QueryChargeResult / TransferComplement / PendingOverTimeSolve / ReverseNotify / RefCompensation / RetrieveMandateStatus | |
| 关键入参 | PaymentOrderPushReq:orderId / custId / amount / bankCode / accountNumber / bankAcctName(收款账户)/ isAcceptOtherAccount(放非本人账户)/ paymentChannel / txnType / loanId;PayDto:payer / beneficiary(收款方) / recipientCode / paymentMerchant(我方通道商户) |
2. 改造点①:放款到客户 / 商户
目标
现网放款到客户;手机分期需放款到商户银行账户。
关键判断(✓ 实证)
PaymentOrderPushReq 已有收款账户字段(bankCode/accountNumber/bankAcctName)+ isAcceptOtherAccount(放到非本人账户);PayDto.beneficiary 为收款方。pmt 不区分客户/商户,只把钱转到给定收款账户——放款到商户对 pmt 基本透明。
怎么改(时序)
- 编排/账务经
IInnerPaymentService.paymentOrderPush发放款指令,收款账户填商户账户 +isAcceptOtherAccount=Y+paymentChannel。 - pmt 建
PmtPaymentOrder/Flow→ThirdPaymentFactory.getThirdPayment(channel).transfer(PayDto)。 PaystackOuting:账户名核验 → 创建 recipient(paystack.pay.recipient.url) → 放款(paystack.pay.url);Monnify 同理(monnify.pay.url)。- 异步 transfer/disburse 回调 → 更新
PmtPaymentOrder状态。 - pmt 通知账务放款结果 → 账务建据。⚠ 通知机制(
paymentResult接口回调 vs MQzooPaymentResult/afterPaymentInput)待确认。
改动落点
- pmt 侧:基本零改(收款方字段、isAcceptOtherAccount、beneficiary、recipient 创建均已支持)。
- 账务/编排域(主要改动):发放款指令时填商户收款账户 + isAcceptOtherAccount + 选通道。商户账户来源见依赖。
内部依赖
- 账务域:放款指令入参(
PaymentOrderPushReq契约)+ 建据回调(结果通知)。 - ✓ 渠道商品域:门店表收款三件套
payee_bvn/payee_bank_account/payee_account_name(门店即 POS 点);SA 办单时按store_id取并随放款指令传入。见 07-渠道商品域。
外部依赖
- Paystack:transfer recipient API + transfer + callback;Monnify:disburse + callback。
- Provider:商户号、callback/webhook 注册。
配置(Apollo,✓ 实证键名)
paystack_transfer_authorization_secret_key(Map,加 MVP 商户条目)、paystack.pay.recipient.url、paystack.pay.url、paystack.pay.query.url;monnify_secrity_key_json / monnify_api_key(Map)、monnify.pay.url、monnify.pay.query.url、monnify.auth.login.url。URL 切生产。
异常 / 回滚(✓ 现网 Job)
失败/超时 → QueryTransferResult / TransferComplement / PendingOverTimeSolve;冲正 → ReverseNotify;代偿 → RefCompensation。
待确认
- ⚠
isAcceptOtherAccount现网语义与取值(是否即”放到非客户本人账户”,能否直接用于商户放款)。 - ⚠
paymentChannel由谁决定(入参指定 / 路由配置 / 按产品)。 - ⚠ 放款结果通知账务的机制(接口回调 vs MQ)。
3. 改造点②:手机分期多期代扣调度
目标
按每期还款日代扣(现网单期到期代扣)。
现状(✓ 实证)
IThirdPayment.repayment / batchRepayment 已实现;卡扣(Paystack recurring)+ Mandate(Monnify)已有;账务 Job NormalWithholding / OverdueWithholding 调度代扣;入口 repayOrderPush / repayOrderBatchPush。
怎么改
- 账务(还款中心)按每期
due_date生成代扣任务(主改动在账务域,多期还款计划/排程表层已支持)。 - 经
IInnerPaymentService.repayOrderPush(单笔)/repayOrderBatchPush(批量)发扣款。 - pmt
repayment(PayDto)走 Mandate / 卡扣(monnify.repay.url/paystack.repay.url)。 - collection/charge 回调 →
repayResult通知账务销账。
改动落点
- 账务域:按期调度(多期)。pmt 侧复用
repayOrderPush,基本零改。
待确认
- ⚠ 多期场景
repayOrderPush入参是否需带期次(term)。 - ⚠ 批量代扣
repayOrderBatchPush的触发方与批次组织。
4. 改造点③:代扣授权 Mandate(手机分期还款)
现状(✓ 实证)
MonnifyMandatePayment + MonnifyMandateRecord/Result + 创建/debit/status(MonnifyCreateMandateReq / MonnifyDebitMandateReqDto / MonnifyMandateStatusReqDto);RetrieveMandateStatus Job 轮询;contractCode 配置。
怎么改 / 流程
签约或首次绑定阶段创建 mandate → 还款时 debit → status 轮询。
配置
contractCode(Monnify Mandate)、mandate 相关 URL(⚠ 具体键名待确认)。
待确认
- ⚠ mandate 创建在哪个业务环节触发(签约 / 首次还款 / 绑卡)。
- ⚠ NIBSS direct debit 是经 Monnify 还是直连。
5. 改造点④:通道接入(配置 + Provider 对接)
Apollo 配置项清单(✓ 实证 @Value / @ApolloJsonValue)
- Paystack:
pc_paystack_authorization_secret_key(Map)、paystack_transfer_authorization_secret_key(Map)、paystack.pay.recipient.url、paystack.pay.url、paystack.pay.query.url、paystack.repay.url、paystack.partial.repay.url、paystack.batch.repay.url、paystack.repay.query.url、paystack.balance.query.url、paystack_dispute_* - Monnify:
monnify_secrity_key_json(Map)、monnify_api_key(Map)、monnify.auth.login.url、monnify.pay.url、monnify.pay.query.url、monnify.repay.url、monnify.repay.query.url、monnify.balance.query.url、monnify.merchant.bindAccount.config.mapping、contractCode
Provider 对接(非代码)
开 Paystack/Monnify 商户号;注册 callback/webhook URL;Paystack transfer recipient;Monnify reserved account / NIBSS mandate contractCode。
待确认
- ⚠ 通道路由配置(哪个产品/业务线走哪家)存哪:Apollo 还是
PayChannelAvailableInfo表。 - ⚠ merchant/channel 命名规则(现网 PC/NC;MVP 现金贷/手机分期如何映射到密钥 Map 的 key)。
6. zoo / MQ 链路(待确认重点)
账务 fcs 配置中发 plutus-pay-charge、zooPaymentProcess,消费 zooPaymentResult;而 pmt 入口是 IInnerPaymentService(HTTP)。
- ⚠ 放款/还款是走
IInnerPaymentService(HTTP) 还是 MQ topic(plutus-pay-charge / zooPaymentProcess)? - ⚠ “zoo” 的角色:是放款编排中间层(独立服务)还是同一服务的 MQ 侧?是否在本地代码内。
7. 待确认清单(汇总给后端架构讲解人)
- 放款结果通知账务的机制:接口回调 / MQ。
isAcceptOtherAccount语义与商户放款适用性。paymentChannel选择来源(入参 / 配置 / 按产品)。- 通道路由配置存放位置(Apollo / DB 表)。
- merchant/channel 命名与 MVP 业务线映射。
- 多期
repayOrderPush是否需带期次;批量代扣触发方。 - Mandate 创建触发环节;NIBSS 直连 vs 经 Monnify。
- zoo / MQ 在放款还款链路中的角色与是否在本地代码。
商户银行账户来源✓ 已确认:渠道商品域门店表收款三件套(payee_bvn/payee_bank_account/payee_account_name);SA 办单时按store_id取并随放款指令传入。见 07-渠道商品域。
8. 验收
- 放款到客户(现金贷)、放款到商户(手机分期)经
transfer+ 通道成功,回调更新状态、通知账务建据。 - 多期借据按每期
due_date自动代扣(Mandate / 卡扣)+ 主动还款,repayResult触发销账。 - 失败/超时/冲正经现网 Job 兜底,幂等不重复。