feat(收口): 补齐 8 月迭代缺口并同步 Spec 与证据链
Some checks failed
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Has been cancelled

- 新增六对成对迁移 000232–000237:H5 弹窗类型、退款结算标识与申请人备注、优先轮询事实字段与两个新终态、通道阈值命中留痕、手机号最近解绑人、提现资格校验留痕
- 退款:原因必填与申请人备注、来源支付与渠道流水冻结、线下处理流水号补录审计、按订单查询可选退款方式、企微审批材料补齐且新增字段缺失映射即明确失败
- 优先轮询:人工关闭、有效期到期独立周期任务、失败与过期人工重触发、事实字段与异常重试查询、资产解析端点只读投影
- 通道阈值:命中事实同事务留痕与命中记录查询;员工账单:列表筛选与详情投影;商户池:列表投影与统计周期语义;H5:弹窗类型与类别排序
- 手机号:有效关联数量与最近解绑人、短信验证码失败次数限制;导出:佣金明细十五列与报表序号列
- 时间筛选:三处新增筛选纳入统一严格解析契约,员工账单产生时间参数改名
- 同步 12 份主 Spec 需求、两端点与异步任务证据链,门禁 context-health 与 OpenSpec 校验通过
This commit is contained in:
2026-09-18 15:34:29 +08:00
parent 5e78809b93
commit 5ed6b39deb
142 changed files with 7878 additions and 964 deletions

View File

@@ -39,23 +39,51 @@
- **WHEN** 系统判定该支付单原路退款的可退性
- **THEN** 判定结果为不可用且只允许客户收款信息退款,系统不因该结果新增商户凭证键或人工退款开关
### Requirement: 商户池唯一性与轮询配置
系统 SHALL 为每种支付方式最多启用一个商户池;停用历史池可保留,但不得同时启用多个同支付方式池。商户池成员支付方式 MUST 与池一致,成员按明确顺序排列;金额/笔数方式必须配置 `每轮累计``自然日累计``自然月累计` 统计周期,时间方式必须配置最小为 1 分钟的数值、单位和起始时间。
金额和笔数轮询只统计已确认支付成功结果,不在预下单时预占,也不因退款回冲。支付创建时 MUST 冻结本次路由所属的统计世代;首次成功只按支付 ID 一次性计入冻结商户和冻结统计世代,当前选路只读取当前统计世代。达到阈值的成员在当前周期跳过;所有成员达到阈值时新支付失败。时间轮询自起始时间按固定时段和成员顺序选择,成员停用即时跳下一个可用成员但不重置时段。预下单失败不得自动切换或重试,失败单不计入统计;客户再次发起时重新选择。修改阈值保留当前统计,修改统计周期、金额/笔数方式、时间周期、起始时间或每轮排序按 PRD 规则开启新周期;自然周期排序调整保留未移除成员累计。
金额和笔数轮询只统计已确认支付成功结果,不在预下单时预占,也不因退款回冲。支付创建时 MUST 冻结本次路由所属的统计世代;首次成功只按支付 ID 一次性计入冻结商户和冻结统计世代,当前选路只读取当前统计世代;金额与笔数累计 MUST 只统计与当前统计世代匹配的成功事实(自然日与自然月方式另加支付时间不早于当期窗口起点)。达到阈值的成员在当前周期跳过;全部成员达到阈值时的行为按统计周期区分:`每轮累计` MUST 视为当轮结束以保存成功时间为新起点开启新一轮并从零重新累计MUST NOT 因当轮全部达标而拒绝创建,开启新一轮 MUST 以条件更新递增统计世代,仅在当前世代未被并发改变时成功,更新冲突 MUST 按并发冲突拒绝创建本次支付且 MUST NOT 在旧世代上重复累计;`自然日累计``自然月累计` MUST 拒绝创建新支付单并提示当前周期暂无可用商户。池内只有一个启用成员时该成员 MUST 被固定选中MUST NOT 因达到阈值而在当前周期被跳过,也 MUST NOT 因「全部成员达标」而拒绝创建,该规则优先于上句的自然周期拒绝语义。时间轮询自起始时间按固定时段和成员顺序选择,成员停用即时跳下一个可用成员但不重置时段;修改时间周期数值、单位、起始时间或成员顺序并保存成功后,系统 MUST 以保存成功时间为新起点并从前述成员列表第一项重新计算时段MUST NOT 沿用请求提交前的起点。预下单失败不得自动切换或重试,失败单不计入统计;客户再次发起时重新选择。修改阈值保留当前统计,修改统计周期、金额/笔数方式、时间周期、起始时间或每轮排序按 PRD 规则开启新周期;自然周期排序调整保留未移除成员累计。
#### Scenario: 并发预下单未预占额度
- **WHEN** 多个客户并发创建金额或笔数轮询支付单且当前成员尚未达到阈值
- **THEN** 系统可使这些支付单均命中当前成员,只有后续确认成功的支付才计入累计,已创建支付单不因轮询切换改挂商户
#### Scenario: 迟到首次成功归属冻结统计世代
- **GIVEN** 支付已创建但尚未成功,之后商户池切换统计周期、成员或排序
- **WHEN** 该支付首次确认成功
- **THEN** 系统仅将金额或笔数写入该支付创建时冻结的商户和统计世代,不得改写当前选路统计或重复累计
#### Scenario: 每轮累计全部达标开启新一轮
- **GIVEN** 启用商户池统计周期为每轮累计,且本轮全部成员均已达到阈值
- **WHEN** 客户创建新的支付单
- **THEN** 系统开启新一轮、各成员从零累计,并选中成员顺序第一项,不返回暂无可用商户
#### Scenario: 当期没有可用商户
- **WHEN** 启用商户池中不存在启用且未达阈值的成员,或商户池已停用
- **THEN** 系统拒绝创建新支付单并提示暂无可用商户,不回退到旧综合支付配置
#### Scenario: 自然周期全部达标拒绝创建
- **GIVEN** 启用商户池统计周期为自然日累计或自然月累计,且当前周期全部成员均已达到阈值
- **WHEN** 客户创建新的支付单
- **THEN** 系统拒绝创建并提示当前周期暂无可用商户,不回退到旧综合支付配置
#### Scenario: 单成员池达标后仍可收款
- **GIVEN** 启用商户池只有一个启用成员,且该成员在当前自然日或自然月周期内已达到阈值
- **WHEN** 客户创建新的支付单
- **THEN** 系统仍选中该成员,不返回暂无可用商户
#### Scenario: 修改时间轮询配置后起点重算
- **GIVEN** 时间轮询商户池已存在起始时间与成员顺序
- **WHEN** 授权账号修改周期数值、单位、起始时间或成员顺序并保存成功
- **THEN** 系统以保存成功时间作为新起点,后续时段从成员列表第一项重新计算,不沿用请求提交前的时段
### Requirement: 新支付商户快照与历史兼容
C 端套餐购买、C 端资产钱包充值及代理在线预存款充值 SHALL 按支付方式通过对应启用商户池选择实际商户;后台线下订单和钱包余额支付 MUST NOT 经过商户池。代理在线充值的全局允许范围、其与商户池方式的交集及对外方式查询由对应代理自充能力定义;本能力在方式已获准后负责实际商户选择,并在无可用商户时拒绝创建。每笔通过商户池创建的支付单 MUST 保存商户 ID、商户名称/支付方式/服务商类型/商户号或应用标识快照、商户池 ID/名称快照、轮询方式快照及统计世代快照,但不得复制敏感凭证。支付、回调验签、查单和原路退款读取该实际商户当前凭证;服务商类型和退款必需凭证完整性只用于原路退款路径的可退性判定,不提供人工开关;实际渠道退款调用与退款终态由 `order-refund-exchange` 能力实现,本能力 MUST NOT 发起渠道退款请求。
@@ -113,6 +141,33 @@ C 端套餐购买、C 端资产钱包充值及代理在线预存款充值 SHALL
- **GIVEN** 存在 merchant ID 为空的历史支付
- **WHEN** 商户池功能已上线且独立 Change 尚未按数据留存期删除旧读取路径
- **THEN** 系统仍按该支付的 `payment_config_id` 处理回调、查询和退款,不自动删除旧配置或将其改挂商户
### Requirement: 商户池列表投影
商户池列表与详情 SHALL 在既有配置字段之外返回:启用成员数量与成员总数量、当前命中成员、最近配置更新时间。当前命中成员 MUST 以与支付创建相同的选择规则只读计算:金额/笔数方式取成员顺序中第一个未达阈值的成员,「每轮累计」全部达标时取成员顺序第一项;时间方式按当前时段计算结果。该计算 MUST 为只读MUST NOT 创建支付单、MUST NOT 推进统计世代、MUST NOT 计入成功累计。商户池停用或没有可用成员时当前命中成员 SHALL 返回空值 MUST NOT 阻断列表响应。成员数量与当前命中成员 MUST 按该页池集合批量计算MUST NOT 逐池放大查询次数。
#### Scenario: 列表展示商户数量与更新时间
- **WHEN** 授权账号查询商户池列表
- **THEN** 每行返回启用成员数、成员总数与最近配置更新时间
#### Scenario: 当前命中成员按顺序计算
- **GIVEN** 金额轮询商户池的成员顺序为 A、B且 A 尚未达到阈值
- **WHEN** 查询商户池列表
- **THEN** 当前命中成员返回 A且查询本身不产生支付单、不推进统计世代
#### Scenario: 停用池无当前成员
- **WHEN** 查询一个已停用且无可用成员的商户池
- **THEN** 当前命中成员为空值,其余字段正常返回
#### Scenario: 批量计算不放大查询
- **GIVEN** 一页返回多个商户池
- **WHEN** 查询该页列表
- **THEN** 系统以批量方式读取成员与成功累计,查询次数不随池数量线性增长
## 可达操作索引
本节只用于入口导航,不是行为 Requirement业务义务以上述 Requirements 为准。