| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193 |
- package com.etotem.cfc.service;
- import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
- import com.etotem.cfc.entity.CfRateTier;
- import com.etotem.cfc.entity.CfTransferRecord;
- import com.etotem.cfc.entity.Product;
- import com.etotem.cfc.entity.ReferralTree;
- import com.etotem.cfc.entity.User;
- import com.etotem.cfc.mapper.CfTransferRecordMapper;
- import com.etotem.cfc.mapper.ProductMapper;
- import com.etotem.cfc.mapper.ReferralTreeMapper;
- import com.etotem.cfc.mapper.UserMapper;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import org.springframework.stereotype.Service;
- import org.springframework.transaction.annotation.Transactional;
- import javax.annotation.Resource;
- import java.util.ArrayList;
- import java.util.Date;
- import java.util.List;
- /**
- * 统一 CF 值分佣服务。
- * 规则:
- * - 普通订单(商品/套餐/测评):当前消费人返 CF + 推荐人按团队规模阶梯比例分润
- * - 会员/订阅订单:只返推荐人,不返当前人
- * - 同家庭互推:跳过本人,上溯到第一个非同家庭引荐人
- */
- @Service
- public class CfCommissionService {
- private static final Logger log = LoggerFactory.getLogger(CfCommissionService.class);
- @Resource
- private ReferralTreeMapper referralTreeMapper;
- @Resource
- private UserMapper userMapper;
- @Resource
- private CfReferralService cfReferralService;
- @Resource
- private PlatformPointsService platformPointsService;
- @Resource
- private CfTransferRecordMapper cfTransferRecordMapper;
- @Resource
- private PpointConfigService ppointConfigService;
- @Resource
- private SysConfigService sysConfigService;
- @Resource
- private ProductMapper productMapper;
- /**
- * 通用分佣(双返):当前人 + 推荐人
- */
- @Transactional
- public void settle(Long orderId, String orderType, Long buyerUserId, Long buyerFamilyId,
- Integer orderAmountCent, Long productId) {
- // 当前消费人返 CF(个人钱包)
- int buyerReturn = calcBuyerReturn(orderType, orderAmountCent, productId, buyerUserId);
- if (buyerReturn > 0) {
- try {
- platformPointsService.earn(buyerUserId, buyerReturn, "order_consume", orderId,
- "消费返CF:" + orderType);
- record(buyerUserId, null, null, buyerReturn, "allocate", "order_consume", orderId, "消费返CF");
- } catch (Exception e) {
- log.error("当前人返CF失败: buyer={}, orderId={}, err={}", buyerUserId, orderId, e.getMessage());
- }
- }
- // 推荐人分润
- distributeToReferrers(orderId, orderType, buyerUserId, buyerFamilyId, orderAmountCent, productId);
- }
- /**
- * 会员/订阅专用:只返推荐人
- */
- @Transactional
- public void settleReferrerOnly(Long orderId, String orderType, Long buyerUserId, Long buyerFamilyId,
- Integer orderAmountCent) {
- distributeToReferrers(orderId, orderType, buyerUserId, buyerFamilyId, orderAmountCent, null);
- }
- /**
- * 计算当前消费人返 CF。
- * 商品:floor(orderAmount/100) × P点 × shareBps/10000
- * 非商品:floor(orderAmount/100) × serviceRateBps/10000
- */
- private int calcBuyerReturn(String orderType, Integer orderAmountCent, Long productId, Long buyerUserId) {
- if (orderAmountCent == null || orderAmountCent <= 0) return 0;
- int amountYuan = orderAmountCent / 100;
- if ("product".equals(orderType) && productId != null) {
- try {
- Product p = productMapper.selectById(productId);
- if (p == null) return 0;
- int effectivePpoint = ppointConfigService.getEffectivePpoint(productId, p.getCategoryId());
- if (effectivePpoint <= 0) return 0;
- int shareBps = getSysBps("product_platform_points_share", 1000);
- return amountYuan * effectivePpoint / 100 * shareBps / 10000;
- } catch (Exception e) {
- return 0;
- }
- }
- int serviceRateBps = getSysBps("commission_service_rate", 1000);
- return amountYuan * serviceRateBps / 10000;
- }
- /**
- * 推荐人分润:查全链路 → 同家庭跳过上溯 → 按阶梯比例
- */
- private void distributeToReferrers(Long orderId, String orderType, Long buyerUserId, Long buyerFamilyId,
- Integer orderAmountCent, Long productId) {
- if (orderAmountCent == null || orderAmountCent <= 0) return;
- int amountYuan = orderAmountCent / 100;
- // 取买家全链路推荐人(referral_tree,含全部层级)
- List<ReferralTree> referrals = referralTreeMapper.selectList(
- new LambdaQueryWrapper<ReferralTree>()
- .eq(ReferralTree::getChildId, buyerUserId)
- .orderByAsc(ReferralTree::getLevel));
- if (referrals == null || referrals.isEmpty()) return;
- List<Long> processed = new ArrayList<>();
- for (ReferralTree ref : referrals) {
- Long referrerId = ref.getParentId();
- if (processed.contains(referrerId)) continue;
- processed.add(referrerId);
- User referrer = userMapper.selectById(referrerId);
- if (referrer == null) continue;
- // 同家庭跳过(D5):不返,继续上溯(循环继续)
- if (buyerFamilyId != null && buyerFamilyId.equals(referrer.getFamilyId())) {
- continue;
- }
- // 按团队规模匹配阶梯比例
- int teamSize = cfReferralService.getTotalTeamSize(referrerId);
- CfRateTier tier = cfReferralService.matchRateTier(teamSize);
- int ratePercent = tier == null ? 0 : tier.getRatePercent();
- if (ratePercent <= 0) continue;
- // 分润基数:商品按 P点,非商品按服务费率
- int base = calcReferrerBase(orderType, amountYuan, productId);
- if (base <= 0) continue;
- int share = base * ratePercent / 100;
- if (share <= 0) continue;
- try {
- platformPointsService.earn(referrerId, share, "referral_dist", orderId,
- "推荐分润:" + orderType);
- record(referrerId, null, referrer.getFamilyId(), share, "allocate", "referral_dist", orderId, "推荐分润");
- } catch (Exception e) {
- log.error("推荐人分润失败: referrer={}, orderId={}, err={}", referrerId, orderId, e.getMessage());
- }
- }
- }
- private int calcReferrerBase(String orderType, int amountYuan, Long productId) {
- if ("product".equals(orderType) && productId != null) {
- try {
- Product p = productMapper.selectById(productId);
- if (p == null) return 0;
- return ppointConfigService.getEffectivePpoint(productId, p.getCategoryId());
- } catch (Exception e) {
- return 0;
- }
- }
- int serviceRateBps = getSysBps("commission_service_rate", 1000);
- return amountYuan * serviceRateBps / 10000;
- }
- private int getSysBps(String key, int def) {
- try {
- String v = sysConfigService.getValue(key);
- if (v != null && !v.isEmpty()) return Integer.parseInt(v);
- } catch (Exception e) {
- log.warn("读取系统配置失败: key={}, err={}", key, e.getMessage());
- }
- return def;
- }
- private void record(Long fromUserId, Long toUserId, Long familyId, int amount, String type,
- String refType, Long refId, String remark) {
- CfTransferRecord r = new CfTransferRecord();
- r.setFromUserId(fromUserId);
- r.setToUserId(toUserId);
- r.setFamilyId(familyId);
- r.setAmount(amount);
- r.setType(type);
- r.setRefType(refType);
- r.setRefId(refId);
- r.setRemark(remark);
- r.setCreatedAt(new Date());
- try { cfTransferRecordMapper.insert(r); } catch (Exception e) { log.warn("写流转记录失败: {}", e.getMessage()); }
- }
- }
|