docs: 归档 refactor-agent-series-grant 变更文档
将已完成的变更(proposal、design、tasks、delta specs)归档至 openspec/changes/archive/2026-03-04-refactor-agent-series-grant/。变更内容:合并系列分配和套餐分配为系列授权(Grant)、新增梯度佣金模式、新增代理层强充层级规则。50/50 任务全部完成。 Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -0,0 +1,158 @@
|
||||
## 1. 数据库迁移文件准备
|
||||
|
||||
- [x] 1.1 使用 db-migration 规范创建迁移文件:
|
||||
- **删除** `tb_shop_series_allocation` 的 3 列:`enable_one_time_commission`、`one_time_commission_trigger`、`one_time_commission_threshold`
|
||||
- **新增** `commission_tiers_json JSONB NOT NULL DEFAULT '[]'`(梯度模式专属阶梯金额)
|
||||
- DOWN 脚本添加说明注释(不恢复数据)
|
||||
|
||||
## 2. 删除旧接口(Handler / routes / DTO / Service)
|
||||
|
||||
- [x] 2.1 删除文件:
|
||||
- `internal/handler/admin/shop_series_allocation.go`
|
||||
- `internal/handler/admin/shop_package_allocation.go`
|
||||
- `internal/routes/shop_series_allocation.go`
|
||||
- `internal/routes/shop_package_allocation.go`
|
||||
- `internal/model/dto/shop_series_allocation.go`
|
||||
- `internal/model/dto/shop_package_allocation.go`
|
||||
- `internal/service/shop_series_allocation/`(整个目录)
|
||||
- `internal/service/shop_package_allocation/`(整个目录)
|
||||
- [x] 2.2 `internal/bootstrap/types.go`:删除 `ShopSeriesAllocation`、`ShopPackageAllocation` 两个 Handler 字段
|
||||
- [x] 2.3 `internal/bootstrap/handlers.go`:删除对应 Handler 初始化行;删除对应 service 引用
|
||||
- [x] 2.4 `internal/bootstrap/services.go`:删除 `ShopSeriesAllocation`、`ShopPackageAllocation` 两个 Service 字段及初始化;移除对应 import
|
||||
- [x] 2.5 `pkg/openapi/handlers.go`:删除 `ShopSeriesAllocation`、`ShopPackageAllocation` 两行
|
||||
- [x] 2.6 `internal/routes/admin.go`:删除 `registerShopSeriesAllocationRoutes`、`registerShopPackageAllocationRoutes` 两处调用
|
||||
- [x] 2.7 运行 `go build ./...` 确认无编译错误
|
||||
|
||||
## 3. Model 更新
|
||||
|
||||
- [x] 3.1 `internal/model/shop_series_allocation.go`:
|
||||
- 删除 `EnableOneTimeCommission`、`OneTimeCommissionTrigger`、`OneTimeCommissionThreshold` 三个字段
|
||||
- 新增 `CommissionTiersJSON string` 字段(JSONB,默认 `'[]'`)
|
||||
- 新增辅助类型 `AllocationCommissionTier struct { Threshold int64; Amount int64 }`
|
||||
- 新增 `GetCommissionTiers() ([]AllocationCommissionTier, error)` 方法
|
||||
- 新增 `SetCommissionTiers(tiers []AllocationCommissionTier) error` 方法
|
||||
- [x] 3.2 `internal/model/package.go`:
|
||||
- `OneTimeCommissionTier` 新增 `Operator string` 字段(json:"operator")
|
||||
- 新增运算符常量:`TierOperatorGT = ">"` / `TierOperatorGTE = ">="` / `TierOperatorLT = "<"` / `TierOperatorLTE = "<="`
|
||||
- [x] 3.3 运行 `go build ./...` 确认无编译错误
|
||||
|
||||
## 4. 修复梯度模式计算引擎
|
||||
|
||||
- [x] 4.1 `internal/service/commission_calculation/service.go`:
|
||||
修改 `calculateChainOneTimeCommission` 中梯度模式分支:
|
||||
- 原来:直接把 `config.Tiers`(全局)传给 `matchOneTimeCommissionTier`
|
||||
- 新的:从 `currentSeriesAllocation.GetCommissionTiers()` 取专属金额列表,结合 `config.Tiers`(取 operator/dimension/stat_scope/threshold)做匹配
|
||||
- 匹配逻辑:根据代理销售统计和 tier.Operator 判断是否命中 threshold → 查专属列表同 threshold 的 amount → 即 myAmount;未命中任何阶梯时 myAmount = 0
|
||||
- commission_tiers_json 为空时(历史数据)fallback 到 `currentSeriesAllocation.OneTimeCommissionAmount`
|
||||
- [x] 4.2 修改 `matchOneTimeCommissionTier`:接受 agentTiers `[]AllocationCommissionTier` 参数作为金额来源;根据 `tier.Operator` 选择对应比较逻辑(>、>=、<、<=),Operator 为空时默认 `>=`
|
||||
- [x] 4.3 运行 `go build ./...` 确认无编译错误
|
||||
|
||||
## 5. 修复强充层级
|
||||
|
||||
- [x] 5.1 `internal/service/order/service.go` `checkForceRechargeRequirement()`:
|
||||
- `config.TriggerType == "first_recharge"` 时:直接返回需要强充(不变),不查代理配置
|
||||
- `config.TriggerType == "accumulated_recharge"` 且 `config.EnableForceRecharge == false` 时:
|
||||
从 `result.Card.ShopID`(或 `result.Device.ShopID`)查询该代理的 `ShopSeriesAllocation`,
|
||||
若该分配 `EnableForceRecharge=true` 则返回代理强充配置,查询不到时降级返回 `need_force_recharge=false`
|
||||
- [x] 5.2 验证 `GetPurchaseCheck` 调用路径已覆盖新逻辑(复用同一函数,无需额外修改)
|
||||
- [x] 5.3 运行 `go build ./...` 确认无编译错误
|
||||
|
||||
## 6. 新系列授权 DTO
|
||||
|
||||
- [x] 6.1 创建 `internal/model/dto/shop_series_grant_dto.go`,定义:
|
||||
- `GrantPackageItem`(package_id、cost_price、remove *bool)
|
||||
- `ShopSeriesGrantPackageItem`(package_id、package_name、package_code、cost_price、shelf_status、status)
|
||||
- `GrantCommissionTierItem`(operator string、threshold int64、amount int64)
|
||||
—— operator 仅出现在响应中(从 PackageSeries 合并),请求中不传 operator
|
||||
- [x] 6.2 定义 `ShopSeriesGrantResponse`:
|
||||
- id、shop_id/name、series_id/name/code、commission_type
|
||||
- one_time_commission_amount(固定模式有效,梯度模式返回 0)
|
||||
- commission_tiers []GrantCommissionTierItem(梯度模式有值,固定模式为空)
|
||||
- force_recharge_locked、force_recharge_enabled、force_recharge_amount
|
||||
- allocator_shop_id/name、status、packages、created_at、updated_at
|
||||
- [x] 6.3 定义 `CreateShopSeriesGrantRequest`:
|
||||
- shop_id、series_id
|
||||
- one_time_commission_amount *int64(固定模式必填)
|
||||
- commission_tiers []GrantCommissionTierItem(梯度模式必填)
|
||||
- enable_force_recharge *bool、force_recharge_amount *int64
|
||||
- packages []GrantPackageItem
|
||||
- [x] 6.4 定义 `UpdateShopSeriesGrantRequest`:
|
||||
- one_time_commission_amount *int64
|
||||
- commission_tiers []GrantCommissionTierItem
|
||||
- enable_force_recharge *bool、force_recharge_amount *int64
|
||||
- [x] 6.5 定义 `ManageGrantPackagesRequest`(packages []GrantPackageItem)
|
||||
- [x] 6.6 定义 `ShopSeriesGrantListRequest`(page、page_size、shop_id *uint、series_id *uint、allocator_shop_id *uint、status *int)及列表 DTO(`ShopSeriesGrantListItem` 含 package_count、`ShopSeriesGrantPageResult`)
|
||||
|
||||
## 7. 新系列授权 Service
|
||||
|
||||
- [x] 7.1 创建 `internal/service/shop_series_grant/service.go`,定义 Service 结构及 New() 构造函数
|
||||
(依赖:db、shopSeriesAllocationStore、shopPackageAllocationStore、shopPackageAllocationPriceHistoryStore、shopStore、packageStore、packageSeriesStore)
|
||||
|
||||
- [x] 7.2 实现私有方法 `getParentCeilingFixed()`:固定模式天花板查询
|
||||
- allocatorShopID=0 → 读 PackageSeries.commission_amount
|
||||
- allocatorShopID>0 → 读分配者自身的 ShopSeriesAllocation.one_time_commission_amount
|
||||
|
||||
- [x] 7.3 实现私有方法 `getParentCeilingTiered()`:梯度模式天花板查询
|
||||
- allocatorShopID=0 → 读 PackageSeries.config.Tiers 中各 threshold 的 amount
|
||||
- allocatorShopID>0 → 读分配者自身 ShopSeriesAllocation.commission_tiers_json
|
||||
|
||||
- [x] 7.4 实现 `Create()`:
|
||||
- 查询 PackageSeries 确认 commission_type
|
||||
- 检查重复授权:shop_id + series_id 已有 active 记录 → 错误"该代理已存在此系列授权"
|
||||
- allocator 是代理时:查分配者自身的 ShopSeriesAllocation,无记录 → 错误"当前账号无此系列授权,无法向下分配"
|
||||
- 固定模式:one_time_commission_amount 必填 + 天花板校验
|
||||
- 梯度模式:commission_tiers 必填 + 阶梯数量和 threshold 必须与 PackageSeries 完全一致(不多不少,amount 可为 0)+ 每档位天花板校验
|
||||
- 强充层级判断(TriggerType=first_recharge 或平台已设强充 → locked=true 忽略代理传入;仅 accumulated_recharge 且平台未设时接受代理强充配置)
|
||||
- 事务中创建 ShopSeriesAllocation + N 条 ShopPackageAllocation
|
||||
- 返回聚合响应
|
||||
|
||||
- [x] 7.5 实现 `Get()`:查询 ShopSeriesAllocation → 查 PackageSeries 取全局 tiers(含 operator)→ 关联套餐分配 → 拼装 ShopSeriesGrantResponse
|
||||
(梯度模式下,commission_tiers 响应需将 agent 的 amount 与 PackageSeries tiers 的 operator 按 threshold 合并)
|
||||
|
||||
- [x] 7.6 实现 `List()`:分页查询 → 统计 package_count → 返回 ShopSeriesGrantPageResult
|
||||
|
||||
- [x] 7.7 实现 `Update()`:
|
||||
- 固定模式:含 one_time_commission_amount 时做天花板校验
|
||||
- 梯度模式:含 commission_tiers 时做每档位天花板校验
|
||||
- 平台已设强充时忽略强充变更
|
||||
- 保存更新
|
||||
|
||||
- [x] 7.8 实现 `ManagePackages()`:事务中处理 packages 列表:
|
||||
- remove=true:查找 active 的 ShopPackageAllocation,找到则软删除,找不到则静默忽略
|
||||
- 无 remove 标志:校验套餐归属和分配权限,查现有 active 记录(有则更新 cost_price+写历史,无则新建)
|
||||
|
||||
- [x] 7.9 实现 `Delete()`:检查子级依赖 → 事务软删除 ShopSeriesAllocation + 所有关联 ShopPackageAllocation
|
||||
|
||||
- [x] 7.10 运行 `go build ./...` 确认无编译错误
|
||||
|
||||
## 8. Handler、路由及文档生成器
|
||||
|
||||
- [x] 8.1 创建 `internal/handler/admin/shop_series_grant.go`,实现 Create、Get、List、Update、ManagePackages、Delete 六个 Handler 方法
|
||||
- [x] 8.2 创建 `internal/routes/shop_series_grant.go`,注册路由(Tag: "代理系列授权"):
|
||||
- `GET /shop-series-grants`
|
||||
- `POST /shop-series-grants`
|
||||
- `GET /shop-series-grants/:id`
|
||||
- `PUT /shop-series-grants/:id`
|
||||
- `DELETE /shop-series-grants/:id`
|
||||
- `PUT /shop-series-grants/:id/packages`
|
||||
- [x] 8.3 运行 `go build ./...` 确认无编译错误
|
||||
|
||||
## 9. 依赖注入 & Bootstrap
|
||||
|
||||
- [x] 9.1 `internal/bootstrap/types.go`:添加 `ShopSeriesGrant *admin.ShopSeriesGrantHandler` 字段
|
||||
- [x] 9.2 `internal/bootstrap/services.go`:import shop_series_grant service 包,添加字段并在 `initServices()` 中初始化
|
||||
- [x] 9.3 `internal/bootstrap/handlers.go`:添加 ShopSeriesGrant Handler 初始化
|
||||
- [x] 9.4 `pkg/openapi/handlers.go`:添加 `ShopSeriesGrant: admin.NewShopSeriesGrantHandler(nil)`
|
||||
- [x] 9.5 `internal/routes/admin.go`:添加 `registerShopSeriesGrantRoutes()` 调用
|
||||
- [x] 9.6 运行 `go build ./...` 确认完整构建通过
|
||||
|
||||
## 10. 执行迁移 & 数据验证
|
||||
|
||||
- [x] 10.1 执行迁移(`make migrate-up`),用 db-migration 规范验证:3 列已删除,commission_tiers_json 列已添加
|
||||
- [x] 10.2 db-validation:创建固定模式授权(正常路径),确认 ShopSeriesAllocation 和 ShopPackageAllocation 均创建成功
|
||||
- [x] 10.3 db-validation:固定模式金额超过父级天花板时接口返回错误
|
||||
- [x] 10.4 db-validation:梯度模式创建授权,commission_tiers_json 正确写入
|
||||
- [x] 10.5 db-validation:梯度模式某档位金额超过父级同档位时接口返回错误
|
||||
- [x] 10.6 db-validation:代理自设强充后,购买预检接口返回 need_force_recharge=true,金额与代理设置一致
|
||||
- [x] 10.7 db-validation:平台系列已设强充时,代理自设强充被锁定,购买预检使用平台强充金额
|
||||
- [x] 10.8 db-validation:梯度模式阶梯含 `operator="<"` 时,销售统计低于阈值的代理命中该档位,高于阈值的代理不命中
|
||||
Reference in New Issue
Block a user