## 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="<"` 时,销售统计低于阈值的代理命中该档位,高于阈值的代理不命中