重构: 店铺套餐分配系统从加价模式改为返佣模式
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 5m18s
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 5m18s
主要变更: - 重构分配模型:从加价模式(pricing_mode/pricing_value)改为返佣模式(base_commission + tier_commission) - 删除独立的 my_package 接口,统一到 /api/admin/packages(通过数据权限自动过滤) - 新增批量分配和批量调价功能,支持事务和性能优化 - 新增配置版本管理,订单创建时锁定返佣配置 - 新增成本价历史记录,支持审计和纠纷处理 - 新增统计缓存系统(Redis + 异步任务),优化梯度返佣计算性能 - 删除冗余的梯度佣金独立 CRUD 接口(合并到分配配置中) - 归档 3 个已完成的 OpenSpec changes 并同步 8 个新 capabilities 到 main specs 技术细节: - 数据库迁移:000026_refactor_shop_package_allocation - 新增 Store:AllocationConfigStore, PriceHistoryStore, CommissionStatsStore - 新增 Service:BatchAllocationService, BatchPricingService, CommissionStatsService - 新增异步任务:统计更新、定时同步、周期归档 - 测试覆盖:批量操作集成测试、梯度佣金 CRUD 清理验证 影响: - API 变更:删除 4 个梯度 CRUD 接口(POST/GET/PUT/DELETE /:id/tiers) - API 新增:批量分配、批量调价接口 - 数据模型:重构 shop_series_allocation 表结构 - 性能优化:批量操作使用 CreateInBatches,统计使用 Redis 缓存 相关文档: - openspec/changes/archive/2026-01-28-refactor-shop-package-allocation/ - openspec/specs/agent-available-packages/ - openspec/specs/allocation-config-versioning/ - 等 8 个新 capability specs
This commit is contained in:
64
openspec/specs/agent-available-packages/spec.md
Normal file
64
openspec/specs/agent-available-packages/spec.md
Normal file
@@ -0,0 +1,64 @@
|
||||
# Capability: 代理可售套餐查询
|
||||
|
||||
## Purpose
|
||||
|
||||
本 capability 定义代理用户如何通过统一的套餐管理接口查询可售套餐,系统如何自动过滤并返回代理专属字段(成本价、返佣信息等)。
|
||||
|
||||
## Requirements
|
||||
|
||||
### Requirement: 代理查询可售套餐列表
|
||||
|
||||
系统 SHALL 通过统一的套餐列表接口(`/api/admin/packages`)为代理用户自动过滤可售套餐。代理用户查询时,系统 MUST 只返回被分配的套餐,响应 MUST 包含成本价、利润空间、返佣信息等代理专属字段。
|
||||
|
||||
#### Scenario: 代理查询自动过滤为已分配套餐
|
||||
- **WHEN** 代理用户调用 `GET /api/admin/packages`
|
||||
- **THEN** 系统通过 JOIN `tb_shop_package_allocation` 自动过滤,只返回该代理被分配的套餐
|
||||
|
||||
#### Scenario: 平台用户查询返回所有套餐
|
||||
- **WHEN** 平台用户调用 `GET /api/admin/packages`
|
||||
- **THEN** 系统返回所有套餐(不应用代理权限过滤)
|
||||
|
||||
#### Scenario: 响应包含代理专属字段
|
||||
- **WHEN** 代理用户查询套餐列表
|
||||
- **THEN** 每个套餐包含:cost_price(成本价)、profit_margin(利润空间)、current_commission_rate(当前返佣比例)
|
||||
|
||||
#### Scenario: 响应包含梯度返佣信息
|
||||
- **WHEN** 代理用户查询套餐列表,且该系列启用了梯度返佣
|
||||
- **THEN** 响应包含 tier_info:enabled、current_sales(本周期销量)、current_tier_id(当前档位)、next_threshold(下一档阈值)、next_rate(下一档返佣比例)
|
||||
|
||||
#### Scenario: 按系列筛选
|
||||
- **WHEN** 代理指定套餐系列 ID 筛选
|
||||
- **THEN** 系统只返回该系列下已分配的套餐
|
||||
|
||||
#### Scenario: 只返回启用且上架的套餐
|
||||
- **WHEN** 代理查询可售套餐
|
||||
- **THEN** 系统只返回 status=1(启用)且 shelf_status=1(上架)的套餐
|
||||
|
||||
---
|
||||
|
||||
### Requirement: 代理查询可售套餐详情
|
||||
|
||||
系统 SHALL 通过统一的套餐详情接口(`/api/admin/packages/:id`)为代理用户返回套餐详细信息,包含完整的价格信息。
|
||||
|
||||
#### Scenario: 代理查询已分配套餐详情
|
||||
- **WHEN** 代理查询一个已被分配的套餐详情
|
||||
- **THEN** 系统返回套餐完整信息,包含:成本价、建议售价、利润空间、价格来源(系列分配)
|
||||
|
||||
#### Scenario: 代理查询未分配的套餐
|
||||
- **WHEN** 代理查询一个未被分配的套餐详情
|
||||
- **THEN** 系统返回 404 或权限错误(数据权限过滤生效)
|
||||
|
||||
---
|
||||
|
||||
### Requirement: 删除独立的 my-packages 接口
|
||||
|
||||
系统 SHALL 删除以下独立接口及相关代码:
|
||||
- `GET /api/admin/my-packages`
|
||||
- `GET /api/admin/my-packages/:id`
|
||||
- `GET /api/admin/my-series-allocations`
|
||||
|
||||
功能 MUST 通过统一的 `/api/admin/packages` 接口实现,依赖数据权限自动过滤机制。
|
||||
|
||||
#### Scenario: 调用已删除的接口返回404
|
||||
- **WHEN** 代理调用 `GET /api/admin/my-packages`
|
||||
- **THEN** 系统返回 404 Not Found
|
||||
67
openspec/specs/allocation-config-versioning/spec.md
Normal file
67
openspec/specs/allocation-config-versioning/spec.md
Normal file
@@ -0,0 +1,67 @@
|
||||
# Capability: 分配配置版本管理
|
||||
|
||||
## Purpose
|
||||
|
||||
本 capability 定义如何管理套餐系列分配的返佣配置版本,确保订单创建时锁定配置,支持配置历史查询和审计。
|
||||
|
||||
## Requirements
|
||||
|
||||
### Requirement: 返佣配置变更时创建新版本
|
||||
|
||||
系统 SHALL 在代理修改套餐系列分配的返佣配置时,创建新的配置版本记录。旧版本 MUST 被标记为失效(设置 effective_to 时间戳),新版本 MUST 记录生效时间(effective_from)。
|
||||
|
||||
#### Scenario: 修改基础返佣配置时创建新版本
|
||||
- **WHEN** 代理将基础返佣从20%修改为25%
|
||||
- **THEN** 系统失效当前配置版本,创建新版本(version + 1)
|
||||
|
||||
#### Scenario: 修改梯度返佣开关时创建新版本
|
||||
- **WHEN** 代理启用或禁用梯度返佣
|
||||
- **THEN** 系统失效当前配置版本,创建新版本
|
||||
|
||||
#### Scenario: 仅修改非配置字段时不创建新版本
|
||||
- **WHEN** 代理修改分配的状态(启用/禁用),但不修改返佣配置
|
||||
- **THEN** 系统不创建新配置版本
|
||||
|
||||
#### Scenario: 新版本记录正确的生效时间
|
||||
- **WHEN** 代理在2026-01-28 10:00:00修改返佣配置
|
||||
- **THEN** 新版本的 effective_from 为 2026-01-28 10:00:00
|
||||
|
||||
#### Scenario: 旧版本记录正确的失效时间
|
||||
- **WHEN** 代理在2026-01-28 10:00:00修改返佣配置
|
||||
- **THEN** 旧版本的 effective_to 为 2026-01-28 10:00:00
|
||||
|
||||
---
|
||||
|
||||
### Requirement: 订单创建时锁定配置版本
|
||||
|
||||
系统 SHALL 在创建充值订单时,查询当前生效的配置版本并锁定到订单。订单 MUST 记录配置版本ID和配置快照(返佣模式、返佣值)。
|
||||
|
||||
#### Scenario: 订单创建时查询当前生效配置
|
||||
- **WHEN** 下级客户在2026-01-28 10:30:00发起充值
|
||||
- **THEN** 系统查询2026-01-28 10:30:00时生效的配置版本(effective_from <= 10:30:00 AND effective_to IS NULL)
|
||||
|
||||
#### Scenario: 订单锁定配置版本ID
|
||||
- **WHEN** 订单创建时,查询到配置版本ID为123
|
||||
- **THEN** 订单记录 allocation_config_id = 123
|
||||
|
||||
#### Scenario: 订单记录配置快照
|
||||
- **WHEN** 订单创建时,配置为百分比200(20%)
|
||||
- **THEN** 订单记录 locked_commission_mode = "percent", locked_commission_value = 200
|
||||
|
||||
#### Scenario: 配置变更后订单使用锁定的配置
|
||||
- **WHEN** 订单创建后,代理修改了返佣配置
|
||||
- **THEN** 订单仍然按照锁定的配置计算返佣
|
||||
|
||||
---
|
||||
|
||||
### Requirement: 查询历史配置版本
|
||||
|
||||
系统 SHALL 允许代理查询指定分配的所有历史配置版本,按生效时间倒序排列。
|
||||
|
||||
#### Scenario: 查询分配的配置版本历史
|
||||
- **WHEN** 代理查询分配ID为123的配置版本历史
|
||||
- **THEN** 系统返回该分配的所有版本记录,最新版本在最前
|
||||
|
||||
#### Scenario: 历史版本包含完整配置信息
|
||||
- **WHEN** 查询历史配置版本
|
||||
- **THEN** 每个版本包含:版本号、返佣模式、返佣值、梯度开关、生效时间、失效时间
|
||||
59
openspec/specs/allocation-price-history/spec.md
Normal file
59
openspec/specs/allocation-price-history/spec.md
Normal file
@@ -0,0 +1,59 @@
|
||||
# Capability: 分配成本价历史管理
|
||||
|
||||
## Purpose
|
||||
|
||||
本 capability 定义如何记录和查询套餐分配的成本价变更历史,支持审计和纠纷处理,确保历史记录不可篡改。
|
||||
|
||||
## Requirements
|
||||
|
||||
### Requirement: 成本价调整时记录历史
|
||||
|
||||
系统 SHALL 在代理调整套餐分配的成本价时,创建成本价变更历史记录。历史记录 MUST 包含:旧成本价、新成本价、变更原因、变更人、生效时间。
|
||||
|
||||
#### Scenario: 单个调整时创建历史记录
|
||||
- **WHEN** 代理将套餐A的成本价从10000分调整为11000分,原因为"市场调价"
|
||||
- **THEN** 系统创建历史记录:old = 10000, new = 11000, reason = "市场调价"
|
||||
|
||||
#### Scenario: 批量调整时批量创建历史记录
|
||||
- **WHEN** 代理批量调整100个套餐的成本价
|
||||
- **THEN** 系统创建100条历史记录
|
||||
|
||||
#### Scenario: 历史记录包含变更人信息
|
||||
- **WHEN** 用户ID为456的代理调整成本价
|
||||
- **THEN** 历史记录的 changed_by = 456
|
||||
|
||||
#### Scenario: 历史记录记录生效时间
|
||||
- **WHEN** 代理在2026-01-28 10:00:00调整成本价
|
||||
- **THEN** 历史记录的 effective_from = 2026-01-28 10:00:00
|
||||
|
||||
---
|
||||
|
||||
### Requirement: 查询成本价变更历史
|
||||
|
||||
系统 SHALL 允许代理查询指定套餐分配的成本价变更历史,按生效时间倒序排列。
|
||||
|
||||
#### Scenario: 查询套餐分配的成本价历史
|
||||
- **WHEN** 代理查询分配ID为123的成本价历史
|
||||
- **THEN** 系统返回该分配的所有成本价变更记录,最新变更在最前
|
||||
|
||||
#### Scenario: 历史记录包含完整变更信息
|
||||
- **WHEN** 查询成本价历史
|
||||
- **THEN** 每条记录包含:旧成本价、新成本价、变更原因、变更人、生效时间
|
||||
|
||||
#### Scenario: 支持按时间范围筛选历史
|
||||
- **WHEN** 代理查询2026年1月的成本价变更
|
||||
- **THEN** 系统返回effective_from在2026-01-01至2026-01-31之间的记录
|
||||
|
||||
---
|
||||
|
||||
### Requirement: 支持审计和纠纷处理
|
||||
|
||||
成本价历史记录 SHALL 支持审计和纠纷处理,系统 MUST 保证历史记录不可篡改(只能创建,不能修改或删除)。
|
||||
|
||||
#### Scenario: 历史记录不可修改
|
||||
- **WHEN** 尝试修改已创建的历史记录
|
||||
- **THEN** 系统拒绝操作
|
||||
|
||||
#### Scenario: 历史记录不可删除
|
||||
- **WHEN** 尝试删除已创建的历史记录
|
||||
- **THEN** 系统拒绝操作
|
||||
87
openspec/specs/commission-stats-caching/spec.md
Normal file
87
openspec/specs/commission-stats-caching/spec.md
Normal file
@@ -0,0 +1,87 @@
|
||||
# Capability: 返佣统计缓存管理
|
||||
|
||||
## Purpose
|
||||
|
||||
本 capability 定义如何使用 Redis 和异步任务管理梯度返佣统计数据,支持高并发场景下的性能优化和数据一致性。
|
||||
|
||||
## Requirements
|
||||
|
||||
### Requirement: 异步更新梯度统计数据
|
||||
|
||||
系统 SHALL 在充值订单成功后,通过异步任务更新梯度统计数据,而不是实时计算。异步任务 MUST 使用 Asynq 队列系统实现。
|
||||
|
||||
#### Scenario: 充值成功后发送异步任务
|
||||
- **WHEN** 下级客户充值100元成功
|
||||
- **THEN** 系统立即返回成功,并发送异步任务 "commission:stats:update" 到队列
|
||||
|
||||
#### Scenario: 异步任务更新统计数据
|
||||
- **WHEN** 异步任务执行,payload 包含 allocation_id=123, sales_count=1, sales_amount=10000
|
||||
- **THEN** 系统更新 allocation_id=123 当前周期的统计数据
|
||||
|
||||
#### Scenario: 异步任务失败时重试
|
||||
- **WHEN** 异步任务执行失败(如数据库连接超时)
|
||||
- **THEN** 系统自动重试(最多3次)
|
||||
|
||||
---
|
||||
|
||||
### Requirement: 使用 Redis 缓存统计数据
|
||||
|
||||
系统 SHALL 使用 Redis 缓存梯度统计数据,key 格式为 `commission:stats:{allocation_id}:{period}`,支持原子递增操作。
|
||||
|
||||
#### Scenario: Redis 原子递增销量
|
||||
- **WHEN** 异步任务更新统计时,allocation_id=123,销量+1
|
||||
- **THEN** 系统执行 HINCRBY commission:stats:123:2026-01 total_count 1
|
||||
|
||||
#### Scenario: Redis 原子递增销售额
|
||||
- **WHEN** 异步任务更新统计时,allocation_id=123,销售额+10000
|
||||
- **THEN** 系统执行 HINCRBY commission:stats:123:2026-01 total_amount 10000
|
||||
|
||||
#### Scenario: Redis key 设置过期时间
|
||||
- **WHEN** 创建 Redis key 时,当前周期结束时间为2026-01-31 23:59:59
|
||||
- **THEN** 系统设置 key 过期时间为 2026-02-07 23:59:59(周期结束后7天)
|
||||
|
||||
---
|
||||
|
||||
### Requirement: 定时同步到数据库
|
||||
|
||||
系统 SHALL 每小时执行一次定时任务,将 Redis 中的统计数据同步到数据库表 `tb_shop_series_commission_stats`。
|
||||
|
||||
#### Scenario: 每小时同步 Redis 数据到数据库
|
||||
- **WHEN** 定时任务执行
|
||||
- **THEN** 系统扫描所有 Redis key(pattern: commission:stats:*),批量更新数据库
|
||||
|
||||
#### Scenario: 同步时使用乐观锁避免冲突
|
||||
- **WHEN** 多个任务同时更新同一条统计记录
|
||||
- **THEN** 系统使用 version 字段实现乐观锁,失败时重试
|
||||
|
||||
#### Scenario: 同步后不删除 Redis key
|
||||
- **WHEN** 定时任务同步完成
|
||||
- **THEN** Redis key 保留(用于实时查询),等待过期时间自动清理
|
||||
|
||||
---
|
||||
|
||||
### Requirement: 查询统计数据时优先从 Redis 获取
|
||||
|
||||
系统 SHALL 在查询当前周期的统计数据时,优先从 Redis 获取,Redis 不存在时从数据库获取并回写到 Redis。
|
||||
|
||||
#### Scenario: Redis 存在时直接返回
|
||||
- **WHEN** 查询 allocation_id=123 的当前周期统计
|
||||
- **THEN** 系统从 Redis key `commission:stats:123:2026-01` 获取数据并返回
|
||||
|
||||
#### Scenario: Redis 不存在时从数据库加载
|
||||
- **WHEN** 查询 allocation_id=123 的当前周期统计,Redis key 不存在
|
||||
- **THEN** 系统从数据库查询,并回写到 Redis
|
||||
|
||||
---
|
||||
|
||||
### Requirement: 周期结束后归档统计数据
|
||||
|
||||
系统 SHALL 在每个统计周期结束后,执行归档任务:确保 Redis 数据已同步到数据库,更新统计状态为 "completed",清理 Redis key。
|
||||
|
||||
#### Scenario: 月度周期结束时归档
|
||||
- **WHEN** 2026年1月31日 23:59:59,月度周期结束
|
||||
- **THEN** 系统执行归档任务:同步数据、更新状态为 "completed"、删除 Redis key
|
||||
|
||||
#### Scenario: 归档后统计数据不再更新
|
||||
- **WHEN** 周期已归档(status = "completed")
|
||||
- **THEN** 新的充值订单不再更新该周期的统计数据,而是创建新周期的统计记录
|
||||
61
openspec/specs/shop-commission-tier/spec.md
Normal file
61
openspec/specs/shop-commission-tier/spec.md
Normal file
@@ -0,0 +1,61 @@
|
||||
# Capability: 店铺返佣梯度管理
|
||||
|
||||
## Purpose
|
||||
|
||||
本 capability 定义代理如何为套餐系列分配配置和管理梯度返佣,包括添加、查询、更新和删除梯度配置。
|
||||
|
||||
## Requirements
|
||||
|
||||
### Requirement: 配置梯度佣金
|
||||
|
||||
系统 SHALL 允许代理为套餐系列分配配置梯度佣金。每个梯度包含:梯度类型(销量/销售额)、周期类型(月度/季度/年度)、阈值、达标后的返佣配置(返佣模式和返佣值)。
|
||||
|
||||
#### Scenario: 添加销量梯度佣金
|
||||
- **WHEN** 代理为分配添加梯度:类型=销量,周期=月度,阈值=100,返佣模式=百分比,返佣值=300(30%)
|
||||
- **THEN** 系统创建梯度配置,当下级月销量达到 100 时,返佣提升到 30%
|
||||
|
||||
#### Scenario: 添加销售额梯度佣金
|
||||
- **WHEN** 代理添加梯度:类型=销售额,周期=季度,阈值=100000分,返佣模式=固定,返佣值=3000分(30元)
|
||||
- **THEN** 系统创建梯度配置,当下级季度销售额达到 1000 元时,返佣提升到固定 30 元
|
||||
|
||||
#### Scenario: 添加多个梯度档位
|
||||
- **WHEN** 代理为同一分配添加多个梯度(如:100件=30%,200件=40%,500件=50%)
|
||||
- **THEN** 系统创建多个梯度记录,支持阶梯提升
|
||||
|
||||
---
|
||||
|
||||
### Requirement: 查询梯度佣金配置
|
||||
|
||||
系统 SHALL 提供梯度佣金配置的查询功能,按分配 ID 查询,返回结果按阈值升序排列。
|
||||
|
||||
#### Scenario: 查询分配的梯度配置
|
||||
- **WHEN** 代理查询指定分配的梯度配置
|
||||
- **THEN** 系统返回该分配下的所有梯度配置,按阈值升序排列
|
||||
|
||||
#### Scenario: 分配无梯度配置
|
||||
- **WHEN** 代理查询一个没有配置梯度的分配
|
||||
- **THEN** 系统返回空列表
|
||||
|
||||
---
|
||||
|
||||
### Requirement: 更新梯度佣金配置
|
||||
|
||||
系统 SHALL 允许代理更新梯度配置的阈值和返佣配置。
|
||||
|
||||
#### Scenario: 更新梯度阈值
|
||||
- **WHEN** 代理将梯度阈值从 100 改为 150
|
||||
- **THEN** 系统更新梯度记录
|
||||
|
||||
#### Scenario: 更新梯度返佣配置
|
||||
- **WHEN** 代理将返佣配置从百分比300(30%)改为百分比400(40%)
|
||||
- **THEN** 系统更新梯度记录
|
||||
|
||||
---
|
||||
|
||||
### Requirement: 删除梯度佣金配置
|
||||
|
||||
系统 SHALL 允许代理删除梯度配置。
|
||||
|
||||
#### Scenario: 删除梯度配置
|
||||
- **WHEN** 代理删除指定的梯度配置
|
||||
- **THEN** 系统软删除该梯度记录
|
||||
107
openspec/specs/shop-package-batch-allocation/spec.md
Normal file
107
openspec/specs/shop-package-batch-allocation/spec.md
Normal file
@@ -0,0 +1,107 @@
|
||||
# Capability: 店铺套餐批量分配
|
||||
|
||||
## Purpose
|
||||
|
||||
本 capability 定义代理如何批量为下级店铺分配套餐系列下的所有套餐,支持批量加价和返佣配置,使用事务确保原子性。
|
||||
|
||||
## Requirements
|
||||
|
||||
### Requirement: 代理为下级店铺批量分配套餐系列
|
||||
|
||||
系统 SHALL 允许代理通过指定套餐系列,批量为下级店铺分配该系列下的所有套餐。分配时 MUST 支持可选的批量加价配置(固定金额或百分比)和返佣配置(固定金额或百分比)。
|
||||
|
||||
#### Scenario: 成功批量分配套餐系列
|
||||
- **WHEN** 代理为直属下级店铺分配套餐系列A,系列包含10个套餐
|
||||
- **THEN** 系统创建1条系列分配记录和10条套餐分配记录
|
||||
|
||||
#### Scenario: 批量分配时应用百分比加价
|
||||
- **WHEN** 代理分配时设置百分比加价10%,上级成本价为100元的套餐
|
||||
- **THEN** 下级的成本价为110元(100 × 1.1)
|
||||
|
||||
#### Scenario: 批量分配时应用固定金额加价
|
||||
- **WHEN** 代理分配时设置固定金额加价1000分(10元),上级成本价为100元的套餐
|
||||
- **THEN** 下级的成本价为110元(100 + 10)
|
||||
|
||||
#### Scenario: 批量分配时不加价
|
||||
- **WHEN** 代理分配时不提供加价配置,上级成本价为100元的套餐
|
||||
- **THEN** 下级的成本价为100元(与上级相同)
|
||||
|
||||
#### Scenario: 尝试分配未拥有的系列
|
||||
- **WHEN** 代理尝试分配自己未被分配的套餐系列
|
||||
- **THEN** 系统返回错误 "您没有该套餐系列的分配权限"
|
||||
|
||||
#### Scenario: 尝试分配给非直属下级
|
||||
- **WHEN** 代理尝试分配给非直属下级店铺
|
||||
- **THEN** 系统返回错误 "只能为直属下级分配套餐"
|
||||
|
||||
#### Scenario: 重复分配同一系列
|
||||
- **WHEN** 代理尝试为同一下级店铺重复分配同一套餐系列
|
||||
- **THEN** 系统返回错误 "该店铺已分配此套餐系列"
|
||||
|
||||
---
|
||||
|
||||
### Requirement: 配置基础返佣(固定金额或百分比)
|
||||
|
||||
批量分配时 MUST 配置基础返佣,支持固定金额和百分比两种模式。基础返佣作为梯度返佣的起始值,未达标时使用基础返佣,达标后使用梯度返佣。
|
||||
|
||||
#### Scenario: 配置固定金额返佣
|
||||
- **WHEN** 代理设置基础返佣为固定金额2000分(20元)
|
||||
- **THEN** 下级客户充值100元时,返佣20元(固定)
|
||||
|
||||
#### Scenario: 配置百分比返佣
|
||||
- **WHEN** 代理设置基础返佣为百分比200(20%)
|
||||
- **THEN** 下级客户充值100元时,返佣20元(100 × 20%)
|
||||
|
||||
#### Scenario: 配置百分比返佣(不同充值金额)
|
||||
- **WHEN** 代理设置基础返佣为百分比200(20%)
|
||||
- **THEN** 下级客户充值200元时,返佣40元(200 × 20%)
|
||||
|
||||
---
|
||||
|
||||
### Requirement: 配置梯度返佣
|
||||
|
||||
批量分配时 MAY 配置梯度返佣。梯度返佣 MUST 包含统计周期(月度/季度/年度)、梯度类型(销量/销售额)、阈值和达标后的返佣配置(固定金额或百分比)。一个系列分配 MAY 配置多个梯度档位。
|
||||
|
||||
#### Scenario: 配置月度销量梯度返佣
|
||||
- **WHEN** 代理配置月度销量梯度:销量达100件,返佣提升到30%
|
||||
- **THEN** 下级店铺月销量达到100件后,后续充值按30%返佣
|
||||
|
||||
#### Scenario: 配置多个梯度档位
|
||||
- **WHEN** 代理配置3个梯度档位:100件30%,200件40%,500件50%
|
||||
- **THEN** 系统创建3条梯度配置记录
|
||||
|
||||
#### Scenario: 配置季度销售额梯度返佣
|
||||
- **WHEN** 代理配置季度销售额梯度:销售额达100000分(1000元),返佣提升到固定3000分(30元)
|
||||
- **THEN** 下级店铺季度销售额达到1000元后,后续充值返佣固定30元
|
||||
|
||||
#### Scenario: 不配置梯度返佣
|
||||
- **WHEN** 代理分配时设置 enable_tier_commission = false
|
||||
- **THEN** 系统不创建梯度配置,所有充值按基础返佣计算
|
||||
|
||||
---
|
||||
|
||||
### Requirement: 批量分配使用事务保证原子性
|
||||
|
||||
批量分配操作 MUST 在单个数据库事务中完成,确保要么全部成功,要么全部失败。
|
||||
|
||||
#### Scenario: 部分套餐分配失败时回滚
|
||||
- **WHEN** 批量分配100个套餐时,第50个套餐因唯一约束冲突失败
|
||||
- **THEN** 系统回滚所有已创建的分配记录,返回错误信息
|
||||
|
||||
#### Scenario: 成功分配后提交事务
|
||||
- **WHEN** 批量分配100个套餐全部成功
|
||||
- **THEN** 系统提交事务,所有分配记录持久化
|
||||
|
||||
---
|
||||
|
||||
### Requirement: 批量分配使用 CreateInBatches 优化性能
|
||||
|
||||
批量创建套餐分配记录时 MUST 使用 GORM 的 CreateInBatches 方法,每批不超过500条,避免单次插入过多数据。
|
||||
|
||||
#### Scenario: 分配1000个套餐时分批插入
|
||||
- **WHEN** 批量分配1000个套餐
|
||||
- **THEN** 系统分为2批插入(500 + 500)
|
||||
|
||||
#### Scenario: 分配200个套餐时单批插入
|
||||
- **WHEN** 批量分配200个套餐
|
||||
- **THEN** 系统使用单批插入
|
||||
35
openspec/specs/shop-package-batch-pricing/spec.md
Normal file
35
openspec/specs/shop-package-batch-pricing/spec.md
Normal file
@@ -0,0 +1,35 @@
|
||||
# Capability: 店铺套餐批量调价
|
||||
|
||||
## Purpose
|
||||
|
||||
本 capability 定义代理如何批量调整指定店铺和系列的套餐成本价,支持固定金额和百分比加价,使用事务确保原子性,并记录调价历史。
|
||||
|
||||
## Requirements
|
||||
|
||||
### Requirement: 批量调整套餐成本价
|
||||
|
||||
系统 SHALL 允许代理批量调整指定店铺和系列的所有套餐成本价。调整 MUST 支持固定金额加价和百分比加价两种模式。
|
||||
|
||||
#### Scenario: 批量应用百分比加价
|
||||
- **WHEN** 代理对店铺10的系列5下的所有套餐应用5%加价
|
||||
- **THEN** 系统计算每个套餐的新成本价 = 当前成本价 × 1.05,并批量更新
|
||||
|
||||
#### Scenario: 批量应用固定金额加价
|
||||
- **WHEN** 代理对店铺10的系列5下的所有套餐应用500分(5元)固定加价
|
||||
- **THEN** 系统计算每个套餐的新成本价 = 当前成本价 + 500,并批量更新
|
||||
|
||||
#### Scenario: 批量调价时记录历史
|
||||
- **WHEN** 批量调整15个套餐的成本价
|
||||
- **THEN** 系统创建15条成本价历史记录
|
||||
|
||||
#### Scenario: 批量调价使用事务
|
||||
- **WHEN** 批量调整100个套餐成本价时,第50个套餐更新失败
|
||||
- **THEN** 系统回滚所有已更新的成本价,返回错误信息
|
||||
|
||||
#### Scenario: 不指定系列时调整店铺所有套餐
|
||||
- **WHEN** 代理对店铺10应用5%加价,不指定系列
|
||||
- **THEN** 系统调整该店铺所有已分配套餐的成本价
|
||||
|
||||
#### Scenario: 验证新成本价不低于上级成本价
|
||||
- **WHEN** 批量调价后,某个套餐的新成本价低于上级成本价
|
||||
- **THEN** 系统返回错误 "成本价不能低于上级成本价"
|
||||
93
openspec/specs/shop-series-allocation/spec.md
Normal file
93
openspec/specs/shop-series-allocation/spec.md
Normal file
@@ -0,0 +1,93 @@
|
||||
# Capability: 店铺套餐系列分配管理
|
||||
|
||||
## Purpose
|
||||
|
||||
本 capability 定义代理如何为下级店铺分配套餐系列,以及平台如何为一级代理分配。分配时需要配置基础返佣和可选的梯度返佣。
|
||||
|
||||
## Requirements
|
||||
|
||||
### Requirement: 为下级店铺分配套餐系列
|
||||
|
||||
系统 SHALL 允许代理为其直属下级店铺分配套餐系列。分配时 MUST 指定基础返佣配置(返佣模式和返佣值),MAY 启用梯度返佣。分配者只能分配自己已被分配的套餐系列。
|
||||
|
||||
#### Scenario: 成功分配套餐系列
|
||||
- **WHEN** 代理为直属下级店铺分配一个自己拥有的套餐系列,设置基础返佣为百分比200(20%)
|
||||
- **THEN** 系统创建分配记录
|
||||
|
||||
#### Scenario: 尝试分配未拥有的系列
|
||||
- **WHEN** 代理尝试分配自己未被分配的套餐系列
|
||||
- **THEN** 系统返回错误 "您没有该套餐系列的分配权限"
|
||||
|
||||
#### Scenario: 尝试分配给非直属下级
|
||||
- **WHEN** 代理尝试分配给非直属下级店铺
|
||||
- **THEN** 系统返回错误 "只能为直属下级分配套餐"
|
||||
|
||||
#### Scenario: 重复分配同一系列
|
||||
- **WHEN** 代理尝试为同一下级店铺重复分配同一套餐系列
|
||||
- **THEN** 系统返回错误 "该店铺已分配此套餐系列"
|
||||
|
||||
---
|
||||
|
||||
### Requirement: 查询套餐系列分配列表
|
||||
|
||||
系统 SHALL 提供分配列表查询,支持按下级店铺筛选、按套餐系列筛选、按状态筛选。
|
||||
|
||||
#### Scenario: 查询所有分配
|
||||
- **WHEN** 代理查询分配列表,不带筛选条件
|
||||
- **THEN** 系统返回该代理创建的所有分配记录
|
||||
|
||||
#### Scenario: 按店铺筛选
|
||||
- **WHEN** 代理指定下级店铺 ID 筛选
|
||||
- **THEN** 系统只返回该店铺的分配记录
|
||||
|
||||
---
|
||||
|
||||
### Requirement: 更新套餐系列分配
|
||||
|
||||
系统 SHALL 允许代理更新分配的基础返佣配置和梯度返佣开关。更新返佣配置时 MUST 创建新的配置版本。
|
||||
|
||||
#### Scenario: 更新基础返佣配置时创建新版本
|
||||
- **WHEN** 代理将基础返佣从20%改为25%
|
||||
- **THEN** 系统更新分配记录,并创建新配置版本
|
||||
|
||||
#### Scenario: 更新不存在的分配
|
||||
- **WHEN** 代理更新不存在的分配 ID
|
||||
- **THEN** 系统返回 "分配记录不存在" 错误
|
||||
|
||||
---
|
||||
|
||||
### Requirement: 删除套餐系列分配
|
||||
|
||||
系统 SHALL 允许代理删除分配记录。如果有下级依赖此分配,MUST 禁止删除。
|
||||
|
||||
#### Scenario: 成功删除无依赖的分配
|
||||
- **WHEN** 代理删除一个没有下级依赖的分配记录
|
||||
- **THEN** 系统软删除该记录
|
||||
|
||||
#### Scenario: 尝试删除有下级依赖的分配
|
||||
- **WHEN** 代理尝试删除一个已被下级使用的分配(下级基于此分配又分配给了更下级)
|
||||
- **THEN** 系统返回错误 "存在下级依赖,无法删除"
|
||||
|
||||
---
|
||||
|
||||
### Requirement: 启用/禁用套餐系列分配
|
||||
|
||||
系统 SHALL 允许代理切换分配的启用状态。禁用后下级 MUST NOT 能使用该分配购买套餐。
|
||||
|
||||
#### Scenario: 禁用分配
|
||||
- **WHEN** 代理将分配状态设为禁用
|
||||
- **THEN** 系统更新状态,下级无法基于此分配购买套餐
|
||||
|
||||
#### Scenario: 启用分配
|
||||
- **WHEN** 代理将禁用的分配设为启用
|
||||
- **THEN** 系统更新状态,下级可以继续使用
|
||||
|
||||
---
|
||||
|
||||
### Requirement: 平台分配套餐系列
|
||||
|
||||
平台管理员 SHALL 能够为一级代理分配套餐系列。平台的成本价基准为 Package.suggested_cost_price。
|
||||
|
||||
#### Scenario: 平台为一级代理分配
|
||||
- **WHEN** 平台管理员为一级代理分配套餐系列
|
||||
- **THEN** 系统创建分配记录
|
||||
Reference in New Issue
Block a user