package cc.mrbird.febs.mall.service.impl; import cc.mrbird.febs.common.enumerates.*; import cc.mrbird.febs.common.utils.RedisUtils; import cc.mrbird.febs.mall.entity.*; import cc.mrbird.febs.mall.mapper.*; import cc.mrbird.febs.mall.service.*; import cc.mrbird.febs.rabbit.producter.AgentProducer; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.RandomUtil; import cn.hutool.core.util.StrUtil; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import lombok.Data; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.*; /** * @author wzy * @date 2022-05-10 **/ @Slf4j @Service @RequiredArgsConstructor public class MemberProfitServiceImpl implements IMemberProfitService { private final MallMemberMapper mallMemberMapper; private final MallOrderInfoMapper mallOrderInfoMapper; private final MallOrderItemMapper mallOrderItemMapper; private final IApiMallMemberWalletService walletService; private final IMallMoneyFlowService moneyFlowService; private final DataDictionaryCustomMapper dataDictionaryCustomMapper; private final MallSystemSettingMapper mallSystemSettingMapper; /** * 直推收益 * * 1、直推收益 1:20;2:30;3:40 返利,隔代奖拿直推收益20% * 2、若非代理推代理,只拿10%,往上找代理给15%,再往上找代理给15%,往上找连续两层。股东套餐同理 * 3、代理推代理按照第1点结算 * * @param orderId */ @Override @Transactional(rollbackFor = Exception.class) public void directProfit(Long orderId) { log.info("######直推奖励, 订单ID:{}######", orderId); MallOrderInfo orderInfo = mallOrderInfoMapper.selectById(orderId); if (orderInfo.getOrderType() == 2) { log.info("积分订单无返利"); return; } MallMember member = mallMemberMapper.selectById(orderInfo.getMemberId()); // 父级会员 MallMember parentMember = mallMemberMapper.selectInfoByInviteId(member.getReferrerId()); if (parentMember == null) { return; } if (parentMember.getAccountLevel() == 0 || MemberLevelEnum.ZERO_LEVEL.getType().equals(parentMember.getLevel())) { log.info("上级:{}未购买会员套餐,无返利", parentMember.getInviteId()); return; } // 非代理推代理,非代理上级拿的收益比例 DataDictionaryCustom indirectPerDic = dataDictionaryCustomMapper.selectDicDataByTypeAndCode(DataDictionaryEnum.UNAGENT_TO_AGENT_PARENT.getType(), DataDictionaryEnum.UNAGENT_TO_AGENT_PARENT.getCode()); // 非代理推代理,非代理上级拿的收益比例 DataDictionaryCustom indirectPerTwoDic = dataDictionaryCustomMapper.selectDicDataByTypeAndCode(DataDictionaryEnum.UNAGENT_TO_AGENT_PARENT_TWO.getType(), DataDictionaryEnum.UNAGENT_TO_AGENT_PARENT_TWO.getCode()); // 非代理推代理,非代理的直推收益比例 DataDictionaryCustom unAgentDirectDic = dataDictionaryCustomMapper.selectDicDataByTypeAndCode(DataDictionaryEnum.UNAGENT_TO_AGENT.getType(), DataDictionaryEnum.UNAGENT_TO_AGENT.getCode()); // 父级需要拥有 此会员 对应级别的直推数量 Integer directCnt = mallMemberMapper.selectOwnCntByInviteIdAndAccountLevel(parentMember.getInviteId(), member.getAccountLevel()); List dataDices = dataDictionaryCustomMapper.selectDicByType(DataDictionaryEnum.DIRECT_BONUS_SETTING.getType()); directCnt = directCnt == null ? 0 : directCnt; List items = mallOrderInfoMapper.getMallOrderItemByOrderId(orderId); if (CollUtil.isEmpty(items)) { return; } // 推荐奖比例 DataDictionaryCustom indrectDicPropDic = dataDictionaryCustomMapper.selectDicDataByTypeAndCode(DataDictionaryEnum.RECOMMEND_BONUS.getType(), DataDictionaryEnum.RECOMMEND_BONUS.getCode()); for (MallOrderItem item : items) { // 减去成本后算收益 减去积分付款 BigDecimal amount = item.getPrice().subtract(item.getCostPrice()).multiply(BigDecimal.valueOf(item.getCnt())).subtract(orderInfo.getScoreAmount()); if (amount.compareTo(BigDecimal.ZERO) < 1) { continue; } // ----- 直推奖 start ------- // 直推返利比例 BigDecimal profitPer = BigDecimal.ZERO; int isSameLevel = 0; // 普通商品 -- 直推上级可拿百分比直推奖励 if (item.getIsNormal() == 1) { profitPer = new BigDecimal(item.getNormalPer()); // 套餐商品 } else { // 判断上级是否与自己购买的套餐符合,若符合则走3级直推逻辑,若不符合则另外一个 if (parentMember.getAccountLevel() >= item.getGoodsLevel()) { for (DataDictionaryCustom dataDic : dataDices) { JSONObject jsonObject = JSONObject.parseObject(dataDic.getValue()); if (directCnt >= jsonObject.getInteger("pushCnt")) { profitPer = jsonObject.getBigDecimal("prop"); } } isSameLevel = 1; // 非代理推代理/非股东推股东 } else { profitPer = new BigDecimal(unAgentDirectDic.getValue()); isSameLevel = 2; } } // 直推奖 BigDecimal profit = amount.multiply(profitPer.divide(new BigDecimal(100), 2, RoundingMode.HALF_UP)); log.info("直推奖励:{}", profit); changeScoreAndCommission(parentMember.getId(), profit, MoneyFlowTypeEnum.DIRECT_BONUS.getValue(), orderInfo.getOrderNo()); // 非代理推代理 if (isSameLevel == 2) { if (StrUtil.isBlank(parentMember.getReferrerIds())) { continue; } List mallMembers = mallMemberMapper.selectParentMemberList(StrUtil.split(parentMember.getReferrerIds(), ','), parentMember.getReferrerId(), 2); if (CollUtil.isEmpty(mallMembers)) { continue; } int index = 1; for (MallMember mallMember : mallMembers) { if (!item.getGoodsLevel().equals(mallMember.getAccountLevel())) { break; } if (index != 2) { indirectPerDic = indirectPerTwoDic; } BigDecimal doubleParentProfit = profit.multiply(new BigDecimal(indirectPerDic.getValue())); changeScoreAndCommission(mallMember.getId(), doubleParentProfit, MoneyFlowTypeEnum.DIRECT_BONUS.getValue(), orderInfo.getOrderNo()); index++; } } // ----- 直推奖 end ------- // =======隔代奖== start ===== if (StrUtil.isBlank(parentMember.getReferrerId())) { continue; } List parents = StrUtil.split(parentMember.getReferrerIds(), ','); List members = mallMemberMapper.selectByInviteIds(parents); if (CollUtil.isEmpty(members)) { return; } BigDecimal direct = profit; for (MallMember parent : members) { if (parent.getInviteId().equals(parentMember.getInviteId())) { continue; } BigDecimal indrectDicProp = new BigDecimal(indrectDicPropDic.getValue()); // 隔代推荐奖 收益 direct = direct.multiply(indrectDicProp.divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP)); // direct 收益小于1,则跳出 if (direct.compareTo(BigDecimal.valueOf(0.01)) < 1) { break; } int reduceResult = walletService.reduce(direct, parent.getId(), "score"); if (reduceResult == 2) { continue; } walletService.add(direct, parent.getId(), "balance"); moneyFlowService.addMoneyFlow(parent.getId(), direct, MoneyFlowTypeEnum.RECOMMEND_BONUS.getValue(), orderInfo.getOrderNo(), FlowTypeEnum.BALANCE.getValue()); moneyFlowService.addMoneyFlow(parent.getId(), direct.negate(), MoneyFlowTypeEnum.RECOMMEND_BONUS.getValue(), orderInfo.getOrderNo(), FlowTypeEnum.SCORE.getValue()); } // =======隔代奖== end ===== } } /** * 直推20%,隔代收益为直推奖励金额的30%,a_b_c_d,d购买1000套餐,c得200,b得200*30%=60元,a得60*30%=18元。。。 * 以此类推,结算到一元为止。 * * @param orderId */ @Override @Transactional(rollbackFor = Exception.class) public void dynamicProfit(Long orderId, Integer isNormal) { MallOrderInfo orderInfo = mallOrderInfoMapper.selectById(orderId); if (orderInfo.getOrderType() == 2) { log.info("积分订单无返利"); return; } MallMember member = mallMemberMapper.selectById(orderInfo.getMemberId()); if (StrUtil.isBlank(member.getReferrerId())) { return; } // 直推奖励字典 DataDictionaryCustom dic = dataDictionaryCustomMapper.selectDicDataByTypeAndCode(DataDictionaryEnum.DYNAMIC_BONUS.getType(), DataDictionaryEnum.DYNAMIC_BONUS.getCode()); // 直接父级 MallMember parent = mallMemberMapper.selectInfoByInviteId(member.getReferrerId()); List items = mallOrderInfoMapper.getMallOrderItemByOrderId(orderId); for (MallOrderItem item : items) { item.setHasSettle(1); mallOrderItemMapper.updateById(item); // 减去成本后算收益 BigDecimal amount = item.getPrice().subtract(item.getCostPrice()).multiply(BigDecimal.valueOf(item.getCnt())); if (amount.compareTo(BigDecimal.ZERO) < 1) { continue; } // 判断套餐或者普通商品,结算对应商品的动态分红 // if (!Objects.equals(item.getIsNormal(), isNormal)) { // continue; // } // =======直推返利== start ===== // 直接奖励收益 BigDecimal dynamicProfit = amount.multiply(new BigDecimal(dic.getValue()).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP)); if (dynamicProfit.compareTo(BigDecimal.ZERO) < 1) { continue; } // int reduce = walletService.reduce(dynamicProfit, parent.getId(), "score"); // if (reduce == 2) { // continue; // } // walletService.add(dynamicProfit, parent.getId(), "commission"); // moneyFlowService.addMoneyFlow(parent.getId(), dynamicProfit, MoneyFlowTypeEnum.DYNAMIC_ACHIEVE.getValue(), orderInfo.getOrderNo(), FlowTypeEnum.COMMISSION.getValue()); // moneyFlowService.addMoneyFlow(parent.getId(), dynamicProfit.negate(), MoneyFlowTypeEnum.DYNAMIC_ACHIEVE.getValue(), orderInfo.getOrderNo(), FlowTypeEnum.SCORE.getValue()); // dynamicProfit = changeScoreAndCommission(parent.getId(), dynamicProfit, MoneyFlowTypeEnum.DYNAMIC_ACHIEVE.getValue(), orderInfo.getOrderNo()); if (dynamicProfit.compareTo(BigDecimal.ZERO) < 1) { continue; } // =======直推返利== end ===== // =======隔代奖== start ===== if (StrUtil.isBlank(parent.getReferrerId())) { continue; } List parents = StrUtil.split(parent.getReferrerIds(), ','); List members = mallMemberMapper.selectByInviteIds(parents); if (CollUtil.isEmpty(members)) { return; } BigDecimal direct = dynamicProfit; for (MallMember parentMember : members) { if (parent.getInviteId().equals(parentMember.getInviteId())) { continue; } // 直推数量 Integer directCnt = mallMemberMapper.selectOwnCntByInviteId(parentMember.getInviteId()); List dataDices = dataDictionaryCustomMapper.selectDicByType(DataDictionaryEnum.INDIRECT_BONUS_SETTING.getType()); directCnt = directCnt == null ? 0 : directCnt; // 隔代比例 BigDecimal indrectDicProp = BigDecimal.ZERO; for (DataDictionaryCustom dataDic : dataDices) { JSONObject jsonObject = JSONObject.parseObject(dataDic.getValue()); if (directCnt >= jsonObject.getInteger("pushCnt")) { indrectDicProp = jsonObject.getBigDecimal("prop"); } } // 隔代推荐奖 收益 direct = direct.multiply(indrectDicProp.divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP)); // direct 收益小于1,则跳出 if (direct.compareTo(BigDecimal.ONE) < 1) { break; } // int reduceResult = walletService.reduce(direct, parentMember.getId(), "score"); // if (reduceResult == 2) { // continue; // } // // walletService.add(direct, parentMember.getId(), "commission"); // moneyFlowService.addMoneyFlow(parentMember.getId(), direct, MoneyFlowTypeEnum.RECOMMEND_BONUS.getValue(), orderInfo.getOrderNo(), FlowTypeEnum.COMMISSION.getValue()); // moneyFlowService.addMoneyFlow(parentMember.getId(), direct.negate(), MoneyFlowTypeEnum.RECOMMEND_BONUS.getValue(), orderInfo.getOrderNo(), FlowTypeEnum.SCORE.getValue()); // changeScoreAndCommission(parentMember.getId(), direct, MoneyFlowTypeEnum.RECOMMEND_BONUS.getValue(), orderInfo.getOrderNo()); } // =======隔代奖== end ===== } } @Override @Transactional(rollbackFor = Exception.class) public void agentProfit(Integer type) { log.info("#####==代理分红--{}==start==#####", type); if (type == null) { return; } MallSystemSetting systemSetting = mallSystemSettingMapper.selectById(1L); if (systemSetting == null) { log.info("没有系统配置"); return; } BigDecimal hundred = BigDecimal.valueOf(100); DataDictionaryCustom dic = dataDictionaryCustomMapper.selectDicDataByTypeAndCode(DataDictionaryEnum.AGENT_BONUS_RELEASE.getType(), DataDictionaryEnum.AGENT_BONUS_RELEASE.getCode()); if (dic == null || StrUtil.isBlank(dic.getValue()) || Integer.parseInt(dic.getValue()) == 0) { log.info("不进行代理分红"); return; } // 代理 BigDecimal waitToBonus = systemSetting.getAgentBonus().multiply(new BigDecimal(dic.getValue()).divide(hundred, 2, RoundingMode.HALF_UP)); // 代理 List mallMembers = mallMemberMapper.selectAgentOrPartnetMemberList(type); if (CollUtil.isEmpty(mallMembers) || waitToBonus.compareTo(BigDecimal.ZERO) < 1) { log.info("待分红金额不足或会员不足"); return; } BigDecimal perBonus = waitToBonus.divide(new BigDecimal(mallMembers.size()), 2, RoundingMode.HALF_UP); mallMembers.forEach(item -> { changeScoreAndCommission(item.getId(), perBonus, type.equals(AccountLevelEnums.VVIP.getLevel()) ? MoneyFlowTypeEnum.AGENT_BONUS.getValue() : MoneyFlowTypeEnum.PARTNER_BONUS.getValue(), null); }); if (type.equals(AccountLevelEnums.VVIP.getLevel())) { changeSystemBonus(null, waitToBonus,null); } else { changeSystemBonus(null, null, waitToBonus); } bonusRecord(waitToBonus, type, null, null); log.info("#####==代理分红 -- {}==end==#####", type); } private BigDecimal changeScoreAndCommission(Long memberId, BigDecimal income, Integer type, String orderNo) { Map map = new HashMap<>(); map.put("amount", income); int reduce = walletService.reduce(income, memberId, "score", map); if (reduce == 2) { return BigDecimal.ZERO; } income = map.get("amount"); walletService.add(income, memberId, "balance"); moneyFlowService.addMoneyFlow(memberId, income, type, orderNo, FlowTypeEnum.BALANCE.getValue()); moneyFlowService.addMoneyFlow(memberId, income.negate(), type, orderNo, FlowTypeEnum.SCORE.getValue()); return income; } @Override public void allInternetProfit() { log.info("###全网分红执行--start--###"); MallSystemSetting systemSetting = mallSystemSettingMapper.selectById(1L); if (systemSetting == null) { log.info("没有系统配置"); return; } BigDecimal hundred = BigDecimal.valueOf(100); DataDictionaryCustom dic = dataDictionaryCustomMapper.selectDicDataByTypeAndCode(DataDictionaryEnum.ALL_INTERNET_BONUS_RELEASE.getType(), DataDictionaryEnum.ALL_INTERNET_BONUS_RELEASE.getCode()); if (dic == null || StrUtil.isBlank(dic.getValue()) || Integer.parseInt(dic.getValue()) == 0) { log.info("不进行全网分红"); return; } // 全网分红 BigDecimal waitToBonus = systemSetting.getAllBonus().multiply(new BigDecimal(dic.getValue()).divide(hundred, 2, RoundingMode.HALF_UP)); List mallMembers = mallMemberMapper.selectMemberAfterLevelList(MemberLevelEnum.FIRST_LEVEL.getType()); if (CollUtil.isEmpty(mallMembers) || waitToBonus.compareTo(BigDecimal.ZERO) < 1) { log.info("待分红金额不足或会员不足"); return; } List dicList = dataDictionaryCustomMapper.selectDicByType(DataDictionaryEnum.INTERNET_LEVEL_BONUS.getType()); if (CollUtil.isEmpty(dicList)) { return; } Map levelBonusMap = new HashMap<>(); dicList.forEach(item -> { BigDecimal levelRatio = new BigDecimal(item.getValue()).divide(hundred, 2, RoundingMode.HALF_UP); levelBonusMap.put(item.getCode(), waitToBonus.multiply(levelRatio)); }); Map> levelMemberMap = new HashMap<>(); // TODO 并发处理 mallMembers.forEach(item -> { String level = item.getLevel(); // 全网分红 -- 代理和股东当作是女王殿下级别 if (MemberLevelEnum.getLevelCode(level) > MemberLevelEnum.FOUR_LEVEL.getCode()) { level = MemberLevelEnum.FOUR_LEVEL.getType(); } List memberList = levelMemberMap.get(level); if (CollUtil.isEmpty(memberList)) { memberList = new ArrayList<>(); } memberList.add(item); levelMemberMap.put(item.getLevel(), memberList); }); if (levelMemberMap.isEmpty()) { return; } BigDecimal totalBonus = BigDecimal.ZERO; for (Map.Entry> entry : levelMemberMap.entrySet()) { BigDecimal levelBonus = levelBonusMap.get(entry.getKey()); List memberList = entry.getValue(); if (CollUtil.isEmpty(memberList) || levelBonus.compareTo(BigDecimal.ZERO) < 1) { continue; } BigDecimal perBonus = levelBonus.divide(BigDecimal.valueOf(memberList.size()), 2, RoundingMode.HALF_UP); memberList.forEach(item -> { changeScoreAndCommission(item.getId(), perBonus, MoneyFlowTypeEnum.ALL_INTERNET_BONUS.getValue(), null); }); totalBonus = totalBonus.add(levelBonus); } changeSystemBonus(totalBonus, null, null); log.info("###全网分红执行--end--###"); } @Override @Transactional(rollbackFor = Exception.class) public void orderBonus(Long orderId) { log.info("###订单分红消息开始执行###"); MallOrderInfo orderInfo = mallOrderInfoMapper.selectById(orderId); if (orderInfo.getOrderType() == 2) { log.info("积分订单无返利"); return; } List items = mallOrderInfoMapper.getMallOrderItemByOrderId(orderId); if (CollUtil.isEmpty(items)) { return; } DataDictionaryCustom allInternetBonusDic = dataDictionaryCustomMapper.selectDicDataByTypeAndCode(DataDictionaryEnum.ALL_INTERNET_BONUS.getType(), DataDictionaryEnum.ALL_INTERNET_BONUS.getCode()); DataDictionaryCustom agentBonusDic = dataDictionaryCustomMapper.selectDicDataByTypeAndCode(DataDictionaryEnum.AGENT_ALL_BONUS.getType(), DataDictionaryEnum.AGENT_ALL_BONUS.getCode()); DataDictionaryCustom partnerBonusDic = dataDictionaryCustomMapper.selectDicDataByTypeAndCode(DataDictionaryEnum.PARNER_ALL_BONUS.getType(), DataDictionaryEnum.PARNER_ALL_BONUS.getCode()); String id = RandomUtil.randomNumbers(16); // 全网分红 BigDecimal totalBonus = BigDecimal.ZERO; // 代理分红 BigDecimal agentTotalBonus = BigDecimal.ZERO; // 股东分红 BigDecimal partnerTotalBonus = BigDecimal.ZERO; BigDecimal hundred = new BigDecimal(100); for (MallOrderItem item : items) { // 减去成本后算收益 BigDecimal amount = item.getPrice().subtract(item.getCostPrice()).multiply(BigDecimal.valueOf(item.getCnt())).subtract(orderInfo.getScoreAmount()); if (amount.compareTo(BigDecimal.ZERO) < 1) { continue; } if (item.getIsNormal() == 1) { BigDecimal bonus = amount.multiply(BigDecimal.valueOf(item.getNormalBonus()).divide(hundred, 2, RoundingMode.HALF_UP)); log.info("{}-普通商品分红:{}, 明细ID:{}", id, bonus, item.getId()); bonusRecord(bonus, 1, item.getOrderId(), item.getId()); totalBonus = totalBonus.add(bonus); } else { BigDecimal bonus = amount.multiply(new BigDecimal(allInternetBonusDic.getValue()).divide(hundred, 2, RoundingMode.HALF_UP)); bonusRecord(bonus, 1, item.getOrderId(), item.getId()); log.info("{}-套餐全网分红:{}, 明细ID:{}", id, bonus, item.getId()); totalBonus = totalBonus.add(bonus); BigDecimal agentBonus = amount.multiply(new BigDecimal(agentBonusDic.getValue()).divide(hundred, 2, RoundingMode.HALF_UP)); bonusRecord(agentBonus, 2, item.getOrderId(), item.getId()); log.info("{}-套餐代理分红:{}, 明细ID:{}", id, agentBonus, item.getId()); BigDecimal partnerBonus = amount.multiply(new BigDecimal(partnerBonusDic.getValue()).divide(hundred, 2, RoundingMode.HALF_UP)); bonusRecord(partnerBonus, 3, item.getOrderId(), item.getId()); log.info("{}-套餐股东分红:{}, 明细ID:{}", id, partnerBonus, item.getId()); agentTotalBonus = agentTotalBonus.add(agentBonus); partnerTotalBonus = partnerTotalBonus.add(partnerBonus); } } changeSystemBonus(totalBonus, agentTotalBonus, partnerTotalBonus); log.info("###订单分红消息结束执行###"); } private void changeSystemBonus(BigDecimal totalBonus, BigDecimal agentTotalBonus, BigDecimal partnerBonus) { boolean flag = false; int index = 0; while (!flag) { MallSystemSetting setting = mallSystemSettingMapper.selectById(1L); if (setting == null) { return; } LambdaQueryWrapper update = new LambdaQueryWrapper<>(); update.eq(MallSystemSetting::getId, setting.getId()) .eq(MallSystemSetting::getRevision, setting.getRevision()); setting.setAllBonus(setting.getAllBonus().add(totalBonus == null ? BigDecimal.ZERO : totalBonus)); setting.setAgentBonus(setting.getAgentBonus().add(agentTotalBonus == null ? BigDecimal.ZERO : agentTotalBonus)); setting.setPartnerBonus(setting.getPartnerBonus().add(partnerBonus == null ? BigDecimal.ZERO : partnerBonus)); setting.setRevision(setting.getRevision() + 1); int i = mallSystemSettingMapper.update(setting, update); if (i > 0 || index > 2) { flag = true; } index++; } } private final MallBonusRecordMapper mallBonusRecordMapper; private void bonusRecord(BigDecimal amount, Integer type, Long orderId, Long orderItemId) { MallBonusRecord record = new MallBonusRecord(); record.setAmount(amount); record.setCreateTime(new Date()); record.setType(type); record.setOrderId(orderId); record.setOrderItemId(orderItemId); mallBonusRecordMapper.insert(record); } }