统一还款防重复治理
先考虑做对账,,再观察下重复数据情况
1. 文档目的
统一用户主动卡还款、第三方 Web H5、虚拟账号转账和系统自动代扣的敞口计算与防重复规则。
本文重点回答四个问题:
- 每种还款方式从什么时候开始占用敞口。
- 敞口金额怎么算、会阻断哪些还款。
- 敞口保持多久,什么情况下释放、升级或转人工。
- 通道成功但 FCS 尚未入账、结果未知和迟到资金如何持续保护并完成处置。
Monnify 按卡月度失败限额、渐进降频和自动代扣暂停规则由 37-Monnify按卡月度失败限额与自动代扣控频 独立承担。
还款 H5 的页面、文案、30 分钟支付会话和通道接口详见 35-还款H5支付会话时效与代扣在途拦截 —— 暂hold。当前代码分析统一放在文末第 14 节,不穿插在业务规则中。
2. 适用范围与责任
2.1 适用范围
- 用户主动银行卡还款。
- Paystack、Monnify 等第三方 Web H5 还款。
- Monnify 虚拟账号转账,包括无意图到账和迟到到账。
- 系统日常自动代扣。
- 通道查询、回调、FCS 入账、补偿、人工挂起和退款/溢缴款。
2.2 责任边界
| 责任方 | 业务责任 |
|---|---|
| FCS | 当前应还、贷款余额、还款分配、业务入账、溢缴款和最终还款结果的权威 |
| 统一还款编排 | 计算可还金额,维护软保护和硬敞口,决定是否允许新还款、阻断范围及下一处理动作 |
| PMT | 创建支付尝试、调用通道、保存参考号和流水、接收回调、主动查询、失败分类及通知补偿 |
| H5/App | 展示服务端状态和可用操作;不得根据倒计时、回跳或按钮点击自行释放敞口 |
| 运营/财务 | 处理自动补偿无法解决的未知、资金冲突、超额、退款和人工补账 |
3. 敞口模型
3.1 三类保护
| 类型 | 含义 | 是否扣减可还金额 | 默认阻断范围 |
|---|---|---|---|
软保护 SOFT_INTENT | 用户近期可能通过虚拟账号转账,但尚无通道请求或到账证据 | 否 | 只暂停自动代扣;用户主动换方式时需确认替换 |
支付风险 PAYMENT_RISK | 通道请求准备发送、已经发送、处理中或结果未知 | 是 | 阻断与该金额重叠的新还款;未知或无法安全分配时阻断整笔贷款 |
真实资金 CONFIRMED_FUNDS | 通道成功或虚拟账号已经到账,等待 FCS 入账或退款 | 是 | 保护实际成功/到账金额;冲突、超额或无法分配时阻断整笔贷款 |
业务上只把 PAYMENT_RISK 和 CONFIRMED_FUNDS 叫作“硬敞口”。软保护用于调度,不代表已经发生资金。
3.2 敞口金额怎么算
敞口维度至少包含:业务产品 + 客户 + 借据。
同一逻辑还款意图下的执行预占、PMT 订单、通道流水和成功资金只计算一次,不能重复扣减。
硬敞口金额
= 未释放的 PAYMENT_RISK 金额
+ 未完成入账/退款的 CONFIRMED_FUNDS 金额
可发起金额
= max(FCS 当前剩余应还 - 硬敞口金额, 0)阻断范围分为两类:
| 阻断范围 | 适用条件 | 处理 |
|---|---|---|
金额级 AMOUNT_ONLY | 金额、币种、贷款归属和状态都可信,且业务已支持安全分笔 | 只保护对应金额,用户可以偿还剩余未覆盖金额 |
贷款级 LOAN_HARD | 结果未知、金额冲突、多候选、人工挂起,或业务尚未支持安全分笔 | 当前贷款可发起金额直接按 0 处理 |
首期无法证明金额级并发安全的业务,必须使用 LOAN_HARD,不能自行开放剩余金额还款。
3.3 通用状态
| 状态 | 保护类型 | 产品/技术含义 | 可以退出的条件 |
|---|---|---|---|
SOFT_INTENT_ACTIVE | 软保护 | 已展示虚拟账号并登记转账意愿 | 2 小时到期无到账,或原子替换为其他主动方式 |
EXECUTION_RESERVED | 支付风险 | 已预占金额,准备调用通道 | 证明请求未发送后释放;已发送或无法确认则继续保护 |
CHANNEL_PROCESSING | 支付风险 | 通道处理中 | 明确成功、明确失败/失效或转未知核对 |
UNKNOWN_RECONCILING | 支付风险、贷款级阻断 | 结果未知,系统正在查原交易 | 查得终态;超过自动核对时限后转人工 |
CHANNEL_SUCCESS | 真实资金 | 通道成功,等待 FCS | 进入 FCS 入账 |
POSTING | 真实资金 | FCS 正在入账 | 入账完成或发现冲突 |
POSTED | 无 | FCS 入账完成 | 读取最新余额决定后续可还金额 |
CONFIRMED_FAILED | 无 | 权威终态失败,内部无成功资金 | 完成幂等关单并保存失败事实;通道专项计数按独立需求处理 |
EXPIRED_NO_PAYMENT | 无 | 通道明确过期且无资金 | 完成幂等关单 |
MANUAL_REVIEW_HOLD | 支付风险或真实资金、贷款级阻断 | 自动处理无法安全得出结论 | 人工确认成功、失败、重复资金或继续挂起 |
4. 各还款方式怎么计算和处理
4.1 总表
| 还款方式 | 什么时候开始保护 | 敞口金额 | 时间 | 成功怎么处理 | 失败/到期/未知怎么处理 |
|---|---|---|---|---|---|
| 用户主动卡还款 | 浏览和选卡不占用;服务端接受提交、准备调用通道前创建执行预占 | 服务端确认的本次还款金额 | 未发送预占 2 分钟;通道已发送后无固定自动释放时间 | 转真实资金,保护成功金额至 FCS 入账 | 明确失败无资金则释放;未知自动查单 30 分钟,仍未知则贷款级挂起 |
| Paystack Web H5 | 浏览页面不占用;用户确认付款、创建 Checkout 前预占 | 本次 Checkout 金额 | 我方页面及 Paystack 会话暂定 30 分钟;最迟 45 分钟转人工 | 转真实资金,保护成功金额至 FCS 入账 | 页面到期先查原单;明确失败/过期无资金才释放;仍未知则挂起 |
| Monnify Web H5 | 用户确认付款、创建 Monnify Invoice 前预占 | 本次 Invoice 金额 | 创建时设置 expiryDate=服务端创建时间+30分钟;我方页面与 Invoice 同时到期;最迟 45 分钟转人工 | 以 Invoice/关联交易权威结果确认成功,转真实资金并保护至 FCS 入账 | 30 分钟到期查询原 Invoice;只有 Invoice 明确失效/过期、关联交易无成功资金时才释放;仍待处理或未知则继续保护,45 分钟转人工 |
| 系统自动代扣 | 进入候选池不占用;选定订单、创建代扣订单和调用通道前预占 | 本次任务确定的扣款金额 | 未发送预占 2 分钟;已发送后自动核对 30 分钟 | 转真实资金,保护至 FCS 入账 | 明确失败释放;未知 30 分钟后贷款级挂起;通道专项控频按对应独立需求执行 |
| 虚拟账号主动转账 | 展示虚拟账号并创建转账意愿后仅建立软保护 | 软保护金额为 0;到账后按实际到账金额形成真实资金 | 软保护 2 小时;重复进入不续期 | 到账后保护实际金额至 FCS 入账/退款 | 2 小时无到账则结束软保护;迟到到账仍接收并按真实资金处理 |
| 虚拟账号无意图/迟到到账 | 到账前无法占用;收到有效资金时立即形成真实资金 | 实际到账金额;超过应还部分进入溢缴款/退款 | 到账后无固定自动释放时间 | 唯一匹配后入账;完成后按最新余额重算 | 多候选、与其他成功重叠或超额时贷款级挂起 |
以上时间为首版可配置值。到达自动处理时限只表示升级处理,不能把可能已经发生的支付自动当成失败。
4.2 主动卡还款、Web H5 和自动代扣流程
flowchart TD A[用户提交或任务选中订单] --> B[读取FCS剩余应还和全部保护] B --> C{存在贷款级阻断?} C -- 是 --> X[拦截 不创建订单 不调用通道] C -- 否 --> D{本次金额超过可发起金额?} D -- 是 --> X D -- 否 --> E[原子创建2分钟执行预占] E --> F{准备调用前再次校验} F -- 不通过 --> G[确认未发送 释放预占] F -- 通过 --> H[标记发送中并调用通道] H --> I{通道结果} I -- 成功 --> J[升级为真实资金] J --> K[FCS入账与补偿] K --> L[入账完成 读取最新余额重算] I -- 明确失败且无资金 --> M[关单并释放支付风险] I -- 处理中或未知 --> N[保留支付风险 查询原交易] N --> O{自动核对时限内得到终态?} O -- 是 --> I O -- 否 --> P[贷款级人工挂起并群播报]
执行预占的释放必须同时满足:
- 状态明确为“请求未发送”。
- 不存在 PMT 支付订单、通道参考号和通道流水。
- 不存在成功回调、查询成功或到账事实。
只要处于发送中、已发送或无法确认是否发送,就不能按 2 分钟自动释放。
4.3 Web H5 特殊时间线
flowchart LR A[T0 创建Paystack会话或Monnify Invoice并占用金额] --> B[T+30分钟 页面及支付会话到期并查原单] B --> C{通道} C -- 成功 --> D[真实资金 等待FCS入账] C -- 明确失败或过期无资金 --> E[释放支付风险] C -- 处理中或未知 --> F[继续保护并补偿查询] F --> G[T+45分钟仍未知 转人工挂起]
- Paystack 专用 Integration 可将会话超时设为 30 分钟;共享 Integration 修改前必须完成影响评估。
- Monnify 使用 Invoice Create 获取
checkoutUrl,创建时将必填expiryDate设置为服务端创建时间加 30 分钟,格式为YYYY-MM-DD HH:MM:SS。 - Monnify 到期查询使用原
invoiceReference,不能通过重新创建 Invoice 判断旧单失败。 - 页面倒计时、用户关闭页面和回跳结果都不能直接释放敞口。
- 详细页面行为和通道接口见 35-还款H5支付会话时效与代扣在途拦截 —— 暂hold。
4.4 虚拟账号流程
flowchart TD A[展示虚拟账号] --> B[建立2小时软保护 暂停自动代扣] B --> C{2小时内到账?} C -- 是 --> D[按实际到账金额建立真实资金] D --> E{能唯一匹配贷款?} E -- 是 --> F[FCS入账] F --> G[读取最新余额重算] E -- 否 --> H[贷款级人工挂起] C -- 否 --> I[结束软保护 自动代扣可重新评估] I --> J{之后发生迟到到账?} J -- 否 --> K[结束] J -- 是 --> D B --> L{用户主动改用卡或H5?} L -- 是 --> M[确认替换软意图] M --> N{原子创建新执行预占成功?} N -- 是 --> O[结束软保护 进入新支付流程] N -- 否 --> B
补充规则:
- 软保护不扣减可发起金额,但保护期内自动代扣必须跳过。
- 重复进入、复制账号或刷新不重新计算 2 小时。
- 同一贷款新的软保护窗口至少间隔 30 分钟,同一自然日最多 3 次;超过后仍可查看稳定虚拟账号,但不再新增自动代扣保护。
- 用户点击“已转账”不能升级为真实资金,只能触发页面查询提示。
- 用户改用其他主动方式时,服务端必须原子完成“关闭软保护 + 创建新执行预占”;新预占失败时保留原软保护。
- 软保护结束或被替换后,虚拟账号迟到到账仍必须接收。若与其他成功资金重叠,进入贷款级挂起和退款/溢缴款处置。
5. 时间与处理时限
| 场景 | 首版时间 | 到时动作 | 是否自动释放 |
|---|---|---|---|
| 执行预占,且确认请求未发送 | 2 分钟 | 关闭预占,重新计算可还金额 | 是 |
| 执行预占,但发送状态不明 | 2 分钟 | 转 UNKNOWN_RECONCILING,查询原交易 | 否 |
| 主动卡/自动代扣结果未知 | T+1、5、15、30 分钟查询 | 30 分钟仍未知则人工挂起 | 否 |
| Paystack/Monnify Web H5 | 页面 30 分钟 | 关闭页面继续支付并查原交易 | 否 |
| Monnify Invoice | expiryDate=创建时间+30分钟 | 页面到期并查询原 Invoice | 否;只有 Invoice 明确失效/过期、关联交易无成功资金才释放 |
| Web H5 到期后仍未知 | 45 分钟 | 人工挂起并群播报 | 否 |
| 虚拟账号软保护 | 2 小时 | 无到账则结束软保护并允许任务重新评估 | 是,仅结束软保护 |
| 通道成功/虚拟账号到账待 FCS | 立即、T+1、3、10 分钟补偿 | 15 分钟告警;30 分钟人工挂起 | 否 |
| P0 人工事件未认领 | 10 分钟 | 群提醒并升级负责人 | 否 |
| P1 人工事件未认领 | 30 分钟 | 群提醒并升级负责人 | 否 |
所有时间按服务端时间计算并支持按业务、国家和通道配置。调整只能改变查询和升级节奏,不能把“已发送/未知/已成功”的硬敞口配置成自动释放。
6. 结果处理
6.1 统一决策表
| 权威结果 | 内部资金事实 | 处理结果 | 敞口 |
|---|---|---|---|
| 成功 | 金额、币种、参考关系一致 | 进入 FCS 入账 | 转 CONFIRMED_FUNDS,保护成功金额 |
| 明确失败/过期 | 无成功回调、无到账、无 FCS 入账 | 幂等关单 | 释放当前 PAYMENT_RISK |
| 处理中 | 无冲突 | 查询原交易 | 保持 PAYMENT_RISK |
| 未知/超时 | 无法确认是否发送或受理 | 自动核对;到时限转人工 | LOAN_HARD,不释放 |
| 失败结果与成功事实冲突 | 存在成功回调、到账或 FCS 入账 | 人工核对 | CONFIRMED_FUNDS + LOAN_HARD |
| 虚拟账号多候选 | 无法唯一匹配 | 人工核对 | CONFIRMED_FUNDS + LOAN_HARD |
| 实际资金超过剩余应还 | 存在超额 | 入账可还部分,剩余进入溢缴款/退款 | 保护至入账和退款完成 |
6.2 幂等规则
- 同一通道交易参考号永久只消费一次。
- 同一资金事实最多匹配一个逻辑还款意图。
- 同一逻辑意图中的预占、支付订单、流水和资金不能重复计入敞口。
- 回调、主动查询和补偿重复到达只更新同一资金事实。
- FCS 已入账后再次通知返回原结果,不重复更新贷款。
- 明确失败只释放当前失败尝试,不释放其他软保护或真实资金。
7. 自动补偿、人工挂起与群播报
7.1 自动处理队列
| 队列 | 处理对象 | 自动动作 | 转人工条件 |
|---|---|---|---|
| 预占回收 | EXECUTION_RESERVED 未推进 | 核对是否存在订单、参考号、流水或发送证据 | 无法证明未发送,或发现无主通道请求 |
| 通道核对 | UNKNOWN_RECONCILING | 只查询原参考号 | 到自动核对时限仍未知,或状态冲突 |
| FCS 入账补偿 | CONFIRMED_FUNDS 未入账 | 重试通知并读取 FCS 结果 | 30 分钟仍未入账、金额冲突或多候选 |
| 虚拟账号匹配 | 已到账未入账 | 按客户、贷款、币种和余额唯一匹配 | 多候选、无候选、超额或与其他成功重叠 |
7.2 人工挂起
进入 MANUAL_REVIEW_HOLD 后:
- 保持支付风险或真实资金,并把阻断范围升级为
LOAN_HARD。 - 停止该贷款的新主动还款、自动代扣、自动重试和自动结算。
- 创建唯一异常事件,记录 owner、级别、首次发现时间、处理时限和下一步动作。
- 群消息发送失败不能解除挂起。
- 人工结论只能是:确认成功并入账、确认失败无资金并释放、重复资金进入退款/溢缴款、继续未知保持挂起。
7.3 群播报
- P0/P1 创建人工挂起后立即发送到按业务配置的支付、FCS、运营和财务群。
- 消息包含:级别、业务、脱敏事件号、通道、金额与币种、冲突状态、owner、处理时限和受限详情链接。
- 禁止包含姓名、手机号、BVN、完整卡号、账号、Token、原始鉴权数据和完整通道报文。
- 同一异常只发送一次首次消息;状态升级、超时和关闭时更新,不因轮询重复刷屏。
8. 页面状态与埋点
H5 详细交互、英文文案和事件字典由 35-还款H5支付会话时效与代扣在途拦截 —— 暂hold 统一维护。本文只定义产品需要识别的场景。
| 产品场景 | 页面/owner | 关键事件 | 服务端属性 | 衡量指标 |
|---|---|---|---|---|
| 页面进入与可还状态 | 还款首页 / wp_h5 | repayment_page_view | page_state、protection_level、block_scope、has_active_intent | 各保护层级用户占比 |
| 提交还款 | 提交区 / wp_h5 | repayment_submit_click、repayment_submit_result | payment_method、result_status、blocked_reason、intent_reused | 提交成功率、复用率、硬敞口拦截率 |
| 虚拟账号软保护替换 | 替换弹窗 / wp_h5 | repayment_soft_intent_replace_view;repayment_soft_intent_replace_click;repayment_soft_intent_replace_result | action_type、target_method、protection_level | 替换确认率、原子替换成功率 |
| 自动代扣/硬敞口阻断 | 阻断弹窗 / wp_h5 | repayment_duplicate_block_view;repayment_duplicate_block_click | active_stage、protection_level、block_scope | 阻断量、查看状态率 |
| 状态查询 | 结果页 / wp_h5 | repayment_status_refresh_click;repayment_status_refresh_result | before_status、after_status、result_status | 未知转终态率、等待时间 |
埋点结果必须来自服务端业务状态。禁止采集金额、卡号、银行账号、BVN、手机号、Token、通道参考号、内部订单号或原始错误文本。Native 与 H5 各自上报自己负责的页面生命周期。
9. 监控指标
- 三类保护的创建数、金额、平均存续时间和状态转换。
AMOUNT_ONLY/LOAN_HARD数量、金额和拦截转化损失。- 软保护创建、复用、无到账到期、主动替换、保护期内到账和迟到到账。
- 执行预占确认未发送释放数、僵尸预占数和无主通道风险数。
- 未知订单数量、金额、年龄、查询次数和最终成功/失败/人工比例。
- 通道成功待 FCS 入账数量、金额、最长时长和补偿成功率。
- 虚拟账号多候选、超额、重复资金和退款积压。
- 敞口服务可用率、原子预占耗时、从严关闭请求数和恢复时间。
- 人工挂起存量、超时、认领时间、关闭时间和群播报成功率。
10. 上线方案
10.1 数据盘点
- 回填或隔离 FCS、PMT、WebPay、自动代扣和虚拟账号现有非终态订单。
- 确认每类历史状态对应软保护、支付风险、真实资金或无需保护。
10.2 影子运行
- 先记录敞口计算结果,不拦截现网。
- 对比现网实际调用和新规则本应拦截,计算误拦截、漏拦截及回收影响。
- 重点核对软保护无到账、执行预占僵尸、未知订单和成功待入账样本。
10.3 分阶段启用
- 先启用执行预占、跨入口硬敞口和原交易查询。
- 再启用虚拟账号软保护、替换流程和迟到到账处置。
- 最后启用金额级并发;未完成专项验收的业务继续使用
LOAN_HARD。
10.4 降级
- 敞口控制不可用时,禁止新卡扣、Checkout 创建和自动代扣。
- 原交易查询、回调、虚拟账号到账、FCS 入账和补偿必须继续运行。
- 硬敞口读取失败不能默认无敞口。
- 回滚不删除已有意图、敞口、资金事实和审计记录。
11. 验收标准
11.1 通用敞口
- 同一逻辑意图的预占、订单、流水和资金只计一次。
- 可发起金额严格等于 FCS 剩余应还减去未释放硬敞口。
LOAN_HARD存在时任何新增还款均在创建订单和调用通道前被拦截。- 只有确认未发送的 2 分钟执行预占可以自动释放。
- 已发送、未知和成功待入账不会因本地超时自动释放。
- FCS 入账后读取最新余额重算,不直接恢复原额度。
- 敞口服务不可用时新支付从严关闭,资金接收和原交易处理不受影响。
11.2 各方式
- 主动卡连续提交两次只产生一个有效执行预占和最多一次通道调用。
- Web H5 页面与通道支付会话均按 30 分钟到期;Monnify Invoice 的
expiryDate等于服务端创建时间加 30 分钟,到期后先查询原 Invoice。 - 自动代扣进入候选池不占敞口,调用前必须完成原子预占。
- 虚拟账号页面只建立 2 小时软保护,不扣减可还金额。
- 软保护重复进入不续期,超过每日次数不再暂停自动代扣。
- 软保护替换和新执行预占原子完成;失败时保留原软保护。
- 点击“已转账”不形成真实资金;实际到账才形成
CONFIRMED_FUNDS。 - 无意图或迟到到账全部接收;冲突和超额进入贷款级人工处置。
11.3 人工与数据
- 自动补偿达到时限才转人工;状态冲突和无主支付风险可以立即转人工。
- 人工挂起先升级贷款级阻断,再群播报;群消息失败不解锁。
- 页面和埋点状态来自服务端,不以点击、倒计时或回跳代替业务结果。
- 埋点和群消息均不包含客户、银行卡或通道敏感信息。
- 看板可以分开展示软保护、支付风险、真实资金和金额级/贷款级阻断。
12. 待确认参数
| 参数 | 本文暂定值 | 待确认方 |
|---|---|---|
| 执行预占未发送自动释放 | 2 分钟 | 支付/FCS研发 |
| 主动卡、自动代扣自动核对时限 | 30 分钟 | 支付/运营 |
| Web H5 未知转人工 | 45 分钟 | 支付/运营 |
| FCS 入账告警/转人工 | 15/30 分钟 | FCS/财务 |
| 虚拟账号软保护 | 2 小时 | 支付/催收 |
| 新软保护最小间隔 | 30 分钟 | 产品/催收 |
| 同贷款每日软保护上限 | 3 次 | 产品/催收 |
| 金额级并发开放范围 | 未完成专项验收前关闭 | FCS/支付 |
Monnify Invoice expiryDate 时区 | 本期按 Africa/Lagos;Sandbox、生产分别验证 | 支付/通道 |
13. 外部规则参考
14. 当前代码分析参考
本节只说明需求形成时的代码依据,不代表目标业务规则。代码版本变化后需重新核对。
14.1 分析版本
| 系统 | 分析版本 | 说明 |
|---|---|---|
FCS fund-control | dev / 97f2312e49278f5698c6b2040cbcafe6c9d7a378 | 本地与远端 dev 一致 |
PMT payment-middle | origin/master / 6aeda9b1d8c16e8a1cdd0be0e62ef81ec23d9b4e | 结论以只读获取的远端代码为准 |
H5 wp_h5 | dev / f76dec622f70e928a8bdf292e2341a12ded318a7 | 本地与远端 dev 一致 |
未读取生产 Apollo 和生产数据库。生产状态及通道参数需上线前核对。
14.2 当前记录方式与缺口
| 方式 | 当前记录方式 | 主要缺口 |
|---|---|---|
| 主动卡/Web H5 | FCS 保存 WebPay 初始化订单;PMT 保存支付订单和流水 | 不同参考号之间缺少客户/贷款级统一敞口 |
| 自动代扣 | FCS 生成 NC/OC 等订单,PMT 选择卡/Token/Mandate | 在途检查未完整覆盖其他主动方式,检查和创建存在竞争窗口 |
| 虚拟账号 | PMT 保存账号、绑定和入账流水,通知 FCS 入账 | 外部资金不可阻止;多候选时存在一笔资金结算多订单风险 |
| 查询与回调 | PMT 按支付订单/流水更新并通知 FCS | 主要按订单号锁定,未知与明确失败未统一治理 |
14.3 关键代码证据
| 系统 | 代码位置/方法 | 分析结论 |
|---|---|---|
| FCS | OrderFacility.isExistOnTheWayOrder | 通用在途未完整覆盖 PHP、VP 等入口 |
| FCS | OrderFacility.checkSelfOrderOnWay | 只检查同交易类型,不是跨方式防重 |
| FCS | PlutusBusiness.plutusWebPayInit | 初始化使用短时客户锁,但不同初始化可产生新参考号 |
| FCS | PlutusBusiness.plutusWebPayCallBackEvents | WebPay 回调后才创建 PHP 业务订单 |
| FCS | FcsJobBusiness.generateCommonChargeOrder | 自动代扣检查与订单创建不是统一原子占用 |
| PMT | InnerPaymentService.repayOrderForH5 | 主要按调用方 orderId 幂等 |
| PMT | checkPaymentOrderPending | 部分处理中订单可能被本地置失败后放行新尝试 |
| PMT | VaOrderSettleBusiness.trySettleRepayOnTransaction | 异常多绑定时存在一笔入账结算多订单风险 |
| PMT | MonnifyRepayCallbackBusiness | 主要消费成功回调,失败和处理中依赖同步结果或主动查询 |
| PMT | Paystack/Monnify WebPay 初始化 | 当前 Monnify 仍使用交易初始化获取 Checkout,需改为 Invoice Create,并通过必填 expiryDate 设置 30 分钟有效期 |