package cc.mrbird.febs.mall.service.impl; import cc.mrbird.febs.common.enumerates.*; import cc.mrbird.febs.mall.entity.*; import cc.mrbird.febs.mall.mapper.*; import cc.mrbird.febs.mall.service.*; import cc.mrbird.febs.system.mapper.UserMapper; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.json.JSONUtil; import com.alibaba.fastjson.JSONObject; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.ibatis.session.ExecutorType; import org.apache.ibatis.session.SqlSession; import org.mybatis.spring.SqlSessionTemplate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; /** * @author wzy * @date 2021-09-26 **/ @Slf4j @Service @RequiredArgsConstructor public class AgentServiceImpl implements IAgentService { private final DataDictionaryCustomMapper dataDictionaryCustomMapper; private final MallMemberMapper memberMapper; private final MallOrderInfoMapper mallOrderInfoMapper; private final IApiMallMemberWalletService iApiMallMemberWalletService; private final IMallMoneyFlowService mallMoneyFlowService; private final MallMemberWalletMapper mallMemberWalletMapper; private final SqlSessionTemplate sqlSessionTemplate; private final IApiMallMemberWalletService memberWalletService; @Override @Transactional(rollbackFor = Exception.class) public void autoUpAgentLevel(Long memberId) { MallMember member = memberMapper.selectById(memberId); if(StrUtil.isBlank(member.getReferrerIds())) { return; } List ids = StrUtil.split(member.getReferrerIds(), ','); List parentMembers = memberMapper.selectByInviteIds(ids); for (MallMember parent : parentMembers) { // 未激活用户无法升级 if (AgentLevelEnum.ZERO_LEVEL.name().equals(member.getLevel())) { continue; } DataDictionaryCustom nextLevel = dataDictionaryCustomMapper.selectNextAgentLevelInfo(parent.getLevel()); if (nextLevel == null) { log.info("当前层级无下一级:{}", parent.getLevel()); continue; } AgentInfo agentInfo = JSONObject.parseObject(nextLevel.getValue(), AgentInfo.class); if (!directMemberCnt(parent, agentInfo)) { continue; } if (!agentCntFinish(parent, agentInfo)) { continue; } if (!teamIncome(parent, agentInfo)) { continue; } parent.setLevel(nextLevel.getCode()); memberMapper.updateById(parent); } } /** * 判断直推人数是否达标 * * @param member * @return */ private boolean directMemberCnt(MallMember member, AgentInfo agentInfo) { List childs = memberMapper.selectByRefererId(member.getInviteId()); if (CollUtil.isEmpty(childs)) { return false; } if (childs.size() >= agentInfo.getDirectCnt()) { return true; } log.info("用户:{}直推数量未达标, 当前等级:{}, 当前数量:{}, 目标数量:{}", member.getPhone(), member.getLevel(), childs.size(), agentInfo.getLastAgentCnt()); return false; } /** * 判断下级代理数量是否达标 * * @return */ private boolean agentCntFinish(MallMember member, AgentInfo agentInfo) { if (agentInfo.getLastAgentCnt() == null || agentInfo.getLastAgentCnt() == 0) { return true; } // 直推用户 List directMember = memberMapper.selectByRefererId(member.getInviteId()); if (CollUtil.isEmpty(directMember)) { return false; } // 用户团队达到指定代理数量,且都不在同一条线 int i = 0; for (MallMember child : directMember) { List mallMembers = memberMapper.selectChildAgentList(child.getInviteId(), member.getLevel()); if (CollUtil.isNotEmpty(mallMembers)) { i++; } } if (i >= agentInfo.getLastAgentCnt()) { return true; } log.info("用户:{}代理数量未达标, 当前等级:{}, 当前数量:{}, 目标数量:{}", member.getPhone(), member.getLevel(), i, agentInfo.getLastAgentCnt()); return false; } /** * 团队业绩是否达标 * * @param agentInfo * @return */ private boolean teamIncome(MallMember member, AgentInfo agentInfo) { BigDecimal totalIncome = memberMapper.selectAchieveByMemberId(member.getInviteId(), 2); BigDecimal targetIncome = agentInfo.getTeamIncome().multiply(new BigDecimal("10000")); if (totalIncome.compareTo(targetIncome) >= 0) { return true; } log.info("用户:{}团队业绩未达标, 当前等级:{}, 当前数量:{}, 目标数量:{}", member.getPhone(), member.getLevel(), totalIncome, targetIncome); return false; } @Override @Transactional(rollbackFor = Exception.class) public void returnMoneyToAgent(Long orderId) { } @Override public void rankReturnMoney(Long orderId) { } @Override @Transactional(rollbackFor = Exception.class) public void perkMoneyConsumer(long orderId) { MallOrderInfo mallOrderInfo = mallOrderInfoMapper.selectById(orderId); if(ObjectUtil.isEmpty(mallOrderInfo)){ return; } if(2 != mallOrderInfo.getStatus()){ return; } /** * 分享补贴 直推消费额10% */ BigDecimal amount = mallOrderInfo.getAmount(); Long memberId = mallOrderInfo.getMemberId(); MallMember mallMember = memberMapper.selectById(memberId); //补贴对象 直属上级 MallMember mallMemberUp = memberMapper.selectInfoByInviteId(mallMember.getReferrerId()); if(ObjectUtil.isNotEmpty(mallMemberUp)){ //分享补贴百分比 DataDictionaryCustom sharePerkDic = dataDictionaryCustomMapper.selectDicDataByTypeAndCode( DataDictionaryEnum.SHARE_PERK.getType(), DataDictionaryEnum.SHARE_PERK.getCode()); String sharePerk = ObjectUtil.isEmpty(sharePerkDic.getValue()) ? "0" : sharePerkDic.getValue(); BigDecimal sharePerkPercent = new BigDecimal(sharePerk).abs().divide(new BigDecimal(100)); //分享补贴金额 BigDecimal sharePerkAmount = amount.multiply(sharePerkPercent); //所有合伙人补贴至消费礼包的三倍额度需要复购一次。 MallMemberWallet mallMemberWallet = mallMemberWalletMapper.selectWalletByMemberId(mallMemberUp.getId()); BigDecimal totalScore = mallMemberWallet.getTotalScore(); if(totalScore.compareTo(sharePerkAmount) < 0){ sharePerkAmount = totalScore; } if(BigDecimal.ZERO.compareTo(sharePerkAmount) < 0){ //减少补贴额度 memberWalletService.reduce(sharePerkAmount, memberId, "totalScore"); iApiMallMemberWalletService.addBalance(sharePerkAmount, mallMemberUp.getId()); mallMoneyFlowService.addMoneyFlow( mallMemberUp.getId(), sharePerkAmount, MoneyFlowTypeEnum.DYNAMIC_ACHIEVE.getValue(), mallOrderInfo.getOrderNo(), FlowTypeEnum.BALANCE.getValue()); } } /** * 星级奖励 * 从最顶级级别的合伙人开始补贴 * 补贴完,把已经补贴的合伙人加入下一个级别 */ List sevenLevelRecord = getStarRecord(null, MemberLevelEnum.SEVEN_LEVEL.name(), amount, mallOrderInfo.getOrderNo(), memberId,MoneyFlowTypeEnum.STAR_PERK_SEVEN.getValue()); List sixLevelRecord = getStarRecord(sevenLevelRecord, MemberLevelEnum.SIX_LEVEL.name(), amount, mallOrderInfo.getOrderNo(), memberId,MoneyFlowTypeEnum.STAR_PERK_SIX.getValue()); List fifthLevelRecord = getStarRecord(sixLevelRecord, MemberLevelEnum.FIFTH_LEVEL.name(), amount, mallOrderInfo.getOrderNo(), memberId,MoneyFlowTypeEnum.STAR_PERK_FIVE.getValue()); List fourLevelRecord = getStarRecord(fifthLevelRecord, MemberLevelEnum.FOUR_LEVEL.name(), amount, mallOrderInfo.getOrderNo(), memberId,MoneyFlowTypeEnum.STAR_PERK_FOUR.getValue()); List thirdLevelRecord = getStarRecord(fourLevelRecord, MemberLevelEnum.THIRD_LEVEL.name(), amount, mallOrderInfo.getOrderNo(), memberId,MoneyFlowTypeEnum.STAR_PERK_THREE.getValue()); List secondLevelRecord = getStarRecord(thirdLevelRecord, MemberLevelEnum.SECOND_LEVEL.name(), amount, mallOrderInfo.getOrderNo(), memberId,MoneyFlowTypeEnum.STAR_PERK_TWO.getValue()); } /** * * @param mallMembersOlds 高一级别的用户 * @param LevelParam 当前级别 * @param amount 补贴金额的基数 * @param orderNo 订单编号 * @param memberId 会员id * @return */ public List getStarRecord(List mallMembersOlds,String LevelParam,BigDecimal amount,String orderNo,Long memberId,int starPerkType){ long start = System.currentTimeMillis(); //根据用户的level获取用户 List mallMemberStars = memberMapper.selectMemberWithLevel(LevelParam); if(CollUtil.isNotEmpty(mallMembersOlds)){ for(MallMember mallMemberOld : mallMembersOlds){ mallMemberStars.add(mallMemberOld); } } if(CollUtil.isNotEmpty(mallMemberStars)){ List mallMemberStarIds = mallMemberStars.stream().map(MallMember::getId).collect(Collectors.toList()); //当前等级的总贡献点 List mallMemberWallets = mallMemberWalletMapper.selectSumStarByIds(mallMemberStarIds); Integer starSum = mallMemberWallets.stream().mapToInt(MallMemberWallet::getStar).sum(); //星级补贴比例 DataDictionaryCustom starPerkDic = dataDictionaryCustomMapper.selectDicDataByTypeAndCode( "AGENT_LEVEL_REQUIRE", LevelParam); String starPerkStr = starPerkDic.getValue(); AgentInfo agentInfo = JSONObject.parseObject(starPerkStr, AgentInfo.class); BigDecimal profitProp = agentInfo.getProfitProp().abs().divide(new BigDecimal(100)); //当前等级的星级补贴 BigDecimal starPerkAmountSum = amount.multiply(profitProp); //当前等级的每一个贡献点的补贴金额 BigDecimal starPerkAmountAva = starPerkAmountSum.divide(new BigDecimal(starSum),BigDecimal.ROUND_DOWN).setScale(2, BigDecimal.ROUND_DOWN); /** * 给当前等级的每个用户发放星级奖励 * 生成星级奖励的流水 */ if(CollUtil.isNotEmpty(mallMemberWallets)){ //给当前等级的每个用户发放星级奖励 int count = 0; List> result = new ArrayList<>(); List> resultReduce = new ArrayList<>(); List mallMoneyFlows = new ArrayList<>(); for(MallMemberWallet mallMemberWallet : mallMemberWallets){ Map hashMap = new HashMap<>(); Integer starCnt = mallMemberWallet.getStar(); //当前用户的星级奖励 BigDecimal starPerkAmount = starPerkAmountAva .multiply(new BigDecimal(starCnt)).abs().setScale(2, BigDecimal.ROUND_DOWN); BigDecimal totalScorePerk = mallMemberWallet.getTotalScore(); if(totalScorePerk.compareTo(starPerkAmount) < 0){ starPerkAmount = totalScorePerk; } if(BigDecimal.ZERO.compareTo(starPerkAmount) < 0){ hashMap.put("id",mallMemberWallet.getId()); hashMap.put("starPerkAmount",starPerkAmount); result.add(hashMap); resultReduce.add(hashMap); //生成星级奖励的流水对象 MallMoneyFlow mallMoneyFlow = new MallMoneyFlow(); mallMoneyFlow.setMemberId(mallMemberWallet.getMemberId()); mallMoneyFlow.setAmount(starPerkAmount); mallMoneyFlow.setType(starPerkType); mallMoneyFlow.setOrderNo(orderNo); mallMoneyFlow.setRtMemberId(memberId); mallMoneyFlow.setStatus(2); mallMoneyFlow.setFlowType(FlowTypeEnum.BALANCE.getValue()); mallMoneyFlows.add(mallMoneyFlow); } count = count + 1; if (count % 1000 == 0 || count == mallMemberWallets.size()) { if(CollUtil.isNotEmpty(result)){ int resultCount = mallMemberWalletMapper.updateStarByList(result); if(resultCount>0){ log.info("============余额新增============第{}条数据===========",resultCount); } //每更新完一批数据,在result内进行删除操作。 result.clear(); int resultReduceCount = mallMemberWalletMapper.updateTotalScoreByList(resultReduce); if(resultReduceCount>0){ log.info("============额度减少============第{}条数据===========",resultReduceCount); } //每更新完一批数据,在result内进行删除操作。 resultReduce.clear(); } } } if(CollUtil.isNotEmpty(mallMoneyFlows)){ SqlSession sqlSession = sqlSessionTemplate.getSqlSessionFactory().openSession(ExecutorType.BATCH,false); MallMoneyFlowMapper mallMoneyFlowMapper = sqlSession.getMapper(MallMoneyFlowMapper.class); for(int i = 1; i <= mallMoneyFlows.size(); i++){ mallMoneyFlowMapper.insertMoneyFlow(mallMoneyFlows.get(i-1)); if (i % 1000 == 0 || i == mallMoneyFlows.size()) { log.info("============插入流水============第{}条数据===========",mallMoneyFlows.size()); sqlSession.commit(); sqlSession.clearCache(); } } sqlSession.close(); } } } long end = System.currentTimeMillis(); log.info("============订单:{},时间:{}===========",orderNo,(end - start)/1000); return mallMemberStars; } }