|
|
@@ -1,5 +1,5 @@
|
|
|
# 分销与积分体系重构设计 v2
|
|
|
-> 从两级分销 → 一级分销(统一40%)+ 间接邀请积分 + 能量师团队分红
|
|
|
+> 从两级分销 → 一级分销(统一40%)+ 间接邀请积分 + 能量师月度分红(资金池竞争制)
|
|
|
> 状态:v1.0 参数全部锁定,待编码实现
|
|
|
|
|
|
---
|
|
|
@@ -7,8 +7,8 @@
|
|
|
## 一、设计目标
|
|
|
|
|
|
1. **简化层级**:取消二级佣金(A的下级B再推荐C,A不再拿C的佣金)
|
|
|
-2. **扩大分销主体**:所有付费用户(C端/家庭套餐/超级会员)均可发展下级,系统运营官(tarunner)有每日邀请上限
|
|
|
-3. **能量师团队制**:能量师组建团队,享受团队销售利润分红
|
|
|
+2. **扩大分销主体**:所有付费用户(C端/家庭套餐)均可发展下级,系统运营官(tarunner)有每日邀请上限
|
|
|
+3. **能量师团队制**:能量师组建团队,享受月度资金池分红(个人池5%+团队池5%,按占比竞争分配)
|
|
|
4. **合规性**:一级分销 + 团队分红(非直推计酬),符合《禁止传销条例》
|
|
|
|
|
|
---
|
|
|
@@ -33,10 +33,6 @@
|
|
|
|
|
|
---
|
|
|
|
|
|
-## 三、佣金与积分触发事件
|
|
|
-
|
|
|
----
|
|
|
-
|
|
|
## 三、触发事件与结算规则
|
|
|
|
|
|
### 3.1 直接邀请佣金(一级)
|
|
|
@@ -48,7 +44,8 @@
|
|
|
| 购买 超级会员 ¥1,314 | 40% 佣金(¥525.60) | 10 积分 | ❌ |
|
|
|
| 购买 能量师 ¥1,314+ | 40% 佣金(¥525.60) | 10 积分 | ✅(能量师的直接上级拿佣金,能量师自己的团队拿分红) |
|
|
|
|
|
|
-> **注意**:直接邀请不赠送积分,仅结算佣金。间接邀请不结算佣金,仅奖励 10 积分。团队分红不是多级佣金,而是能量师作为团队长的管理绩效奖。
|
|
|
+> **注意**:直接邀请不赠送积分,仅结算佣金。间接邀请不结算佣金,仅奖励 10 积分。团队分红不是多级佣金,而是能量师作为团队长的月度资金池竞争分配(按占池比例)。
|
|
|
+> 更多分红细则见 §4.3。
|
|
|
|
|
|
|
|
|
|
|
|
@@ -90,26 +87,75 @@
|
|
|
|
|
|
> 10 积分为示例值,通过 `sys_config.indirect_invite.points` 可动态调整。
|
|
|
|
|
|
-### 4.3 能量师团队分红(与积分挂钩)
|
|
|
+### 4.3 能量师月度分红(资金池竞争制)
|
|
|
+
|
|
|
+> 平台拿出月总收入的 **10%** 作为分红总池,拆分为个人分红池(5%)和团队分红池(5%),按参与者的销售占比竞争分配。
|
|
|
+
|
|
|
+#### 核心公式
|
|
|
|
|
|
```
|
|
|
-能量师 A 的直接下级团队购买:
|
|
|
-├── B 购买 → A 团队分红基数 += 购买金额
|
|
|
-├── C 购买 → A 团队分红基数 += 购买金额
|
|
|
-└── D 购买 → A 团队分红基数 += 购买金额
|
|
|
+平台月总收入 = 当月所有付费订单实付金额总和(扣除退款)
|
|
|
|
|
|
-月末结算:
|
|
|
-团队分红金额 = 团队月度总销售额 × 团队分红比例(5%)
|
|
|
+个人分红池 = 平台月总收入 × 5%
|
|
|
+团队分红池 = 平台月总收入 × 5%
|
|
|
+总分红池 = 平台月总收入 × 10%
|
|
|
```
|
|
|
|
|
|
-团队分红可额外挂钩积分激励:每月团队销售产生的积分可转化为能量师个人积分,作为其团队贡献值的计算依据。
|
|
|
+#### 个人分红
|
|
|
+
|
|
|
+```
|
|
|
+个人当月直接销售额 = 该能量师直接下级的所有付费订单总和
|
|
|
+所有活跃能量师直接销售总额 = Σ(每个人直接销售额)
|
|
|
+个人分红 = (个人直接销售额 / 所有活跃能量师直接销售总额) × 个人分红池
|
|
|
+```
|
|
|
+
|
|
|
+#### 团队分红
|
|
|
+
|
|
|
+```
|
|
|
+个人当月团队销售额 = 该能量师团队的总付费订单(不限层级,逐层递归,
|
|
|
+ 遇到当月无直接销售的成员则截断该分支,不计入)
|
|
|
+所有能量师团队销售总额 = Σ(每个人团队销售额)
|
|
|
+团队分红 = (个人团队销售额 / 所有能量师团队销售总额) × 团队分红池
|
|
|
+```
|
|
|
+
|
|
|
+#### 单人月分红总额
|
|
|
+
|
|
|
+```
|
|
|
+月分红总额 = 个人分红 + 团队分红
|
|
|
+```
|
|
|
+
|
|
|
+#### 示例
|
|
|
+
|
|
|
+```
|
|
|
+平台月总收入:¥100,000
|
|
|
+个人分红池:¥5,000 团队分红池:¥5,000
|
|
|
+
|
|
|
+参与分红的活跃能量师共 3 人:
|
|
|
+
|
|
|
+ 个人直销额 占个人池 个人分红 团队销售额 占团队池 团队分红
|
|
|
+A ¥20,000 20% ¥1,000 ¥40,000 20% ¥1,000
|
|
|
+B ¥50,000 50% ¥2,500 ¥100,000 50% ¥2,500
|
|
|
+C ¥30,000 30% ¥1,500 ¥60,000 30% ¥1,500
|
|
|
+ ──────── ────── ──────── ──────── ────── ────────
|
|
|
+总计 ¥100,000 100% ¥5,000 ✅ ¥200,000 100% ¥5,000 ✅
|
|
|
+```
|
|
|
+
|
|
|
+#### 月月独立判定
|
|
|
+
|
|
|
+```
|
|
|
+当月无直接销售 → 当月不参与任何分红(个人池 + 团队池均不参与)
|
|
|
+下月有销售 → 自动恢复,无需申请
|
|
|
+无"累积月数"概念,每月独立评判
|
|
|
+```
|
|
|
|
|
|
| 指标 | 默认值 | 说明 |
|
|
|
|------|--------|------|
|
|
|
-| 团队分红比例 | **5%** | 团队月度总销售额的 5% |
|
|
|
+| 个人分红池比例 | **5%** | 平台月总收入×5% 作为个人分红竞争池 |
|
|
|
+| 团队分红池比例 | **5%** | 平台月总收入×5% 作为团队分红竞争池 |
|
|
|
| 结算周期 | **每月** | 每月 1 日结算上月数据 |
|
|
|
-| 最低发放门槛 | ¥50 | 分红 < ¥50 滚入下月 |
|
|
|
-| 计算范围 | 直接下级 | 仅第一层,不递归 |
|
|
|
+| 最低发放门槛 | ¥100 | 分红 < ¥100 滚入下月 |
|
|
|
+| 团队层级 | **不限层级** | 递归至当月无销售成员截断该分支 |
|
|
|
+| 分红数据基数 | 订单实付金额 | 扣除退款后的实付金额 |
|
|
|
|
|
|
### 4.4 积分抵扣兑换规则(用户侧)
|
|
|
|
|
|
@@ -128,17 +174,22 @@
|
|
|
场景:推广者 A 发展了 2 个直接下级 B、C
|
|
|
|
|
|
B 通过 A 的推广码购买 C端会员 ¥131
|
|
|
-→ A 佣金 = ¥131 × 40% = ¥52.40
|
|
|
+→ A 佣金 = ¥131 × 40% = ¥52.40(即时结算)
|
|
|
+→ A 的个人直销额增加 ¥131(计入月度个人分红池竞争)
|
|
|
|
|
|
C 通过 B 的推广码购买 家庭套餐 ¥686(A 的间接邀请)
|
|
|
→ A 佣金 = 0(只有直接邀请才有佣金)
|
|
|
→ A 获得间接积分 = 10 积分
|
|
|
+
|
|
|
+月末结算(A 为能量师):
|
|
|
+- 个人当月直接销售额 = ¥131 + ...(A 所有直接下级本月购买)
|
|
|
+- 团队当月销售额 = A + B + C + ...(递归,遇无销售截断)
|
|
|
+- 个人分红 = (个人直接销售额 / 全部分红池) × 平台总收入 × 5%
|
|
|
+- 团队分红 = (团队销售额 / 全部团队池) × 平台总收入 × 5%
|
|
|
```
|
|
|
|
|
|
---
|
|
|
|
|
|
-## 五、与现有 sys_config 的对应关系
|
|
|
-
|
|
|
## 五、与旧体系对比
|
|
|
|
|
|
| 维度 | 旧体系(两级分销) | 新体系(一级+团队分红) |
|
|
|
@@ -185,33 +236,78 @@ public void settleFirstLevelCommission(Long buyerId, Long productId, int amountF
|
|
|
commissionRepo.save(c);
|
|
|
}
|
|
|
|
|
|
-// 2. 团队分红(月度批量结算,仅能量师)
|
|
|
+// 2. 团队分红(月度批量结算,资金池竞争制)
|
|
|
@Scheduled(cron = "0 0 1 * * ?") // 每月1日 00:00
|
|
|
-public void settleTeamBonus() {
|
|
|
- // 找出所有能量师
|
|
|
- List<User> practitioners = userRepo.findByVipType("practitioner");
|
|
|
+public void settleMonthlyBonus() {
|
|
|
+ // 第一步:计算平台当月总收入(实付金额,扣除退款)
|
|
|
+ int totalRevenue = orderRepo.sumMonthlyPaidAmount(LocalDate.now().withDayOfMonth(1));
|
|
|
+ int personalPool = totalRevenue * 5 / 100; // 5% 个人分红池
|
|
|
+ int teamPool = totalRevenue * 5 / 100; // 5% 团队分红池
|
|
|
+
|
|
|
+ // 第二步:查询所有能量师,判定当月资格
|
|
|
+ List<User> allPractitioners = userRepo.findByVipType("practitioner");
|
|
|
|
|
|
- for (User practitioner : practitioners) {
|
|
|
- // 直接下级团队
|
|
|
- List<User> directTeam = userRepo.findByReferrerId(practitioner.getId());
|
|
|
-
|
|
|
- // 计算团队月度购买总额
|
|
|
- int teamMonthlySales = commissionRepo.sumTeamMonthlySales(directTeam);
|
|
|
+ // 统计每个能量师当月直接销售额
|
|
|
+ Map<Long, Integer> personalSales = new HashMap<>();
|
|
|
+ for (User p : allPractitioners) {
|
|
|
+ int sales = orderRepo.sumDirectMonthlySales(p.getId(), yearMonth);
|
|
|
+ personalSales.put(p.getId(), sales);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 第三步:筛选活跃能量师(当月有直接销售)
|
|
|
+ List<Long> activeIds = personalSales.entrySet().stream()
|
|
|
+ .filter(e -> e.getValue() > 0)
|
|
|
+ .map(e -> e.getKey())
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ // 第四步:计算活跃能量师的团队销售额(递归,遇无销售截断)
|
|
|
+ Map<Long, Integer> teamSales = new HashMap<>();
|
|
|
+ for (Long id : activeIds) {
|
|
|
+ teamSales.put(id, calcTeamSalesRecursive(id, yearMonth));
|
|
|
+ }
|
|
|
+
|
|
|
+ // 第五步:计算总分母
|
|
|
+ int totalPersonalSales = personalSales.entrySet().stream()
|
|
|
+ .filter(e -> activeIds.contains(e.getKey()))
|
|
|
+ .mapToInt(e -> e.getValue()).sum();
|
|
|
+ int totalTeamSales = teamSales.values().stream().mapToInt(Integer::intValue).sum();
|
|
|
+
|
|
|
+ // 第六步:对每个活跃能量师计算占比和分红
|
|
|
+ for (Long id : activeIds) {
|
|
|
+ int pSales = personalSales.get(id);
|
|
|
+ int tSales = teamSales.getOrDefault(id, 0);
|
|
|
|
|
|
- // 团队分红 = 销售额 × 5%
|
|
|
- BigDecimal bonus = new BigDecimal(teamMonthlySales).multiply(new BigDecimal("0.05"));
|
|
|
+ // 个人分红 = (个人销售额 / 总个人销售额) × 个人分红池
|
|
|
+ int personalBonus = totalPersonalSales > 0
|
|
|
+ ? (int)((long)pSales * personalPool / totalPersonalSales) : 0;
|
|
|
+ // 团队分红 = (团队销售额 / 总团队销售额) × 团队分红池
|
|
|
+ int teamBonus = totalTeamSales > 0
|
|
|
+ ? (int)((long)tSales * teamPool / totalTeamSales) : 0;
|
|
|
|
|
|
- if (bonus.compareTo(new BigDecimal(5000)) < 0) continue; // < ¥50 跳过
|
|
|
+ if (personalBonus + teamBonus < 10000) continue; // < ¥100 滚入下月
|
|
|
|
|
|
- // 创建分红记录
|
|
|
- Commission c = new Commission();
|
|
|
- c.setUserId(practitioner.getId());
|
|
|
- c.setAmountFen(bonus.intValue());
|
|
|
- c.setLevel(0); // 0 = 团队分红(特殊标记)
|
|
|
- c.setStatus("available");
|
|
|
- c.setRemark("月度团队分红");
|
|
|
- commissionRepo.save(c);
|
|
|
+ // 写入分红记录
|
|
|
+ insertBonusRecord(id, yearMonth, totalRevenue,
|
|
|
+ personalPool, teamPool,
|
|
|
+ pSales, totalPersonalSales, personalBonus,
|
|
|
+ tSales, totalTeamSales, teamBonus);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// 递归计算团队销售额:有销售则继续向下,遇无销售截断
|
|
|
+private int calcTeamSalesRecursive(Long userId, String yearMonth) {
|
|
|
+ int selfSales = orderRepo.sumDirectMonthlySales(userId, yearMonth);
|
|
|
+ List<User> subordinates = userRepo.findByReferrerId(userId);
|
|
|
+
|
|
|
+ int teamSales = selfSales;
|
|
|
+ for (User sub : subordinates) {
|
|
|
+ int subSales = orderRepo.sumDirectMonthlySales(sub.getId(), yearMonth);
|
|
|
+ if (subSales > 0) {
|
|
|
+ teamSales += calcTeamSalesRecursive(sub.getId(), yearMonth);
|
|
|
+ }
|
|
|
+ // 无销售截断,不继续向下
|
|
|
}
|
|
|
+ return teamSales;
|
|
|
}
|
|
|
```
|
|
|
|
|
|
@@ -229,33 +325,62 @@ ALTER TABLE commissions
|
|
|
MODIFY COLUMN level INT COMMENT '0=团队分红 1=一级佣金 2=预留';
|
|
|
```
|
|
|
|
|
|
-#### 新增 `team_bonus_monthly` 汇总表(可选,用于对账)
|
|
|
+#### 新增 `monthly_bonus_records` 月度分红结算表
|
|
|
|
|
|
```sql
|
|
|
-CREATE TABLE `team_bonus_monthly` (
|
|
|
+CREATE TABLE `monthly_bonus_records` (
|
|
|
`id` BIGINT PRIMARY KEY AUTO_INCREMENT,
|
|
|
- `practitioner_id` BIGINT NOT NULL,
|
|
|
- `year_month` VARCHAR(7) NOT NULL, -- '2026-06'
|
|
|
- `team_sales_fen` INT NOT NULL DEFAULT 0,
|
|
|
- `bonus_fen` INT NOT NULL DEFAULT 0,
|
|
|
- `member_count` INT NOT NULL DEFAULT 0,
|
|
|
- `settled_at` DATETIME,
|
|
|
- UNIQUE KEY `uk_practitioner_month` (`practitioner_id`, `year_month`)
|
|
|
-) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
|
|
+ `energy_master_id` BIGINT NOT NULL COMMENT '能量师用户ID',
|
|
|
+ `year_month` VARCHAR(7) NOT NULL COMMENT '结算月份(如 2026-06)',
|
|
|
+
|
|
|
+ -- 平台数据
|
|
|
+ `platform_revenue_fen` BIGINT NOT NULL DEFAULT 0 COMMENT '平台当月总收入(分)',
|
|
|
+ `personal_pool_fen` BIGINT NOT NULL DEFAULT 0 COMMENT '个人分红池总金额(分)',
|
|
|
+ `team_pool_fen` BIGINT NOT NULL DEFAULT 0 COMMENT '团队分红池总金额(分)',
|
|
|
+
|
|
|
+ -- 个人销售数据
|
|
|
+ `personal_sales_fen` BIGINT NOT NULL DEFAULT 0 COMMENT '个人直接销售金额(分)',
|
|
|
+ `total_personal_sales_fen` BIGINT NOT NULL DEFAULT 0 COMMENT '所有活跃能量师直接销售总额(分)',
|
|
|
+ `personal_share_pct` INT NOT NULL DEFAULT 0 COMMENT '个人占池百分比(万分比,如 2000=20%)',
|
|
|
+
|
|
|
+ -- 团队销售数据
|
|
|
+ `team_sales_fen` BIGINT NOT NULL DEFAULT 0 COMMENT '个人团队销售金额(分)',
|
|
|
+ `total_team_sales_fen` BIGINT NOT NULL DEFAULT 0 COMMENT '所有活跃能量师团队销售总额(分)',
|
|
|
+ `team_share_pct` INT NOT NULL DEFAULT 0 COMMENT '团队占池百分比(万分比)',
|
|
|
+
|
|
|
+ -- 分红结果
|
|
|
+ `personal_bonus_fen` BIGINT NOT NULL DEFAULT 0 COMMENT '个人分红金额(分)',
|
|
|
+ `team_bonus_fen` BIGINT NOT NULL DEFAULT 0 COMMENT '团队分红金额(分)',
|
|
|
+ `total_bonus_fen` BIGINT NOT NULL DEFAULT 0 COMMENT '总分红金额(分)',
|
|
|
+
|
|
|
+ -- 资格状态
|
|
|
+ `qualified` TINYINT(1) NOT NULL DEFAULT 0 COMMENT '当月是否合格(0=不合格 1=合格)',
|
|
|
+
|
|
|
+ -- 结算状态
|
|
|
+ `status` VARCHAR(20) NOT NULL DEFAULT 'pending' COMMENT 'pending/approved/paid/cancelled',
|
|
|
+ `settled_at` DATETIME COMMENT '结算处理时间',
|
|
|
+ `paid_at` DATETIME COMMENT '实际发放时间',
|
|
|
+ `remark` VARCHAR(200) COMMENT '备注',
|
|
|
+
|
|
|
+ UNIQUE KEY `uk_master_month` (`energy_master_id`, `year_month`),
|
|
|
+ INDEX `idx_year_month` (`year_month`),
|
|
|
+ INDEX `idx_status` (`status`)
|
|
|
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='能量师月度分红结算表';
|
|
|
```
|
|
|
|
|
|
### 6.3 sys_config 参数
|
|
|
|
|
|
```sql
|
|
|
--- 一级分销佣金(统一比例)
|
|
|
INSERT INTO sys_config (`key`, `value`, `desc`, `value_type`) VALUES
|
|
|
+-- 一级分销佣金(统一比例)
|
|
|
('commission.level1.rate_unified', '4000', '一级佣金统一万分比(4000=40%)', 'percent'),
|
|
|
-- 间接邀请积分
|
|
|
('commission.indirect_invite.points', '10', '间接邀请(二级)每次付费奖励积分(固定值)', 'number'),
|
|
|
--- 团队分红
|
|
|
-('commission.team_bonus.rate', '500', '团队月度分红万分比(500=5%)', 'percent'),
|
|
|
-('commission.team_bonus.min_payout', '5000', '团队分红最低发放金额(分,¥50)', 'amount'),
|
|
|
-('commission.team_bonus.settlement_day', '1', '月度分红结算日(每月第几天)', 'number'),
|
|
|
+-- 分红方案(资金池制)
|
|
|
+('bonus.personal.pool_rate', '500', '个人分红池占总收入万分比(500=5%)', 'percent'),
|
|
|
+('bonus.team.pool_rate', '500', '团队分红池占总收入万分比(500=5%)', 'percent'),
|
|
|
+('bonus.settlement_day', '1', '月度结算日(每月第几天)', 'number'),
|
|
|
+('bonus.min_payout', '10000', '最低发放金额(分,¥100),不足滚入下月', 'amount'),
|
|
|
-- 团队规模上限
|
|
|
('commission.team.max_members', '5', '能量师直接下级人数上限(0=不限制)', 'number'),
|
|
|
-- tarunner(系统运营官)每日邀请上限
|
|
|
@@ -313,7 +438,7 @@ INSERT INTO sys_config (`key`, `value`, `desc`, `value_type`) VALUES
|
|
|
| `UserService.hasPermission()` | 推广权限从 `practitioner` 扩展为所有付费用户 | 修改判断条件 |
|
|
|
| 个人中心推广码 | 能量师专属 → 所有付费用户可见 | UI 改为按角色展示 |
|
|
|
| 提现系统 | 不影响 | 佣金来源变了,提现逻辑不变 |
|
|
|
-| 团队分红 | 新功能 | 新增月度定时任务 |
|
|
|
+| 团队分红(资金池制) | 新功能(替换旧5%单轨) | 新增 monthly_bonus_records 表 + 递归团队计算 |
|
|
|
|
|
|
---
|
|
|
|
|
|
@@ -321,13 +446,19 @@ INSERT INTO sys_config (`key`, `value`, `desc`, `value_type`) VALUES
|
|
|
|
|
|
| 决策项 | 结论 | 落地位置 |
|
|
|
|--------|------|---------|
|
|
|
-| 佣金比例(一级) | C端15% / 家庭18% / 能量师20% | sys_config `commission.level1.*` |
|
|
|
-| 团队分红比例 | 5%(月度直接下级销售额) | sys_config `commission.team_bonus.rate` |
|
|
|
+| 佣金比例(一级) | **统一40%**(所有付费用户) | sys_config `commission.level1.rate_unified=4000` |
|
|
|
+| 间接邀请 | **10积分**(无佣金) | sys_config `commission.indirect_invite.points=10` |
|
|
|
+| 种子用户 | **不限创始人码,仅限时间+名额**,同样享受40%分佣 | phase1-user-stories US-6.x |
|
|
|
+| 个人分红池 | **平台月总收入×5%**,按个人直接销售占比竞争分配 | sys_config `bonus.personal.pool_rate=500` |
|
|
|
+| 团队分红池 | **平台月总收入×5%**,按团队销售额占比竞争分配 | sys_config `bonus.team.pool_rate=500` |
|
|
|
+| 分红淘汰规则 | **月月独立**:当月无销售当月不参与,下月自动恢复 | monthly_bonus_records.qualified |
|
|
|
+| 最低发放金额 | **¥100**,不足滚入下月 | sys_config `bonus.min_payout=10000` |
|
|
|
+| 团队层级 | **不限层级**,遇当月无销售成员截断该分支 | calcTeamSalesRecursive() |
|
|
|
| 团队规模上限 | 直接下级 **5人**,之后按负载放开 | 代码硬上限 + 配置化预留 |
|
|
|
| tarunner 邀请策略 | **选项A**:默认日限,按需放开 | sys_config `tarunner.invite_daily_limit` + `system.allow_tarunner` |
|
|
|
| 超级会员上线节奏 | 暂缓,v1.0 不包含 | 文档标记「暂缓」,不投入开发 |
|
|
|
| 升级路径 | 全部含在当前版本,不分拆 v1.1 | 实现清单归一到 v1.0 |
|
|
|
-| 团队分红基数 | 所有购买事件(C端/家庭/能量师)均计入 | `team_bonus_monthly` 聚合逻辑 |
|
|
|
+| 分红数据基数 | 订单实付金额(扣除退款) | orderRepo.sumMonthlyPaidAmount() |
|
|
|
|
|
|
---
|
|
|
|