Administrator
2025-05-22 ff55c5334fc35594d2f0c680c29afd309cf367a2
src/main/java/cc/mrbird/febs/vip/service/impl/VipCommonServiceImpl.java
@@ -1,16 +1,15 @@
package cc.mrbird.febs.vip.service.impl;
import cc.mrbird.febs.common.enumerates.FlowTypeEnum;
import cc.mrbird.febs.common.enumerates.MoneyFlowTypeEnum;
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.enumerates.*;
import cc.mrbird.febs.common.exception.FebsException;
import cc.mrbird.febs.mall.dto.ScoreSettingDto;
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;
import cc.mrbird.febs.rabbit.producter.AgentProducer;
import cc.mrbird.febs.vip.entity.MallVipBenefits;
import cc.mrbird.febs.vip.entity.MallVipConfig;
import cc.mrbird.febs.vip.mapper.MallVipConfigMapper;
@@ -18,7 +17,10 @@
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.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -26,8 +28,12 @@
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;
import java.util.Map;
import java.util.logging.Handler;
import java.util.stream.Collectors;
@Slf4j
@@ -36,128 +42,407 @@
public class VipCommonServiceImpl implements IVipCommonService {
    private final MallOrderInfoMapper mallOrderInfoMapper;
    private final MallOrderItemMapper mallOrderItemMapper;
    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;
    private final DataDictionaryCustomMapper  dataDictionaryCustomMapper;
    /**
     * 根据订单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);
        BigDecimal scorePercent = BigDecimal.ONE;
        DataDictionaryCustom dic = dataDictionaryCustomMapper.selectDicDataByTypeAndCode(
                DataDictionaryEnum.SCORE_SIGN_SETTING.getType(),
                DataDictionaryEnum.SCORE_SIGN_SETTING.getCode());
        if (dic != null) {
            ScoreSettingDto scoreSettingDto = JSONObject.parseObject(dic.getValue(), ScoreSettingDto.class);
            BigDecimal bigDecimal = ObjectUtil.isEmpty(scoreSettingDto.getScorePercent()) ? BigDecimal.ONE : new BigDecimal(scoreSettingDto.getScorePercent());
            if (bigDecimal.compareTo(BigDecimal.ZERO) > 0) {
                scorePercent = bigDecimal;
            }
        }
        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");
        // 下单自己获得积分,推荐人获得积分
        //<memberId,积分数量>的map
        Map<Long, BigDecimal> recommendScoreMap = new HashMap<>();
        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).multiply(scorePercent).setScale(0, RoundingMode.HALF_DOWN);
            log.info("下单获得积分:{}", mineScore);
            if(mineScore.compareTo(BigDecimal.ZERO) > 0){
                mallMoneyFlowService.addMoneyFlow(
                        memberId,
                        mineScore,
                        ScoreFlowTypeEnum.MINE_RECOMMEND.getValue(),
                        mallOrderInfo.getOrderNo(),
                        FlowTypeEnum.PRIZE_SCORE.getValue(),
                        StrUtil.format( ScoreFlowTypeEnum.MINE_RECOMMEND.getDesc(),mineScore),
                        2);
                mallMemberWalletService.add(mineScore,memberId , "prizeScore");
                // 记录会员购买获得的经验
                BigDecimal multiply = amount.multiply(minePercent).setScale(2, RoundingMode.HALF_DOWN);
                mallMoneyFlowService.addMoneyFlow(
                        memberId,
                        multiply,
                        ScoreFlowTypeEnum.BUY.getValue(),
                        mallOrderInfo.getOrderNo(),
                        FlowTypeEnum.SCORE.getValue(),
                        StrUtil.format(ScoreFlowTypeEnum.BUY.getDesc(),multiply),
                        2
                );
                // 更新会员钱包中的分数
                mallMemberWalletService.add(multiply, memberId, "score");
                // 发送会员等级升级消息
                agentProducer.sendVipLevelUp(memberId);
            }
            // 计算推荐人获得的积分
            if(StrUtil.isNotEmpty(member.getReferrerId())){
                MallMember refMember = mallMemberMapper.selectInfoByInviteId(member.getReferrerId());
                BigDecimal otherPercent = happyMemberLevel.getOtherPercent();
                BigDecimal otherScore = amount.multiply(otherPercent).multiply(scorePercent).setScale(0, RoundingMode.HALF_DOWN);
                log.info("推荐人获得积分:{}", otherScore);
                if(otherScore.compareTo(BigDecimal.ZERO) > 0){
                    mallMoneyFlowService.addMoneyFlow(
                            refMember.getId(),
                            otherScore,
                            ScoreFlowTypeEnum.OTHER_RECOMMEND.getValue(),
                            mallOrderInfo.getOrderNo(),
                            FlowTypeEnum.PRIZE_SCORE.getValue(),
                            StrUtil.format( ScoreFlowTypeEnum.OTHER_RECOMMEND.getDesc(),otherScore),
                            2);
                    mallMemberWalletService.add(otherScore,refMember.getId() , "prizeScore");
                    // 记录会员购买获得的经验
                    BigDecimal multiply = amount.multiply(otherPercent).setScale(2, RoundingMode.HALF_DOWN);
                    mallMoneyFlowService.addMoneyFlow(
                            refMember.getId(),
                            multiply,
                            ScoreFlowTypeEnum.BUY.getValue(),
                            mallOrderInfo.getOrderNo(),
                            FlowTypeEnum.SCORE.getValue(),
                            StrUtil.format(ScoreFlowTypeEnum.BUY.getDesc(),multiply),
                            2
                    );
                    // 更新会员钱包中的分数
                    mallMemberWalletService.add(multiply, refMember.getId(), "score");
                    // 发送会员等级升级消息
                    agentProducer.sendVipLevelUp(refMember.getId());
                }
            }
        }
        // 发送分销等级升级消息
        agentProducer.sendSaleLevelUp(orderId);
    }
    @Override
    public void levelUp(Long orderId) {
        MallOrderInfo mallOrderInfo = mallOrderInfoMapper.selectOrderDetailsById(orderId);
        if (mallOrderInfo == null) {
            return;
        }
        MallMember member = mallMemberMapper.selectById(mallOrderInfo.getMemberId());
    /**
     * 根据订单ID升级会员等级
     * 当订单完成时,根据会员当前的经验值升级会员等级
     *
     * @param orderId 订单ID
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void levelUp(Long orderId) {
        // 根据订单中的会员ID获取会员信息
        MallMember member = mallMemberMapper.selectById(orderId);
        // 如果会员信息为空,则记录日志并返回
        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;
        }
        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);
        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);
            mallMemberMapper.updateById(update);
        }
        // 更新会员的导演等级为当前会员等级代码
        member.setDirector(code);
        // 更新会员信息
        mallMemberMapper.updateById(member);
    }
    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
    @Transactional(rollbackFor = Exception.class)
    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)
                .orderByDesc(MallMember::getId)
                .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;
        }
        // 计算返佣金额
        List<MallOrderItem> mallOrderItems = mallOrderItemMapper.selectList(
                new LambdaQueryWrapper<MallOrderItem>()
                        .eq(MallOrderItem::getOrderId, orderId)
                        .eq(MallOrderItem::getState, 1)
        );
        if(CollUtil.isEmpty(mallOrderItems)){
            return;
        }
        BigDecimal amount = mallOrderItems.stream().map(MallOrderItem::getLevelOnePrice).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal returnPercent = happySaleLevel.getReturnPercent();
        BigDecimal multiply = amount.multiply(returnPercent).setScale(2, RoundingMode.HALF_DOWN);
        log.info("团长获得返佣:{}",multiply);
        // 如果返佣金额小于等于0,则直接返回
        if(BigDecimal.ZERO.compareTo(multiply) >=0){
            return;
        }
        // 如果返佣金额大于等于订单金额,则直接返回
        if(multiply.compareTo(amount) > 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(), "totalScore");
        MallAchieveRecord mallAchieveRecord = new MallAchieveRecord();
        mallAchieveRecord.setMemberId(storeMasterMember.getId());
        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;
    }
}