10 KiB
商户支付路由当前行为
Purpose
管理实际收款商户、商户池轮询和全局微信授权配置,使新线上支付的收款身份可冻结、历史支付可继续使用其原商户,并避免凭证泄露或无配置时静默回退;本能力不新增任何支付渠道退款能力。
Requirements
Requirement: 商户与微信授权配置管理
系统 SHALL 将实际收款商户与微信授权配置分离。一个商户 MUST 仅对应 wechat 或 alipay 一种支付方式,并保存名称、支付方式、服务商类型、商户号或应用标识、敏感凭证、状态和备注;微信直连与富友均为微信支付商户。平台最多存在一个启用的微信授权配置,该配置保存 C 端公众号 H5/JSSDK、小程序登录所需参数,C 端微信登录、OpenID 和微信支付 AppID MUST 只读取该配置。
超级管理员和平台用户可创建、编辑、启用、停用商户、商户池和微信授权配置,其他角色无管理入口。仅上述角色的专用管理列表和详情响应可返回完整凭证;日志、审计快照、错误、导出、支付快照和其他业务响应 MUST NOT 保存或返回敏感凭证。被支付单引用的商户 MUST NOT 删除且其支付方式、服务商类型、商户号/应用标识不得修改;未被引用商户仅可移出所有商户池并经二次确认删除。停用只影响新支付单,历史支付的回调、查单和已有可达的原路退款仍使用该商户当前凭证;服务商无既有退款能力时保持不支持,本能力不得为此新增渠道退款调用或人工开关。
Scenario: 受引用商户停用
- WHEN 管理员停用已被支付单命中的商户
- THEN 新支付单不再选择该商户,已命中支付单的回调、查询和原路退款仍按该商户处理
Scenario: 非管理角色读取配置
- WHEN 不具备超级管理员或平台用户身份的账号请求商户或微信授权配置
- THEN 系统拒绝访问且不返回任何凭证或身份字段
Scenario: 凭证轮换后处理历史支付
- GIVEN 已被支付单引用的商户或当前微信授权配置完成凭证更新
- WHEN 更新提交后创建支付、处理回调、查单或原路退款
- THEN 系统只使用更新后的当前有效凭证,不得继续使用更新前的缓存凭证
Requirement: 商户池唯一性与轮询配置
系统 SHALL 为每种支付方式最多启用一个商户池;停用历史池可保留,但不得同时启用多个同支付方式池。商户池成员支付方式 MUST 与池一致,成员按明确顺序排列;金额/笔数方式必须配置 每轮累计、自然日累计 或 自然月累计 统计周期,时间方式必须配置最小为 1 分钟的数值、单位和起始时间。
金额和笔数轮询只统计已确认支付成功结果,不在预下单时预占,也不因退款回冲。支付创建时 MUST 冻结本次路由所属的统计世代;首次成功只按支付 ID 一次性计入冻结商户和冻结统计世代,当前选路只读取当前统计世代。达到阈值的成员在当前周期跳过;所有成员达到阈值时新支付失败。时间轮询自起始时间按固定时段和成员顺序选择,成员停用即时跳下一个可用成员但不重置时段。预下单失败不得自动切换或重试,失败单不计入统计;客户再次发起时重新选择。修改阈值保留当前统计,修改统计周期、金额/笔数方式、时间周期、起始时间或每轮排序按 PRD 规则开启新周期;自然周期排序调整保留未移除成员累计。
Scenario: 并发预下单未预占额度
- WHEN 多个客户并发创建金额或笔数轮询支付单且当前成员尚未达到阈值
- THEN 系统可使这些支付单均命中当前成员,只有后续确认成功的支付才计入累计,已创建支付单不因轮询切换改挂商户
Scenario: 迟到首次成功归属冻结统计世代
- GIVEN 支付已创建但尚未成功,之后商户池切换统计周期、成员或排序
- WHEN 该支付首次确认成功
- THEN 系统仅将金额或笔数写入该支付创建时冻结的商户和统计世代,不得改写当前选路统计或重复累计
Scenario: 当期没有可用商户
- WHEN 启用商户池中不存在启用且未达阈值的成员,或商户池已停用
- THEN 系统拒绝创建新支付单并提示暂无可用商户,不回退到旧综合支付配置
Requirement: 新支付商户快照与历史兼容
C 端套餐购买、C 端资产钱包充值及代理在线预存款充值 SHALL 按支付方式通过对应启用商户池选择实际商户;后台线下订单和钱包余额支付 MUST NOT 经过商户池。代理在线充值的全局允许范围、其与商户池方式的交集及对外方式查询由对应代理自充能力定义;本能力在方式已获准后负责实际商户选择,并在无可用商户时拒绝创建。每笔通过商户池创建的支付单 MUST 保存商户 ID、商户名称/支付方式/服务商类型/商户号或应用标识快照、商户池 ID/名称快照、轮询方式快照及统计世代快照,但不得复制敏感凭证。支付、回调验签、查单和已有可达的原路退款读取该实际商户当前凭证;服务商类型和退款必需凭证完整性只用于已有退款路径的能力判定,不提供人工开关,也不得新增渠道退款能力。
上线迁移在存在唯一当前生效综合支付配置时复制完整凭证:具备完整凭证的微信/支付宝方式创建商户和各自单成员启用池,微信授权字段完整时创建全局微信授权配置;不完整的支付方式不建池,授权字段不完整时不建授权配置并使相关 C 端微信功能明确失败。没有当前生效综合支付配置时迁移仅创建 Schema 和管理入口,不创建商户、商户池或微信授权配置数据;新订单按暂无可用商户失败,微信授权相关功能明确返回未配置。存在多条当前生效综合支付配置时迁移 MUST 失败。迁移完成后部署支持按 merchant ID 或旧 payment_config_id 双读的 API/Worker;三类后续新支付 MUST 立即只走商户池并冻结路由,无可用池、成员或停用池时明确失败且不回退旧综合支付配置。merchant ID 为空仅表示历史订单,继续按 payment_config_id 服务历史回调、查询和已有原路退款,直到独立 Change 按数据留存期删除旧读取路径。本 Change MUST NOT 自动删除旧配置或旧读取路径。
Scenario: 新支付冻结实际商户
- WHEN 客户以微信或支付宝创建覆盖范围内的新线上支付单
- THEN 系统选择并冻结一个实际商户和商户池路由快照,并使用该商户的服务商凭证发起支付
Scenario: 迁移后的新支付只走商户池
- GIVEN 迁移完成且已部署支持 merchant ID 或旧
payment_config_id双读的 API/Worker - WHEN 客户创建覆盖范围内的后续新线上支付
- THEN 系统立即经启用商户池选择并冻结实际商户;无可用池、成员或池已停用时明确失败,不得走旧综合支付配置创建
Scenario: 历史支付保留旧读取路径
- GIVEN 支付单 merchant ID 为空
- WHEN 该支付经过回调、查单或已有原路退款路径
- THEN 系统仅按其
payment_config_id处理,不因当前商户池推断或改写其商户,直到独立 Change 按数据留存期删除旧读取路径
Scenario: 旧支付单回调
- WHEN 商户池切换后收到未带新商户快照的历史支付单回调
- THEN 系统按既有综合支付配置兼容处理该历史单,不将其改挂到任何新商户
Scenario: 微信授权配置迁移缺失
- GIVEN 当前生效综合支付配置的微信授权字段不完整
- WHEN 执行商户池配置迁移后访问 C 端微信登录、OpenID、JSSDK 或微信支付 AppID 功能
- THEN 系统明确返回微信授权未配置,不得回退旧综合支付配置
Scenario: 多个当前生效综合支付配置
- GIVEN 存在多条当前生效综合支付配置
- WHEN 执行商户池配置迁移
- THEN 迁移失败且不选择任一配置作为复制来源
Scenario: 富友双读兼容基线
- GIVEN 富友
CommonQuery未经第三方实测 - WHEN 系统以商户当前凭证完成富友支付的本地双读配置来源和商户加载接线,且不改变现有
CommonQuery请求格式、签名算法、验签、状态映射或恢复语义 - THEN 系统保留该兼容基线且不新增富友退款;未第三方实测可以记录,但不得作为本 Change 的实施、验证或归档阻塞
Scenario: 维护者指定测试环境的配置迁移验证
- GIVEN 维护者指定的
junhong_cmp_testPostgreSQL、Redis DB6 与当前 Change fixture - WHEN 本地工作区以明确
DB_*完成 migration up/down/up 和数据行为验证后提交推送 Iteration/8-11 - THEN Gitea 只构建/部署
cmp-test测试镜像并检查迁移版本;测试日志保存在/opt/junhong_cmp/logs,不得自动执行迁移或重置整库
Scenario: 历史支付路径保留
- GIVEN 存在 merchant ID 为空的历史支付
- WHEN 商户池功能已上线且独立 Change 尚未按数据留存期删除旧读取路径
- THEN 系统仍按该支付的
payment_config_id处理回调、查询和退款,不自动删除旧配置或将其改挂商户
可达操作索引
本节只用于入口导航,不是行为 Requirement;业务义务以上述 Requirements 为准。
商户与微信授权配置
GET /api/admin/payment-merchants(查询支付商户);POST /api/admin/payment-merchants(创建支付商户);GET /api/admin/payment-merchants/{id}(查询支付商户详情);PUT /api/admin/payment-merchants/{id}(更新支付商户);DELETE /api/admin/payment-merchants/{id}(删除支付商户);GET /api/admin/wechat-authorizations(获取微信授权配置);PUT /api/admin/wechat-authorizations/current(保存微信授权配置)。
商户池
GET /api/admin/payment-merchant-pools(查询商户池);POST /api/admin/payment-merchant-pools(创建商户池);GET /api/admin/payment-merchant-pools/{id}(查询商户池详情);PUT /api/admin/payment-merchant-pools/{id}(更新商户池);POST /api/admin/payment-merchant-pools/{id}/enable(启用商户池);POST /api/admin/payment-merchant-pools/{id}/disable(停用商户池)。