Files
2026-09-12 11:27:50 +08:00

156 lines
7.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## ADDED Requirements
### Requirement: 商户池详情入口
系统 SHALL 与支付商户保持一致,以点击列表中商户池名称的方式进入独立详情页,并且不再在行操作中提供“详情”入口。
#### Scenario: 点击商户池名称进入详情页
- **GIVEN** 管理员位于支付商户与商户池管理页的“商户池”页签
- **WHEN** 管理员点击列表中某个商户池名称
- **THEN** 系统 MUST 跳转到该商户池的详情页
- **AND** 详情页 MUST 通过 `GET /api/admin/payment-merchant-pools/{id}` 加载数据
- **AND** 列表行操作 MUST NOT 再提供“详情”操作
#### Scenario: 商户池名称以可点击样式展示
- **GIVEN** 商户池列表加载成功
- **WHEN** 页面渲染商户池名称列
- **THEN** 商户池名称 MUST 以可点击样式展示
- **AND** 点击名称 MUST NOT 触发表格行选中或其他行操作
#### Scenario: 非平台账号不能查看商户池详情
- **GIVEN** 当前登录账号的 `user_type` 不是 `1``2`
- **WHEN** 用户点击商户池名称或直接访问商户池详情页地址
- **THEN** 系统 MUST NOT 展示商户池详情数据
- **AND** 路由 MUST 按平台账号限制拦截该访问
### Requirement: 商户池详情信息完整
系统 SHALL 在商户池详情页展示详情接口返回的全部业务字段,并 SHALL 以支付商户名称展示成员商户,不得展示 `id``member_ids` 原始标识。
#### Scenario: 展示轮询策略与阈值字段
- **GIVEN** 管理员进入某个商户池详情页
- **WHEN** 详情数据加载成功
- **THEN** 详情 MUST 展示商户池名称、支付方式、启停状态、轮询策略、路由世代和备注
- **AND** `strategy``amount``count` 时 MUST 展示统计周期和对应阈值
- **AND** `strategy``time` 时 MUST 展示时间单位、时间长度和时间起点
#### Scenario: 成员商户按名称展示
- **GIVEN** 商户池详情返回 `member_ids`
- **WHEN** 页面展示成员信息
- **THEN** 页面 MUST 展示成员商户名称和成员数量
- **AND** 页面 MUST NOT 展示 `member_ids` 原始 ID
- **AND** 成员名称无法解析时 MUST 展示“未知商户”而不是 ID
#### Scenario: 未返回的字段不渲染
- **GIVEN** 商户池详情接口未返回创建时间或更新时间
- **WHEN** 页面展示商户池详情
- **THEN** 页面 MUST NOT 渲染对应字段的空白行
### Requirement: 商户池成员顺序单一数据源
系统 SHALL 使用单一数据源维护商户池成员顺序,保证新增、编辑和拖拽排序成员时不会出现递归更新错误,并且提交顺序与页面展示顺序一致。
#### Scenario: 新增商户池不再递归更新
- **WHEN** 管理员点击“新增商户池”
- **THEN** 系统 MUST NOT 抛出 `Maximum recursive updates exceeded`
- **AND** 表单 MUST 正常打开并允许选择成员
#### Scenario: 拖拽后按展示顺序提交
- **GIVEN** 商户池表单中存在多个成员商户
- **WHEN** 管理员拖拽调整成员顺序并提交
- **THEN** `member_ids` MUST 按拖拽后的顺序提交
- **AND** 再次编辑该商户池时 MUST 按提交顺序展示成员
### Requirement: 商户凭证字段枚举契约
系统 SHALL 按 `payment_method``provider_type` 组合枚举商户凭证的必填键与可选键,并在提交前校验字段枚举、必填键、值类型与商户标识一致性。
字段枚举以后端契约为准(键名与渠道配置字段一致),前端必须与后端保持一致,后端新增或调整字段时需同步更新前端枚举。`credentials` MUST 为扁平 JSON 对象,必填键为:
- `payment_method=wechat``provider_type=wechat``wx_mch_id``wx_api_v3_key``wx_cert_content``wx_key_content``wx_serial_no``wx_notify_url`
- `payment_method=wechat``provider_type=wechat_v2``wx_mch_id``wx_api_v2_key``wx_notify_url`
- `payment_method=wechat``provider_type=fuiou``fy_mchnt_cd``fy_ins_cd``fy_term_id``fy_private_key``fy_public_key``fy_api_url``fy_notify_url`
- `payment_method=alipay``provider_type=alipay``ali_app_id``ali_private_key``ali_public_key``ali_notify_url``ali_return_url`
可选键为:`wechat` 可附 `wx_api_v2_key``alipay` 可附 `ali_production`(布尔,是否生产环境)与 `ali_pay_expire_minutes`(整数,支付过期分钟数)。除 `ali_production``ali_pay_expire_minutes` 外,凭证值 MUST 为字符串。`merchant_identity` MUST 分别等于 `wx_mch_id``fy_mchnt_cd``ali_app_id`
#### Scenario: 提交微信直连凭证
- **GIVEN** 管理员提交 `payment_method=wechat``provider_type=wechat` 的商户凭证
- **THEN** 请求 MUST 包含 `wx_mch_id``wx_api_v3_key``wx_cert_content``wx_key_content``wx_serial_no``wx_notify_url`
- **AND** 请求 MAY 附带 `wx_api_v2_key`
- **AND** `merchant_identity` MUST 等于 `wx_mch_id`
#### Scenario: 提交微信直连 V2 凭证
- **GIVEN** 管理员提交 `payment_method=wechat``provider_type=wechat_v2` 的商户凭证
- **THEN** 请求 MUST 包含 `wx_mch_id``wx_api_v2_key``wx_notify_url`
- **AND** `merchant_identity` MUST 等于 `wx_mch_id`
#### Scenario: 提交富友凭证
- **GIVEN** 管理员提交 `payment_method=wechat``provider_type=fuiou` 的商户凭证
- **THEN** 请求 MUST 包含 `fy_mchnt_cd``fy_ins_cd``fy_term_id``fy_private_key``fy_public_key``fy_api_url``fy_notify_url`
- **AND** `merchant_identity` MUST 等于 `fy_mchnt_cd`
#### Scenario: 提交支付宝凭证
- **GIVEN** 管理员提交 `payment_method=alipay``provider_type=alipay` 的商户凭证
- **THEN** 请求 MUST 包含 `ali_app_id``ali_private_key``ali_public_key``ali_notify_url``ali_return_url`
- **AND** 请求 MAY 附带 `ali_production``ali_pay_expire_minutes`
- **AND** `merchant_identity` MUST 等于 `ali_app_id`
#### Scenario: 缺少必填字段时拒绝提交
- **WHEN** 提交的凭证缺少当前服务商组合的必填键
- **THEN** 前端 MUST 阻止提交并提示缺失的凭证字段名
#### Scenario: 拒绝不属于当前服务商的凭证字段
- **WHEN** 提交的凭证包含必填键与可选键之外的字段名
- **THEN** 前端 MUST 阻止提交并提示该字段不属于当前服务商支持的字段
#### Scenario: 校验凭证值类型
- **GIVEN** 凭证包含 `ali_production``ali_pay_expire_minutes`
- **WHEN** 管理员提交凭证
- **THEN** `ali_production` MUST 以布尔值提交
- **AND** `ali_pay_expire_minutes` MUST 以正整数提交
- **AND** 其余凭证字段 MUST 以字符串提交
#### Scenario: 校验商户标识一致性
- **WHEN** `merchant_identity``wx_mch_id``fy_mchnt_cd``ali_app_id` 的值不一致
- **THEN** 前端 MUST 阻止提交并提示商户标识必须与对应凭证字段一致
### Requirement: 商户凭证访问控制
系统 SHALL 仅允许超级管理员(`user_type=1`)与平台用户(`user_type=2`)读取和写入商户凭证,且凭证内容 MUST NOT 进入日志、审计记录或支付快照。
#### Scenario: 平台账号可读写凭证
- **GIVEN** 当前登录账号的 `user_type``1``2`
- **WHEN** 账号打开支付商户管理页、支付商户详情页或提交商户凭证
- **THEN** 系统 MUST 允许读取凭证配置状态与写入凭证
#### Scenario: 非平台账号不可读写凭证
- **GIVEN** 当前登录账号的 `user_type``3``4`
- **WHEN** 账号访问支付商户管理页或支付商户详情页
- **THEN** 系统 MUST 拒绝访问并 MUST NOT 返回凭证字段或凭证状态
- **AND** 页面 MUST NOT 渲染凭证写入入口
#### Scenario: 凭证不写入日志与快照
- **WHEN** 创建、更新或删除支付商户成功或失败
- **THEN** 凭证内容 MUST NOT 出现在浏览器存储、页面日志、错误上报或支付快照中
- **AND** 页面 MUST 只展示“已配置/未配置”状态与 `credential_version`