1. 文档定位
本文说明 DGJ2.0 中“银行通道接入、支付中心结果落账、授信分期与分期还款”三层业务。它面向产品、前端、后端、测试、财务和运维,用于回答以下问题:
- 服务站为什么能看到某一种银行或授信通道,注册、签约和二维码分别由谁提供。
- 用户完成支付后,采购单、付款单、账户流水和还款单怎样变化。
- 分期申请、分期账单、主动还款、自动还款和到期提醒怎样串联。
- 外部系统已成功而 DGJ2 未落账时,怎样判断、补偿和验收。
本文依据当前仓库代码整理。外部支付中心、OPS Manager、银行网关的数据库表、生产路由、签名算法和重试策略不在本仓库中,均标为“待外部确认”。
2. 业务边界
2.1 本文包含
- B2B、工行、工行 E 贷、民生、京东数科、拉卡拉、泰隆、小雨点、网商银行等适配入口。
- 银行资料、贷款人资料和通道资格查询。
- 注册、短信、签约、支付二维码、还款二维码、支付链接和状态查询。
- 支付中心支付成功、支付异常、授信还款、分期到期和逾期锁站回调。
- 分期签约、可分期判断、分期模型、token、提交、账单、服务费和合同。
- 分期还款单创建、无页面支付、银联支付、B2B 支付和自动还款落账。
- 本地付款单、付款明细、账户、采购支付快照和还款单的排查方法。
2.2 本文不包含
- 专属授信资金池、专属返利、额度冻结、占用和释放的完整算法,见《32_专属授信_返利与资金池》。
- 通用支付故障的全量排查清单,见《18_财务和支付排查手册》。
- 采购单创建、支付前状态和支付后履约全流程,见《03_采购_采购退货与采购入库》。
- 银行侧清结算、对账、拒付、证书轮换和真实商户配置。
- 支付中心、OPS Manager 内部表结构及其定时任务。
2.3 三层职责
| 层级 | 主要职责 | DGJ2 代表代码 | 是否直接认定资金成功 |
|---|---|---|---|
| 通道适配层 | 查询资格、注册签约、获取二维码或链接、主动查询 | application/controllers/financial/*、application/Providers/OpsManager/Financial/* | 否 |
| 支付结果层 | 消费支付中心消息,校验业务单,生成财务数据并推进订单 | application/controllers/tasks/PayCenterNotify.php | 是,以支付中心成功事件为准 |
| 授信分期层 | 分期签约、分期申请、账单查询、还款单创建和还款落账 | BaitiaoInstallmentSer、两个 Baitiao Provider、RepaymentOrderModel | 申请成功不等于还款成功;还款以回调为准 |
flowchart LR
U[服务站用户] --> C[DGJ2 金融 Controller]
C --> S[Financial Service 或分期 Service]
S --> O[OPS Manager / 支付中心]
O --> B[银行或授信机构]
B --> O
O --> M[paycenter_notify]
M --> N[PayCenterNotify]
N --> P[付款单和账户流水]
N --> R[采购单或还款单状态]
3. 参与角色与前置条件
| 角色 | 主要动作 | 必要上下文 | 典型失败原因 |
|---|---|---|---|
| 服务站主账号/员工 | 注册、签约、申请分期、发起支付或还款 | sid、user_id、手机号、菜单权限 | 站点不存在、手机号不匹配、权限被锁 |
| 采购业务 | 创建待支付采购单并请求支付 | billNo、供应商、金额、来源类型 | 单据状态不是待支付、金额不一致 |
| 财务人员 | 查看付款、账户和还款结果 | 服务站数据权限、业务单号 | 分表查错、只看主单未看明细 |
| OPS Manager | 聚合银行和授信接口 | 服务站、承运/供货方编码、账户标识 | 通道未开通、参数映射错误 |
| 支付中心 | 创建支付、接收银行结果、投递 MQ | 来源单号、支付单号、支付类型 | 回调延迟、重复、乱序 |
| 银行/授信机构 | 开户签约、收款、放款、分期和还款 | 商户、主体、银行卡、风控材料 | 风控拒绝、签名失败、渠道维护 |
| DGJ2 MQ 消费者 | 将成功结果落入本地账务和业务状态 | 可查询到原单、账户和供应商 | 原单缺失、状态异常、局部写入失败 |
通用前置条件:
sid必须对应有效服务站,当前用户必须属于该站点。- 需要支付的采购单通常处于
PoOrderEnums::BILLSTATUS_WAIT_PAY;支付超时的特定预订单提货单有兼容处理。 - 银行通道必须完成准入或签约,且 OPS Manager 能查询到对应服务站配置。
- 分期业务还需要供货方编码
shipperCode、授信调整单号adjustNo或分期单号installmentNo。 - 页面展示“已签约”“可支付”不等于资金已到账,最终必须核对支付中心事件和 DGJ2 财务落账。
4. 代码入口地图
4.1 银行与金融 Controller
| Controller | 公开方法 | 业务用途 | 下游 |
|---|---|---|---|
financial/B2bPay.php | queryWhite | 查询 B2B 版本或白名单资格 | B2bPayProvider |
financial/BridgeBank.php | findbyid、listpage、save、download | 桥接银行资料维护和下载 | BridgeBankSer |
financial/OtherBank.php | data、findbyid、listpage、loaner、save、download | 他行融资预加载、银行和贷款人资料 | OtherBankSer |
financial/Cmbc.php | queryRegister、sendSms、register | 民生注册状态、短信和注册 | CmbcProvider |
financial/Icbc.php | getQRCode、getQRCodeBaitiaoReturn、getQRCodeByActivity | 工行采购、授信还款和活动支付二维码 | IcbcProvider |
financial/Icbc.php | getLoanNotify、getQrCodeOfJumpPage | 放款通知和银行跳转页 | IcbcProvider |
financial/IcbcE.php | ableCreateIcbcEAccount、createIcbcEAccount、balance | 工行 E 账户资格、开户和余额 | FinancialProvider |
financial/Jdsk.php | queryStatus、queryRefundStatus、payUrl、domain | 京东数科状态、退款和支付链接 | JdskProvider |
financial/Lakala.php | queryStatus、sendSms、creditRegInfo、creditReg | 拉卡拉准入和授信注册 | LakalaProvider |
financial/Lakala.php | payQrcode、repayQrcode | 拉卡拉支付与还款二维码 | LakalaProvider |
financial/Mxsk.php | getCreditUrl | 获取授信申请地址 | MxskProvider |
financial/MyBank.php | getQRCode、getQRCodeBaitiaoReturn、getQRCodeByActivity | 网商采购、还款和活动二维码 | MyBankProvider |
financial/TaiLong.php | queryStatus、textMessageForSign、sign | 泰隆状态、签约短信和签约 | TaiLongSer |
financial/TaiLong.php | textMessageForPay、submitPayOrder | 支付短信和支付提交 | TaiLongSer |
financial/Xiaoyudian.php | sendSms、registerStatus、registerInfo、registerQrcode | 小雨点注册链 | XiaoyudianProvider |
financial/Xiaoyudian.php | payQrcode、repayQrcode | 小雨点支付与还款二维码 | XiaoyudianProvider |
4.2 分期 Controller
application/controllers/financial/BtInstallment.php 是薄 Controller:读取 getThoroughData(),调用 BaitiaoInstallmentSer,再统一通过 splash() 返回成功或错误。
| 接口方法 | 核心输入 | Service 方法 | 结果含义 |
|---|---|---|---|
querySignStatus | sid | getSignStatus | 查询分期协议签约状态 |
sendSms | 用户、手机号 | sendSms | 发送 FQ签约 验证码 |
getSignUrl | sid、手机号、验证码 | getSignUrl | 验证短信后返回签约 URL |
queryEnableInstallment | sid、shipperCode、adjustNoList | 同名方法 | 批量判断账单是否可分期 |
getInstallmentModeList | adjustNo | 同名方法 | 查询可选分期模型 |
queryInstallmentModeCreateToken | adjustNo、模型编码 | 同名方法 | 生成本次分期提交 token |
installmentSubmit | token | 同名方法 | 向 OPS Manager 提交分期申请 |
listInstallmentModelListV2 | adjustNo、模型列表 | 同名方法 | 新版模型批量查询 |
installmentTokenV2 | adjustNo、code、amount | 同名方法 | 新版 token 与首还金额 |
queryInstallmentWaitPayList | sid | 同名方法 | 待还账单并补充聚合金额 |
queryBtInstallmentMoney | sid | 同名方法 | 聚合待还笔数和金额 |
installmentReturnSubmit | orders、sid、user_id、shipperCode | 同名方法 | 本地建还款单并远程批量登记 |
installmentReturnNoPagePay | 账户类型、站点、供货方、来源单号 | 同名方法 | 账户余额类无页面还款 |
installmentReturnUnion | sourceNo | 同名方法 | 银联还款二维码 |
installmentReturnB2B | 账户类型、站点、供货方、来源单号 | 同名方法 | 工行 B2B/B2C 还款 |
queryInstallmentOrderList | sid、分页、adjustNo | 同名方法 | 分期批次列表 |
queryInstallmentOrderDetailList | 分期号、账单号、逾期/支付状态 | 同名方法 | 分期明细列表 |
installmentServerFeeList | 客户、业务号、计费时间、分页 | installmentServerFee | 分期服务费 |
queryInstallmentContract | sid | getContractUrl | 分期合同地址 |
5. 通道能力矩阵
| 通道 | 资格/状态 | 注册/签约 | 支付入口 | 还款入口 | 主动退款查询 | 备注 |
|---|---|---|---|---|---|---|
| B2B | queryWhite | 外部完成 | 支付中心预支付 | preparedPay/baitiaoReturn | 未在该 Controller 暴露 | 需区分资格和真实付款结果 |
| 桥接银行 | 列表/详情 | 保存银行资料 | 无直接二维码 | 无 | 无 | 更接近资料管理适配器 |
| 他行融资 | 预加载/详情/列表 | 保存银行和贷款人 | 由支付中心账户路由 | 可走无页面支付 | 无 | 账户类型通常为他行融资 |
| 民生 | queryRegister | 短信、register | 外部聚合 | 外部聚合 | 无 | 注册成功不等于支付成功 |
| 工行 | 放款查询 | 外部签约 | 采购/活动二维码 | 授信还款二维码 | 无 | 支持跳转页 |
| 工行 E | 可开户、余额 | 创建 E 账户 | 账户支付 | 未暴露 | 无 | 账户标识见 10 |
| 京东数科 | 支付状态 | 外部准入 | 支付 URL | 未暴露 | queryRefundStatus | 状态查询用于未知结果核验 |
| 拉卡拉 | queryStatus | 短信、资料、注册 | payQrcode | repayQrcode | 无 | 还可查询注册余额 |
| 泰隆 | queryStatus | 签约短信、签约 | 支付短信、提交支付单 | 未暴露 | 无 | 提交后仍需查最终结果 |
| 小雨点 | 注册状态/资料 | 短信、注册二维码 | payQrcode | repayQrcode | 无 | 二维码由 OPS Manager 返回 |
| 网商银行 | 外部状态 | 外部准入 | 采购/活动二维码 | 授信还款二维码 | 无 | 本地账户类型编码 18 |
| 授信分期 | 签约、逾期、可分期 | 短信和签约 URL | 分期申请 token | 三种还款方式 | 由支付中心处理 | 申请、还款是两张不同业务单 |
6. 外部接口边界
6.1 OPS Manager 分期接口
| Provider 常量 | 外部路径后缀 | 本地用途 |
|---|---|---|
BAITIAO_ENABLE_INSTALLMENT | /account/baitiao/installment/queryAdjustEnableInstallment | 批量判断账单是否可分期 |
BAITIAO_INSTALLMENT_MODE_LIST | /installment/listInstallmentModelList | 查询旧版分期模型 |
BAITIAO_INSTALLMENT_MODE_CREATETOKEN | /installment/selectInstallmentModelCreateToken | 选择模型并生成 token |
BAITIAO_INSTALLMENT_SUBMIT | /installment/submitApplyByToken | token 提交分期 |
BAITIAO_INSTALLMENT_WAIT_APY_LIST | /installment/listWaitingPayList | 查询待还列表,常量名保留历史拼写 APY |
BAITIAO_INSTALLMENT_SIGN_STATUS | /installment/querySignStatus | 查询签约状态 |
BAITIAO_INSTALLMENT_SIGN_URL | /installment/openSignUrl | 获取签约地址 |
BAITIAO_INSTALLMENT_ORDER_LIST | /installment/orderBatch/listPage | 分期批次分页 |
BAITIAO_INSTALLMENT_ORDER_DETAIL_LIST | /installment/order/listPage | 分期明细分页 |
BAITIAO_INSTALLMENT_CONTRACT | /installment/queryContract | 查询合同 |
BAITIAO_DELAY_LOCK | /account/baitiao/delayLock | 申请延期锁定 |
BAITIAO_OVERDUE_INFO | /account/baitiao/getOverdueInfo | 查询逾期信息 |
BAITIAO_INSTALLMENT_MODE_LIST_V2 | /installment/listInstallmentModelListV2 | 新版模型列表 |
BAITIAO_INSTALLMENT_MODE_TOKEN_V2 | /installment/selectInstallmentModelCreateTokenV2 | 新版 token |
BAITIAO_INSTALLMENT_APPLY | /account/baitiao/installment/Apply | 分期申请列表 |
BAITIAO_INSTALLMENT_SERVICE_FEE | /paycenter/dgj/installment/service/fee/listpage | 查询服务费 |
6.2 分期还款接口
| Provider 常量 | 外部路径 | 参数核心 |
|---|---|---|
BAITIAO_INSTALLMENT_RETURN_SUBMIT | /account/baitiao/return/submitWhenInstallOrder | sourceNo、installNo、returnAmount |
BAITIAO_INSTALLMENT_RETURN_BATCH_SUBMIT | /account/baitiao/return/batchSubmitWhenInstallOrder | 多笔还款数组 |
BAITIAO_INSTALLMENT_RETURN_NOPAGE_PAY | /account/baitiao/return/noPagePay | accountKey、sourceOrderIds |
BAITIAO_INSTALLMENT_RETURN_UNION | /cashier/unionPayChannel/getQRCodeBaitiaoReturn | sourceOrderIds |
BAITIAO_INSTALLMENT_RETURN_B2B | paycenter/preparedPay/baitiaoReturn | accountKey、sourceOrderIds |
Provider 统一以外部响应 code == 0 作为成功;非零直接抛出外部 message。这只能说明接口调用成功,不能替代银行资金终态。
7. 请求字段与口径
7.1 分期申请核心字段
| 字段 | 来源 | 含义 | 规则 |
|---|---|---|---|
sid | 登录上下文/请求 | 服务站 ID | Provider 中多数转字符串 |
shipperCode | 账单或页面 | 供货方/货主编码 | 可分期判断和还款必需 |
adjustNo | 授信账单 | 授信调整单号 | 分期模型查询的主业务键 |
adjustNoList | 页面选择 | 多个授信账单号 | 批量可分期判断 |
installmentModelCode | 模型列表 | 分期方案编码 | 旧版 token 接口使用 |
code | 页面 | 新版模型编码 | Service 映射为外部模型字段 |
amount | 页面 | 首还金额 | V2 映射为 firstReturnAmount,单位待外部合同确认 |
token | 外部模型接口 | 一次性提交凭证 | 不应复用或长期缓存 |
installmentNo | 外部分期单 | 分期批次/订单号 | 列表和还款关联 |
7.2 还款请求示例
{
"sid": "10001",
"user_id": "20001",
"shipperCode": "SUPPLIER_DEMO",
"orders": [
{
"installNo": "INSTALLMENT_DEMO_001",
"returnAmount": 123400
}
]
}
字段解释:
returnAmount在还款单本地字段和回调处理中按“分”解释;展示付款单时除以 100 转“元”。联调必须再次核对外部契约。sourceNo不由前端传入,由KzOrderNo::getHKDNo($sid)加批次内索引生成。uid记录发起人,自动还款没有本地原单时会取服务站主账号,取不到则为0。shipperCode用于匹配供应商和组成账户键,传错会导致财务往来对象错误。
7.3 还款账户键
无页面支付和 B2B 还款使用:
accountKey = accountType + "-" + sid + "-" + shipperCode
这是跨系统业务键,不是本地账户表主键。任何一段错误都可能出现“支付中心找不到账户”或资金进入错误账户域。
8. 账户类型与支付状态
8.1 系统账户编码
AccountEnums 用支付中心账户类型拼成本地 number:SYSTEM_NUMBER_PREFIX('10') + payTypeCode。
| 支付类型编码 | 业务名称 | 典型用途 |
|---|---|---|
01 | 企业付款账户 | 对公付款 |
02 | 个人付款账户 | 对私付款 |
05 | 返利账户 | 返利抵扣 |
06 | 待退款账户 | 退款暂存、无页面支付 |
07 | 快准授信账户 | 白条/授信支付 |
08 | 他行融资账户 | 外部融资资金 |
09 | 原路退回标识 | 退款路由兼容 |
10 | 工行 E 贷标识 | 工行 E 贷支付 |
11 | 信 E | 信 E 通道 |
12 | 银联付款账户 | 银联支付 |
15 | 专属返利账户 | 专属返利抵扣 |
18 | 网商付款账户 | 网商银行 |
20 | 预充值账户 | 预存余额 |
100 | 混合支付 | 多账户组合 |
99 | 零元订单过滤标识 | 不生成真实资金付款 |
8.2 本地付款状态
PaymentEnums 值 | 名称 | 使用提醒 |
|---|---|---|
0 | 已确认 | 历史确认态 |
1 | 已提交 | 已提交、未完全确认 |
2 | 已确认 V2 | 新确认态 |
6 | 已取消 | 撤销或失效 |
这些状态是本地付款单状态,不等价于支付中心 payStatus。支付回调代码明确要求 payStatus == '02' 才进入成功落账。
8.3 分期配置枚举
| 值 | 含义 |
|---|---|
01 | 不分期 |
02 | 下单即分期 |
03 | 下单后指定天数开始分期 |
isInstallment = 1 | 开启分期,映射到 03 |
isInstallment = 0 | 不分期,映射到 01 |
9. 银行注册与签约流程
sequenceDiagram
participant U as 服务站用户
participant C as Financial Controller
participant S as Service/Provider
participant O as OPS Manager
participant B as 银行
U->>C: 查询资格/状态(sid)
C->>S: 映射登录上下文
S->>O: 查询通道状态
O->>B: 查询主体或协议
B-->>O: 未注册/处理中/已开通/拒绝
O-->>S: code/message/data
S-->>C: data 或抛异常
C-->>U: 统一 splash 响应
U->>C: 短信/注册/签约
C->>S: 主体资料+验证码
S->>O: 注册或签约
O->>B: 实际开户/签约
B-->>U: 可能跳转银行页面
业务判断:
- “发送短信成功”只代表验证码请求成功。
- “返回签约 URL”只代表获得签约入口。
- 用户从银行页面返回后,应再次查询签约/注册状态,不能只信前端跳转结果。
- 状态“处理中”不可重复提交敏感资料,除非外部明确允许。
- 注册资料包含身份证、银行卡、营业执照等敏感信息,日志和文档必须脱敏。
10. 采购支付主流程
flowchart TD
A[采购单进入待支付] --> B[请求支付中心预支付]
B --> C{选择账户和银行通道}
C --> D[获取二维码/链接/短信]
D --> E[用户完成银行操作]
E --> F[银行通知支付中心]
F --> G[支付中心投递 paycenter_pay_result]
G --> H{payStatus == 02?}
H -- 否 --> I[NACK并告警]
H -- 是 --> J{原单类型}
J -- 预订单 --> K[校验预订单可支付状态]
J -- 采购单 --> L[校验待支付或兼容超时状态]
K --> M[创建付款主单与明细]
L --> M
M --> N[写账户流水和采购支付信息]
N --> O[推进原单后续状态]
O --> P[事务提交后ACK]
10.1 支付成功事件关键字段
| 字段 | 作用 | 本地使用方式 |
|---|---|---|
sourceOrderNo | 来源业务单号 | 查询预订单或采购单 |
sourceOrderType | 来源类型 | 04 预订单,01 采购单 |
payOrderNo | 支付中心单号 | 支付追踪和幂等核对 |
mainPayTypeCode | 主支付类型 | 零元订单和主账户判断 |
payStatus | 支付结果 | 必须为 02 |
payStatusMsg | 状态说明 | 失败日志和告警 |
payTime | 资金完成时间 | 缺失时回退当前时间 |
detailTotalAmount | 支付明细总额 | 外部资金单位需按接口合同核对 |
details | 分账户支付明细 | 按 payAccountTypeCode 绑定 |
10.2 原单校验
- 预订单允许状态来自
PreOrderEnums的待支付、取消、自动取消兼容集合。 - 普通采购单只接受待支付和特定支付超时状态。
- 原单不存在、状态不允许或重复成功消息会抛异常并返回 NACK。
mainPayTypeCode == 99时走零元订单兼容,不应按普通资金明细入账。
10.3 本地落账结果
一次正常支付至少需要核对:
- 采购/预订单状态是否推进。
SCM_PAYMENT主单是否生成。SCM_PAYMENT_INFO是否按账户拆出明细。SCM_ACCOUNT是否存在支付类型对应的系统账户。SCM_ACCOUNT_INFO是否产生正确方向和金额的账户流水。SCM_PO_ORDER_PAYINFO是否记录采购支付快照。- 支付中心单号、来源单号和本地付款单号是否能互相追踪。
11. 分期签约与申请流程
flowchart TD
A[查询签约状态] --> B{已签约?}
B -- 否 --> C[发送 FQ签约 短信]
C --> D[校验验证码]
D --> E[获取外部签约URL]
E --> F[用户完成签约]
F --> A
B -- 是 --> G[批量查询账单可分期]
G --> H[选择 adjustNo]
H --> I[查询分期模型]
I --> J[选择期数/首还金额]
J --> K[生成一次性 token]
K --> L[按 token 提交]
L --> M[查询分期批次和明细]
11.1 短信签约安全边界
BaitiaoInstallmentSer::getSignUrl 先使用本地短信服务校验 user_id + code,再请求外部签约地址。需要回归:
- 验证码错误、过期、已使用。
- 同一用户连续发送和频率限制。
- A 用户的验证码不能给 B 用户使用。
- 页面手机号和服务站主体手机号不一致。
- 外部签约 URL 超时后重取,旧 URL 是否失效。
11.2 可分期判断
queryEnableInstallment 同时传 sid、shipperCode 和 adjustNoList。因此“某账单可分期”至少取决于:
- 服务站授信资格。
- 该供货方是否支持分期。
- 账单是否满足金额、期限和状态条件。
- 账单是否已经分期或正在处理。
页面不能仅凭金额大于零显示“可分期”,必须使用外部返回结果。
11.3 token 语义
token 是“分期方案快照”的一次性凭证,可能固化账单、期数、费率、首还金额和有效期。高风险行为:
- token 生成后修改账单选择再直接提交。
- 重复点击导致同一 token 多次提交。
- 缓存旧 token,跨用户或跨站点复用。
- 前端自行计算服务费并覆盖外部结果。
12. 分期待还金额口径
queryInstallmentWaitPayList 对外部返回的每个分组补充六个聚合字段:
| 字段 | 计算方式 | 单位 |
|---|---|---|
pendingMoney | 所有 installmentOrderList.totalAmount 求和 | 先按分汇总,再转元 |
pendingNum | 所有待还明细数量 | 笔 |
weekPendingMoney | 到期日小于等于当前日期后第 7 天的金额 | 元 |
weekPendingNum | 上述明细数量 | 笔 |
allExpireAmount | expiredStatus == '02' 的金额 | 元 |
allExpireNum | expiredStatus == '02' 的数量 | 笔 |
代码的“未来七天”截止值由当天零点时间戳加 7 * 24 * 60 * 60 计算。需要注意:
- 包含截止日零点及之前的记录,若到期时间含时分秒,边界可能与产品理解不同。
- 代码对
totalAmount使用分转元,而queryBtInstallmentMoney汇总totalAmountYuan;两个接口的源字段不同。 - 页面合计应使用接口聚合值,不要混加“分”和“元”。
flowchart LR
A[外部待还分组] --> B[遍历 installmentOrderList]
B --> C[全部待还金额/笔数]
B --> D[未来7天金额/笔数]
B --> E[expiredStatus=02 金额/笔数]
C --> F[分转元]
D --> F
E --> F
F --> G[返回页面]
13. 分期还款单创建
13.1 调用链
BtInstallment::installmentReturnSubmit
-> BaitiaoInstallmentSer::installmentReturnSubmit
-> BaitiaoInstallmentValidate::scene('installmentReturnSubmit')
-> KzOrderNo::getHKDNo(sid)
-> RepaymentOrderModel::cancelUnpayByShipperCodeAndSid
-> RepaymentOrderModel::addBatch
-> InstallmentRepayProvider::installmentReturnBatchSubmit
13.2 逐步写入
| 步骤 | 动作 | 本地/外部 | 关键结果 |
|---|---|---|---|
| 1 | 校验 shipperCode 和 orders | 本地 | 缺少则终止 |
| 2 | 逐笔校验 installNo、returnAmount | 本地 | 非法金额终止 |
| 3 | 生成 HKD 还款单号并追加批次索引 | 本地 | 每笔有 sourceNo |
| 4 | 开启还款单数据库事务 | 本地 | 事务开始 |
| 5 | 取消同站点、同供货方未支付旧还款单 | 本地 | 防止多个待支付单并存 |
| 6 | 批量新增还款单 | 本地 | 保存金额、账单、供货方 |
| 7 | 调用外部批量创建还款单 | 外部 | OPS Manager 登记 |
| 8 | 外部成功后提交本地事务 | 本地 | 返回逗号分隔 sourceNo |
13.3 分布式事务窗口
sequenceDiagram
participant S as BaitiaoInstallmentSer
participant DB as DGJ2 DB
participant O as OPS Manager
S->>DB: BEGIN
S->>DB: 取消旧未支付还款单
S->>DB: 批量插入新还款单
S->>O: 批量创建外部还款单
alt 外部失败
O-->>S: error
S->>DB: ROLLBACK
else 外部成功
O-->>S: success
S->>DB: COMMIT
end
高风险点:外部调用在本地数据库事务内。若外部已成功,但本地连接在提交时失败,外部存在还款单而本地没有;直接重试可能生成新的 sourceNo 和重复外部单。恢复前必须同时查询两端,不能只重跑接口。
14. 三种主动还款方式
| 方式 | 本地方法 | 关键参数 | 用户交互 | 最终结果来源 |
|---|---|---|---|---|
| 账户无页面还款 | installmentReturnNoPagePay | accountKey、sourceNo | 无二维码 | 支付中心 MQ |
| 银联在线还款 | installmentReturnUnion | sourceNo | 返回二维码 | 支付中心 MQ |
| 工行 B2B/B2C | installmentReturnB2B | accountKey、sourceNo | 跳转/二维码依外部返回 | 支付中心 MQ |
发起成功只表示支付中心受理。页面应显示“处理中”并轮询业务状态或等待回调,不应立即把本地还款单改为已还款。
15. 授信还款回调
PayCenterNotify::paycenterBaitiaoReturnPayResult 消费 paycenter_baitiao_return_pay_result。
flowchart TD
A[收到授信还款成功事件] --> B[按 sourceNo 查询本地还款单]
B --> C{本地存在?}
C -- 否 --> D{returnMethod == 03?}
D -- 否 --> E[NACK: 单号不存在]
D -- 是 --> F[按 sid/shipperCode/adjustNo 补建自动还款单]
C -- 是 --> G[检查 state]
F --> G
G --> H{state == 1?}
H -- 是 --> I[当前实现抛异常并NACK]
H -- 否 --> J[查询供应商和支付账户]
J --> K[生成其他支出付款单]
K --> L[本金/利息/滞纳金付款明细]
L --> M[写账户流水并更新还款单]
M --> N[事务成功 ACK]
15.1 自动还款补单
当本地不存在 sourceNo 且 returnMethod == '03' 时,消费者允许按事件中的:
sidshipperCodeadjustNo
补建本地还款单。发起人优先取站点主账号,取不到为 0。其他还款方式找不到本地单时直接失败。
15.2 财务拆分
回调 details 按 code 区分并映射到付款类别:
| 费用组成 | 本地用途 | 付款明细 |
|---|---|---|
| 本金 | 更新还款单本金金额 | 其他支出本金类别 |
| 利息 | 更新 interest | 其他支出利息类别 |
| 滞纳金 | 更新 late_fee | 其他支出滞纳金类别 |
外部金额除以 100 写入付款主明细的“元”字段;还款单原始金额保留“分”口径。排查总额时必须统一单位后再比较。
15.3 重复消息风险
当前代码发现 repaymentOrderInfo.state == 1 时抛异常,外层返回 NACK。若 MQ 以 NACK 重投且没有死信上限,已经成功的重复消息可能持续重试。待环境确认消费者重试和死信策略;代码优化方向是将“同一业务结果已成功”识别为幂等 ACK,同时核对金额和支付单号是否一致。
16. 支付异常与未知结果
paycenter_pay_exception 会按来源单号查询采购单,并调用 PoOrderSer::cancelWaitPayOrder 取消待支付订单。处理原则:
- 支付异常消息不能只看错误文案,要核对银行是否真实扣款。
- 若支付中心返回失败但银行已扣款,先冻结人工重试,交由支付中心对账。
- 若采购单已被取消,随后又收到支付成功事件,当前状态校验可能 NACK,属于迟到成功风险。
- 资金结果未知时,优先主动查询支付中心/银行状态,再决定是否补消息。
flowchart TD
A[页面支付失败或超时] --> B{银行是否扣款?}
B -- 否 --> C[查支付中心支付单状态]
B -- 是/不确定 --> D[禁止重复支付]
C --> E{支付中心终态?}
E -- 成功 --> F[查 DGJ2 是否落账]
E -- 失败 --> G[确认采购单取消或可重新支付]
E -- 处理中 --> H[等待回调/对账]
D --> C
F --> I{本地完整?}
I -- 否 --> J[按幂等键补消息或人工补账审批]
17. 到期提醒与逾期锁站
17.1 分期到期提醒
paycenter_installment_expire:
- 按
sid查询服务站联系人。 - 统计
installmentOrderList数量和stayTotalAmountYuan。 - 发送账户主题站内信。
- 发送分期到期短信。
- 站内信或短信失败均返回 NACK。
提醒事件不会直接扣款,也不会更新还款状态。
17.2 逾期锁站状态
lockStatus | 含义 | DGJ2 动作 |
|---|---|---|
01 | 未锁定 | MenuRuleSer::unLockMenu(sid) |
02 | 锁定中 | 10:00 之后执行 lockMenu(sid);10:00 前跳过 |
03 | 延期锁定 | 当前实现执行解锁 |
stateDiagram-v2
[*] --> 正常可用
正常可用 --> 延期锁定: lockStatus=03
延期锁定 --> 正常可用: DGJ2执行解锁
正常可用 --> 已锁站: lockStatus=02且时间不早于10:00
延期锁定 --> 已锁站: 后续收到02且时间满足
已锁站 --> 正常可用: lockStatus=01
批量事件逐站处理;单个站点异常只记录并继续,外层仍可能 ACK。因此必须从日志核对每个 sid 的实际结果,不能只看整条 MQ 是否消费成功。
18. 核心表与分片
| 常量/表 | 关键键 | 读取时机 | 写入时机 | 主要字段/作用 |
|---|---|---|---|---|
SCM_PO_ORDER | id、billNo、sid | 支付回调查原单 | 支付成功/异常推进状态 | 采购主单 |
SCM_PO_ORDER_PAYINFO | 采购单、支付单 | 支付详情 | 支付成功新增 | 采购支付快照 |
SCM_PAYMENT | id、billNo、sid | 财务查询、回调幂等核验 | 支付/还款成功新增 | 付款主单;按站点落分片 |
SCM_PAYMENT_INFO | iid、stlNo、sid | 付款详情 | 按支付账户或费用项新增 | 付款明细 |
SCM_PAYMENT_LOG | 来源单、动作 | 支付审计 | 特定支付动作写入 | 支付日志 |
SCM_ACCOUNT | sid、number | 查系统账户 | 缺少支付类型时创建 | 账户主数据 |
SCM_ACCOUNT_INFO | accId、来源单 | 财务流水 | 支付/还款成功新增 | 账户收支流水 |
SCM_REPAYMENT_ORDER | bill_no、adjust_no、sid | 还款发起和回调 | 发起新增、成功更新 | 授信/分期还款单 |
BS_CONTACT | 供应商编码 | 回调匹配 shipperCode | 本流程通常只读 | 付款往来单位 |
SYS_ADMIN | sid、主账号 | 自动还款补单、提醒 | 只读 | 联系人和发起人 |
SCM_PAYMENT_SUB_NUM = 32,付款相关表查询必须使用项目 Model 的 setSid() 或按 sid 正确路由,不能只查一个物理表后认定“没有付款单”。账户表的具体分片规则应以 Model 为准。
erDiagram
SCM_PO_ORDER ||--o{ SCM_PO_ORDER_PAYINFO : has
SCM_PO_ORDER ||--o{ SCM_PAYMENT_INFO : source
SCM_PAYMENT ||--o{ SCM_PAYMENT_INFO : contains
SCM_ACCOUNT ||--o{ SCM_ACCOUNT_INFO : records
SCM_PAYMENT_INFO }o--|| SCM_ACCOUNT : uses
SCM_REPAYMENT_ORDER ||--o{ SCM_PAYMENT_INFO : settles
BS_CONTACT ||--o{ SCM_PAYMENT : counterparty
19. 业务键追踪
| 业务键 | 产生方 | 贯穿位置 | 排查价值 |
|---|---|---|---|
billNo/sourceOrderNo | 采购/预订单 | 支付中心事件、付款明细、采购支付信息 | 支付主链第一入口 |
payOrderNo | 支付中心 | MQ、支付日志或支付快照 | 判断是否同一笔资金 |
sourceNo/bill_no | DGJ2 还款 Service 或自动还款中心 | 还款单、还款回调、付款明细 stlNo | 还款主链第一入口 |
adjustNo/adjust_no | 授信账单中心 | 分期模型、还款单、回调说明 | 追踪原授信账单 |
installmentNo/installNo | 分期中心 | 分期列表、还款请求 | 追踪分期批次 |
sid | 服务站 | 所有本地分片和外部客户编码 | 分片与数据权限 |
shipperCode | 供货方 | 可分期、账户键、供应商匹配 | 往来对象与授信域 |
20. 事务与一致性矩阵
| 场景 | 本地事务 | 外部调用位置 | 主要一致性风险 |
|---|---|---|---|
| 采购支付结果 | 付款、明细、账户、订单在事务中 | MQ 已在事务前到达 | 本地回滚后消息重试;需幂等 |
| 分期还款单创建 | 还款单事务 | 外部批量创建在本地事务内 | 外部成功、本地提交失败 |
| 授信还款结果 | 还款单、付款和账户流水事务 | 消费外部成功消息 | 重复消息当前 NACK |
| 到期通知 | 无资金事务 | 站内信和短信两次外部调用 | 站内信成功、短信失败导致重投和重复通知 |
| 逾期锁站 | 按站点逐个调用 | 菜单规则/下线链 | 部分站点失败但整批 ACK |
21. 幂等设计检查
当前排查必须至少核对以下幂等键:
- 支付:
sourceOrderNo + payOrderNo + payStatus。 - 还款:
sourceNo,并附加adjustNo、金额和payTypeCode校验。 - 分期提交:token 或外部分期申请号。
- 还款单创建:本地
bill_no与外部sourceNo一致。 - 到期提醒:
sid + 到期日 + installmentOrderNo,当前代码未见本地提醒去重表。 - 锁站:
sid + lockStatus + 事件时间,菜单锁/解锁操作应具备重复执行安全性。
只用“状态已成功”判断幂等还不够,还要检查金额、账户类型和来源单是否一致;否则可能掩盖同单号不同金额的脏消息。
22. MQ 事件地图
Destination:paycenter_notify。
| Routing key | 本地方法 | 对本文的作用 | 失败返回 |
|---|---|---|---|
paycenter_pay_result | paycenterPayResult | 采购/预订单支付成功落账 | NACK |
paycenter_pay_exception | paycenterPayException | 取消待支付采购单并记录原因 | NACK |
paycenter_baitiao_return_pay_result | paycenterBaitiaoReturnPayResult | 授信/分期还款落账 | NACK |
paycenter_baitiao_offline_return | paycenterBaitiaoOfflineReturnPayResult | 线下授信还款落账 | NACK |
paycenter_installment_expire | paycenterInstallmentExpire | 分期到期站内信和短信 | NACK |
paycenter_baitiao_expire | paycenterBaitiaoExpire | 普通授信到期提醒 | NACK |
paycenter_baitiao_service_overdue_change | paycenterBaitiaoServiceOverdueChange | 逾期锁站/解锁 | 外层异常 NACK,单站异常继续 |
paycenter_refund_result | paycenterRefundResult | 退款及额度恢复相关 | NACK |
sequenceDiagram
participant PC as 支付中心
participant MQ as paycenter_notify
participant C as PayCenterNotify
participant DB as DGJ2 DB
PC->>MQ: routing key + message
MQ->>C: 投递
C->>DB: 查业务单和状态
alt 可处理且事务成功
C->>DB: 付款/账户/业务状态
C-->>MQ: ACK
else 暂时失败或数据不完整
C->>DB: ROLLBACK
C-->>MQ: NACK
end
23. 故障树:二维码获取失败
flowchart TD
A[二维码/支付链接获取失败] --> B{Controller 是否收到请求}
B -- 否 --> C[查路由、登录态、菜单权限]
B -- 是 --> D{参数校验是否通过}
D -- 否 --> E[核对 sid、单号、手机号、shipperCode]
D -- 是 --> F{Provider 是否调用外部}
F -- 否 --> G[查本地异常和前置状态]
F -- 是 --> H{外部 code 是否为0}
H -- 否 --> I[按通道错误码查准入/签约/风控]
H -- 是 --> J{data 是否含URL/二维码}
J -- 否 --> K[外部响应契约或字段兼容问题]
J -- 是 --> L[前端展示/CORS/二维码过期问题]
24. 故障树:已扣款但订单未变化
排查顺序必须是资金优先:
- 用银行流水或支付中心单号确认是否真实成功。
- 查支付中心是否生成
paycenter_pay_result。 - 查 RabbitMQ 消费日志是否进入
paycenterPayResult。 - 核对
sourceOrderNo是否能查到正确站点和分片原单。 - 核对
payStatus是否为02。 - 核对原单是否仍在允许支付的状态。
- 查事务异常,确认付款主单、明细、账户流水是否全部回滚。
- 查消息是否 NACK 重试、进入死信或被人工丢弃。
- 未确认外部幂等前,不重新发起支付。
25. 故障树:分期还款后仍显示未还
| 检查点 | 预期 | 异常分支 |
|---|---|---|
| 本地还款单 | bill_no = sourceNo 存在 | 创建阶段本地回滚或分片查错 |
| 外部还款单 | sourceNo 存在且金额一致 | 外部批量创建失败/部分成功 |
| 支付结果 | 支付中心终态成功 | 银行处理中、失败或对账延迟 |
| MQ | 收到还款结果 | binding、积压、NACK、死信 |
本地 state | 已还款 | 回调事务失败或重复消息逻辑 |
| 付款单 | 其他支出主单存在 | 财务落账失败 |
| 付款明细 | 本金/利息/滞纳金匹配 | details.code 映射异常 |
| 账户流水 | 金额和账户类型正确 | 系统账户缺失或流水写入失败 |
26. 只读 SQL 模板
以下 SQL 仅为排查模板。先确认实际物理分表、字段名和环境;禁止直接在生产执行更新。
26.1 按采购单号查主单
SELECT id, sid, billNo, billStatus, totalAmount, srcOrderType, create_time, modify_time
FROM t_scm_po_order
WHERE billNo = 'PO_DEMO';
26.2 按站点计算付款分表
SELECT MOD(10001, 32) AS payment_shard;
再按项目实际命名规则查询对应物理表:
SELECT id, sid, billNo, billType, transType, totalAmount, isDisable, create_time
FROM t_scm_payment_XX
WHERE sid = 10001
AND billNo = 'PAYMENT_DEMO';
26.3 查付款明细来源
SELECT id, iid, sid, stlId, stlNo, amount, accId, wayId, paymentType, create_time
FROM t_scm_payment_info_XX
WHERE sid = 10001
AND stlNo IN ('PO_DEMO', 'HKD_DEMO')
ORDER BY create_time, id;
26.4 查还款单
SELECT id, sid, uid, bill_no, adjust_no, shipper_code,
amount, interest, late_fee, state, create_time, modify_time
FROM t_scm_repayment_order
WHERE sid = 10001
AND (bill_no = 'HKD_DEMO' OR adjust_no = 'ADJUST_DEMO')
ORDER BY create_time DESC;
26.5 查系统账户
SELECT id, sid, number, name, type, create_time
FROM t_scm_account_XX
WHERE sid = 10001
AND number IN ('1006', '1007', '1008', '1012', '1018', '1020');
26.6 对账守恒检查
SELECT stlNo,
COUNT(*) AS detail_count,
ROUND(SUM(amount), 2) AS detail_amount
FROM t_scm_payment_info_XX
WHERE sid = 10001
AND stlNo = 'HKD_DEMO'
GROUP BY stlNo;
将结果与:还款单 (amount + interest + late_fee) / 100、付款主单 totalAmount、支付中心成功明细统一到元后比对。
27. 日志与代码定位命令
rg -n "paycenter_pay_result|paycenter_baitiao_return_pay_result|paycenter_installment_expire" \
application/controllers/tasks application/KzData/Enums/MqEventEnums.php
rg -n "sourceOrderNo|payOrderNo|sourceNo|adjustNo|installmentNo" \
application/controllers/tasks/PayCenterNotify.php \
application/Services/ExclusiveBaitiao
rg -n "getQRCode|payQrcode|repayQrcode|submitPayOrder|queryRefundStatus" \
application/controllers/financial application/Providers/OpsManager/Financial
rg -n "SCM_PAYMENT|SCM_REPAYMENT_ORDER|SCM_PO_ORDER_PAYINFO|SCM_ACCOUNT" \
application/config/tables.php application/models
日志建议同时检索:
PayCenterNotifypayCenterPayResultpaycenterBaitiaoReturnPayResult支付消息通知开始/失败/结束授信还款消息通知- 来源采购单号、还款单号、支付中心单号和
sid
28. 允许的补偿与禁止动作
28.1 补偿前置检查
- 确认外部支付/还款终态和唯一支付单号。
- 确认本地原单、付款、明细、账户流水和还款单的实际状态。
- 确认原消息是否仍在队列、重试或死信中。
- 确认消费者对重复成功是否幂等。
- 制定补偿后的资金守恒验收 SQL。
28.2 可选恢复路径
| 场景 | 优先恢复方式 |
|---|---|
| MQ 未投递 | 由支付中心按原事件 ID/支付单号补投 |
| MQ 在死信 | 审核 payload 后按原消息重放 |
| 本地事务完整回滚 | 修复根因后重放原消息 |
| 外部还款单有、本地无 | 按外部 sourceNo 补齐本地映射后消费结果;不可重新生成新单 |
| 只有提醒失败 | 在确认无重复轰炸风险后重发通知,不触碰资金数据 |
| 单站锁站失败 | 核对最新锁定状态后单站重放/人工执行,不重放过期旧状态 |
28.3 禁止动作
- 未确认银行扣款前让用户再次支付。
- 直接修改采购单为已支付而不生成财务数据。
- 只补付款主单,不补付款明细和账户流水。
- 删除已成功还款单后重新发起。
- 用新
sourceNo替代外部已有的旧还款单。 - 在文档、工单或群聊粘贴完整银行卡、身份证、手机号、签名密钥和证书。
29. 监控建议
| 指标 | 维度 | 告警建议 |
|---|---|---|
| 支付成功回调 NACK 数 | routing key、异常类型 | 连续增长立即告警 |
| 支付成功到本地落账延迟 | 通道、来源类型 | 超业务 SLA 告警 |
| 待支付订单超时量 | 通道、站点 | 与支付中心处理中数量联动 |
| 重复成功消息量 | 来源单号、支付单号 | 识别幂等问题 |
| 外部还款单与本地还款单差异 | sourceNo | 非零告警 |
| 已还款无付款单 | sid、sourceNo | 资金数据完整性告警 |
| 分期到期通知失败 | 短信/站内信 | 分渠道统计 |
| 锁站部分失败 | sid、lockStatus | 每站记录,不能只看批次 |
| Provider 非零 code | 银行、接口 | 按通道错误码聚合 |
| 分期 token 提交失败 | 模型、错误码 | 关注重复和过期 |
30. 安全与合规
- 请求和日志中的银行卡仅保留后四位,身份证仅保留必要掩码。
- 短信验证码不得持久化明文,不得进入普通业务日志。
- 签约 URL、支付 URL 和二维码通常包含短期凭证,不应长期保存或公开。
- Provider 配置中的密钥、证书、商户号不写入知识库。
- 人工补账必须有审批、操作人、原始支付凭证、SQL 前后快照和双人复核。
- 生产查询默认只读,先按
sid定位分片,再限制单号和时间范围。
31. 回归清单:通道接入
- [ ] 未开通、审核中、已开通、拒绝四类状态展示正确。
- [ ] 短信发送成功、频控、错误手机号、验证码错误、验证码过期。
- [ ] 重复注册和重复签约不产生冲突主体。
- [ ] 银行跳转成功、取消、超时、返回页刷新。
- [ ] 二维码生成、过期、重复获取和跨账号隔离。
- [ ] 单一银行维护不影响其他银行 Provider。
- [ ] 外部
code != 0时前端显示可理解错误,不泄露敏感响应。 - [ ] 服务站被锁定后金融菜单和接口权限一致。
32. 回归清单:采购支付
- [ ] 普通采购单待支付成功。
- [ ] 预订单支付成功。
- [ ] 零元订单不生成错误资金流水。
- [ ] 企业、个人、返利、待退款、授信、银联、网商和混合账户拆分。
- [ ] 支付失败和支付异常取消待支付订单。
- [ ] 用户中途取消或二维码过期。
- [ ] 银行成功、回调延迟期间页面状态。
- [ ] 相同成功消息重复投递。
- [ ] 同来源单不同支付单号冲突。
- [ ] 支付成功和支付异常乱序到达。
- [ ] 支付超时后迟到成功。
- [ ] 付款主单、明细、账户流水和采购支付信息金额守恒。
- [ ] 32 分片路由正确。
- [ ] 消费事务中任一步失败后完整回滚。
33. 回归清单:分期申请
- [ ] 未签约不可直接分期。
- [ ] 签约短信与当前用户绑定。
- [ ] 单账单和多账单可分期判断。
- [ ] 不同
shipperCode不混选。 - [ ] 不可分期原因正确展示。
- [ ] 旧版和 V2 模型列表兼容。
- [ ] 首还金额边界、最小金额、最大金额和精度。
- [ ] token 过期、重复使用、跨用户使用。
- [ ] 重复点击提交只产生一笔外部分期申请。
- [ ] 分期批次、明细、服务费和合同可追踪。
- [ ] 未来七天与到期日边界。
- [ ] 分/元聚合无百倍误差。
34. 回归清单:分期还款与逾期
- [ ] 单笔和多笔还款单创建。
- [ ] 同站点同供货方旧未支付单取消。
- [ ] 不同供货方待还款单互不影响。
- [ ] 外部创建失败时本地回滚。
- [ ] 外部成功、本地提交失败的人工恢复演练。
- [ ] 无页面、银联、B2B 三种还款。
- [ ] 主动还款和自动还款回调。
- [ ] 自动还款本地无单时按事件补建。
- [ ] 本金、利息、滞纳金分别落账。
- [ ] 重复还款成功消息的 ACK/NACK 行为。
- [ ] 到期站内信成功、短信失败的重复通知风险。
- [ ]
01/02/03三种逾期锁定状态。 - [ ] 09:59 与 10:00 锁站边界。
- [ ] 批量锁站中单个站点失败仍有可观察记录。
- [ ] 解锁后菜单、接口和登录态一致。
35. 改动风险分级
| 风险级别 | 改动示例 | 最低回归范围 |
|---|---|---|
| P0 | PayCenterNotify、账户类型、金额单位、还款状态、MQ ACK/NACK | 全支付、全还款、重复/乱序、财务守恒、死信恢复 |
| P0 | RepaymentOrderModel、本地与外部创建顺序 | 多笔还款、事务失败、外部成功本地失败 |
| P1 | 单个银行 Provider 请求字段或成功码 | 该银行注册、签约、支付、查询、失败码 |
| P1 | 分期 token、模型或聚合金额 | 全分期申请、账单、金额边界 |
| P1 | MenuRuleSer 锁站逻辑 | 权限、菜单、接口、登录态、延期和解锁 |
| P2 | 页面文案、列表字段或下载展示 | 对应页面、兼容字段、无敏感泄露 |
36. 已确认事实与待确认项
36.1 已从当前代码确认
- 金融通道 Controller 和方法清单。
- 分期 Provider 的外部路径和
code == 0成功判断。 - 分期签约短信、本地验证码校验和签约 URL 顺序。
- 可分期、模型、token、提交、待还列表、服务费和合同调用链。
- 还款单在本地事务内新增并调用外部批量接口。
- 还款账户键由
accountType-sid-shipperCode组成。 - 支付中心 destination 和本文涉及的 routing key。
- 支付成功要求
payStatus == '02'。 - 自动还款可在本地无原单时补建还款单。
- 还款金额按分转元写付款数据。
- 重复已还款消息当前会抛异常并 NACK。
- 分期到期发送站内信和短信。
- 锁站状态
02在 10:00 前被跳过,01/03解锁。
36.2 待环境或外部系统确认
- 各银行生产路由、商户配置、签名算法、证书轮换和超时。
- 外部注册、签约、支付、退款和分期状态全集。
- 分期 token 有效期、幂等约束和重复提交返回。
firstReturnAmount等金额字段的正式单位合同。- 支付中心 publisher confirm、重试次数、死信和消息保留时间。
- 本地付款、账户和还款表的生产唯一索引。
- 支付中心对迟到成功、重复成功和支付异常乱序的责任边界。
- 逾期批量事件是否保证同一站点有序。
- 通知中心短信去重和频控。
37. 证据来源
application/controllers/financial/B2bPay.phpapplication/controllers/financial/BridgeBank.phpapplication/controllers/financial/BtInstallment.phpapplication/controllers/financial/Cmbc.phpapplication/controllers/financial/Icbc.phpapplication/controllers/financial/IcbcE.phpapplication/controllers/financial/Jdsk.phpapplication/controllers/financial/Lakala.phpapplication/controllers/financial/Mxsk.phpapplication/controllers/financial/MyBank.phpapplication/controllers/financial/OtherBank.phpapplication/controllers/financial/TaiLong.phpapplication/controllers/financial/Xiaoyudian.phpapplication/Services/Financial/*application/Providers/OpsManager/Financial/*application/Services/ExclusiveBaitiao/BaitiaoInstallmentSer.phpapplication/Providers/OpsManager/Baitiao/BaitiaoInstallmentProvider.phpapplication/Providers/OpsManager/Baitiao/InstallmentRepayProvider.phpapplication/controllers/tasks/PayCenterNotify.phpapplication/controllers/tasks/QPayCenterNotify.phpapplication/KzData/Enums/AccountEnums.phpapplication/KzData/Enums/PaymentEnums.phpapplication/KzData/Enums/InstallmentEnums.phpapplication/KzData/Enums/MqEventEnums.phpapplication/config/tables.php
38. 一页式交接结论
- 银行 Controller 只负责“能否用、怎样签、怎样拿入口”,不能据此认定资金成功。
- 采购支付以
paycenter_pay_result且payStatus == '02'为资金成功入口。 - 支付成功后必须同时核对原单、付款主单、付款明细、账户流水和采购支付快照。
- 分期申请围绕
adjustNo -> model -> token -> submit;token 是一次性方案快照。 - 分期还款围绕
installmentNo -> sourceNo -> repayment_order -> paycenter callback。 - 外部金额多为分,本地财务展示多为元,任何修改先做单位表。
- 还款单创建存在“外部成功、本地提交失败”的分布式事务窗口。
- 重复已还款消息当前可能持续 NACK,是生产重试风险点。
- 到期提醒失败会重投,逾期锁站批量中单站失败可能被整批 ACK 掩盖。
- 所有人工恢复都必须以原支付单号/还款单号为幂等键,并完成资金守恒验收。
请求-日志-数据变更追踪卡
多入口请求链路
| 场景 | 调用方与入口 | 请求载荷/上下文 | Controller/Consumer | Service/Provider | 汇合点 | 最终业务事实 |
|---|---|---|---|---|---|---|
| 分期配置/签约 | /financial/BtInstallment | 站点、授信、分期模式、签约参数 | Financial Controller | OpsManager Financial Provider | station/application ID | 获取模式、签约 URL 和签约状态 |
| 分期申请 | PC 金融页面 | 来源订单、期数、金额、服务费 | Financial Controller | BAITIAO Provider | apply/order ID | 外部授信分期订单受理 |
| 支付回调 | PayCenter MQ | 支付单、来源单、支付/白条事件 | PayCenterNotify | Payment/Baitiao Service | payOrderNo | 本地支付和授信占用落账 |
| 退款/还款 | Financial 页面/回调 | 原订单、退款/还款单、金额 | Financial Controller/Consumer | Provider/Repayment Service | original pay/order ID | 外部退款还款与本地额度恢复 |
日志证据矩阵
| 链路段 | 日志来源 | 可检索锚点 | 成功信号 | 失败信号 | 与下一段关联方式 | | --- | --- | --- | --- | --- | --- | --- | | 签约申请 | Financial Controller/Provider | request_id、sid、application/token ID | 返回受理/签约 URL | 配置关闭、token 过期、外部拒绝 | application ID 查签约状态 | | 分期下单 | Provider | 来源单、installment order ID、金额/期数 | 外部订单 accepted | 超时、金额/期数不支持、重复 | 外部订单号关联本地来源单 | | 支付回调 | PayCenterNotify | payOrderNo、来源单、event/message ID | 支付/授信记录一次落库 | 重复占额、迟到/乱序 | payOrderNo 查本地资金表 | | 退款还款 | Provider/Consumer | original pay、refund/repayment ID | 外部成功且额度/余额一次恢复 | 外部成功本地失败、重复返还 | 原支付单串联正反向流水 |
环节数据变更台账
| 步骤 | 代码位置 | 事务 | 读取事实 | 写入表/缓存/MQ | 字段或数量变化 | 回查证据 |
|---|---|---|---|---|---|---|
| 获取模式/签约 | BtInstallment + Financial Provider | 外部边界 | 站点开关、授信状态 | 外部签约、本地关系/状态 | unsigned -> pending/signed | station/application ID、外部状态 |
| 分期申请 | Financial Service | 本地事务 + 外部非原子 | 可用额度、来源订单、金额 | 本地申请/关系、外部分期订单 | available old -> old-n 或进入冻结;申请 pending | 来源单、外部订单、额度前后值 |
| 支付落账 | PayCenterNotify | 回调事务 | 成功事件、当前支付状态 | 支付表、业务/授信关系 | payment -> confirmed;冻结 -> 已用;重复 0 增量 | payOrderNo、金额、额度流水 |
| 退款还款 | Refund/Repayment Service | 外部与本地非原子 | 原支付/已退/未还金额 | 退款还款表、授信额度 | refunded/repaid +n;available +n,不超过原占用 | 原支付+反向单、资金守恒 |
| 人工补偿 | 幂等补偿入口 | 小批事务 | 外部最终态、本地差异 | 缺失本地记录或重查外部 | 只补断点;同原单重跑 0 变化 | 前后快照、原支付/还款键 |
子模块追踪:bank-pay 银行与聚合支付
| 环节 | 入口/触发 | 请求/业务键 | 代码链路 | 读取事实 | 写入与字段变化 | 日志证据 | 异常与补偿 |
|---|---|---|---|---|---|---|---|
| 发起通道 | 选择银行/聚合渠道支付 | sourceOrderNo、payOrderNo、channel、amount | application/controllers/financial/B2bPay.php、application/controllers/financial/Icbc.php、application/controllers/financial/Lakala.php | 待支付关系、渠道配置名、金额和重复单 | 本地资金事务 none -> pending;银行调用事务外 | request ID + pay/source order + channel/code | timeout 先查渠道最终态,不切通道重复扣款 |
| 结果落账 | Pay/QPay 回调 | message ID、payOrderNo、channel status | application/controllers/tasks/QPayCenterNotify.php | 外部成功、已有 Payment/Info 和来源态 | 回调本地事务 pending -> confirmed/failed,首次成功记账 | message ID + payOrderNo + channel result | 重复 0 增量;失败后换通道前确认原单已终结 |
子模块追踪:installment-config 授信分期模式配置
| 环节 | 入口/触发 | 请求/业务键 | 代码链路 | 读取事实 | 写入与字段变化 | 日志证据 | 异常与补偿 |
|---|---|---|---|---|---|---|---|
| 获取/保存模式 | 站点配置可用期数和模式 | sid、config/mode ID、operator | application/controllers/financial/BtInstallment.php -> application/Services/ExclusiveBaitiao/BaitiaoInstallmentSer.php | 站点授信、外部支持模式和原配置 | 配置本地事务 old modes -> new modes | request ID + sid + mode/version | 外部不支持的模式零写入;敏感配置值不入文档 |
| 运行读取 | 下单展示/校验分期选项 | sid、order amount、scene | application/KzData/Enums/InstallmentEnums.php | enabled、额度、期数门槛和服务费规则 | 查询只读 不写 | request ID + sid + selected mode | 页面选项不等于最终可申请;提交必须重验 |
子模块追踪:installment-sign 分期签约
| 环节 | 入口/触发 | 请求/业务键 | 代码链路 | 读取事实 | 写入与字段变化 | 日志证据 | 异常与补偿 |
|---|---|---|---|---|---|---|---|
| 发起签约 | 未签约站点开通分期 | sid、application/sign ID | application/Providers/OpsManager/Baitiao/BaitiaoInstallmentProvider.php | 授信资格、本地签约态和外部合同字段 | 外部调用事务外;本地关系 unsigned -> pending | request ID + sid/application ID + provider code | timeout 按申请键回查;禁止重复签约流程 |
| 状态确认 | 外部签约结果查询/回调 | external sign ID、status | application/Services/ExclusiveBaitiao/BaitiaoInstallmentSer.php | 两端签约态、版本和幂等键 | 本地事务 pending -> signed/failed,重复结果 0 变化 | external/local sign IDs + status | 乱序不回退 signed;合同细节需目标环境验证 |
子模块追踪:installment-apply 分期申请与服务费
| 环节 | 入口/触发 | 请求/业务键 | 代码链路 | 读取事实 | 写入与字段变化 | 日志证据 | 异常与补偿 |
|---|---|---|---|---|---|---|---|
| 提交申请 | 已签约订单选择期数 | sourceOrderNo、installmentOrderNo、period、principal | application/Services/ExclusiveBaitiao/BaitiaoInstallmentSer.php | signed、available、期数、服务费率和已有申请 | 本地申请事务写关系 none -> pending,额度 available -n, frozen +n | request ID + source/installment order + amount | 额度不足/重复来源零写入;服务费与本金分别保存 |
| 外部受理 | 提交 OpsManager 分期 | local/external application ID | application/Providers/OpsManager/Baitiao/BaitiaoInstallmentProvider.php | 本地 pending 快照和外部受理结果 | 外部调用事务外;受理号回写本地关系 | request ID + both IDs + provider code | timeout 查外部申请;拒绝按规则释放 frozen |
子模块追踪:installment-pay 分期支付回调
| 环节 | 入口/触发 | 请求/业务键 | 代码链路 | 读取事实 | 写入与字段变化 | 日志证据 | 异常与补偿 |
|---|---|---|---|---|---|---|---|
| 成功回调 | 支付中心分期结果 | message ID、payOrderNo、installment/source order | application/controllers/tasks/PayCenterNotify.php | payStatus=02、frozen、已有支付和来源态 | 回调本地事务 payment pending -> confirmed、frozen -n, used +n | message ID + three order IDs + amount | 重复 0 增量;支付成功但额度未转只补额度段 |
| 对账回查 | 资金或额度不平 | payOrderNo、额度流水 ID | application/KzData/Enums/PaymentEnums.php | Payment/Info、申请、额度前后和服务费 | 查询只读;本金+服务费与支付明细守恒 | payOrderNo + ledger IDs | 外部最终态为仲裁;禁止只改余额无流水 |
子模块追踪:installment-lock 延迟、逾期与锁定
| 环节 | 入口/触发 | 请求/业务键 | 代码链路 | 读取事实 | 写入与字段变化 | 日志证据 | 异常与补偿 |
|---|---|---|---|---|---|---|---|
| 到期扫描 | 定时任务检查未还分期 | batch、sid、installment order、dueAt | application/Services/ExclusiveBaitiao/BaitiaoInstallmentSer.php | 未还本金/服务费、到期时间和现有锁因 | 每单本地事务 normal -> due/overdue/locked | task + sid/order + dueAt/status | 已还清扫描 0 变化;时区和调度需环境确认 |
| 解锁 | 全部逾期还清 | sid、open overdue orders | application/KzData/Enums/AccountEnums.php | 所有有效逾期和站点锁态 | 条件满足才本地事务 locked -> unlocked | sid + overdue IDs + action | 不因一单还清解锁其他逾期;菜单缓存另同步 |
子模块追踪:installment-refund 分期退款
| 环节 | 入口/触发 | 请求/业务键 | 代码链路 | 读取事实 | 写入与字段变化 | 日志证据 | 异常与补偿 |
|---|---|---|---|---|---|---|---|
| 发起/结果 | 订单退货取消分期支付 | original payNo、refundNo、principal/fee | application/controllers/tasks/PayCenterNotify.php | 原支付、已退本金/服务费、used/frozen | 退款本地事务 refunded +n、used/frozen -n, available +n | message ID + original/refund/order IDs | 不超过原占用;服务费退款规则按外部合同确认 |
| 退款回查 | 外部成功本地额度未恢复 | refundNo、ledger IDs | application/Services/ExclusiveBaitiao/BaitiaoInstallmentSer.php | 外部终态、退款关系和额度流水 | 查询只读;幂等补缺失额度/状态 | refundNo + ledger before/after | 不重复发起退款;禁止余额直改无反向流水 |
子模块追踪:installment-repay 分期还款与额度恢复
| 环节 | 入口/触发 | 请求/业务键 | 代码链路 | 读取事实 | 写入与字段变化 | 日志证据 | 异常与补偿 |
|---|---|---|---|---|---|---|---|
| 发起还款 | 线上/自动/线下确认还款 | repaymentNo、installment order、amount | application/Providers/OpsManager/Baitiao/InstallmentRepayProvider.php | 应还、已还、逾期、通道和重复键 | 本地关系 none -> pending,外部还款调用事务外 | request ID + repayment/installment IDs | timeout 查外部终态;线上线下共享幂等键 |
| 还款落账 | 还款结果确认 | external repayment ID、status | application/Services/ExclusiveBaitiao/BaitiaoInstallmentSer.php | 成功金额、used、已还和锁态 | 回调本地事务 repaid +n, used -n, available +n、partial/paid | both repayment IDs + ledger | 不超过应还/原占额;全还后再解锁,重复 0 增量 |