日期:2026-09-01 状态:待评审 分支:cfc 主分支
当前系统存在两套并行的返利/分佣体系:
| 体系 | 服务 | 表 | 作用域 | 用途 | 状态 |
|---|---|---|---|---|---|
| 新 CF 值分佣 | CommissionDistService |
commission_dist_log / user_platform_balance |
个人 | 商品订单 P点分润 | 仅商品订单 |
| 旧佣金体系 | CommissionService.settle/settleTwoLevel |
commission_records / family_earnings |
个人+家庭 | 套餐/测评/会员/订阅订单 L1/L2 佣金 | @Deprecated,仍被调用 |
问题:
settleTwoLevel 仍被 5 个订单服务调用(套餐/测评/会员/订阅),与需求"全部走 CF 值体系"冲突。PromotionTierService.updateTeamSize() 全库无调用者,等级评估链路断裂。promotion_tier_config 表列(min_team_size_1st/2nd + commission_rate_l1/l2)与实体 PromotionTierConfig(min_team_size + profit_share_percent + enabled)不一致,等级配置实际未接通。| # | 决策点 | 结论 |
|---|---|---|
| D1 | 返佣比例模型 | 纯团队规模阶梯(cf_rate_tier 动态可配置) |
| D2 | CF 值归属维度 | 返给个人钱包(user_platform_balance),不进家庭池 |
| D3 | 会员升级特例 | 仅 membership/subscription 订单不返当前人,只返推荐人 |
| D4 | 优惠券绑定 | 用 CF 兑换的券放进家庭共享池(券绑 family_id,全家可用) |
| D5 | 同家庭互推 | 跳过本人,上溯到第一个非同家庭的引荐人 |
| D6 | 分润结算主体 | 个人维度(A/B 引荐人不同则各自独立结算) |
| D7 | 团队规模口径 | 推荐人全层级下线总人数(promotion_tier.total_team_size) |
cf_rate_tier — 分佣阶梯配置CREATE TABLE IF NOT EXISTS cf_rate_tier (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
tier_name VARCHAR(50) NOT NULL COMMENT '档位名称: 铜牌/银牌/金牌/铂金/钻石',
min_team_size INT NOT NULL DEFAULT 0 COMMENT '团队规模下限(含)',
rate_percent INT NOT NULL DEFAULT 0 COMMENT '返佣比例(%),如10表示10%',
sort_order INT NOT NULL DEFAULT 0 COMMENT '排序,越大越高',
enabled TINYINT DEFAULT 1 COMMENT '1启用/0停用',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_min_size (min_team_size)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='CF值返佣阶梯配置';
种子数据(默认 5 档,管理端可动态增删改):
| tier_name | min_team_size | rate_percent |
|---|---|---|
| 铜牌 | 0 | 5 |
| 银牌 | 3 | 10 |
| 金牌 | 10 | 15 |
| 铂金 | 30 | 20 |
| 钻石 | 100 | 25 |
user_platform_balance(不新建)经核对,user_platform_balance 表已具备 family_id 列及完整字段(available/frozen/withdrawn/exchanged/total_earned),PlatformPointsService 即为个人 CF 钱包服务(earn/spend/freeze/unfreeze/withdraw)。直接复用,无需新建 user_cf_wallet 表。
转让时个人钱包变动复用 PlatformPointsService.spend/earn,通过 cf_transfer_record 记录流转明细。
cf_transfer_record — CF 流转记录CREATE TABLE IF NOT EXISTS cf_transfer_record (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
from_user_id BIGINT COMMENT '转出用户ID(null=平台/家庭池)',
to_user_id BIGINT COMMENT '转入用户ID',
family_id BIGINT COMMENT '所属家庭ID',
amount INT NOT NULL COMMENT 'CF值数量',
type VARCHAR(16) NOT NULL COMMENT 'transfer成员转让/allocate管理员分配/refund退款回补',
ref_type VARCHAR(50) COMMENT '关联业务类型',
ref_id BIGINT COMMENT '关联业务ID',
remark VARCHAR(255),
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
INDEX idx_from (from_user_id),
INDEX idx_to (to_user_id),
INDEX idx_family (family_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='CF值流转记录';
| 表 | 操作 | 说明 |
|---|---|---|
promotion_tier |
删除 team_size_1st/2nd/3rd;新增 rate_percent INT DEFAULT 0 |
团队规模只留 total_team_size 一个口径 |
promotion_tier_config |
废弃(保留历史数据,业务不再读取) | 替代者为 cf_rate_tier |
coupon |
新增 family_id BIGINT NULL |
券绑定家庭(NULL=不绑定) |
user_platform_balance |
复用,不改表 | 已有 family_id 列及完整字段,直接作为个人 CF 钱包 |
referral_tree:已支持全层级(path 物化路径)。user_platform_balance / platform_balance_log:个人 CF 值余额与流水(复用为个人钱包)。commission_dist_log:商品订单分润流水(迁移后并入通用分润流水体系)。family_platform_balance / family_platform_exchange_record:仅作优惠券兑换用途(用个人 CF 兑换后券挂家庭),不再承接返佣。CfCommissionService(新建)@Service
public class CfCommissionService {
/** 通用分佣入口(商品/套餐/测评订单:当前人+推荐人双返) */
void settle(Long orderId, String orderType, Long buyerUserId, Long buyerFamilyId,
Integer orderAmountCent, Long productId);
/** 会员/订阅专用(只返推荐人,不返当前人) */
void settleReferrerOnly(Long orderId, String orderType, Long buyerUserId, Long buyerFamilyId,
Integer orderAmountCent);
}
List<ReferralNode> getEffectiveReferrers(Long buyerUserId, Long buyerFamilyId) {
// 1. 查 referral_tree WHERE child_id=buyerUserId ORDER BY level ASC
// 2. 对每个 referrer R:
// a. R.familyId == buyerFamilyId → 跳过(同家庭不返),查 R 的引荐人继续上溯
// b. R.familyId != buyerFamilyId → 加入结果集
// 3. 上溯终止:无更上级 / 已找到非同家庭引荐人
}
决策 D5:同家庭互推时跳过本人,上溯到第一个非同家庭的引荐人。避免"自家消费返自己家人"的无效内耗与刷单。
int getRatePercent(Long referrerUserId) {
// 1. 查 promotion_tier.total_team_size(全层级下线人数)
// 2. SELECT rate_percent FROM cf_rate_tier
// WHERE enabled=1 AND min_team_size <= total_team_size
// ORDER BY min_team_size DESC LIMIT 1
// 3. 无匹配 → 0
}
分润CF = floor(orderAmountCent / 100) × 分润基数比例 × rate_percent / 100
其中:
- 商品订单:分润基数比例 = 商品 P点 ppointConfig(如 sourcePpoint 已含此义)
- 非商品订单(套餐/测评/会员/订阅):分润基数比例 = sys_config.commission_service_rate(默认 10%)
简化统一为:
商品:cf = floor(sourcePpoint) × rate_percent / 100 (sourcePpoint 来自 PpointConfigService)
非商品:cf = floor(orderAmountCent / 100) × serviceRateBps / 10000 × rate_percent / 100
platformPointsService.earn(buyerUserId, cf, "order_consume", orderId, ...) → 个人钱包platformPointsService.earn(referrerUserId, cf, "referral_dist", orderId, ...) → 个人钱包cf_transfer_record 记录 from=平台 to=受益人(type=allocate)以 (ref_type='referral_dist'|'order_consume', ref_id=orderId) 为幂等键,platform_balance_log 存在即跳过。platformPointsService.earn 当前实现无幂等检查,实现时需补(仿 FamilyPlatformPointsService.earn 的 (ref_type, ref_id) 去重)。
| 订单类型 | 文件:行 | 原调用 | 新调用 | 当前人返 CF | 推荐人分润 |
|---|---|---|---|---|---|
| 测评 | AssessmentOrderService.java:76 |
commissionService.settle(...) |
cfCommissionService.settle(...) |
✅ | ✅ |
| 套餐 | PackagePaymentService.java:220 |
commissionService.settle(...) |
cfCommissionService.settle(...) |
✅ | ✅ |
| 套餐 | PaymentService.java:240 |
commissionService.settle(...) |
cfCommissionService.settle(...) |
✅ | ✅ |
| 商品 | ProductOrderService.java:645 |
commissionDistService.distribute(...) |
cfCommissionService.settle(...) |
✅ | ✅ |
| 会员 | MembershipService.java:784 |
commissionService.settleTwoLevel(...) |
cfCommissionService.settleReferrerOnly(...) |
❌ | ✅ |
| 订阅 | MemberSubscriptionService.java:174 |
commissionService.settleTwoLevel(...) |
cfCommissionService.settleReferrerOnly(...) |
❌ | ✅ |
| 订阅 | MemberSubscriptionService.java:255 |
commissionService.settleTwoLevel(...) |
cfCommissionService.settleReferrerOnly(...) |
❌ | ✅ |
| 活动 | ActivityOrderService |
无 | 无 | ❌ | ❌ |
商品订单当前 ProductOrderService:633 用 platformPointsService.earn(buyerId, cfValue, "product_order", ...) 返个人钱包,:827 confirmReceive 用 familyPlatformPointsService.earn(familyId, ...) 返家庭池。
本次设计决定:
:633 个人 CF 返现:保留(属于分佣双返中的"当前人返")。:827 confirmReceive 家庭池返 CF:保留不动(属于"确认收货额外积分",非本次推荐分佣范畴)。若后续需统一口径,另行提任务。待产品确认项:确认收货返家庭池 CF 是否仍需保留(与"返佣只进个人钱包"是否冲突)。
推荐绑定:CommissionService.bindReferral(userId, referralCode)
→ 建立 referral_tree 关系(path 物化路径)
→ promotionTierService.updateTeamSize(referrerId, 全链路上溯, +1)
(对 referrer 及其所有祖先 promotion_tier.total_team_size +1)
PromotionTierService.refreshRate(referrerUserId)
→ 查 total_team_size → JOIN cf_rate_tier → rate_percent
→ 写回 promotion_tier.rate_percent + tier(档位名)
触发时机:
bindReferral 后(实时)PromotionTierCheckScheduledTask(现有,改调 refreshRate 批量刷新)CommissionService.settle/settleTwoLevel → 标 @Deprecated + 保留(历史读取),删除全部调用点。PromotionTierEvalService.evaluateTier(基于 promotion_tier_config)→ 改读 cf_rate_tier。PromotionTierConfig 实体 → 不再使用。| 接口 | 说明 | 返回 |
|---|---|---|
POST /api/commission/cf/rate |
我的团队规模 + 当前返佣比例 | { totalTeamSize, ratePercent, tierName } |
POST /api/commission/cf/summary |
我的 CF 钱包汇总 | { available, frozen, totalEarned, totalSpent } |
POST /api/commission/cf/list |
CF 分润/消费流水(分页) | Page<PlatformBalanceLog> |
POST /api/commission/cf/wallet |
个人 CF 余额 | PlatformPointsService.getBalance |
| 接口 | 说明 | 约束 |
|---|---|---|
POST /api/cf/transfer/send |
成员间转让 CF | 双方同家庭;转出余额足;type=transfer |
POST /api/cf/transfer/list |
转让记录(分页) | 按 family_id 或 userId 查询 |
| 接口 | 说明 |
|---|---|
POST /api/coupon/family/list |
查询家庭共享券(user_coupon.family_id=familyId) |
| 复用 | POST /api/family-platform/exchange-coupon(兑换后券挂 family_id) |
| 接口 | 说明 |
|---|---|
POST /api/admin/cf-rate-tier/list |
阶梯配置列表 |
POST /api/admin/cf-rate-tier/save |
新增/更新档位 |
POST /api/admin/cf-rate-tier/delete |
删除档位 |
pages/promotion/*)team.vue:展示全层级团队总人数 + 当前返佣比例 + 档位名(调 /api/commission/cf/rate)commission.vue:改用 CF 分润流水(调 /api/commission/cf/list)index.vue:头部汇总改用个人 CF 钱包(调 /api/commission/cf/summary)/api/cf/transfer/send| 场景 | 处理 |
|---|---|
| 同家庭互推 | 跳过本人,上溯到非同家庭引荐人(D5) |
| 无有效推荐人 | 不产生分润,结束 |
| 余额不足 | spend 抛异常,前端提示"CF值不足" |
| 重复结算 | earn 补幂等(ref_type+ref_id 去重) |
| 团队规模未更新 | 定时任务兜底刷新 |
| 孤儿用户(无 family) | 分润照常走个人钱包,family_id 冗余为空 |
getRatePercent 阶梯匹配(边界 0/2/3/9/10);同家庭上溯逻辑;幂等防重。cf_rate_tier 建表 + 种子;promotion_tier 精简加列;coupon 加 family_id;user_platform_balance 补 family_id。CfCommissionService 核心 + PlatformPointsService.earn 幂等补丁。updateTeamSize 调用链 + refreshRate + 定时任务改造。settle/settleTwoLevel 调用点摘除 + @Deprecated。family_earnings 不在本次范围)。invite_milestone / referral_leaderboard / onboarding 现有逻辑。commission_records 数据到 CF 体系(历史只读)。PointsExchangeProduct 不动)。