feat: 资产套餐历史增加主子层级查询
This commit is contained in:
@@ -87,6 +87,100 @@
|
||||
- **WHEN** 平台赠送套餐,零售价 9900 分,成本价 0 分
|
||||
- **THEN** 创建的套餐使用记录 `paid_amount = 0`,`retail_amount = 9900`
|
||||
|
||||
|
||||
### Requirement: 资产套餐层级投影
|
||||
系统 SHALL 在后台资产详情套餐列表和 H5 资产套餐历史中,直接依据既有 `master_usage_id` 返回主套餐与关联加油包的层级,不新增关联表。普通主项 SHALL 显式返回 `master_usage_id=null`、`children` 数组和 `expand_by_default`;存在至少一个可展示关联子项时默认展开,否则不展开。子项 SHALL 保留自身使用记录 ID、原主记录 ID、状态、购买创建时间、生效时间及该入口既有历史字段。正常项 SHALL 省略关系异常字段,所有叶子 SHALL 返回 `children=[]`、`expand_by_default=false`。主套餐或加油包失效、过期、用尽、退款均 MUST NOT 拆散既有关系或改写其生命周期事实。
|
||||
|
||||
#### Scenario: 多个主套餐分别关联子项
|
||||
- **WHEN** 同一可见资产范围内有多个主套餐,各自关联不同加油包
|
||||
- **THEN** 每个加油包仅出现在其原主套餐的 `children` 中,不在顶层重复出现;有子项的主套餐默认展开
|
||||
|
||||
#### Scenario: 无子项的主套餐
|
||||
- **WHEN** 某主套餐没有可展示关联加油包
|
||||
- **THEN** 该主项返回 `master_usage_id=null`、`children=[]`、`expand_by_default=false`,不返回关系异常字段
|
||||
|
||||
#### Scenario: 已失效历史关系
|
||||
- **WHEN** 主套餐或关联加油包已失效、过期、用尽或退款,但使用记录仍处于本入口可展示范围
|
||||
- **THEN** 响应保留原主子关系及各自原状态,不因历史状态将子项拆为顶层记录
|
||||
|
||||
### Requirement: 套餐历史整组筛选与分页
|
||||
系统 SHALL 将一个主套餐及其全部可展示子项作为一组,每组占一个分页名额;主记录物理缺失的每条异常独立项也各占一个名额。`total` SHALL 表示筛选后、分页前的顶层项数量,子项不另计数且 MUST NOT 跨页。已有 `status` 和套餐类型筛选条件 SHALL 在同一条使用记录上联合匹配;组内任一记录满足全部条件即选中整组,返回其完整可展示父子,不因筛选拆关系。异常独立项仅以自身字段匹配。未传筛选条件时 SHALL 返回范围内全部组及异常独立项。
|
||||
|
||||
#### Scenario: 子项数量超过页大小
|
||||
- **WHEN** 一个主套餐含三个子项,另有一个无子项主套餐,以 `page_size=1` 查询且无筛选
|
||||
- **THEN** `total=2`;包含三个子项的组在同一页完整返回,子项不消耗额外分页名额,另一页只返回另一个主项
|
||||
|
||||
#### Scenario: 状态或类型仅命中子项
|
||||
- **WHEN** 主项不满足筛选条件,但某个子项满足该请求的全部筛选条件
|
||||
- **THEN** 该组被选中,返回主项及其全部可展示子项,包括未命中条件的同组记录;主项不被标记为缺失
|
||||
|
||||
#### Scenario: 联合条件不能分摊给不同记录
|
||||
- **WHEN** 请求同时指定状态和套餐类型,组内只有主项满足状态、只有子项满足类型,且没有任何一条记录同时满足二者
|
||||
- **THEN** 该组不进入结果,也不计入 `total`
|
||||
|
||||
#### Scenario: 异常独立项计数
|
||||
- **WHEN** 筛选后有一个正常关系组和两条主记录物理缺失的加油包
|
||||
- **THEN** `total=3`,两条异常项各自占一个分页名额,即使它们指向同一个缺失主记录也不合并
|
||||
|
||||
#### Scenario: 无匹配与超出末页
|
||||
- **WHEN** 没有任何顶层项匹配,或请求页码超出筛选结果末页
|
||||
- **THEN** `items=[]`;无匹配时 `total=0`,超出末页时仍返回筛选后的真实顶层项总数
|
||||
|
||||
### Requirement: 套餐历史稳定排序
|
||||
系统 SHALL 将顶层项按自身创建时间倒序排列,同时间按 `package_usage_id` 倒序排列。每组子项 SHALL 依次分为三桶:非待生效且有生效时间的记录按生效时间正序;非待生效但生效时间为空的记录按购买创建时间正序;待生效记录按购买创建时间正序并排最后。各桶排序时间相同 SHALL 按 `package_usage_id` 正序。桶归属及排序 MUST NOT 改变记录状态;后台与 H5 对相同输入集合 SHALL 返回相同顺序。
|
||||
|
||||
#### Scenario: 混合生效时间与历史状态
|
||||
- **WHEN** 同组包含有生效时间的已用完记录、无生效时间的已失效记录和待生效记录
|
||||
- **THEN** 三者依次位于第一、第二、第三桶;已失效记录保持已失效状态,不被重新标记为待生效
|
||||
|
||||
#### Scenario: 同时间的确定顺序
|
||||
- **WHEN** 多个顶层项创建时间相同,或同桶子项排序时间相同
|
||||
- **THEN** 顶层按使用记录 ID 倒序,子项按使用记录 ID 正序;数据不变时重复请求及相邻页边界保持一致
|
||||
|
||||
### Requirement: 物理缺失与不可展示关系区分
|
||||
系统 SHALL 仅在 `master_usage_id` 指向的主使用记录物理不存在时返回顶层异常独立项,保留原字段及非空主记录 ID,并返回 `relationship_status=master_missing`、`relationship_status_name=关联主套餐缺失`、`children=[]`、`expand_by_default=false`。主记录未出现在筛选结果或某一页 MUST NOT 被认定为物理缺失。范围内的子项所指父记录实际存在,但处于其他资产、H5 其他世代或已软删除而不可展示时,整个查询 SHALL 返回统一读取错误,不返回部分成功列表,不越界补显、不静默丢项,也不返回物理缺失标识。商品记录缺失 MUST NOT 等同于主使用记录缺失。
|
||||
|
||||
#### Scenario: 主套餐物理缺失
|
||||
- **WHEN** 加油包所引用的主使用记录物理不存在
|
||||
- **THEN** 返回带既定 `master_missing` 标识及中文名称的异常独立项,保留原主记录 ID,不猜测替代主套餐
|
||||
|
||||
#### Scenario: 父子原本分处明细分页两侧
|
||||
- **WHEN** 父子记录都在当前入口可展示范围,但按旧明细分页会落在不同页,或父项不满足展示筛选
|
||||
- **THEN** 系统仍按真实关系返回同一个完整关系组,不将子项标记为主套餐缺失
|
||||
|
||||
#### Scenario: 主使用记录软删除或范围不可见
|
||||
- **WHEN** 范围内某子项的主使用记录仍物理存在,但已软删除、属于其他资产,或不属于 H5 当前世代
|
||||
- **THEN** 整个查询返回统一读取错误;不暴露父项内容或具体不可见原因,不静默丢项,不返回 `master_missing`
|
||||
|
||||
#### Scenario: 商品缺失但使用关系存在
|
||||
- **WHEN** 主使用记录及其子项均可展示,但关联套餐商品已软删除或物理缺失
|
||||
- **THEN** 主子关系保持不变,历史名称沿用既有快照回退规则,不因商品缺失返回关系异常
|
||||
|
||||
### Requirement: 套餐历史读取范围与兼容边界
|
||||
系统 SHALL 保留各入口既有资产解析及授权前置校验:后台读取当前解析资产的全部世代,H5 通过当前客户资产绑定校验后仅读取资产实体当前世代;卡按卡载体、设备按设备载体读取,MUST NOT 为补齐关系而合并其他资产或扩张 H5 世代。后台 SHALL 继续只支持已有状态筛选,H5 SHALL 继续支持状态和套餐类型筛选;H5 类型匹配 SHALL 保留排除已软删除商品的既有口径,不将用于历史展示的软删除商品自动作为类型命中项。
|
||||
|
||||
系统 SHALL 保留后台默认页大小 50、最大 100 和 `items/total/page/page_size` 响应字段;H5 默认页大小 20、最大 100 和 `items/total/page/size` 响应字段。两端仍接收 `page/page_size`,页码小于 1 时归一为 1,页大小小于 1 时使用各自默认值,超过上限时截断。除明确变更的层级、分页和筛选语义外,系统 SHALL 保留各入口既有套餐字段和可见性:后台成本价仅平台类账号可见;H5 MUST NOT 因共享投影而新增填充原先未填的订单、退款、成本价、零售价或生效条件字段。当前生效套餐及修改套餐接口的响应 MUST NOT 被本次历史层级变更连带改变。
|
||||
|
||||
#### Scenario: 两端保留各自世代范围
|
||||
- **WHEN** 同一资产有多个世代的独立主子组,后台有权查看该资产,H5 客户具有有效绑定
|
||||
- **THEN** 后台可返回全部世代内的组,H5 只返回资产当前世代内的组,不为对齐两端数量而扩大或缩小范围
|
||||
|
||||
#### Scenario: 未通过既有资产授权
|
||||
- **WHEN** 代理请求其店铺范围外的资产,或 H5 客户请求非其有效绑定资产
|
||||
- **THEN** 沿用既有拒绝行为,不返回该资产任何主项或子项,也不因补查主记录绕过授权
|
||||
|
||||
#### Scenario: 字段可见性与其他接口不变
|
||||
- **WHEN** 平台、代理和 H5 客户分别读取其可见资产历史,并调用原有当前套餐或修改套餐接口
|
||||
- **THEN** 历史主子项均遵守各入口既有字段可见性;代理与 H5 不因层级投影获取平台成本价,其他套餐接口保持原响应结构
|
||||
|
||||
#### Scenario: 已软删除商品不成为类型筛选命中项
|
||||
- **WHEN** H5 按套餐类型筛选,组内只有已软删除商品对应的使用记录具有该类型
|
||||
- **THEN** 该记录不使整组命中;若组内另一条记录满足全部条件而选中该组,已软删除商品对应的可展示使用记录仍随组保留
|
||||
|
||||
#### Scenario: 商品批量读取失败的既有差异
|
||||
- **WHEN** 关联商品批量读取发生数据库错误,而非单纯商品记录不存在
|
||||
- **THEN** 后台沿用使用记录快照继续投影的既有行为;H5 沿用读取失败响应,不因共享关系投影统一为另一入口的行为
|
||||
|
||||
## 可达操作索引
|
||||
|
||||
本节只用于入口导航,不是行为 Requirement;业务义务以上述 Requirements 为准。
|
||||
|
||||
Reference in New Issue
Block a user