feat(收口): 补齐 8 月迭代缺口并同步 Spec 与证据链
Some checks failed
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Has been cancelled
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:
@@ -118,6 +118,8 @@
|
||||
|
||||
提现申请 SHALL 先校验申请店铺存在有效资料资格,再冻结可提现余额、金额、手续费、收款信息和可选发票快照,并创建企业微信审批。余额不足、资格无效或非本人代理时,系统 MUST NOT 创建提现申请、审批实例或任何冻结。发票为申请级材料,若上传 MUST 按当时有效合同主体校验并冻结至该次审批快照。本地 MUST NOT 提供人工通过或驳回终审。审批 MUST 使用业务类型 `commission_withdrawal_approval`。
|
||||
|
||||
提现申请 SHALL 记录本次提现所依据的有效资料资格版本标识与当次校验结果,校验结果至少包含校验时间、是否通过,以及未通过时的稳定原因(资格不存在、已失效、已停用或资料未通过审批)。校验通过时,该记录 MUST 随每次提交或重提冻结进当次审批尝试快照,并在提现详情可查询(此处「审批材料」指本地不可变审批尝试快照,本能力 MUST NOT 要求新增企业微信模板控件),详情返回的资格校验结果与快照一致:通过时未通过原因为空字符串;上线前产生、无资格校验留痕的历史尝试按「无留痕」返回(版本标识为 0、校验时间为空、是否通过为 0、未通过原因为空字符串)。校验未通过时,系统 MUST 按既有资料资格校验的拒绝语义处理:MUST NOT 创建提现申请、审批实例与审批尝试,因此该情形 MUST NOT 产生带未通过原因的审批尝试快照,未通过稳定原因 MUST 记录在该次拒绝的结果与审计事实中。两种情形均 MUST NOT 改写历史尝试的校验结果。该记录 MUST NOT 改变既有冻结、扣减、释放、驳回重提与通过后撤销的任何语义。
|
||||
|
||||
每次提交或重提 MUST 新增一条不可变的审批尝试记录,冻结该次金额、手续费、实际到账、收款信息与申请级发票快照,并为其创建独立的审批实例;提现申请行只保存最新审批实例标识用于列表投影,MUST NOT 作为历史事实来源。企业微信通过即视为已到账:系统 MUST 保持 `WithdrawalStatusApproved`(2)并在同一事务内仅一次从冻结余额扣减,同时写入到账时间;MUST NOT 使用已到账状态值 4。
|
||||
|
||||
企业微信驳回时,系统 MUST 仅一次释放本次尝试的冻结余额并记录释放时间;`cancelled` 与 `deleted` MUST 按驳回同等处理。驳回后代理可修改金额、收款信息和本次发票重新提交,每次新建审批尝试记录与审批实例;资料资格保持有效。企业微信对已通过申请撤销时,系统 MUST NOT 回滚已到账金额、MUST NOT 重新冻结,MUST 保持通过状态并写入正交的异常标记与原因供详情展示与人工处理,MUST NOT 自动重提。
|
||||
@@ -159,6 +161,17 @@
|
||||
- **WHEN** 同一审批终态被重复投递或乱序到达
|
||||
- **THEN** 系统至多扣减或释放一次,不产生第二笔冻结
|
||||
|
||||
#### Scenario: 资料校验结果可追溯
|
||||
|
||||
- **WHEN** 代理在有效资料资格下提交提现申请,随后该资格被替换
|
||||
- **THEN** 该次提现尝试仍返回提交时冻结的资格版本标识与校验结果,不被新版本改写
|
||||
|
||||
#### Scenario: 资格失效时的校验原因
|
||||
|
||||
- **GIVEN** 代理店铺资料资格已被超级管理员作废
|
||||
- **WHEN** 代理发起提现并被拒绝
|
||||
- **THEN** 拒绝结果与审计记录包含稳定原因(资格已失效),且不创建提现申请、审批实例或冻结
|
||||
|
||||
### Requirement: 提现本地人工终审边界
|
||||
|
||||
系统 SHALL 拒绝本地人工通过与驳回已关联审批实例的提现申请;该判定 MUST 以申请记录中是否已关联审批实例为准,MUST NOT 依赖任何新增配置开关。本地接口拒绝时 MUST 返回稳定的状态冲突错误且 MUST NOT 改变申请状态、余额或流水。
|
||||
@@ -189,6 +202,50 @@
|
||||
- **WHEN** 同一未结算尝试的释放被重复执行
|
||||
- **THEN** 系统至多释放一次,冻结余额与可提现余额不被重复调整
|
||||
|
||||
|
||||
### Requirement: 注册审批材料带出业务员
|
||||
|
||||
代理注册审批材料 SHALL 在既有字段之外带出「业务员」,取上级代理店铺当前业务员的名称快照,用于审批人在企业微信侧确认将同步给新代理的初始业务员。上级店铺当前无业务员时该字段 MUST 以空值提交并在材料中标记为无,MUST NOT 以提交人、上级店铺主账号或其它账号填充。该字段 MUST 为只读快照:审批通过时写入新店铺的初始业务员仍按既有规则取上级业务员当时值,MUST NOT 因审批材料快照与通过时值不同而改写通过结果或回滚。企业微信模板控件缺失导致该字段无法提交时 MUST 明确失败并提示需配置控件,MUST NOT 静默丢弃。
|
||||
|
||||
#### Scenario: 审批材料展示将同步的业务员
|
||||
|
||||
- **GIVEN** 上级代理店铺存在启用的业务员
|
||||
- **WHEN** 创建代理注册审批实例
|
||||
- **THEN** 审批材料包含该业务员名称快照
|
||||
|
||||
#### Scenario: 上级无业务员
|
||||
|
||||
- **GIVEN** 上级代理店铺当前没有启用业务员
|
||||
- **WHEN** 创建代理注册审批实例
|
||||
- **THEN** 业务员字段以空值提交并标记为无,不使用其它账号填充
|
||||
|
||||
#### Scenario: 快照与实际同步值不同
|
||||
|
||||
- **GIVEN** 审批材料创建后上级店铺业务员发生变更
|
||||
- **WHEN** 企业微信最终通过该注册申请
|
||||
- **THEN** 新店铺初始业务员按通过时上级业务员写入,历史审批材料快照不被改写
|
||||
|
||||
|
||||
### Requirement: 店铺下级代理数量投影
|
||||
|
||||
店铺列表与详情 SHALL 返回该店铺的直接下级代理数量,口径为未删除且上级店铺标识等于该店铺的店铺数。数量 MUST 一次批量聚合完成,MUST NOT 逐店查询放大查询次数。数量 MUST 受既有店铺数据范围约束:范围外店铺按不可见处理。该字段 MUST 只读,MUST NOT 影响上下级关系、佣金关系、通知范围或任何既有写入语义。
|
||||
|
||||
#### Scenario: 展示下级数量
|
||||
|
||||
- **GIVEN** 某代理店铺存在三家直接下级店铺
|
||||
- **WHEN** 查询该店铺详情或列表
|
||||
- **THEN** 下级代理数量返回三
|
||||
|
||||
#### Scenario: 无下级返回零
|
||||
|
||||
- **WHEN** 查询一家没有任何直接下级的店铺
|
||||
- **THEN** 下级代理数量返回零而非空值
|
||||
|
||||
#### Scenario: 数据范围外不泄露
|
||||
|
||||
- **WHEN** 平台用户查询其数据范围外店铺
|
||||
- **THEN** 系统不返回该店铺及其下级数量
|
||||
|
||||
## 可达操作索引
|
||||
|
||||
本节只用于入口导航,不是行为 Requirement;业务义务以上述 Requirements 为准。
|
||||
|
||||
@@ -363,7 +363,7 @@
|
||||
|
||||
佣金明细及导出 MUST 使用既有佣金数据范围:代理仅可读取自身及其既有可见范围内的事实,平台与超级管理员遵循既有范围;无权记录不得通过关联 ID、汇总或导出泄露存在性。
|
||||
|
||||
佣金明细导出 MUST 使用佣金记录粒度,原佣金与回溯记录各占一行,并冻结创建时筛选条件、操作者与可见范围。回溯后余额为对应钱包变动提交后的实际余额,可为负数;金额保持分,展示层转元 MUST NOT 改变负数或余额事实。
|
||||
佣金明细导出 MUST 使用佣金记录粒度,原佣金与回溯记录各占一行,并冻结创建时筛选条件、操作者与可见范围。导出列 MUST 按下列顺序输出且至少包含:店铺、业务员、用户组、资产类型、设备类型、设备型号、资产标识、订单号、下单时间、佣金金额、佣金来源、佣金状态、关联佣金明细、入账后金额与创建时间。其中订单号 MUST 与原发放记录一致(回溯记录沿用被回溯记录订单号),下单时间 MUST 取原充值订单的创建时间,资产类型 MUST 区分卡与设备,设备类型、设备型号、业务员与用户组 MUST 按导出执行时该资产与店铺的当前归属补充;缺失值 MUST 以空值导出并 MUST NOT 阻断导出,MUST NOT 因个别行缺值丢失整行或整列。列名与金额单位 MUST 与既有导出口径一致,导出粒度、创建期冻结与执行期只读语义 MUST NOT 改变。回溯记录金额 MUST 为负数、可提现标识为不可提现。回溯后余额为对应钱包变动提交后的实际余额,可为负数;金额保持分,展示层转元 MUST NOT 改变负数或余额事实。
|
||||
|
||||
#### Scenario: 代理查询越权回溯记录
|
||||
|
||||
@@ -381,6 +381,23 @@
|
||||
- **WHEN** 导出含回溯记录的佣金明细
|
||||
- **THEN** 原佣金与回溯记录各占一行,回溯行金额为负数、可提现标识为不可提现、含关联佣金明细与退款单标识,且回溯后余额为负数时原样导出
|
||||
|
||||
#### Scenario: 导出包含归属与设备维度列
|
||||
|
||||
- **GIVEN** 一条佣金记录关联的资产为绑定设备的卡,且其店铺存在业务员与用户组
|
||||
- **WHEN** 导出佣金明细
|
||||
- **THEN** 该行的业务员、用户组、资产类型、设备类型与设备型号按导出执行时的当前归属与资产属性导出
|
||||
|
||||
#### Scenario: 下单时间取原订单创建时间
|
||||
|
||||
- **WHEN** 导出原佣金记录与其对应的回溯记录
|
||||
- **THEN** 两行的下单时间均为被关联原充值订单的创建时间
|
||||
|
||||
#### Scenario: 归属缺失不阻断导出
|
||||
|
||||
- **GIVEN** 某佣金记录关联店铺当前没有业务员或资产无设备型号
|
||||
- **WHEN** 导出佣金明细
|
||||
- **THEN** 对应列以空值导出,其余行与列正常产出
|
||||
|
||||
## 可达操作索引
|
||||
|
||||
本节只用于入口导航,不是行为 Requirement;业务义务以上述 Requirements 为准。
|
||||
|
||||
@@ -68,6 +68,41 @@
|
||||
- **WHEN** 生产者向公共可靠事件存储提交超过字段上限的事件标识或父事件标识
|
||||
- **THEN** 系统在持久化边界返回明确的参数错误而不是数据库字段错误
|
||||
|
||||
|
||||
### Requirement: 资产与卡详情的优先轮询状态投影
|
||||
|
||||
资产解析接口(`GET /api/admin/assets/resolve/{identifier}`)的卡与设备两个分支 SHALL 返回该资产或卡的优先轮询状态投影,至少包含:是否处于优先轮询中、最近触发场景、最近轮询结果、最近轮询时间与失败原因。本能力 MUST NOT 为投影新增独立端点,投影 MUST 落在该既有解析端点内。投影口径 MUST 与该卡在优先轮询事实表中的未完成活动项一致:存在待执行或执行中的项时「是否处于优先轮询中」为真,最近触发场景取最近触发类型,最近轮询结果取最近一次执行结果(执行成功、轮询失败、已关闭、已过期或处理中),最近轮询时间取最近一次执行或触发时间,失败原因取最近一次可安全展示的失败原因。无任何优先轮询事实时字段以否或空值返回,MUST NOT 以普通轮询结果填充。
|
||||
|
||||
投影 MUST 只读:读取 MUST NOT 创建、合并、推进或出队任何优先轮询项,MUST NOT 触发上游调用。投影 MUST 受既有资产数据权限约束,越权资产 MUST 按不存在处理,MUST NOT 通过该字段泄露范围外资产。
|
||||
|
||||
#### Scenario: 资产存在未完成优先项
|
||||
|
||||
- **GIVEN** 某卡的资产存在待执行的优先轮询项
|
||||
- **WHEN** 查询该资产详情
|
||||
- **THEN** 响应返回处于优先轮询中为真、最近触发场景与最近轮询时间
|
||||
|
||||
#### Scenario: 优先项失败展示原因
|
||||
|
||||
- **GIVEN** 某卡的优先轮询项已因尝试次数达到上限进入失败终态
|
||||
- **WHEN** 查询该卡详情
|
||||
- **THEN** 响应返回最近轮询结果为轮询失败及可安全展示的失败原因
|
||||
|
||||
#### Scenario: 无优先轮询事实
|
||||
|
||||
- **WHEN** 查询一个从未进入优先轮询、也无历史优先项的资产详情
|
||||
- **THEN** 各投影字段以否或空值返回,不使用普通轮询结果填充
|
||||
|
||||
#### Scenario: 读取不改变队列
|
||||
|
||||
- **GIVEN** 某卡处于优先轮询执行中
|
||||
- **WHEN** 连续查询该资产详情
|
||||
- **THEN** 优先轮询项状态、触发次数与尝试次数均不因读取而改变
|
||||
|
||||
#### Scenario: 越权资产
|
||||
|
||||
- **WHEN** 调用者查询其数据范围外资产的详情
|
||||
- **THEN** 响应与资产不存在不可区分,不返回任何优先轮询状态
|
||||
|
||||
## 可达操作索引
|
||||
|
||||
本节只用于入口导航,不是行为 Requirement;业务义务以上述 Requirements 为准。
|
||||
|
||||
@@ -47,3 +47,45 @@
|
||||
#### Scenario: 换运营商后周期归属
|
||||
- **WHEN** 持锁卡更换运营商后到达新计费周期
|
||||
- **THEN** 旧周期锁保留,新周期按新运营商的上游流量重置日计算并处理
|
||||
|
||||
|
||||
### Requirement: 通道阈值命中事实留痕与查询
|
||||
|
||||
系统 SHALL 在创建通道阈值停机锁的同一事务内持久化该次命中事实,至少包含:触发时该卡当前计费周期的累计流量读数、本次判定的阈值数值与单位、计费周期起点、判定时间与触发来源(自动判定或重放)。累计流量 MUST 取与停机判定相同的网关累计读数换算值,MUST NOT 使用本地用量统计或套餐真流量;阈值 MUST 取该次判定实际生效的通道配置值(含改阈值前的历史值),使历史命中在配置变更后仍可解释。
|
||||
|
||||
周期恢复 SHALL 同步记录解锁时间与复机结果(未发起复机时的跳过原因、发起后的确认结果或转人工标记),MUST NOT 覆盖停机时的命中事实。本次上线前已存在的锁行 SHALL 保留其创建时间作为判定时间,命中数值与阈值 MAY 为空(历史读数不可重建),读侧 MUST 按「无」展示而不阻断查询。系统 MUST 提供受既有权限控制的命中记录查询,支持按运营商通道、卡、计费周期与判定时间范围筛选,并返回上述字段;查询 MUST 受数据范围约束,越权与不存在 MUST 不可区分,MUST NOT 返回凭证或上游响应原文。留痕与查询 MUST NOT 改变既有达量判定、停机调用、持锁拒绝复机与新周期解锁语义,MUST NOT 因留痕失败而放行或延迟停机。
|
||||
|
||||
#### Scenario: 达量命中留下数字证据
|
||||
|
||||
- **WHEN** 某卡当前周期累计流量达到通道阈值并创建停机锁
|
||||
- **THEN** 命中事实保存该次判定的累计流量、阈值、单位、周期起点与判定时间,可按卡与周期查询
|
||||
|
||||
#### Scenario: 改阈值后历史命中仍可解释
|
||||
|
||||
- **GIVEN** 某卡已按旧阈值命中并持锁
|
||||
- **WHEN** 通道阈值随后被修改
|
||||
- **THEN** 该次命中事实仍返回命中时的阈值与单位,不被新配置改写
|
||||
|
||||
#### Scenario: 新周期恢复留痕
|
||||
|
||||
- **WHEN** 新计费周期处理持锁卡并按其条件解锁或复机
|
||||
- **THEN** 记录解锁时间与复机结果或跳过原因,停机命中事实保持不变
|
||||
|
||||
#### Scenario: 越权查询命中记录
|
||||
|
||||
- **WHEN** 调用者查询其数据范围外卡的命中记录
|
||||
- **THEN** 响应与记录不存在不可区分
|
||||
|
||||
#### Scenario: 留痕不影响停机语义
|
||||
|
||||
- **GIVEN** 命中事实写入遇到异常
|
||||
- **WHEN** 达量判定与停机任务执行
|
||||
- **THEN** 系统按既有可靠机制处理停机,MUST NOT 因留痕失败而放行或延迟停机
|
||||
|
||||
## 可达操作索引
|
||||
|
||||
本节只用于入口导航,不是行为 Requirement;业务义务以上述 Requirements 为准。
|
||||
|
||||
### 运营商通道阈值命中
|
||||
|
||||
`GET /api/admin/carrier-traffic-threshold-hits`(查询通道阈值命中记录)。
|
||||
|
||||
@@ -126,6 +126,75 @@
|
||||
- **WHEN** 超级管理员停用已被核销申请引用的线下收款方式
|
||||
- **THEN** 新申请不可选择该方式,历史申请仍展示其冻结名称和稳定编码
|
||||
|
||||
|
||||
### Requirement: 员工账单列表查询与筛选
|
||||
|
||||
账单列表 SHALL 在既有可见性范围内支持以下筛选:账单编号(精确)、来源订单号(精确)、来源业务类型、账单状态、产生时间范围、核销通过时间范围、欠款人姓名或账号(模糊)、客户名称(模糊)。账单编号 MUST 为账单自身的唯一标识(即账单记录标识);系统 MUST NOT 为满足本要求新增编号字段或编号生成规则。欠款人姓名或账号与客户名称的模糊匹配 MUST 由服务端按去空白后的子串匹配实现,MUST NOT 要求调用方先获得账号 ID 或客户 ID。
|
||||
|
||||
产生时间范围 MUST 使用统一参数名 `start_time` 与 `end_time`;核销通过时间范围 MUST 使用 `decided_start_time` 与 `decided_end_time`。两类时间参数 MUST 使用同一严格解析契约:取值为带显式时区的 RFC3339 秒级时间,解析结果归一为 UTC 瞬时,筛选区间为闭区间(含两端),开始时间晚于结束时间时拒绝请求;旧参数名与旧格式(含仅日期的取值)MUST 被拒绝,MUST NOT 保留静默兼容或别名。
|
||||
|
||||
核销通过时间 MUST 取该账单经「状态为已通过的分摊」关联到的申请表审批终态时间;账单从未存在已通过分摊时该筛选 MUST 不命中该账单。系统 MUST NOT 使用分摊记录的释放时间作为核销通过时间:该字段在既有实现中同时承担「审批通过转为已核销」与「驳回或释放预占」两种语义。
|
||||
|
||||
列表响应 SHALL 同时返回「未核销金额」与「剩余可核销金额」两个金额:未核销金额 MUST 为应收金额减已核销金额;剩余可核销金额 MUST 为应收金额减已核销金额再减审批中预占金额,已关闭账单两者均为零。已核销金额大于应收金额(异常数据)时,两个金额 MUST 均按 0 返回,MUST NOT 返回负数。列表 MUST NOT 因新增模糊筛选改变既有可见性规则:欠款人仅可见本人账单,超级管理员可见全部。
|
||||
|
||||
#### Scenario: 按账单编号精确查询
|
||||
|
||||
- **WHEN** 超级管理员以账单编号筛选账单列表
|
||||
- **THEN** 系统返回该编号对应账单,且不返回其它账单
|
||||
|
||||
#### Scenario: 按核销通过时间筛选
|
||||
|
||||
- **WHEN** 调用方以核销通过时间范围筛选
|
||||
- **THEN** 系统只返回在该范围内存在已通过分摊的账单,从未核销的账单不出现在结果中;筛选依据为该账单已通过分摊关联的申请表审批终态时间
|
||||
|
||||
#### Scenario: 拒绝旧时间参数与旧格式
|
||||
|
||||
- **WHEN** 调用方携带旧参数名或仅日期、无时区、带小数秒的时间取值请求账单列表
|
||||
- **THEN** 系统以参数非法错误拒绝请求,且不返回任何账单
|
||||
|
||||
#### Scenario: 按员工姓名或客户名称模糊查询
|
||||
|
||||
- **WHEN** 调用方提交员工姓名子串或客户名称子串
|
||||
- **THEN** 系统返回欠款人账号名称或客户名称包含该子串的账单,无需调用方提供账号 ID 或客户 ID
|
||||
|
||||
#### Scenario: 未核销金额与剩余可核销金额
|
||||
|
||||
- **GIVEN** 一张应收 100 元、已核销 30 元且存在审批中预占 20 元的账单
|
||||
- **WHEN** 查询账单列表
|
||||
- **THEN** 未核销金额返回 70 元,剩余可核销金额返回 50 元
|
||||
|
||||
#### Scenario: 已关闭账单两个金额为零
|
||||
|
||||
- **WHEN** 查询一张已关闭账单
|
||||
- **THEN** 未核销金额与剩余可核销金额均返回零,已核销金额保持关闭时的值
|
||||
|
||||
|
||||
### Requirement: 员工账单详情投影
|
||||
|
||||
账单详情 SHALL 在既有账单、来源、客户与员工信息之外,返回该账单的操作日志与来源订单快照。操作日志 MUST 取该账单维度既有审计事实的投影,至少包含动作、操作账号名称、操作时间与变更前后摘要,MUST NOT 包含支付凭证内容、完整收款信息或其它敏感原文。来源订单快照 MUST 取来源订单或来源充值记录的既有只读字段投影,至少包含来源单号、来源业务类型、来源实收或充值金额、来源创建时间与资产标识;客户与员工信息 MUST 复用账单创建时冻结的快照。来源记录不可读或字段缺失时 MUST 返回空值 MUST NOT 阻断详情响应,MUST NOT 为此新增来源业务写入路径。
|
||||
|
||||
#### Scenario: 详情返回操作日志
|
||||
|
||||
- **WHEN** 授权账号查询一条存在创建、提交与审批终态的账单详情
|
||||
- **THEN** 响应的操作日志按时间升序返回各次动作、操作账号名称、操作时间与前后值摘要
|
||||
|
||||
#### Scenario: 详情返回来源订单快照
|
||||
|
||||
- **GIVEN** 账单来源为后台线下套餐订单或代理线下充值
|
||||
- **WHEN** 查询该账单详情
|
||||
- **THEN** 响应返回来源单号、来源业务类型、来源金额、来源创建时间与资产标识
|
||||
|
||||
#### Scenario: 来源记录不可读
|
||||
|
||||
- **GIVEN** 账单来源记录已被物理删除或字段为空
|
||||
- **WHEN** 查询该账单详情
|
||||
- **THEN** 来源订单快照对应字段返回空值,详情其余内容正常返回
|
||||
|
||||
#### Scenario: 操作日志不含敏感原文
|
||||
|
||||
- **WHEN** 账单存在包含凭证上传与收款方式变更的操作
|
||||
- **THEN** 操作日志只返回对象键引用、编码与名称摘要,不返回凭证内容或完整收款文本
|
||||
|
||||
## 可达操作索引
|
||||
|
||||
本节只用于入口导航,不是行为 Requirement;业务义务以上述 Requirements 为准。
|
||||
|
||||
@@ -67,6 +67,9 @@
|
||||
| `GET /api/admin/shops/{shop_id}/withdrawal-requests` | `start_time`/`end_time`(同上,解析失败静默忽略) | 提现申请创建时间 | 解析严格化,非法格式一律拒绝 | 必改 |
|
||||
| `GET /api/admin/authorizations` | `start_time`/`end_time`(date-only `2006-01-02`) | 授权发生时间 | 解析严格化;区间由「起始闭、结束开且结束日加一天」改为闭区间含两端 | 必改 |
|
||||
| `GET /api/admin/expiring-assets` | `expires_from`/`expires_to`(date-only,按上海自然日比较) | 当前生效主套餐最终到期时刻 | 改名为 `start_time`/`end_time`,按时刻闭区间比较;保留既有的剩余天数上下限筛选 | 必改 |
|
||||
| `GET /api/admin/employee-collection-bills` | `created_from`/`created_to`(date-only `2006-01-02`) | 账单产生时间与核销通过时间 | 产生时间改名为 `start_time`/`end_time` 并改用严格解析,旧参数名与旧格式一律拒绝;另新增 `decided_start_time`/`decided_end_time` 按核销通过时间闭区间筛选 | 必改 |
|
||||
| `GET /api/admin/polling-priority-items` | 无时间参数 | 优先轮询项入队时间 | 新增 `start_time`/`end_time` | 必改 |
|
||||
| `GET /api/admin/carrier-traffic-threshold-hits` | 端点本次新建 | 阈值命中判定时间 | 新建即使用 `start_time`/`end_time` | 必改 |
|
||||
| 换货导出(导出场景 `exchange`) | `created_at_start`/`created_at_end`(宽松) | 换货单创建时间 | 与换货列表同步改名并收紧关键字的筛选键 | 必改 |
|
||||
| 代理充值导出(导出场景 `agent_recharge`) | `start_date`/`end_date`(宽松) | 代理充值记录创建时间 | 与代理充值列表同步改名并收紧筛选键 | 必改 |
|
||||
| 订单导出(导出场景 `order`) | `start_time`/`end_time`(宽松) | 订单创建时间 | 参数名不变,解析收紧 | 必改 |
|
||||
@@ -75,7 +78,11 @@
|
||||
| `GET /api/admin/package-traffic-alerts` | `start_time`/`end_time`(RFC3339 秒级) | 预警触发时间 | 保持 | 已符合 |
|
||||
| `POST /api/admin/package-traffic-alerts/export` | `start_time`/`end_time`(RFC3339 秒级,创建时冻结) | 预警触发时间 | 保持 | 已符合 |
|
||||
|
||||
被替换的旧参数与旧格式 MUST 在受影响端点被拒绝:`created_at_start`/`created_at_end`、`start_date`/`end_date`、date-only、无时区串、空格分隔时间、小数秒与 `±hhmm` 偏移。未列入上表的端点(资产钱包流水、客户钱包流水、设备资产列表及其导出、代理主钱包流水及其导出、手机号—资产关联列表、佣金统计类接口、审计类列表、员工代收款账单、轮询告警历史、企业卡与企业设备授权列表、IoT 卡资产列表、套餐导出、退款导出)本期 MUST NOT 新增时间参数、MUST NOT 改变参数名与格式。
|
||||
被替换的旧参数与旧格式 MUST 在受影响端点被拒绝:`created_at_start`/`created_at_end`、`start_date`/`end_date`、`created_from`/`created_to`、date-only、无时区串、空格分隔时间、小数秒与 `±hhmm` 偏移;被拒绝时 MUST 以参数非法错误返回,MUST NOT 静默忽略该条件后返回全量或按旧格式筛选。未列入上表的其余端点(资产钱包流水、客户钱包流水、设备资产列表及其导出、代理主钱包流水及其导出、手机号—资产关联列表、佣金统计类接口、审计类列表、轮询告警历史、企业卡与企业设备授权列表、IoT 卡资产列表、套餐导出、退款导出)本期 MUST NOT 新增时间参数、MUST NOT 改变参数名与格式;本次已纳入上表的端点不再受该限制。
|
||||
|
||||
同一端点存在两个时间筛选字段时,主时间字段 MUST 使用统一的 `start_time` 与 `end_time`;第二个字段 MUST 使用「业务语义 + 时间后缀」的固定命名,本变更的核销通过时间为 `decided_start_time` 与 `decided_end_time`。两类字段 MUST 使用同一解析器与同一闭区间语义,MUST NOT 为第二个字段引入不同的格式接受范围、边界规则或静默兼容。计费周期起点不属于本条的第二个范围筛选字段:它是精确匹配键,沿用既有参数名 `period_start`,取值 MUST 复用同一共享严格解析器与同一格式接受范围(同一瞬时作为闭区间两端解析),MUST NOT 复制第二套时间解析。
|
||||
|
||||
受影响端点与本次新增筛选 MUST 复用既有共享严格解析器,MUST NOT 复制或新增第二套时间解析实现(含既有的账单日期解析与客户端可选时间解析)。
|
||||
|
||||
#### Scenario: 换货列表按新参数筛选
|
||||
|
||||
@@ -102,6 +109,21 @@
|
||||
- **WHEN** 请求以 `start_time` 与 `end_time` 查询临期资产列表
|
||||
- **THEN** 系统按当前生效主套餐最终到期时刻执行闭区间筛选,并继续应用既有的剩余天数上下限筛选
|
||||
|
||||
#### Scenario: 员工账单列表按统一参数与通过时间筛选
|
||||
|
||||
- **WHEN** 请求以 `start_time`/`end_time` 与 `decided_start_time`/`decided_end_time` 查询员工代收款账单列表
|
||||
- **THEN** 系统分别按账单产生时间与核销通过时间执行闭区间筛选,两个条件的边界都包含端点
|
||||
|
||||
#### Scenario: 员工账单列表拒绝旧参数名与旧格式
|
||||
|
||||
- **WHEN** 请求携带 `created_from`/`created_to`,或对时间参数提交 date-only、无时区或小数秒取值
|
||||
- **THEN** 系统以参数非法错误码拒绝请求,MUST NOT 按旧格式筛选或忽略该条件
|
||||
|
||||
#### Scenario: 优先轮询项与阈值命中按统一参数筛选
|
||||
|
||||
- **WHEN** 请求以 `start_time` 与 `end_time` 查询优先轮询项列表或通道阈值命中记录
|
||||
- **THEN** 系统分别按入队时间与判定时间执行闭区间筛选,且开始时间晚于结束时间时以参数非法错误码拒绝
|
||||
|
||||
#### Scenario: 未列入端点保持既有行为
|
||||
|
||||
- **WHEN** 调用未列入上表的端点并携带其既有时间参数(含宽松格式)
|
||||
|
||||
@@ -39,7 +39,9 @@
|
||||
|
||||
### Requirement: 运营弹窗实时匹配
|
||||
|
||||
系统 SHALL 允许超级管理员和平台用户管理全局运营弹窗的标题、内容、有效期、启停、优先级、店铺/设备类型/卡类型范围、四种页面(首页、资产详情、套餐购买、资产钱包充值)、频率和一个可选受控操作。范围同一维度多选为任一匹配,未配置范围即全量;已配置范围而当前资产在该维度没有可判定值时该配置不命中。H5 请求必须携带当前页面资产标识。操作仅可为套餐购买或资产钱包充值,不得配置任意 URL。
|
||||
系统 SHALL 允许超级管理员和平台用户管理全局运营弹窗的标题、内容、**弹窗类型**、有效期、启停、优先级、店铺/设备类型/卡类型范围、四种页面(首页、资产详情、套餐购买、资产钱包充值)、频率和一个可选受控操作。弹窗类型 MUST 为必填单选,取值范围为 `套餐政策推广` 与 `通用公告`;创建 MUST 提供该字段,更新按既有部分更新语义(未传时保持原值),一经传入 MUST 按同一取值域校验。类型变更而请求未显式传优先级时,该配置的显式优先级 MUST 保持不变(类型缺省优先级只在创建路径生效,类别序仍保证 `套餐政策推广` 优先于 `通用公告`)。范围同一维度多选为任一匹配,未配置范围即全量;已配置范围而当前资产在该维度没有可判定值时该配置不命中。H5 请求必须携带当前页面资产标识。操作仅可为套餐购买或资产钱包充值,不得配置任意 URL。
|
||||
|
||||
候选排序 SHALL 先按有效优先级类别再按显式优先级:风险换卡提醒高于全部运营弹窗;运营弹窗内 `套餐政策推广` MUST 高于 `通用公告`;同一类别内按显式优先级降序、相同优先级取最近更新时间最新。类别顺序 MUST 表达为显式的类别排序,MUST NOT 依赖类型取值的字典序(否则「通用公告」会排在「套餐政策推广」之前,与本条相反)。显式优先级缺省时 MUST 取该类型的默认值。既有配置在本次上线时 MUST 被赋予一个确定类型(默认 `通用公告`),其显式优先级取值与同类别内相对顺序 MUST 保持不变。
|
||||
|
||||
运营弹窗仅在客户请求候选时实时匹配并创建或复用通知;每客户每配置支持仅一次或每天一次。候选只返回优先级最高一条,同优先级取最近更新时间最新,启停操作同样更新最近更新时间。配置修改形成新版本,既有通知保留原快照且不被改写;修改后的仅一次配置可向原命中客户重新投放。配置到期或停用停止新投放,历史通知在通知中心展示 90 天。
|
||||
|
||||
@@ -50,9 +52,21 @@
|
||||
|
||||
#### Scenario: 优先级与最近更新排序
|
||||
|
||||
- **WHEN** 多条运营配置同时命中且优先级相同
|
||||
- **WHEN** 多条同类型运营配置同时命中且优先级相同
|
||||
- **THEN** 系统只返回最近更新时间最新的一条
|
||||
|
||||
#### Scenario: 推广优先于公告
|
||||
|
||||
- **GIVEN** 一条 `套餐政策推广` 配置与一条 `通用公告` 配置同时命中,且公告配置的显式优先级更高
|
||||
- **WHEN** 客户请求候选
|
||||
- **THEN** 系统返回 `套餐政策推广` 配置,类型类别优先于显式优先级
|
||||
|
||||
#### Scenario: 既有配置类型补齐
|
||||
|
||||
- **GIVEN** 一条本次上线前创建的运营配置
|
||||
- **WHEN** 上线迁移完成
|
||||
- **THEN** 该配置具有确定类型(默认 `通用公告`)且其显式优先级与同类别内顺序不变
|
||||
|
||||
#### Scenario: 独立卡的设备类型维度
|
||||
|
||||
- **WHEN** 命中的运营配置配置了设备类型范围,但当前资产是未绑定设备的独立卡
|
||||
|
||||
@@ -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 为准。
|
||||
|
||||
@@ -158,7 +158,7 @@
|
||||
|
||||
查询与导出 MUST 按请求人可见店铺范围过滤快照行;越权与不存在 MUST 统一按资源不可见处理。
|
||||
|
||||
导出 MUST 复用既有异步导出任务:创建时冻结筛选条件、操作者与可见店铺范围,派发时冻结表头,执行期 MUST 只读快照表并施加冻结的店铺范围。导出列 MUST 与页面展示字段一致并包含合计行;分母为零的比率或卡均 MUST 写作「-」;导出 MUST NOT 包含顶部文字总结。执行期 MUST 按任务内冻结的账号类型复核导出资格,MUST NOT 因创建者角色、店铺归属或筛选条件变化扩大数据集或重新解释筛选。
|
||||
导出 MUST 复用既有异步导出任务:创建时冻结筛选条件、操作者与可见店铺范围,派发时冻结表头,执行期 MUST 只读快照表并施加冻结的店铺范围。导出列 MUST 与页面展示字段一致并包含合计行;第一列 MUST 为「序号」,按导出结果的展示顺序从 1 开始连续递增,合计行的序号列 MUST 留空(不写入任何数字或文字),且合计行其余各列的既有表示 MUST NOT 因新增序号列而改变。分母为零的比率或卡均 MUST 写作「-」;导出 MUST NOT 包含顶部文字总结。执行期 MUST 按任务内冻结的账号类型复核导出资格,MUST NOT 因创建者角色、店铺归属或筛选条件变化扩大数据集或重新解释筛选。
|
||||
|
||||
#### Scenario: 无权用户类型请求报表
|
||||
|
||||
@@ -170,6 +170,12 @@
|
||||
- **WHEN** 以同一筛选条件调用汇总查询并创建导出
|
||||
- **THEN** 导出行集合与汇总结果一致,列与页面展示字段一致且包含合计行
|
||||
|
||||
#### Scenario: 导出包含序号列
|
||||
|
||||
- **GIVEN** 一次激活情况或套餐续费导出产出 N 条分组行与一行合计
|
||||
- **WHEN** 读取导出文件
|
||||
- **THEN** 首列为序号,分组行序号为 1 至 N 连续递增,合计行的序号列不写入数字
|
||||
|
||||
#### Scenario: 创建后权限变化
|
||||
|
||||
- **WHEN** 导出任务创建后创建者的可见店铺范围发生变化再执行该任务
|
||||
|
||||
@@ -81,6 +81,8 @@
|
||||
|
||||
线上订单原路可退条件按渠道契约在创建、提交和执行前重复预检:冻结实际商户的退款必需凭证不完整、服务商类型不具备退款能力、或原交易超出渠道可退时限时禁用原路并说明原因,只允许客户收款信息退款。富友原交易的原始日期必须回传渠道;未回传时仅支持 30 天内原交易,回传后可退 360 天内原交易,超出该范围的申请不得选择原路。
|
||||
|
||||
系统 SHALL 提供按来源订单查询可选退款方式的只读接口,返回可选方式集合、每种方式当前是否可用与不可用原因、原收款商户标识与名称、原支付渠道交易流水号与商户退款能力校验结果。该查询 MUST 与创建、重提使用同一方式判定实现,且原路可退的凭证判定 MUST 复用执行前预检所用的同一凭证判定来源,MUST NOT 引入第二套独立判定或独立开关;审批提交只消费已冻结的申请材料,MUST NOT 在提交环节引入新的方式判定。判定所需事实缺失时 MUST 返回不可用原因而非报错。查询 MUST 受既有订单数据范围约束,越权与订单不存在 MUST 不可区分。
|
||||
|
||||
#### Scenario: 无权威实收金额
|
||||
|
||||
- **WHEN** 来源订单无法取得权威实收金额,或取得的金额非正
|
||||
@@ -106,6 +108,17 @@
|
||||
|
||||
- **WHEN** 富友原交易的原始支付时间早于可退时限
|
||||
- **THEN** 系统禁用原路退款并说明原因,只允许客户收款信息退款
|
||||
|
||||
#### Scenario: 查询可选退款方式
|
||||
|
||||
- **GIVEN** 一张线上支付订单的原收款商户凭证不完整
|
||||
- **WHEN** 授权账号查询该订单的可选退款方式
|
||||
- **THEN** 系统返回客户收款信息退款为可用、原路退款为不可用及缺失凭证原因,并返回原收款商户与原支付渠道交易流水号
|
||||
|
||||
#### Scenario: 查询越权订单
|
||||
|
||||
- **WHEN** 调用者查询其数据范围外订单的可选退款方式
|
||||
- **THEN** 响应与订单不存在不可区分
|
||||
### Requirement: 企业微信唯一终审与审批尝试重提
|
||||
|
||||
退款申请 SHALL 保存退款原因、冻结实收金额、唯一关联套餐及其使用情况、方式、金额和当次材料快照。超级管理员、平台用户和代理可在各自订单数据范围内创建、修改并重提未成功申请;企业微信是唯一终审,本地 MUST NOT 人工通过、拒绝或退回已关联审批实例的申请。每次创建或重提 MUST 新增一条不可变的审批尝试记录,并以该尝试记录作为通用审批业务标识;同一申请每次提交各自持有独立审批实例,历史尝试材料与审批结果不被覆盖。退款单 SHALL 仅保存最新尝试与最新审批实例引用用于展示。
|
||||
@@ -347,6 +360,74 @@
|
||||
- **WHEN** 换货记录的迁移状态为 `failed`,且该记录保存了最近一次失败原因
|
||||
- **THEN** 导出行的迁移状态为“迁移失败”,且导出不输出该失败原因
|
||||
|
||||
|
||||
### Requirement: 退款原因必填与申请人备注
|
||||
|
||||
退款申请创建与重新提交时 SHALL 强制填写退款原因:原因去除首尾空白后为空 MUST 以参数非法错误拒绝,MUST NOT 落库申请或审批尝试。该校验 MUST 只作用于创建与重提用例:历史申请与补发历史审批的路径不受本约束、MUST NOT 因历史原因缺失而阻断。退款申请 SHALL 支持可选申请人备注,创建与重提均可填写或替换,并 MUST 冻结进当次审批尝试快照;既有申请的历史尝试快照 MUST NOT 因重提被改写,且申请人备注 MUST NOT 复用或改写退款单既有的审批备注字段(该字段语义与展示口径不变)。退款原因与备注的冻结语义 MUST 与既有实收金额、方式、金额、材料快照一致,MUST 随每次重提新增而非覆盖。
|
||||
|
||||
#### Scenario: 原因为空被拒绝
|
||||
|
||||
- **WHEN** 创建或重提请求的退款原因缺失或仅含空白字符
|
||||
- **THEN** 系统以参数非法错误拒绝,且不创建申请、不创建审批实例
|
||||
|
||||
#### Scenario: 备注冻结进当次快照
|
||||
|
||||
- **WHEN** 提交人填写备注后提交退款申请
|
||||
- **THEN** 该次审批尝试快照保存该备注,后续重提修改备注 MUST NOT 改写历史尝试快照
|
||||
|
||||
|
||||
### Requirement: 退款渠道标识与线下处理流水号
|
||||
|
||||
退款单 MUST 持久化并可查询「来源支付单号」与「原支付渠道交易流水号」,不得仅通过订单与支付单关联在读取时推导;两者取创建申请时冻结的原成功支付事实;重提时两者 MUST 与冻结实收金额同批从同一原成功支付事实重新冻结,历史尝试快照 MUST NOT 被改写。原路退款成功后的渠道退款流水号沿用既有事实,MUST NOT 被本要求改变。退款申请 SHALL 支持登记线下退款处理流水号或凭证编号:仅客户收款信息退款(线下到账)方式允许由授权账号在申请创建后补录或更正,其余退款方式 MUST NOT 登记(登记请求 MUST 以状态非法拒绝);每次登记 MUST 写入审计(操作者、时间、前后值),MUST NOT 因登记改变退款状态、实收金额、套餐失效或佣金回溯规则。列表、详情与导出 SHALL 返回来源支付单号、原支付渠道交易流水号与线下退款处理流水号。
|
||||
|
||||
#### Scenario: 退款单保存来源支付事实
|
||||
|
||||
- **GIVEN** 来源订单存在成功支付记录
|
||||
- **WHEN** 创建退款申请
|
||||
- **THEN** 退款单持久化该来源支付单号与原支付渠道交易流水号,列表、详情与导出均返回这两个值
|
||||
|
||||
#### Scenario: 原支付事实缺失
|
||||
|
||||
- **GIVEN** 来源订单为后台线下订单或员工代收订单,没有线上支付记录
|
||||
- **WHEN** 创建退款申请
|
||||
- **THEN** 两个字段以空值保存并返回,不阻断申请创建
|
||||
|
||||
#### Scenario: 登记线下退款处理流水号
|
||||
|
||||
- **GIVEN** 一笔客户收款信息退款已完成
|
||||
- **WHEN** 授权账号登记线下退款处理流水号或凭证编号
|
||||
- **THEN** 系统保存该值并写审计,退款状态、实收金额与佣金回溯行为不变
|
||||
|
||||
#### Scenario: 登记操作留痕
|
||||
|
||||
- **WHEN** 同一字段被再次更正
|
||||
- **THEN** 审计记录包含操作者、时间与前后值,历史值可追溯
|
||||
|
||||
|
||||
### Requirement: 企业微信退款审批材料字段
|
||||
|
||||
退款审批材料 SHALL 在既有字段之外带出:资产类型(卡或设备)、设备类型与设备型号(资产为设备时)、当前退款套餐已用量与套餐总量、原支付渠道交易流水号。套餐已用量与总量 MUST 采用与退款展示字段相同的解析规则与真流量口径;资产类型 MUST 沿用退款申请的下单快照推导;设备类型与设备型号 MUST 取退款申请关联设备,无关联设备时以空值提交;原支付渠道交易流水号 MUST 取创建申请时冻结的原成功支付事实。上述字段 MUST 在提交时冻结进当次审批尝试快照,使审批人在企业微信侧可直接看到用量数字。任一材料在提交时不可解析 MUST 以空值或零值提交并 MUST NOT 阻断审批提交;材料 MUST NOT 包含凭证内容、完整收款文本或商户密钥。
|
||||
|
||||
企业微信模板控件缺失导致本次新增字段无法提交时 MUST 明确失败并提示需配置控件,MUST NOT 静默丢弃该字段;本约束 MUST 只作用于本次新增字段,既有未映射的可选控件 MUST 保持既有跳过行为。
|
||||
|
||||
#### Scenario: 审批材料带出套餐用量
|
||||
|
||||
- **GIVEN** 退款申请关联的套餐使用记录存在真已用量与真总量
|
||||
- **WHEN** 提交企业微信退款审批
|
||||
- **THEN** 审批材料包含资产类型、设备类型与型号(适用时)、套餐已用量与总量及原支付渠道交易流水号
|
||||
|
||||
#### Scenario: 套餐事实不可解析
|
||||
|
||||
- **GIVEN** 退款申请未关联任何套餐使用记录
|
||||
- **WHEN** 提交企业微信退款审批
|
||||
- **THEN** 套餐已用量与总量以零值或空值提交,审批提交正常完成
|
||||
|
||||
#### Scenario: 模板缺少控件
|
||||
|
||||
- **GIVEN** 企业微信退款审批场景未配置套餐用量控件映射
|
||||
- **WHEN** 提交退款审批
|
||||
- **THEN** 系统明确失败并指出缺失控件,不静默丢弃该字段
|
||||
|
||||
## 可达操作索引
|
||||
|
||||
本节只用于入口导航,不是行为 Requirement;业务义务以上述 Requirements 为准。
|
||||
@@ -357,7 +438,7 @@
|
||||
|
||||
### 退款管理
|
||||
|
||||
`GET /api/admin/refunds`(退款申请列表);`POST /api/admin/refunds`(创建退款申请);`GET /api/admin/refunds/{id}`(退款申请详情);`POST /api/admin/refunds/{id}/trigger-approval`(补发历史退款审批);`POST /api/admin/refunds/{id}/approve`(审批通过退款申请);`POST /api/admin/refunds/{id}/reject`(审批拒绝退款申请);`POST /api/admin/refunds/{id}/resubmit`(重新提交退款申请);`POST /api/admin/refunds/{id}/return`(退回退款申请)。
|
||||
`GET /api/admin/refunds`(退款申请列表);`POST /api/admin/refunds`(创建退款申请);`GET /api/admin/refunds/{id}`(退款申请详情);`POST /api/admin/refunds/{id}/trigger-approval`(补发历史退款审批);`POST /api/admin/refunds/{id}/approve`(审批通过退款申请);`POST /api/admin/refunds/{id}/reject`(审批拒绝退款申请);`POST /api/admin/refunds/{id}/resubmit`(重新提交退款申请);`POST /api/admin/refunds/{id}/return`(退回退款申请);`GET /api/admin/refunds/order-options`(按来源订单查询可选退款方式);`POST /api/admin/refunds/{id}/offline-settlement`(登记或更正线下退款处理流水号)。
|
||||
|
||||
### 换货管理
|
||||
|
||||
|
||||
@@ -79,6 +79,8 @@
|
||||
|
||||
仅超级管理员和平台用户可在其资产数据范围内查看关联手机号。资产详情 MUST 列出该资产全部当前关联手机号;资产列表、卡与设备两类导出以及批量任务结果中,具备资产数据权限的账号可见完整关联手机号,不做脱敏。按资产查询 MUST 一次批量聚合完成。后台 MUST NOT 提供补录或修改关联的入口。
|
||||
|
||||
关联查询 SHALL 额外返回两项投影:该手机号当前有效关联资产数量,以及每条关系的最近解绑人与最近解绑时间。数量口径 MUST 与该手机号「最多关联十项」的上限判定完全一致(只统计当前有效关系、卡与设备分别计一项),MUST 按当页涉及的手机号集合一次批量聚合,MUST NOT 逐手机号或逐资产放大查询次数。最近解绑人 MUST 取最近一次解除该关系的后台账号名称与账号标识快照,并随既有解绑方式、解绑时间、解绑原因一并返回;关系仍有效时该字段为空,MUST NOT 以创建人或最后更新人填充。以上字段 MUST 只读,MUST NOT 改变既有解绑、换绑、上限判定与审计规则。
|
||||
|
||||
#### Scenario: 数据范围外不可见
|
||||
|
||||
- **WHEN** 平台用户查询其资产数据范围之外的资产的关联手机号
|
||||
@@ -99,6 +101,29 @@
|
||||
- **WHEN** 导出 IoT 卡场景或设备场景
|
||||
- **THEN** 两类导出均包含关联手机号列,且设备导出列组解析对新增列保持正确
|
||||
|
||||
#### Scenario: 数量与上限口径一致
|
||||
|
||||
- **GIVEN** 某手机号当前有效关联十项资产
|
||||
- **WHEN** 查询其中任一关联
|
||||
- **THEN** 返回的当前有效关联资产数量为十,与上限判定使用的计数相同
|
||||
|
||||
#### Scenario: 已解绑关系展示解绑人
|
||||
|
||||
- **GIVEN** 一条关系已被后台账号 A 通过单项解绑失效
|
||||
- **WHEN** 查询该关系
|
||||
- **THEN** 返回最近解绑人为 A 的名称与标识、解绑时间与解绑原因
|
||||
|
||||
#### Scenario: 有效关系无解绑人
|
||||
|
||||
- **WHEN** 查询一条仍有效的关联
|
||||
- **THEN** 最近解绑人与最近解绑时间均为空,且不以创建人或更新时间填充
|
||||
|
||||
#### Scenario: 数量批量聚合
|
||||
|
||||
- **GIVEN** 一页返回多项资产或手机号的关联
|
||||
- **WHEN** 查询该页
|
||||
- **THEN** 系统按该页涉及的手机号集合一次读取计数,查询次数不随行数线性增长
|
||||
|
||||
### Requirement: 后台解除关联
|
||||
|
||||
仅超级管理员和平台用户可在资产数据范围内解除关联,必须二次确认并填写原因;代理、企业和个人客户无后台解除能力。单项解除必须指定一条资产—手机号关系;勾选批量解除与 CSV 导入解除按资产解除该项资产全部当前有效关系。逐资产独立执行并返回成功数、失败数与逐项结果。越权、资产不存在与已无有效关系三种情况 MUST 对调用方返回统一失败文案「无权限操作该资源或资源不存在」。
|
||||
@@ -154,6 +179,46 @@ CSV 导入按资产标识定位资产,逐行独立执行:成功行提交,
|
||||
- **WHEN** 导入资产或修改后台资产属性
|
||||
- **THEN** 关联记录数不变,不产生任何手机号—资产关系
|
||||
|
||||
|
||||
### Requirement: 短信验证码校验失败次数限制
|
||||
|
||||
系统 SHALL 对短信验证码校验实施失败次数限制,作用域覆盖注册、绑定、换绑与换证的全部短信验证码校验流程:失败计数按窗口续期维护——每次校验失败在窗口内累加计数并重置窗口时长,相邻两次失败间隔不超过窗口时长即持续累加;计数达到上限后短时间内的后续校验 MUST 被拒绝并返回可定位的限流错误码与提示;校验成功 MUST 清零该手机号的失败计数。失败计数与锁定 MUST 以手机号维度按原子操作维护,并发提交 MUST NOT 绕过计数;锁定检查 MUST 先于验证码比对,锁定期内即使提交正确验证码也 MUST NOT 通过;锁定期为自计数达到上限起的一个窗口时长,锁定期间的提交在比对前即被拒绝且不再计数,因此锁定不因再次提交而续期;锁定到期后 MUST 自动恢复可校验状态,MUST NOT 需要人工解锁。阈值与窗口 MUST 为固定常量或既有服务端配置,MUST NOT 新增对外可配置项或接口。错误提示 MUST NOT 泄露验证码正确性、剩余失败次数或内部键名。
|
||||
|
||||
失败计数的写入或读取失败 MUST NOT 阻断校验流程的成功路径:计数不可用时系统 MUST 放行并记录,MUST NOT 因限流计数故障阻断注册、绑定、换绑、换证与登录的成功路径。发送侧既有频率限制、验证码有效期与一次性消费语义 MUST 保持不变;校验失败 MUST NOT 消费验证码,MUST NOT 影响既有链路的成功结果。
|
||||
|
||||
#### Scenario: 连续失败达到上限
|
||||
|
||||
- **WHEN** 同一手机号在窗口内连续提交错误验证码达到上限
|
||||
- **THEN** 后续校验被拒绝并返回限流错误,即使提交的是正确验证码也不通过
|
||||
|
||||
#### Scenario: 锁定到期恢复
|
||||
|
||||
- **GIVEN** 某手机号因失败次数达到上限被短时锁定
|
||||
- **WHEN** 锁定窗口结束且提交正确验证码
|
||||
- **THEN** 系统正常通过校验
|
||||
|
||||
#### Scenario: 成功后清零
|
||||
|
||||
- **GIVEN** 某手机号已有若干次失败计数但未达上限
|
||||
- **WHEN** 一次校验成功
|
||||
- **THEN** 该手机号失败计数被清零,后续失败重新计数
|
||||
|
||||
#### Scenario: 并发提交不绕过计数
|
||||
|
||||
- **WHEN** 同一手机号并发提交多个错误验证码
|
||||
- **THEN** 失败计数按实际提交次数累加,不因并发而丢失计数
|
||||
|
||||
#### Scenario: 失败不消费验证码
|
||||
|
||||
- **WHEN** 一次校验因验证码错误或限流失败
|
||||
- **THEN** 该验证码保持可再次校验(在有效期与计数限制允许范围内),不产生任何业务事实
|
||||
|
||||
#### Scenario: 计数不可用不阻断成功路径
|
||||
|
||||
- **GIVEN** 失败计数所依赖的存储不可用
|
||||
- **WHEN** 注册、绑定、换绑、换证或登录提交正确验证码
|
||||
- **THEN** 校验正常通过,不因计数故障被拒绝,且计数不可用的事实被记录
|
||||
|
||||
## 可达操作索引
|
||||
|
||||
本节只用于入口导航,不是行为 Requirement;业务义务以上述 Requirements 为准。
|
||||
|
||||
@@ -144,4 +144,4 @@
|
||||
|
||||
### 轮询管理-优先队列
|
||||
|
||||
`POST /api/admin/polling-priority-items`(人工优先入队);`GET /api/admin/polling-priority-items`(查询优先轮询项列表);`GET /api/admin/polling-priority-items/{id}`(查询优先轮询项详情)。
|
||||
`POST /api/admin/polling-priority-items`(人工优先入队);`GET /api/admin/polling-priority-items`(查询优先轮询项列表);`GET /api/admin/polling-priority-items/{id}`(查询优先轮询项详情);`POST /api/admin/polling-priority-items/{id}/close`(人工关闭优先轮询项);`POST /api/admin/polling-priority-items/{id}/retrigger`(人工重触发优先轮询项)。
|
||||
|
||||
@@ -123,7 +123,13 @@
|
||||
|
||||
### Requirement: 优先项尝试次数与出队
|
||||
|
||||
优先轮询项 SHALL 使用自身固定的最大尝试次数常量(3),MUST NOT 新增可维护的参数配置项,MUST NOT 改变普通轮询的失败重试策略。尝试次数 MUST 只在真正发起执行后累加。未达上限的可恢复失败 MUST 回到活动状态并沿用既有轮询间隔重新排期;达到上限 MUST 记录失败终态与可安全展示的失败原因后出队。卡不存在等业务校验类失败 MUST 直接进入失败终态且不重试。执行成功 MUST 记录完成终态并出队,资产继续按普通轮询运行。本能力 MUST NOT 引入有效期字段,MUST NOT 建立独立异常记录表。
|
||||
优先轮询项 SHALL 使用自身固定的最大尝试次数常量(3),MUST NOT 新增可维护的参数配置项,MUST NOT 改变普通轮询的失败重试策略。尝试次数 MUST 只在真正发起执行后累加。未达上限的可恢复失败 MUST 回到活动状态并沿用既有轮询间隔重新排期;达到上限 MUST 记录失败终态与可安全展示的失败原因后出队。卡不存在等业务校验类失败 MUST 直接进入失败终态且不重试。执行成功 MUST 记录完成终态并出队,资产继续按普通轮询运行。
|
||||
|
||||
优先项 SHALL 支持人工关闭:具备卡数据权限的超级管理员与平台账号可对未完成(待执行或执行中)的项执行关闭,关闭 MUST 填写原因并 MUST 记录操作者、时间与原因审计;关闭后该项进入已关闭终态并出队,MUST NOT 再发起任何上游调用,MUST NOT 删除既有执行结果与失败原因。
|
||||
|
||||
优先项 SHALL 具备有效期:有效期取值 MUST 为固定常量(本能力不新增可维护配置项),长度与尝试上限常量一并由服务端固定。入队时间起超过有效期的未完成项 MUST 转入已过期终态并出队,MUST 保留触发类型、尝试次数与最近失败原因,MUST NOT 自动删除事实。既有未完成项 SHALL 自本次上线时刻起算有效期,MUST NOT 在上线后被批量判定为已过期。到期处理 MUST 由独立的周期任务承载,MUST NOT 依赖查询或读侧隐式触发。已过期与已失败的项 SHALL 支持人工重新触发:重新触发 MUST 复用人工优先入队入口为该卡该任务类型建立新的活动项并将尝试次数置零,MUST 记录操作者与原因,MUST NOT 绕过既有并发上限、停复机持锁拒绝与任务类型范围。
|
||||
|
||||
本能力 MUST NOT 建立独立异常记录表:异常、超限与重试事实由优先项自身状态、尝试次数与执行结果承载。
|
||||
|
||||
#### Scenario: 可恢复失败未达上限
|
||||
|
||||
@@ -145,9 +151,36 @@
|
||||
- **WHEN** 优先执行按既有轮询内容完成
|
||||
- **THEN** 该项记录完成终态并出队,资产继续存在于普通轮询
|
||||
|
||||
#### Scenario: 人工关闭
|
||||
|
||||
- **WHEN** 授权账号对一项待执行或执行中的优先项填写原因后执行关闭
|
||||
- **THEN** 该项进入已关闭终态并出队,不再发起上游调用,原因与操作者写入审计
|
||||
|
||||
#### Scenario: 有效期到期
|
||||
|
||||
- **GIVEN** 一项优先项自入队起已超过固定有效期且仍未完成
|
||||
- **WHEN** 调度或维护流程处理该项
|
||||
- **THEN** 该项转入已过期终态并出队,触发类型、尝试次数与最近失败原因被保留
|
||||
|
||||
#### Scenario: 失败项人工重触发
|
||||
|
||||
- **GIVEN** 一项优先项已因达到尝试上限失败或因超期出队
|
||||
- **WHEN** 授权账号填写原因后重新触发
|
||||
- **THEN** 系统为该卡该任务类型建立新的活动项且尝试次数从零开始,并记录操作者与原因
|
||||
|
||||
#### Scenario: 重触发不绕过既有边界
|
||||
|
||||
- **GIVEN** 目标卡持运营商通道阈值停机锁
|
||||
- **WHEN** 授权账号对该卡重新触发优先轮询
|
||||
- **THEN** 系统按既有持锁拒绝语义处理,不发起复机
|
||||
|
||||
### Requirement: 优先轮询事实与查询的可追溯
|
||||
|
||||
系统 SHALL 记录入队(含合并)、领取、每次失败、重试、完成与失败出队的触发类型、触发来源、操作来源、时间与结果。人工入队 MUST 填写原因,并与入队事实一同保存。系统 MUST 提供最小可读接口(列表与详情,支持筛选与分页),其权限 MUST 与人工入队一致:超级管理员与平台账号可查询全部,代理账号仅可查询其自身及下级店铺资产,企业账号 MUST 被拒绝;查询 MUST 按数据权限下推,越权与不存在 MUST 不可区分。查询 MUST NOT 提供优先级分级、有效期或人工重触发入口。
|
||||
系统 SHALL 记录入队(含合并)、领取、每次失败、重试、完成、人工关闭、超期、人工重触发与失败出队的触发类型、触发来源、操作来源、时间与结果。人工入队与人工重触发 MUST 填写原因,并与事实一同保存。
|
||||
|
||||
优先项事实 SHALL 持久化并可查询下列字段:资产类型与资产标识、设备号(资产绑定设备时)、卡 ICCID、店铺标识与代理归属、任务类型、触发类型与触发来源集合、触发次数与最近触发时间、尝试次数与最大尝试次数、执行开始时间、执行结束时间与执行耗时、下一次计划执行时间、入队时间、出队时间、执行结果与失败原因、接口请求与响应摘要引用(复用既有集成交互日志标识,MUST NOT 复制凭证或响应原文)。
|
||||
|
||||
系统 MUST 提供最小可读接口(列表与详情,支持筛选与分页),筛选至少支持状态、任务类型、触发类型、时间范围,以及「异常与重试」视图所需的条件(失败终态、已过期、尝试次数达到上限、存在失败原因)。该视图 MUST 复用同一事实表与同一权限,MUST NOT 新增独立异常事实表。权限 MUST 与人工入队一致:超级管理员与平台账号可查询全部,代理账号仅可查询其自身及下级店铺资产,企业账号 MUST 被拒绝;查询 MUST 按数据权限下推,越权与不存在 MUST 不可区分。查询 MUST NOT 提供优先级分级;有效期、出队时间与最大尝试次数 SHALL 作为只读字段返回;人工关闭与人工重触发 SHALL 为独立受权限控制的写入口,MUST NOT 由查询接口隐式触发。
|
||||
|
||||
#### Scenario: 代理查询范围外资产
|
||||
|
||||
@@ -162,7 +195,17 @@
|
||||
#### Scenario: 查询结果字段
|
||||
|
||||
- **WHEN** 授权账号查询优先轮询项列表或详情
|
||||
- **THEN** 响应给出触发类型、触发来源、次数、最近触发时间与执行结果,不含优先级分级、有效期或人工重触发入口
|
||||
- **THEN** 响应给出资产标识、设备号(适用时)、店铺与代理归属、任务类型、触发类型与来源、触发次数、尝试次数与最大尝试次数、最近与下一次执行时间、执行结果与失败原因、入队与出队时间,且不含优先级分级
|
||||
|
||||
#### Scenario: 异常与重试视图
|
||||
|
||||
- **WHEN** 授权账号以失败终态或尝试次数达到上限作为筛选条件查询优先轮询项
|
||||
- **THEN** 系统返回对应项及其失败原因与尝试次数,数据来源于同一事实表
|
||||
|
||||
#### Scenario: 执行耗时与摘要引用
|
||||
|
||||
- **WHEN** 一项优先执行完成并产生上游交互
|
||||
- **THEN** 该项返回执行开始与结束时间、耗时以及集成交互日志标识,且不返回上游响应原文
|
||||
|
||||
### Requirement: 人工优先入队不受人工触发防滥用配额约束
|
||||
|
||||
|
||||
Reference in New Issue
Block a user