From 9b51a95fa8bc9b3a86108c6900e17fc55f8db467 Mon Sep 17 00:00:00 2001
From: Administrator <15274802129@163.com>
Date: Mon, 19 May 2025 17:02:07 +0800
Subject: [PATCH] refactor(vip): 优化积分和返佣计算逻辑

---
 src/main/java/cc/mrbird/febs/vip/service/impl/VipCommonServiceImpl.java |  438 +++++++++++++++++++++++++++++++++++++++++-------------
 1 files changed, 332 insertions(+), 106 deletions(-)

diff --git a/src/main/java/cc/mrbird/febs/vip/service/impl/VipCommonServiceImpl.java b/src/main/java/cc/mrbird/febs/vip/service/impl/VipCommonServiceImpl.java
index be9569d..65b4263 100644
--- a/src/main/java/cc/mrbird/febs/vip/service/impl/VipCommonServiceImpl.java
+++ b/src/main/java/cc/mrbird/febs/vip/service/impl/VipCommonServiceImpl.java
@@ -2,12 +2,12 @@
 
 import cc.mrbird.febs.common.enumerates.FlowTypeEnum;
 import cc.mrbird.febs.common.enumerates.MoneyFlowTypeEnum;
+import cc.mrbird.febs.common.enumerates.OrderStatusEnum;
 import cc.mrbird.febs.common.enumerates.ScoreFlowTypeEnum;
-import cc.mrbird.febs.mall.entity.MallMember;
-import cc.mrbird.febs.mall.entity.MallOrderInfo;
-import cc.mrbird.febs.mall.entity.MallOrderItem;
-import cc.mrbird.febs.mall.mapper.MallMemberMapper;
-import cc.mrbird.febs.mall.mapper.MallOrderInfoMapper;
+import cc.mrbird.febs.common.exception.FebsException;
+import cc.mrbird.febs.mall.entity.*;
+import cc.mrbird.febs.mall.mapper.*;
+import cc.mrbird.febs.mall.service.IApiMallGoodsService;
 import cc.mrbird.febs.mall.service.IApiMallMemberWalletService;
 import cc.mrbird.febs.mall.service.IApiMallOrderInfoService;
 import cc.mrbird.febs.mall.service.IMallMoneyFlowService;
@@ -19,7 +19,9 @@
 import cc.mrbird.febs.vip.service.IVipCommonService;
 import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
+import cn.hutool.json.JSONUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
@@ -27,6 +29,7 @@
 import org.springframework.transaction.annotation.Transactional;
 
 import java.math.BigDecimal;
+import java.math.RoundingMode;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
@@ -43,151 +46,374 @@
     private final IMallVipConfigService mallVipConfigService;
     private final IMallMoneyFlowService mallMoneyFlowService;
     private final IApiMallMemberWalletService mallMemberWalletService;
+    private final MallMemberWalletMapper mallMemberWalletMapper;
     private final MallMemberMapper mallMemberMapper;
     private final MallVipConfigMapper mallVipConfigMapper;
     private final AgentProducer agentProducer;
-
+    private final IApiMallGoodsService mallGoodsService;
+    private final HappyMemberLevelMapper happyMemberLevelMapper;
+    private final HappySaleLevelMapper happySaleLevelMapper;
+    private final MallAchieveRecordMapper mallAchieveRecordMapper;
+    /**
+     * 根据订单ID获取分数
+     * 此方法处理订单得分逻辑,包括直接购买得分、会员等级得分和推荐人得分
+     *
+     * @param orderId 订单ID,用于查询订单详细信息
+     */
     @Override
     @Transactional(rollbackFor = Exception.class)
     public void getScore(Long orderId) {
+        // 根据订单ID查询订单详细信息
         MallOrderInfo mallOrderInfo = mallOrderInfoMapper.selectOrderDetailsById(orderId);
         if (mallOrderInfo == null) {
+            // 如果订单信息为空,则直接返回
             return;
         }
 
-        Long memberId = mallOrderInfo.getMemberId();
-        MallVipBenefits mallVipBenefits = mallVipConfigService.hasVipBenefits(memberId);
-
-        BigDecimal multiple = BigDecimal.ONE;
-        String name = "";
-        if (mallVipBenefits != null) {
-            multiple = mallVipBenefits.getScoreMultiple();
-            name = mallVipBenefits.getName();
+        if (mallOrderInfo.getStatus() != OrderStatusEnum.FINISH.getValue()) {
+            // 订单不是完成状态
+            return;
         }
 
-        List<String> skuNames = mallOrderInfo.getItems().stream().map(MallOrderItem::getSkuName).collect(Collectors.toList());
-        double sum = mallOrderInfo.getItems().stream().map(MallOrderItem::getAmount).mapToDouble(BigDecimal::doubleValue).sum();
+        // 获取订单金额
+        BigDecimal amount = mallOrderInfo.getAmount();
+        if(BigDecimal.ZERO.compareTo(amount) >= 0){
+            // 如果订单金额小于等于0,则直接返回
+            return;
+        }
 
-        int score = multiple.multiply(BigDecimal.valueOf(sum)).intValue();
+        // 获取会员ID
+        Long memberId = mallOrderInfo.getMemberId();
+        // 根据会员ID查询会员信息
+        MallMember member = mallMemberMapper.selectById(memberId);
 
-        mallMoneyFlowService.addMoneyFlow(memberId, new BigDecimal(score), ScoreFlowTypeEnum.BUY.getValue(), mallOrderInfo.getOrderNo(), FlowTypeEnum.PRIZE_SCORE.getValue(), CollUtil.join(skuNames, ","), 2);
-        mallMemberWalletService.add(new BigDecimal(score), memberId, "prizeScore");
+        // 记录会员购买获得的经验
+        mallMoneyFlowService.addMoneyFlow(
+                memberId,
+                amount,
+                ScoreFlowTypeEnum.BUY.getValue(),
+                mallOrderInfo.getOrderNo(),
+                FlowTypeEnum.SCORE.getValue(),
+                StrUtil.format(ScoreFlowTypeEnum.BUY.getDesc(),amount),
+                2
+        );
+        // 更新会员钱包中的分数
+        mallMemberWalletService.add(amount, memberId, "score");
 
+        // 下单自己获得积分,推荐人获得积分
+        //<memberId,积分数量>的map
         Map<Long, BigDecimal> recommendScoreMap = new HashMap<>();
-        mallOrderInfo.getItems().forEach(item -> {
-            if (StrUtil.isNotBlank(item.getMemberInviteId())) {
-                MallMember mallMember = mallMemberMapper.selectInfoByInviteId(item.getMemberInviteId());
-                if (mallMember == null) {
-                    return;
+        Map<Long, Integer> recommendTypeScoreMap = new HashMap<>();
+        // 获取会员的董事等级代码
+        Integer director = member.getDirector();
+        // 查询与董事等级代码匹配的会员等级信息
+        LambdaQueryWrapper<HappyMemberLevel> happyMemberLevelLambdaQueryWrapper = new LambdaQueryWrapper<HappyMemberLevel>();
+        happyMemberLevelLambdaQueryWrapper.eq(HappyMemberLevel::getCode, director);
+        happyMemberLevelLambdaQueryWrapper.last("limit 1");
+        HappyMemberLevel happyMemberLevel = happyMemberLevelMapper.selectOne(happyMemberLevelLambdaQueryWrapper);
+        log.info("会员等级信息:{}", JSONUtil.toJsonStr(happyMemberLevel));
+        if(ObjectUtil.isNotEmpty(happyMemberLevel)){
+            // 计算自己获得的积分
+            BigDecimal minePercent = happyMemberLevel.getMinePercent();
+            BigDecimal mineScore = amount.multiply(minePercent).setScale(0, RoundingMode.HALF_DOWN);
+            log.info("下单获得积分:{}", mineScore);
+            if(mineScore.compareTo(BigDecimal.ZERO) > 0){
+                recommendScoreMap.put(memberId, mineScore);
+                recommendTypeScoreMap.put(memberId, ScoreFlowTypeEnum.MINE_RECOMMEND.getValue());
+            }
+            // 计算推荐人获得的积分
+            if(StrUtil.isNotEmpty(member.getReferrerId())){
+                MallMember refMember = mallMemberMapper.selectInfoByInviteId(member.getReferrerId());
+                BigDecimal otherPercent = happyMemberLevel.getOtherPercent();
+                BigDecimal otherScore = amount.multiply(otherPercent).setScale(0, RoundingMode.HALF_DOWN);
+                log.info("推荐人获得积分:{}", otherScore);
+                if(otherScore.compareTo(BigDecimal.ZERO) > 0){
+                    recommendScoreMap.put(refMember.getId(), otherScore);
+                    recommendTypeScoreMap.put(memberId, ScoreFlowTypeEnum.OTHER_RECOMMEND.getValue());
                 }
+            }
+        }
 
-                BigDecimal recommendScore = recommendScoreMap.get(mallMember.getId());
-                if (recommendScore != null) {
-                    recommendScore = recommendScore.add(item.getAmount());
-                }
-
-                recommendScoreMap.put(mallMember.getId(), recommendScore);
+        // 为推荐人和自己添加积分流动记录和更新钱包
+        recommendScoreMap.forEach((key, value) -> {
+            if (value != null) {
+                mallMoneyFlowService.addMoneyFlow(
+                        key,
+                        value,
+                        recommendTypeScoreMap.get(key),
+                        mallOrderInfo.getOrderNo(),
+                        FlowTypeEnum.PRIZE_SCORE.getValue(),
+                        StrUtil.format(ScoreFlowTypeEnum.getDescByValue(recommendTypeScoreMap.get(key)),value),
+                        2);
+                mallMemberWalletService.add(value, key, "prizeScore");
             }
         });
 
-        recommendScoreMap.forEach((key, value) -> {
-            mallMoneyFlowService.addMoneyFlow(key, value, ScoreFlowTypeEnum.RECOMMEND.getValue(), mallOrderInfo.getOrderNo(), FlowTypeEnum.PRIZE_SCORE.getValue(), CollUtil.join(skuNames, ","), 2);
-            mallMemberWalletService.add(new BigDecimal(score), key, "prizeScore");
-        });
-
+        // 发送会员等级升级消息
         agentProducer.sendVipLevelUp(orderId);
     }
 
+
+    /**
+     * 根据订单ID升级会员等级
+     * 当订单完成时,根据会员当前的经验值升级会员等级
+     *
+     * @param orderId 订单ID
+     */
     @Override
     public void levelUp(Long orderId) {
+        // 根据订单ID获取订单详细信息
         MallOrderInfo mallOrderInfo = mallOrderInfoMapper.selectOrderDetailsById(orderId);
+        // 如果订单信息为空,则直接返回
         if (mallOrderInfo == null) {
             return;
         }
+        // 如果订单状态不是完成状态,则直接返回
+        if (mallOrderInfo.getStatus() != OrderStatusEnum.FINISH.getValue()) {
+            // 订单不是完成状态
+            return;
+        }
 
+        // 根据订单中的会员ID获取会员信息
         MallMember member = mallMemberMapper.selectById(mallOrderInfo.getMemberId());
+        // 如果会员信息为空,则记录日志并返回
         if (member == null) {
             log.info("会员不存在");
             return;
         }
 
-        MallVipConfig config = mallVipConfigMapper.selectVipConfigByCode(member.getLevel());
-        if (config == null) {
-            log.info("会员等级配置不存在");
+        // 根据会员ID获取会员钱包信息
+        MallMemberWallet mallMemberWallet = mallMemberWalletMapper.selectWalletByMemberId(member.getId());
+        // 如果会员钱包信息为空,则记录日志并返回
+        if (mallMemberWallet == null) {
+            log.info("会员钱包不存在");
+            return;
+        }
+        //当前经验值
+        int score = mallMemberWallet.getScore().intValue();
+
+        // 查询当前经验值对应的会员等级
+        HappyMemberLevel happyMemberLevel = happyMemberLevelMapper.selectOne(
+                new LambdaQueryWrapper<HappyMemberLevel>()
+                        .ge(HappyMemberLevel::getUpgradeScore, score)
+                        .orderByAsc(HappyMemberLevel::getCode)
+                        .last("limit 1")
+        );
+        // 如果查询不到对应的会员等级,则记录日志并返回
+        if (happyMemberLevel == null) {
+            log.info("会员等级不存在");
+            return;
+        }
+        // 获取当前会员等级代码
+        Integer code = happyMemberLevel.getCode();
+        // 如果当前会员等级与会员的导演等级相同,则直接返回
+        if(member.getDirector() == code){
             return;
         }
 
-//        LambdaQueryWrapper<MallVipConfig> configQuery = new LambdaQueryWrapper<>();
-//        configQuery.gt(MallVipConfig::getLevel, config.getLevel())
-//                .orderByAsc(MallVipConfig::getLevel)
-//                .last("limit 1");
-//        MallVipConfig nextLevel = mallVipConfigMapper.selectOne(configQuery);
+        // 更新会员的导演等级为当前会员等级代码
+        member.setDirector(code);
+        // 更新会员信息
+        mallMemberMapper.updateById(member);
 
-        List<MallVipConfig> configs = mallVipConfigMapper.selectVipConfigList();
-
-        String nextLevelCode = "";
-        for (MallVipConfig nextLevel : configs) {
-            if (config.getLevel() >= nextLevel.getLevel()) {
-                continue;
-            }
-
-            // 指定商品
-            if (nextLevel.getType() == 1) {
-                boolean hasMatch = mallOrderInfo.getItems().stream().anyMatch(item -> {
-                    return item.getGoodsId().equals(nextLevel.getTargetId());
-                });
-
-                if (hasMatch) {
-                    nextLevelCode = nextLevel.getCode();
-                    continue;
-                }
-            }
-
-            // 时间区间内金额
-            if (nextLevel.getType() == 2) {
-                Date endTime = DateUtil.endOfDay(new Date());
-                Date startTime = getStartTime(nextLevel.getValidType());
-
-                LambdaQueryWrapper<MallOrderInfo> query = new LambdaQueryWrapper<>();
-                query.ge(MallOrderInfo::getReceivingTime, startTime)
-                        .le(MallOrderInfo::getReceivingTime, endTime)
-                        .eq(MallOrderInfo::getStatus, 4)
-                        .eq(MallOrderInfo::getMemberId, member.getId());
-                List<MallOrderInfo> orderList = mallOrderInfoMapper.selectList(query);
-                if (CollUtil.isEmpty(orderList)) {
-                    continue;
-                }
-
-                double totalAmount = orderList.stream().mapToDouble(item -> {
-                    return item.getAmount().doubleValue();
-                }).sum();
-
-                if (nextLevel.getAmount().compareTo(BigDecimal.valueOf(totalAmount)) <= 0) {
-                    nextLevelCode = nextLevel.getCode();
-                }
-            }
-        }
-
-        if (StrUtil.isNotBlank(nextLevelCode)) {
-            MallMember update = new MallMember();
-            update.setId(member.getId());
-            update.setLevel(nextLevelCode);
-            update.setVipLevelTime(new Date());
-            mallMemberMapper.updateById(update);
-        }
+        // 发送分销等级升级消息
+        agentProducer.sendSaleLevelUp(orderId);
     }
 
-    private Date getStartTime(String type) {
-        Date date = new Date();
-        switch (type) {
-            case "day" :
-                return DateUtil.beginOfDay(date);
-            case "month":
-                return DateUtil.beginOfMonth(date);
-            case "year":
-                return DateUtil.beginOfYear(date);
-            default:
-                return date;
+    /**
+     * 升级销售级别时处理订单相关的逻辑
+     *
+     * @param orderId 订单ID,用于识别和处理特定的订单
+     */
+    @Override
+    public void saleLevelUp(Long orderId) {
+        // 根据订单ID获取订单详细信息
+        MallOrderInfo mallOrderInfo = mallOrderInfoMapper.selectOrderDetailsById(orderId);
+        // 如果订单信息为空,则直接返回
+        if (mallOrderInfo == null) {
+            return;
         }
+        // 如果订单状态不是完成状态,则直接返回
+        if (mallOrderInfo.getStatus() != OrderStatusEnum.FINISH.getValue()) {
+            // 订单不是完成状态
+            return;
+        }
+
+        // 根据订单中的会员ID获取会员信息
+        MallMember member = mallMemberMapper.selectById(mallOrderInfo.getMemberId());
+        // 如果会员信息为空,则记录日志并返回
+        if (member == null) {
+            log.info("会员不存在");
+            return;
+        }
+
+        // 如果会员的推荐人ID为空,则直接返回
+        if(StrUtil.isEmpty(member.getReferrerIds())){
+            return;
+        }
+        // 分割会员的推荐人ID
+        String[] referrerIds = member.getReferrerIds().split(",");
+        // 查询符合条件的团长会员
+        MallMember storeMasterMember = mallMemberMapper.selectOne(
+                new LambdaQueryWrapper<MallMember>()
+                        .in(MallMember::getInviteId, referrerIds)
+                        .eq(MallMember::getAccountStatus, MallMember.ACCOUNT_STATUS_ENABLE)
+                        .eq(MallMember::getAccountType, MallMember.ACCOUNT_TYPE_NORMAL)
+                        .ne(MallMember::getStoreMaster, 0)
+                .orderByAsc(MallMember::getStoreMaster)
+                .last("limit 1")
+        );
+        // 如果没有找到符合条件的团长,则记录日志并返回
+        if (storeMasterMember == null) {
+            log.info("团长不存在");
+            return;
+        }
+        // 根据团长的等级代码查询团长等级信息
+        HappySaleLevel happySaleLevel = happySaleLevelMapper.selectOne(
+                new LambdaQueryWrapper<HappySaleLevel>()
+                        .eq(HappySaleLevel::getCode, storeMasterMember.getStoreMaster())
+        );
+        // 如果团长等级信息不存在,则记录日志并返回
+        if (happySaleLevel == null) {
+            log.info("团长等级不存在");
+            return;
+        }
+        // 计算返佣金额
+        BigDecimal returnPercent = happySaleLevel.getReturnPercent();
+        BigDecimal multiply = mallOrderInfo.getAmount().multiply(returnPercent).setScale(2, RoundingMode.HALF_DOWN);
+        log.info("团长获得返佣:{}",multiply);
+        // 如果返佣金额小于等于0,则直接返回
+        if(BigDecimal.ZERO.compareTo(multiply) >=0){
+            return;
+        }
+        // 如果返佣金额大于等于订单金额,则直接返回
+        if(multiply.compareTo(mallOrderInfo.getAmount()) >= 0){
+            return;
+        }
+        // 记录团长获得返佣
+        mallMoneyFlowService.addMoneyFlow(
+                storeMasterMember.getId(),
+                multiply,
+                ScoreFlowTypeEnum.SALE_RECOMMEND.getValue(),
+                mallOrderInfo.getOrderNo(),
+                FlowTypeEnum.COMMISSION.getValue(),
+                StrUtil.format(ScoreFlowTypeEnum.SALE_RECOMMEND.getDesc(),multiply),
+                2
+        );
+        // 更新会员钱包中的余额
+        mallMemberWalletService.add(multiply, storeMasterMember.getId(), "commission");
+        mallMemberWalletService.add(multiply, storeMasterMember.getId(), "total_score");
+
+        MallAchieveRecord mallAchieveRecord = new MallAchieveRecord();
+        mallAchieveRecord.setMemberId(mallOrderInfo.getMemberId());
+        mallAchieveRecord.setAchieveTime(new Date());
+        mallAchieveRecord.setAmount(mallOrderInfo.getAmount());
+        mallAchieveRecord.setCostAmount(multiply);
+        mallAchieveRecord.setOrderId(mallOrderInfo.getId());
+        mallAchieveRecord.setIsNormal(1);
+        mallAchieveRecord.setPayTime(mallOrderInfo.getPayTime());
+        mallAchieveRecordMapper.insert(mallAchieveRecord);
+
+        this.autoUpAgentLevel(storeMasterMember.getId());
     }
+
+
+    /**
+     * 自动升级代理等级
+     * 根据会员的当前状态和业绩,自动为其升级到下一个代理等级
+     * @param memberId 会员ID,用于识别需要升级的会员
+     */
+    private void autoUpAgentLevel(Long memberId) {
+        // 根据会员ID查询会员信息
+        MallMember member = mallMemberMapper.selectById(memberId);
+
+        // 检查会员账户状态和类型,只有在启用状态和普通类型时才进行升级操作
+        if(MallMember.ACCOUNT_STATUS_ENABLE != member.getAccountStatus()
+                || MallMember.ACCOUNT_TYPE_NORMAL != member.getAccountType() ){
+            return;
+        }
+        // 获取会员当前的店铺主人等级
+        Integer storeMaster = member.getStoreMaster();
+        // 下一个分销等级
+        storeMaster =storeMaster +1;
+        // 根据新的店铺主人等级查询对应的快乐销售等级信息
+        HappySaleLevel happySaleLevel = happySaleLevelMapper.selectOne(
+                new LambdaQueryWrapper<HappySaleLevel>()
+                        .eq(HappySaleLevel::getCode, storeMaster)
+        );
+        // 如果没有找到对应的快乐销售等级信息,则记录日志并返回
+        if (happySaleLevel == null) {
+            log.info("当前等级无下级");
+            return;
+        }
+        // 检查直推会员数量是否达到要求
+        if (!directMemberCnt(member, happySaleLevel.getDirectCnt())) {
+            return;
+        }
+
+        // 检查团队人数是否达到要求
+        if (!teamCntFinish(member, happySaleLevel.getTeamCnt())) {
+            return;
+        }
+
+        // 检查团队业绩是否达到要求
+        if (!teamIncome(member, happySaleLevel.getTeamAmount())) {
+            return;
+        }
+
+        // 更新会员的店铺主人等级
+        member.setStoreMaster(storeMaster);
+        // 更新会员信息
+        mallMemberMapper.updateById(member);
+    }
+
+
+    /**
+     * 判断直推人数是否达标
+     */
+    private boolean directMemberCnt(MallMember member, Integer directCnt) {
+        List<MallMember> childList = mallMemberMapper.selectByRefererId(member.getInviteId());
+        if (CollUtil.isEmpty(childList)) {
+            return false;
+        }
+
+        if (childList.size() >= directCnt) {
+            return true;
+        }
+
+        log.info("用户:{}直推数量未达标, 当前等级:{}, 当前数量:{}, 目标数量:{}", member.getPhone(), member.getStoreMaster(), childList.size(), directCnt);
+        return false;
+    }
+
+    /**
+     * 判断团队数量是否达标
+     */
+    private boolean teamCntFinish(MallMember member, Integer teamCnt) {
+        // 直推用户
+        List<MallMember> teamMember = mallMemberMapper.selectAllChildAgentListByInviteId(member.getInviteId());
+        if (CollUtil.isEmpty(teamMember)) {
+            return false;
+        }
+
+        if (teamMember.size() >= teamCnt) {
+            return true;
+        }
+
+        log.info("用户:{}团队数量未达标, 当前等级:{}, 当前数量:{}, 目标数量:{}", member.getPhone(), member.getStoreMaster(), teamMember.size(), teamCnt);
+        return false;
+    }
+
+    /**
+     * 团队业绩是否达标
+     */
+    private boolean teamIncome(MallMember member, BigDecimal teamAmount) {
+        BigDecimal totalIncome = mallMemberMapper.selectAchieveByMemberId(member.getInviteId(), 2);
+
+        if(totalIncome.compareTo(teamAmount) >= 0){
+            return true;
+        }
+        log.info("用户:{}团队业绩未达标, 当前等级:{}, 当前业绩:{}, 目标业绩:{}", member.getPhone(), member.getStoreMaster(), totalIncome, teamAmount);
+        return false;
+    }
+
 }

--
Gitblit v1.9.1