Explorar el Código

feat: 免费用户可分享推荐并获得40%分佣(与付费用户相同比例)

- OrderService.handleAnnualCommission() 移除 referralCode 检查
- OrderService.handleSuperMemberCommission() 移除 referralCode 检查
- OrderService.handlePractitionerCommission() 免费用户按 C 端半额处理
- distribution-model-v2.md 更新角色矩阵(普通用户可发展下级=✅)
- distribution-model-v2.md 新增免费用户分佣说明
- 影响范围:所有用户(含免费)推荐他人付费时获得40%佣金
liaoxg hace 3 meses
padre
commit
e59f75e6af

+ 7 - 4
docs/distribution-model-v2.md

@@ -17,15 +17,15 @@
 
 | 角色 | 年费 | 可发展下级 | 一级佣金 | 团队分红 | 数据库标记 | 每日邀请上限 |
 |------|------|-----------|---------|---------|-----------|------------|
-| 普通用户 | ¥0 | ❌ | — | — | `vipType=NULL` | — |
-| C端会员 | ¥131 | ✅ | 直接邀请40% | ❌ | `vipType='annual'` | 默认受限,按需放开 |
+| 普通用户 | ¥0 | ✅ | **直接邀请40%**(与付费用户相同) | ❌ | `vipType=NULL` | 默认受限,按需放开 |
+| C 端会员 | ¥131 | ✅ | 直接邀请40% | ❌ | `vipType='annual'` | 默认受限,按需放开 |
 | 家庭套餐 | ¥686 | ✅ | 直接邀请40% | ❌ | `vipType='family_plan'` | 默认受限,按需放开 |
 | 超级会员 | ¥1,314 | ✅ | 直接邀请40% | ❌ | `vipType='super_annual'`(暂缓) | 默认受限,按需放开 |
 | 能量师 | ¥1,314+ | ✅ | 直接邀请40% | ✅ | `vipType='practitioner'` | 默认开放 |
 | 系统运营官 | — | ✅ | 直接邀请40% | ❌ | `role='tarunner'` | 按配置 |
 
 **核心规则:**
-- 只有付费用户可以发展下级(免费用户不行
+- **所有用户(含免费用户)均可发展下级**,免费用户与付费用户享受相同分佣比例(40%
 - 直接邀请佣金 = 购买金额 × 40%,即时结算
 - 间接邀请不结算佣金,仅奖励 10 积分/次
 - 同一用户只能被邀请一次(上级锁定,不可变更)
@@ -48,6 +48,8 @@
 > 更多分红细则见 §4.3。
 > 
 > **种子价用户分佣说明**:以种子价(¥1,314)购买的能量师同样享受 40% 直接邀请佣金,与标准价购买用户权益一致。
+> 
+> **免费用户分佣说明**:免费用户(`vipType=NULL`)推荐他人付费时,同样享受 40% 直接邀请佣金,与付费用户比例相同。佣金在订单支付成功后即时结算。
 
 
 
@@ -448,8 +450,9 @@ INSERT INTO sys_config (`key`, `value`, `desc`, `value_type`) VALUES
 
 | 决策项 | 结论 | 落地位置 |
 |--------|------|---------|
-| 佣金比例(一级) | **统一40%**(所有费用户) | sys_config `commission.level1.rate_unified=4000` |
+| 佣金比例(一级) | **统一40%**(所有用户,含免费用户) | sys_config `commission.level1.rate_unified=4000` |
 | 间接邀请 | **10积分**(无佣金) | sys_config `commission.indirect_invite.points=10` |
+| 免费用户分佣 | ✅ **与付费用户相同比例(40%)** | OrderService 移除 referralCode 检查 |
 | 种子用户 | **不限创始人码,仅限时间+名额**,同样享受40%分佣 | phase1-user-stories US-6.x |
 | 个人分红池 | **平台月总收入×5%**,按个人直接销售占比竞争分配 | sys_config `bonus.personal.pool_rate=500` |
 | 团队分红池 | **平台月总收入×5%**,按团队销售额占比竞争分配 | sys_config `bonus.team.pool_rate=500` |

+ 21 - 19
num-server/src/main/java/com/etotem/num/service/OrderService.java

@@ -104,12 +104,13 @@ public class OrderService {
         }
     }
 
-    /**
-     * US-6.4: C端佣金结算 — 按比例分成
+/**
+     * US-6.4: C 端佣金结算 — 按比例分成
+     * 推荐人无需付费,免费用户与付费用户享受相同分佣比例(40%)。
      */
     private void handleAnnualCommission(Order order, User buyer, User inviter) {
-        // AC 5-7: 收款人必须已付费 (referralCode != null)
-        if (inviter.getReferralCode() == null) return;
+        // 移除付费检查:免费用户也可以获得佣金
+        // if (inviter.getReferralCode() == null) return; // REMOVED
 
         int directRate = configService.getInt("commission.annual.direct_rate", 4000); // 万分比
         int upstreamRate = configService.getInt("commission.annual.upstream_rate", 500);
@@ -117,24 +118,25 @@ public class OrderService {
         int l1Amount = order.getTotalFee() * directRate / 10000;
         int l2Amount = order.getTotalFee() * upstreamRate / 10000;
 
-        String l1Remark = String.format("C端年费直接推荐佣金 (%d%%)", directRate / 100);
-        createCommission(order.getId(), buyer.getId(), inviter.getId(), 1, l1Amount, l1Remark);
+        String l1Remark = String.format("C 端年费直接推荐佣金 (%d%%)", directRate / 100);
+createCommission(order.getId(), buyer.getId(), inviter.getId(), 1, l1Amount, l1Remark);
 
         if (inviter.getInvitedBy() != null && l2Amount > 0) {
             User inviter2 = userRepository.findById(inviter.getInvitedBy()).orElse(null);
-            if (inviter2 != null && inviter2.getReferralCode() != null) {
-                String l2Remark = String.format("C端年费上级佣金 (%d%%)", upstreamRate / 100);
+            if (inviter2 != null && l2Amount > 0) {
+                String l2Remark = String.format("C 端年费上级佣金 (%d%%)", upstreamRate / 100);
                 createCommission(order.getId(), buyer.getId(), inviter2.getId(), 2, l2Amount, l2Remark);
             }
         }
     }
 
     /**
-     * 超级会员佣金结算 — 按比例分成 (同C端年费模式)
+     * 超级会员佣金结算 — 按比例分成 (同 C 端年费模式)
+     * 推荐人无需付费,免费用户与付费用户享受相同分佣比例。
      */
     private void handleSuperMemberCommission(Order order, User buyer, User inviter) {
-        // 收款人必须已付费 (referralCode != null)
-        if (inviter.getReferralCode() == null) return;
+        // 移除付费检查:免费用户也可以获得佣金
+        // if (inviter.getReferralCode() == null) return; // REMOVED
 
         int directRate = configService.getInt("commission.super_member.direct_rate", 3000); // 万分比
         int upstreamRate = configService.getInt("commission.super_member.upstream_rate", 500);
@@ -147,7 +149,7 @@ public class OrderService {
 
         if (inviter.getInvitedBy() != null && l2Amount > 0) {
             User inviter2 = userRepository.findById(inviter.getInvitedBy()).orElse(null);
-            if (inviter2 != null && inviter2.getReferralCode() != null) {
+            if (inviter2 != null && l2Amount > 0) {
                 String l2Remark = String.format("超级会员上级佣金 (%d%%)", upstreamRate / 100);
                 createCommission(order.getId(), buyer.getId(), inviter2.getId(), 2, l2Amount, l2Remark);
             }
@@ -155,12 +157,14 @@ public class OrderService {
     }
 
     /**
-     * US-6.3: B端佣金结算 — 固定金额 + 身份半额 + 升级补差
+     * US-6.3: B 端佣金结算 — 固定金额 + 身份半额 + 升级补差
      */
     private void handlePractitionerCommission(Order order, User buyer, User inviter) {
         // 判断推荐人身份 (US-6.3 §3-4)
+        // 免费用户也可以获得佣金,但能量师推荐仍按固定金额,C 端推荐按半额
         String inviterVipType = inviter.getVipType();
-        if (inviterVipType == null) return; // 推荐人未付费 → 跳过
+        // 移除免费用户检查:免费用户推荐能量师时,按 C 端半额处理
+        // if (inviterVipType == null) return; // REMOVED - 改为按免费用户处理
 
         int l1Default, l1Amount, l2Amount;
         String l1Remark;
@@ -168,12 +172,10 @@ public class OrderService {
         if ("practitioner".equals(inviterVipType)) {
             l1Default = configService.getInt("commission.practitioner.l1", 50000);
             l1Remark = "直接推荐升级能量师 (L1)";
-        } else if ("annual".equals(inviterVipType)) {
-            // AC 4: C端推荐 → 半额
-            l1Default = configService.getInt("commission.practitioner.l1_cend", 20000);
-            l1Remark = "直接推荐升级能量师 (C端半额)";
         } else {
-            return;
+            // 免费用户或 C 端会员 → 半额
+            l1Default = configService.getInt("commission.practitioner.l1_cend", 20000);
+            l1Remark = "直接推荐升级能量师 (免费/C 端半额)";
         }
         l1Amount = l1Default;
         l2Amount = configService.getInt("commission.practitioner.l2", 10000);