归档
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 1m32s

This commit is contained in:
2026-09-14 14:25:03 +08:00
parent 1aa4eacee2
commit 18796b16ff
12 changed files with 125 additions and 16 deletions

View File

@@ -13,7 +13,7 @@
### 导出任务快照
- 创建临期、佣金明细、达量预警导出时,先复用页面 Query 构造器解析全部筛选和时间边界,再保存规范化过滤器、操作者 ID、创建时可见店铺/资产范围、时区、创建时间和口径版本。Worker 只读取该快照,不重新从请求、当前角色或当前页面解析筛选。
- 临期导出以资产为粒度,选择当前有效主套餐最终到期时间和剩余天数;加油包不单独生成行。佣金导出以钱包变动明细为粒度,保存每次变动提交后的实际余额,允许回溯负数。预警导出以预警记录为粒度,套餐/流量/阈值/到期字段读触发快照,店铺/业务员/用户组可按执行时当前归属补全,但必须同时落在创建时冻结范围。
- 临期导出以资产为粒度,选择当前有效主套餐最终到期时间和剩余天数;加油包不单独生成行。佣金明细导出的粒度与列定义由 `add-commission-clawback-records` 确定(佣金记录粒度,原佣金与回溯记录各一行,入账后/回溯后余额可为负);本 Change 只负责统一 `start_time`/`end_time` 参数、闭区间语义与筛选、权限快照冻结,不改变既有导出粒度与列定义。预警导出以预警记录为粒度,套餐/流量/阈值/到期字段读触发快照,店铺/业务员/用户组可按执行时当前归属补全,但必须同时落在创建时冻结范围。
- 导出完成记录结果文件、行数、完成时间和失败安全摘要;任何权限变化、筛选条件变化或后台归属变化不得扩大已创建任务的数据集。失败重试继续使用原快照,不创建第二份不同口径文件。
## Migration Plan

View File

@@ -8,7 +8,7 @@
## What Changes
- 统一日期/时间解析、左闭右开区间和最大范围校验。
- 统一日期/时间解析、闭区间(`start_time <= t <= end_time`,参数为带时区 RFC3339 秒级时间,任一端可省略)和最大范围校验。
- 导出冻结列表筛选、时区和数据范围。
## Capabilities

View File

@@ -8,7 +8,7 @@
- **THEN** 系统仅返回权威时间大于等于开始时间且小于等于结束时间的记录
### Requirement: 三类异步导出及冻结口径
临期列表、佣金明细和套餐流量达量预警 SHALL 复用既有异步导出任务,并在创建时冻结全部页面筛选条件、操作者和可见店铺范围。临期导出一行对应一项资产,仅取当前生效主套餐最终到期时间和剩余天数,加油包不得单独成行。预警导出一行对应一条预警记录,套餐、用量、总量、阈值和到期时间使用触发快照,店铺、业务员和用户组在执行时按当前归属补充。佣金明细必须导出每次佣金钱包变动后的实际余额,回溯记录可为负数
临期列表、佣金明细和套餐流量达量预警 SHALL 复用既有异步导出任务,并在创建时冻结全部页面筛选条件、操作者和可见店铺范围。临期导出一行对应一项资产,仅取当前生效主套餐最终到期时间和剩余天数,加油包不得单独成行。预警导出一行对应一条预警记录,套餐、用量、总量、阈值和到期时间使用触发快照,店铺、业务员和用户组在执行时按当前归属补充。佣金明细导出的记录粒度、列定义与余额口径不属于本需求:本需求只要求其冻结创建时筛选条件、操作者与可见店铺范围,且 MUST NOT 改变既有粒度与列定义
异步执行不得重新解释时间、扩大创建时店铺范围或遗漏页面筛选;文件结果只含创建时有权读取的事实。

View File

@@ -1,8 +1,8 @@
## 1. 统一筛选
- [ ] 1.1 清点本期后台导出/列表入口及现有时间字段和权限 Query。
- [ ] 1.2 实现上海时区日期解析、左闭右开区间、最大范围校验和筛选快照。
- [ ] 1.3 改造导出任务以冻结范围并复用列表 Query更新 DTO/OpenAPI。
- [ ] 1.2 实现上海时区日期解析、闭区间(`start_time <= t <= end_time`,参数为带时区 RFC3339 秒级时间,任一端可省略)、最大范围校验和筛选快照。
- [ ] 1.3 改造导出任务以冻结范围并复用列表 Query更新 DTO/OpenAPI。仅覆盖统一 `start_time`/`end_time` 参数、闭区间语义与筛选、权限与筛选快照冻结;不改变任何导出的记录粒度、列定义与余额口径。
## 2. 验证
- [ ] 2.1 验证日期边界、时间格式、空范围、超限、权限变更和导出/列表一致性。
- [ ] 2.1 验证日期边界、时间格式、空范围、超限、权限变更和导出/列表一致性,并核对佣金明细导出任务的记录粒度、列定义与余额口径未被本 Change 改变
- [ ] 2.2 运行 `gofmt -w``go build ./cmd/api ./cmd/worker``go run cmd/gendocs/main.go``openspec validate add-export-time-filter-standards --strict``openspec doctor --json`;自动化测试按项目决策为 N/A。

View File

@@ -16,7 +16,7 @@
### Requirement: 佣金异常状态可见
系统 SHALL 将佣金记录保持为已冻结、解冻中、已发放、已失效或待人工修正;链路断裂的记录进入待人工修正而不是静默计入可提现余额。
系统 SHALL 将佣金记录保持为已冻结、解冻中、已发放、已失效、回溯或待人工修正;链路断裂的记录进入待人工修正而不是静默计入可提现余额。回溯记录 MUST 为负数且不可提现MUST NOT 计入可提现余额或提高可提现额度。
#### Scenario: 佣金链路断裂
@@ -24,6 +24,12 @@
- **WHEN** 系统处理该记录
- **THEN** 记录保持待人工修正状态且不增加可提现余额
#### Scenario: 回溯记录不计入可提现余额
- **GIVEN** 代理店铺存在已发放佣金及其回溯记录
- **WHEN** 查询佣金明细并按可提现余额判定提现资格
- **THEN** 回溯记录以「回溯」状态与负数金额可见,且不增加该店铺的可提现余额
### Requirement: 代理在线充值本地支付状态
系统 SHALL 将代理在线充值的本地支付投影按 0=待支付、1=已支付、2=已失败、3=已退款返回;订单和资产充值使用各自的状态集。
@@ -55,21 +61,41 @@
### Requirement: 退款佣金回扣可靠完成
系统 SHALL 在退款审批生效时持久化佣金回请求;回请求的投递或处理异常不得静默遗留,且退款单在全部应回扣佣金失效并完成对应钱包流水前不得标记为已回
系统 SHALL 在退款申请已通过时持久化佣金回请求;回请求的投递或处理异常不得静默遗留,且退款单在全部应有回溯明细生成并完成对应钱包流水前不得标记为已回溯。原佣金记录 MUST NOT 因回溯改变状态、金额、佣金来源或发放时间
#### Scenario: 已退款订单佣金回扣失败后恢复
- **WHEN** 已退款订单的佣金回首次处理失败或进程中断
- **THEN** 退款单保持佣金未回扣状态并保留可重试事实,后续成功处理后佣金记录失效、佣金钱包按既有规则扣减且退款单标记为已回扣
- **WHEN** 已退款订单的佣金回首次处理失败或进程中断
- **THEN** 退款单保持回溯未完成状态并保留可重试事实,后续成功处理后佣金仍为已发放、回溯明细与佣金钱包负数流水均已生成且退款单标记为已完成
#### Scenario: 订单佣金未终态
- **WHEN** 退款申请已通过但原订单佣金仍未进入终态
- **THEN** 系统不写回溯明细、不标记回溯完成,并保留可重试事实等待终态
#### Scenario: 终态确无佣金
- **WHEN** 原订单佣金已进入终态且确认无佣金
- **THEN** 系统标记该退款单无需回溯并写入「无需回溯」审计,且不产生任何钱包变动
#### Scenario: 审批异常转人工不回溯
- **WHEN** 退款申请存在审批异常标记(企业微信通过后撤销)
- **THEN** 系统不生成回溯明细与钱包变动,标记该退款单的回溯后处理已闭合并写入转人工审计
### Requirement: 退款后处理可补偿
系统 SHALL 对已退款但佣金未回扣或资产未完成后处理的退款单提供幂等补偿;重复补偿不得重复扣减佣金钱包、重复写回扣流水或重复处理资产。
系统 SHALL 对已通过但回溯未完成或资产未完成后处理的退款单提供幂等补偿;重复补偿不得重复生成回溯明细、重复扣减佣金钱包、重复写负数流水或重复处理资产。
#### Scenario: 遗留退款单补偿
- **WHEN** 补偿流程发现已退款且 `commission_deducted=false` 的退款单
- **THEN** 系统恢复该退款单的唯一后处理请求,并在既有回扣成功后更新其回扣完成标记
- **WHEN** 补偿流程发现已通过且回溯完成事实缺失的退款单
- **THEN** 系统恢复该退款单的唯一后处理请求,并在全部应有回溯明细生成后更新其完成事实
#### Scenario: 周期性补偿
- **WHEN** 补偿扫描按既有周期任务形态执行且存在回溯后处理未闭合的退款单
- **THEN** 系统按固定周期重复补偿直至完成事实落库或该退款单转人工,且不重复产生任何资金事实
### Requirement: 代理商资金概况按店铺 ID 检索
@@ -282,6 +308,79 @@
- **WHEN** 超级管理员请求修改该字典项的稳定编码
- **THEN** 系统拒绝修改编码,但允许修改名称、排序、启停与备注
### Requirement: 套餐退款佣金回溯
系统 SHALL 在退款申请已通过后生成关联原佣金记录与退款单的负数、不可提现回溯明细,并保留原佣金记录不变。回溯明细 MUST 冻结原订单号、原佣金标识、负数金额、不可提现标识、回溯后佣金钱包实际余额与生成时间。换货不在本期范围。
回溯准入 MUST 由退款申请状态与方式得出:仅退款申请已通过时可生成,原路退款还须渠道明确成功。待审批、原路处理中、渠道明确失败与企业微信通过后撤销 MUST NOT 生成回溯明细;渠道明确失败可修改材料后重提,重提后按最终成功金额生成一次。同一退款业务 MUST 幂等幂等依据为「一次退款对应一次原佣金」的唯一事实MUST NOT 依赖退款单上的佣金回扣标记。
原订单佣金未进入终态时系统 MUST 等待终态后再生成MUST NOT 提前判定为无需回溯;确认无佣金时才标记无需回溯。
部分退款按本次成功退款金额与本次退款冻结实收金额的比例对每条原佣金等比例回溯。金额 MUST 以分整数精确计算MUST NOT 溢出或引入浮点误差;每条按分向下取整,舍入差自稳定顺序(原佣金标识升序)末条起向前补足,每条不超过该条剩余可回溯余额;累计回溯 MUST NOT 超过各原佣金的可回溯余额。冻结实收金额缺失或非正时系统 MUST 记录可恢复失败且不落库、不改变余额MUST NOT 以订单标价或申请金额替代。
生成回溯前系统 MUST 先拒绝并释放待审核提现的冻结余额再生成回溯明细与钱包扣款流水佣金钱包余额允许为负MUST NOT 因余额不足而跳过或拒绝回溯。
#### Scenario: 部分退款舍入
- **WHEN** 一笔部分退款关联多条原佣金且比例计算产生分级舍入差
- **THEN** 系统按各条向下取整并自末条起向前补差,回溯总额等于应回溯额且不超过各原佣金可回溯余额
#### Scenario: 全额回溯
- **WHEN** 退款金额与冻结实收金额相等
- **THEN** 系统按各原佣金的剩余可回溯金额回溯,回溯总额等于各原佣金金额之和
#### Scenario: 冻结实收金额非正
- **WHEN** 本次退款冻结实收金额缺失或非正
- **THEN** 系统记录可恢复失败,不写回溯明细、不改变佣金钱包余额,且不以订单标价替代计算
#### Scenario: 原路渠道失败重提后按最终金额回溯
- **GIVEN** 一笔原路退款曾在渠道明确失败并可重提
- **WHEN** 该退款重提后最终渠道明确成功
- **THEN** 系统仅在该退款申请已通过时按其最终成功金额生成一次回溯明细,失败阶段不产生任何回溯事实
#### Scenario: 重复退款消费
- **WHEN** 同一退款完成事件被重复消费
- **THEN** 系统不重复生成回溯明细、钱包扣款或提现释放事实
#### Scenario: 回溯后佣金钱包负余额
- **GIVEN** 店铺佣金钱包余额不足以覆盖本次回溯金额
- **WHEN** 系统生成回溯明细
- **THEN** 钱包余额允许为负并记录回溯后实际余额,且不因余额不足而跳过或拒绝回溯
#### Scenario: 原佣金保持不变
- **WHEN** 一笔已发放佣金被回溯
- **THEN** 该原佣金记录的状态、金额、佣金来源与发放时间均不变,可提现余额按回溯金额减少
### Requirement: 回溯明细关联查询与导出
系统 SHALL 在佣金明细中分别展示原发放佣金和回溯扣款记录,并允许从任一记录查询其关联的退款单、原佣金或全部回溯明细。回溯记录必须显示负数金额、不可提现标识、来源退款单号、原佣金记录号、生成时间和回溯后佣金钱包实际余额。原佣金与回溯记录 MUST 合并为同一列表的同一分页与同一排序口径MUST NOT 因来源表不同而丢失或重复任一条事实。
佣金明细及导出 MUST 使用既有佣金数据范围:代理仅可读取自身及其既有可见范围内的事实,平台与超级管理员遵循既有范围;无权记录不得通过关联 ID、汇总或导出泄露存在性。
佣金明细导出 MUST 使用佣金记录粒度,原佣金与回溯记录各占一行,并冻结创建时筛选条件、操作者与可见范围。回溯后余额为对应钱包变动提交后的实际余额,可为负数;金额保持分,展示层转元 MUST NOT 改变负数或余额事实。
#### Scenario: 代理查询越权回溯记录
- **WHEN** 代理使用回溯记录 ID、原佣金 ID 或退款单号查询其数据范围外的回溯关系
- **THEN** 系统按既有数据范围返回不存在或空结果,不泄露关联事实
#### Scenario: 原佣金与回溯合并分页
- **GIVEN** 同一店铺同时存在原佣金记录与回溯记录
- **WHEN** 查询佣金明细列表并翻页
- **THEN** 两类记录按同一排序口径出现在同一结果集内,任一条不缺失也不重复
#### Scenario: 回溯记录导出
- **WHEN** 导出含回溯记录的佣金明细
- **THEN** 原佣金与回溯记录各占一行,回溯行金额为负数、可提现标识为不可提现、含关联佣金明细与退款单标识,且回溯后余额为负数时原样导出
## 可达操作索引
本节只用于入口导航,不是行为 Requirement业务义务以上述 Requirements 为准。
@@ -296,7 +395,7 @@
### 代理商资金管理
`POST /api/admin/commission-records/{id}/resolve`(修正待审佣金记录);`PUT /api/admin/shops/{id}/credit-limit`(调整既有店铺实际信用额度);`GET /api/admin/shops/{shop_id}/commission-daily-stats`(代理商每日佣金统计);`GET /api/admin/shops/{shop_id}/commission-records`(代理商佣金明细);`GET /api/admin/shops/{shop_id}/commission-stats`(代理商佣金统计);`GET /api/admin/shops/{shop_id}/main-wallet/transactions`(代理商预充值钱包流水);`GET /api/admin/shops/{shop_id}/withdrawal-requests`(代理商提现记录);`POST /api/admin/shops/{shop_id}/withdrawal-requests`(发起提现申请);`GET /api/admin/shops/fund-summary`(代理商资金概况)。
`POST /api/admin/commission-records/{id}/resolve`(修正待审佣金记录);`PUT /api/admin/shops/{id}/credit-limit`(调整既有店铺实际信用额度);`GET /api/admin/shops/{shop_id}/commission-daily-stats`(代理商每日佣金统计);`GET /api/admin/shops/{shop_id}/commission-records`(代理商佣金明细);`GET /api/admin/shops/{shop_id}/commission-records/{id}`(佣金明细详情);`GET /api/admin/shops/{shop_id}/commission-stats`(代理商佣金统计);`GET /api/admin/shops/{shop_id}/main-wallet/transactions`(代理商预充值钱包流水);`GET /api/admin/shops/{shop_id}/withdrawal-requests`(代理商提现记录);`POST /api/admin/shops/{shop_id}/withdrawal-requests`(发起提现申请);`GET /api/admin/shops/fund-summary`(代理商资金概况)。
### 佣金提现审批

View File

@@ -221,9 +221,9 @@
- **THEN** 退款申请标记原路退款失败且不标记已通过,已失效套餐权益不恢复,订单保持已支付
### Requirement: 退款终态事实与失败分类
退款申请 SHALL 保存结构化失败分类、渠道退款状态、渠道退款流水与渠道退款请求号,并在列表、详情和导出中返回冻结实收金额、方式、申请状态、渠道退款状态、失败安全摘要、审批尝试历史和渠道流水,按既有订单数据范围过滤。失败分类 MUST 为稳定枚举,至少覆盖:渠道明确拒绝、渠道凭证失效、渠道余额不足、超时或结果未知、企业微信驳回或关闭、企业微信通过后撤销,以及本地原支付事实不可用。渠道凭证失效与本地原支付事实不可用 MUST 为两个并列分类、语义不得合并:前者指该商户退款必需凭证缺失或失效,后者指本地原支付单、实际收款商户、原渠道流水或可退金额校验不通过。每个分类 MUST 显式标记其是否属于「明确失败」:明确失败表示退款已终结且可进入后续回溯判定,非明确失败表示仍在途或需人工处理。审计 SHALL 记录申请、重提、审批终态、权益处理、渠道调用与恢复,且不得记录凭证内容、完整收款文本或商户密钥。
退款申请 SHALL 保存结构化失败分类、渠道退款状态、渠道退款流水与渠道退款请求号,并在列表、详情和导出中返回冻结实收金额、方式、申请状态、渠道退款状态、失败安全摘要、审批尝试历史和渠道流水,按既有订单数据范围过滤。失败分类 MUST 为稳定枚举,至少覆盖:渠道明确拒绝、渠道凭证失效、渠道余额不足、超时或结果未知、企业微信驳回或关闭、企业微信通过后撤销,以及本地原支付事实不可用。渠道凭证失效与本地原支付事实不可用 MUST 为两个并列分类、语义不得合并:前者指该商户退款必需凭证缺失或失效,后者指本地原支付单、实际收款商户、原渠道流水或可退金额校验不通过。每个分类 MUST 显式标记其是否属于「明确失败」:明确失败表示该次退款尝试已终结且不可自动恢复,非明确失败表示仍在途、可自动恢复或需人工处理。该标记 MUST 仅用于判定尝试终结性与人工处置MUST NOT 作为佣金回溯的准入条件。审计 SHALL 记录申请、重提、审批终态、权益处理、渠道调用与恢复,且不得记录凭证内容、完整收款文本或商户密钥。
为后续佣金回溯能力提供稳定事实,退款终态 SHALL 可按退款单与订单定位,并提供:成功退款金额、冻结实收金额终态时点、结构化失败分类及其明确失败标记,以及区分原路成功与客户收款信息完成的完成事件键。后续回溯判定 MUST 依据上述分类标记而非猜测文本:标记为明确失败的退款才可进入回溯判定,标记为非明确失败的退款(超时或结果未知、企业微信通过后撤销)保持在途或转人工,不得回溯。系统 MUST 保留既有退款佣金回扣事件键的兼容语义;佣金回溯的幂等键为一次退款一次回溯,不依赖退款单上的佣金回扣标记。
为后续佣金回溯能力提供稳定事实,退款终态 SHALL 可按退款单与订单定位,并提供:成功退款金额、冻结实收金额终态时点。佣金回溯准入 MUST 由退款申请状态、审批异常标记与退款方式得出MUST NOT 依据失败分类标记、退款原因文本或新增的独立完成事件键:仅退款申请已通过且不存在审批异常标记时可进入回溯判定,原路退款还须渠道明确成功;待审批、原路处理中、渠道明确失败(可修改材料后重提)与企业微信通过后撤销均不得回溯。系统 MUST 保留既有退款佣金回扣事件键的兼容语义;佣金回溯的幂等键为一次退款一次回溯,不依赖退款单上的佣金回扣标记。
#### Scenario: 渠道失败分类可查询
@@ -235,6 +235,16 @@
- **WHEN** 渠道退款调用或恢复完成后写入审计
- **THEN** 审计只记录业务标识、金额、状态与脱敏摘要,不记录商户密钥或凭证原文
#### Scenario: 回溯准入仅取决于退款申请状态
- **WHEN** 退款申请处于待审批、原路处理中、渠道明确失败或企业微信通过后撤销
- **THEN** 系统不生成任何佣金回溯事实;仅当退款申请已通过(原路退款还须渠道明确成功)时才生成
#### Scenario: 失败分类不决定回溯准入
- **WHEN** 一次退款尝试带有明确失败分类,但该退款申请尚未处于已通过状态
- **THEN** 系统不生成佣金回溯事实,该分类只用于判定尝试终结性与人工处置
### Requirement: 退款展示当前退款套餐用量
退款管理列表、详情与导出 SHALL 返回「当前退款套餐已用量」与「当前退款套餐总量」两个字段,取值为该套餐使用记录当前可取得的真实已用量与真实总量(单位 MB。两个字段 MUST 仅用于展示、查询与导出MUST NOT 参与或改变退款金额校验、冻结实收金额、套餐失效、接续下一套餐、停机评估、佣金回溯或渠道退款任何规则。