Administrator
2025-05-12 78e1837458da467cacefa8e22c2c9616b1dc9f9d
src/main/java/cc/mrbird/febs/vip/service/impl/VipCommonServiceImpl.java
@@ -2,13 +2,11 @@
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.MallGoods;
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;
@@ -21,6 +19,7 @@
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 com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.RequiredArgsConstructor;
@@ -46,164 +45,369 @@
    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);
        MallMember member = mallMemberMapper.selectById(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");
        List<Long> itemGoodsIds = mallOrderInfo.getItems().stream().map(MallOrderItem::getGoodsId).distinct().collect(Collectors.toList());
        List<MallGoods> goodsList = mallGoodsService.listByIds(itemGoodsIds);
        Map<Long, MallGoods> goodsMap = goodsList.stream().collect(Collectors.toMap(MallGoods::getId, MallGoods -> MallGoods));
        // 下单自己获得积分,推荐人获得积分
        //<memberId,积分数量>的map
        Map<Long, BigDecimal> recommendScoreMap = new HashMap<>();
        mallOrderInfo.getItems().forEach(item -> {
            if (StrUtil.isNotBlank(item.getMemberInviteId()) && !member.getInviteId().equals(item.getMemberInviteId())) {
                MallGoods mallGoods = goodsMap.get(item.getGoodsId());
                if (mallGoods.getStaticMulti() == null) {
                    return;
                }
                BigDecimal multi = mallGoods.getStaticMulti().divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP);
                MallMember mallMember = mallMemberMapper.selectInfoByInviteId(item.getMemberInviteId());
                if (mallMember == null) {
                    return;
                }
                BigDecimal recommendScore = recommendScoreMap.get(mallMember.getId());
                recommendScore = recommendScore == null ? BigDecimal.ZERO : recommendScore;
                recommendScore = recommendScore.add(item.getAmount().multiply(multi));
                recommendScoreMap.put(mallMember.getId(), recommendScore);
        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);
        if(ObjectUtil.isNotEmpty(happyMemberLevel)){
            // 计算自己获得的积分
            BigDecimal minePercent = happyMemberLevel.getMinePercent();
            BigDecimal mineScore = amount.multiply(minePercent.divide(BigDecimal.valueOf(100), 4, RoundingMode.HALF_DOWN)).setScale(0, RoundingMode.HALF_DOWN);
            if(BigDecimal.ZERO.compareTo(mineScore) < 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.divide(BigDecimal.valueOf(100), 4, RoundingMode.HALF_DOWN)).setScale(0, RoundingMode.HALF_DOWN);
                if(BigDecimal.ZERO.compareTo(otherScore) < 0){
                    recommendScoreMap.put(refMember.getId(), otherScore);
                    recommendTypeScoreMap.put(memberId, ScoreFlowTypeEnum.OTHER_RECOMMEND.getValue());
                }
            }
        }
        // 为推荐人和自己添加积分流动记录和更新钱包
        recommendScoreMap.forEach((key, value) -> {
            if (value != null) {
                mallMoneyFlowService.addMoneyFlow(key, value, ScoreFlowTypeEnum.RECOMMEND.getValue(), mallOrderInfo.getOrderNo(), FlowTypeEnum.PRIZE_SCORE.getValue(), CollUtil.join(skuNames, ","), 2);
                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");
            }
        });
        // 发送会员等级升级消息
        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 divide = happySaleLevel.getReturnPercent().divide(new BigDecimal(100));
        BigDecimal multiply = mallOrderInfo.getAmount().multiply(divide).setScale(2, RoundingMode.HALF_DOWN);
        // 如果返佣金额小于等于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.BALANCE.getValue(),
                StrUtil.format(ScoreFlowTypeEnum.SALE_RECOMMEND.getDesc(),multiply),
                2
        );
        // 更新会员钱包中的余额
        mallMemberWalletService.add(multiply, storeMasterMember.getId(), "balance");
        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;
    }
}