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 | 431 ++++++++++++++++++++++++++++++++++++++++++----------- 1 files changed, 341 insertions(+), 90 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 fa1618c..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,8 +29,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 @@ -40,129 +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<>(); + 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()); + } + } + } + + // 为推荐人和自己添加积分流动记录和更新钱包 + 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"); + } + }); + + // 发送会员等级升级消息 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