KKSU
2024-06-11 37f13de311a35f45569397422708dd47dab72178
增加节点买卖规则
增加推荐规则奖励
19 files modified
5 files added
580 ■■■■■ changed files
src/main/java/cc/mrbird/febs/dapp/entity/DappAchieveTreeEntity.java 6 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/dapp/entity/DappFundFlowEntity.java 1 ●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/dapp/entity/DbMemberNode.java 28 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/dapp/enumerate/DataDictionaryEnum.java 1 ●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/dapp/enumerate/InviteRule.java 38 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/dapp/enumerate/NodeType.java 56 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/dapp/mapper/DappAchieveTreeDao.java 1 ●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/dapp/mapper/DbMemberNodeMapper.java 11 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/dapp/service/DappSystemService.java 12 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/dapp/service/impl/BscUsdtContractEvent.java 11 ●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/dapp/service/impl/DappMemberServiceImpl.java 20 ●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/dapp/service/impl/DappSystemServiceImpl.java 231 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/dapp/service/impl/DappWalletServiceImpl.java 13 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/dapp/vo/WalletInfoVo.java 3 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/job/MatrixTreeInit.java 20 ●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/rabbit/QueueConstants.java 5 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/rabbit/QueueEnum.java 5 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/rabbit/RabbitConfiguration.java 38 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/rabbit/consumer/ChainConsumer.java 14 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/rabbit/producer/ChainProducer.java 16 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/tree/MatrixTree.java 2 ●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/tree/MemberNode.java 12 ●●●● patch | view | raw | blame | history
src/main/resources/mapper/dapp/DappAchieveTreeDao.xml 6 ●●●●● patch | view | raw | blame | history
src/main/resources/mapper/dapp/DbMemberNodeMapper.xml 30 ●●●●● patch | view | raw | blame | history
src/main/java/cc/mrbird/febs/dapp/entity/DappAchieveTreeEntity.java
@@ -32,4 +32,10 @@
    @TableField(exist = false)
    private String refererId;
    @TableField(exist = false)
    private Long memberId;
    @TableField(exist = false)
    private Long fundId;
}
src/main/java/cc/mrbird/febs/dapp/entity/DappFundFlowEntity.java
@@ -50,6 +50,7 @@
     *
     *  13-节点买入
     *  14-节点返利
     *  15-见点奖
     */
    private Integer type;
src/main/java/cc/mrbird/febs/dapp/entity/DbMemberNode.java
New file
@@ -0,0 +1,28 @@
package cc.mrbird.febs.dapp.entity;
import cc.mrbird.febs.common.entity.BaseEntity;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.math.BigDecimal;
@Data
@TableName("db_member_node")
public class DbMemberNode extends BaseEntity {
    private Long memberId;
    private Long fundId;//流水ID
    private BigDecimal amount;//投入金额
    private Integer type;//类型
    private Integer countFund;//投入轮数
    private Integer perkState;//是否已提取 1-未提取 2-已提取
    private Integer leftRight;//左右节点 1-左 2-右
    private Long leftNode;//左子节点
    private Long rightNode;//右子节点
    private Long parentNode;//父节点memberID
    private Integer workState;//生效状态 1-生效中 2-已出局
    public static final int STATE_ONE = 1;
    public static final int STATE_TWO = 2;
}
src/main/java/cc/mrbird/febs/dapp/enumerate/DataDictionaryEnum.java
@@ -10,6 +10,7 @@
    // 购买节点需要的金额
    BUY_NODE_CNT("BUY_NODE_CNT","BUY_NODE_CNT"),
    BUY_NODE_AMOUNT("BUY_NODE_AMOUNT","BUY_NODE_AMOUNT"),
    // 每日返利的产矿百分比
    REBATE_PERCENT("SYSTEM_SETTING","REBATE_PERCENT"),
src/main/java/cc/mrbird/febs/dapp/enumerate/InviteRule.java
New file
@@ -0,0 +1,38 @@
package cc.mrbird.febs.dapp.enumerate;
import lombok.Getter;
@Getter
public enum InviteRule {
    /**
     *  层级 直推人数 奖励百分比
     */
    LEVEL_10(10,4,1),
    LEVEL_9(9,4,1),
    LEVEL_8(8,4,1),
    LEVEL_7(7,4,1),
    LEVEL_6(6,3,1),
    LEVEL_5(5,3,1),
    LEVEL_4(4,3,1),
    LEVEL_3(3,2,1),
    LEVEL_2(2,2,1),
    LEVEL_1(1,2,1);
    private int level;
    private int InviteNum;
    private int perkPercent;
    InviteRule(int level,int InviteNum,int perkPercent) {
        this.level = level;
        this.InviteNum = InviteNum;
        this.perkPercent = perkPercent;
    }
    public InviteRule getRule(int level) {
        for (InviteRule value : InviteRule.values()) {
            if (value.level == level) {
                return value;
            }
        }
        return null;
    }
}
src/main/java/cc/mrbird/febs/dapp/enumerate/NodeType.java
New file
@@ -0,0 +1,56 @@
package cc.mrbird.febs.dapp.enumerate;
import lombok.Getter;
import java.math.BigDecimal;
@Getter
public enum NodeType {
    /**
     * 节点类型 投注金额 投注奖励
     */
    NODE_13(13,"566.9","793.66"),
    NODE_12(12,"405","566.9"),
    NODE_11(11,"289.3","405"),
    NODE_10(10,"206.6","289.3"),
    NODE_9(9,"147.6","206.6"),
    NODE_8(8,"105.4","147.6"),
    NODE_7(7,"75.3","105.4"),
    NODE_6(6,"53.8","75.3"),
    NODE_5(5,"38.4","53.8"),
    NODE_4(4,"27.4","38.4"),
    NODE_3(3,"19.6","27.4"),
    NODE_2(2,"14","19.6"),
    NODE_1(1,"10","14");
    private int nodeType;
    private String nodeAmount;
    private String nodePerk;
    NodeType(int nodeType, String nodeAmount, String nodePerk) {
        this.nodeType = nodeType;
        this.nodeAmount = nodeAmount;
        this.nodePerk = nodePerk;
    }
    public NodeType getNode(int nodeType) {
        for (NodeType value : NodeType.values()) {
            if (value.nodeType == nodeType) {
                return value;
            }
        }
        return null;
    }
    public NodeType getNodeByAmount(BigDecimal nodeAmount) {
        BigDecimal abs = nodeAmount.abs();
        for (NodeType value : NodeType.values()) {
            if (abs.toString().equals(value.nodeAmount)) {
                return value;
            }
        }
        return null;
    }
}
src/main/java/cc/mrbird/febs/dapp/mapper/DappAchieveTreeDao.java
@@ -11,6 +11,7 @@
    DappAchieveTreeEntity selectByMidNode(@Param("memberId") Long memberId);
    List<DappAchieveTreeEntity> selectTreeList();
    List<DappAchieveTreeEntity> selectTreeListV2();
    DappAchieveTreeEntity selectNewestTreeNode();
src/main/java/cc/mrbird/febs/dapp/mapper/DbMemberNodeMapper.java
New file
@@ -0,0 +1,11 @@
package cc.mrbird.febs.dapp.mapper;
import cc.mrbird.febs.dapp.entity.DbMemberNode;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
public interface DbMemberNodeMapper extends BaseMapper<DbMemberNode> {
    DbMemberNode selectOneByWorkStateAndLeftNodeNullOrRightNodeNull(@Param("workState")int stateOne);
}
src/main/java/cc/mrbird/febs/dapp/service/DappSystemService.java
@@ -1,10 +1,6 @@
package cc.mrbird.febs.dapp.service;
import cc.mrbird.febs.dapp.dto.SystemDto;
import cc.mrbird.febs.dapp.entity.DappMineDataEntity;
import java.math.BigDecimal;
import java.util.Map;
public interface DappSystemService {
@@ -12,16 +8,22 @@
    void achieveTree(Long memberId);
    void achieveTreeV2(Long memberId);
    /**
     * 投入收益
     *
     * @param isReIn
     */
    void putIntoProfit(Long memberId, int isReIn);
    void putIntoProfit(Long meerId, int isReIn);
    void tfcNewPrice(String data);
    void resetMatrix();
    void feeDistribute(String data);
    void invitePerkMsg(Long id);
    void nodePerkMsg(Long id);
}
src/main/java/cc/mrbird/febs/dapp/service/impl/BscUsdtContractEvent.java
@@ -211,8 +211,11 @@
                    }
                    //生成业绩数
                    chainProducer.sendAchieveTreeMsg(fundFlow.getMemberId());
                    //分发手续费给节点
                    buyNodePerk(amount);
                    //发送推荐规则奖励
                    chainProducer.sendInvitePerkMsg(fundFlow.getId());
                    //发送节点投资
                    chainProducer.sendNodePerkMsg(fundFlow.getId());
//                    buyNodePerk(amount);
                }else if(13 == fundFlow.getType()){//认购节点 13
@@ -224,7 +227,9 @@
                    Long memberId = fundFlow.getMemberId();
                    DappMemberEntity dappMemberEntity = dappMemberDao.selectById(memberId);
                    dappMemberEntity.setBuyNode(1);
                    Integer buyNode = dappMemberEntity.getBuyNode();
                    buyNode = buyNode + 1;
                    dappMemberEntity.setBuyNode(buyNode);
                    dappMemberDao.updateById(dappMemberEntity);
                }
            }else{
src/main/java/cc/mrbird/febs/dapp/service/impl/DappMemberServiceImpl.java
@@ -1,6 +1,5 @@
package cc.mrbird.febs.dapp.service.impl;
import cc.mrbird.febs.common.configure.i18n.MessageSourceUtils;
import cc.mrbird.febs.common.contants.AppContants;
import cc.mrbird.febs.common.entity.QueryRequest;
import cc.mrbird.febs.common.exception.FebsException;
@@ -8,13 +7,11 @@
import cc.mrbird.febs.common.utils.LoginUserUtil;
import cc.mrbird.febs.common.utils.RedisUtils;
import cc.mrbird.febs.common.utils.ShareCodeUtil;
import cc.mrbird.febs.dapp.chain.ChainEnum;
import cc.mrbird.febs.dapp.chain.ChainService;
import cc.mrbird.febs.dapp.chain.ContractChainService;
import cc.mrbird.febs.dapp.dto.ApproveDto;
import cc.mrbird.febs.dapp.dto.ConnectDto;
import cc.mrbird.febs.dapp.dto.PriceSettingDto;
import cc.mrbird.febs.dapp.dto.TeamListDto;
import cc.mrbird.febs.dapp.entity.*;
import cc.mrbird.febs.dapp.enumerate.DataDictionaryEnum;
import cc.mrbird.febs.dapp.mapper.*;
@@ -23,7 +20,9 @@
import cc.mrbird.febs.dapp.vo.TeamListVo;
import cc.mrbird.febs.system.entity.User;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@@ -54,6 +53,7 @@
    private final DappAchieveMemberTreeDao dappAchieveMemberTreeDao;
    private final DataDictionaryCustomMapper dataDictionaryCustomMapper;
    private final DappFundFlowDao dappFundFlowDao;
    @Override
    @Transactional(rollbackFor = Exception.class)
@@ -341,7 +341,19 @@
    public TeamListVo findTeamList() {
        DappMemberEntity member = LoginUserUtil.getAppUser();
        DappAchieveMemberTreeEntity topNode = dappAchieveMemberTreeDao.selectNodeByDeep(member.getId(), 1);
//        DappAchieveMemberTreeEntity topNode = dappAchieveMemberTreeDao.selectNodeByDeep(member.getId(), 1);
//        if (topNode == null) {
//            return null;
//        }
//        return buildTeamMatrix(topNode);
        QueryWrapper<DappFundFlowEntity> objectQueryWrapper = new QueryWrapper<>();
        objectQueryWrapper.eq("member_id", member.getId());
        objectQueryWrapper.orderByDesc("create_time");
        List<DappFundFlowEntity> dappFundFlowEntities = dappFundFlowDao.selectList(objectQueryWrapper);
        if(ObjectUtil.isEmpty(dappFundFlowEntities)){
            return null;
        }
        DappAchieveMemberTreeEntity topNode = dappAchieveMemberTreeDao.selectNodeByDeep(dappFundFlowEntities.get(0).getId(), 1);
        if (topNode == null) {
            return null;
        }
src/main/java/cc/mrbird/febs/dapp/service/impl/DappSystemServiceImpl.java
@@ -5,6 +5,8 @@
import cc.mrbird.febs.dapp.dto.SystemDto;
import cc.mrbird.febs.dapp.entity.*;
import cc.mrbird.febs.dapp.enumerate.DataDictionaryEnum;
import cc.mrbird.febs.dapp.enumerate.InviteRule;
import cc.mrbird.febs.dapp.enumerate.NodeType;
import cc.mrbird.febs.dapp.mapper.*;
import cc.mrbird.febs.dapp.service.DappSystemService;
import cc.mrbird.febs.dapp.service.DappWalletService;
@@ -16,6 +18,7 @@
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.QueryWrapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@@ -44,6 +47,8 @@
    private final DappAchieveMemberTreeDao dappAchieveMemberTreeDao;
    private final DappWalletService dappWalletService;
    private final DataDictionaryCustomMapper dataDictionaryCustomMapper;
    private final DbMemberNodeMapper dbMemberNodeMapper;
    @Override
@@ -147,6 +152,97 @@
            }
        }
    }
    @Override
    public void achieveTreeV2(Long fundId) {
        DappFundFlowEntity dappFundFlowEntity = dappFundFlowDao.selectById(fundId);
        if(ObjectUtil.isEmpty(dappFundFlowEntity)){
            return;
        }
        Integer status = dappFundFlowEntity.getStatus();
        if(2 != status){
            return;
        }
        Long memberId = dappFundFlowEntity.getMemberId();
        DappMemberEntity member = dappMemberDao.selectById(memberId);
        if(ObjectUtil.isEmpty(member)){
            return;
        }
        BigDecimal amount = dappFundFlowEntity.getAmount();
        //根据金额判断属于属于购买的哪一个节点
        NodeType nodeType = NodeType.NODE_1.getNodeByAmount(amount);
        /**
         * 获取一条最老的左右节点未满的记录
         * 然后生成一条新的记录
         * 如果添加的为左节点,那么没人出局
         * 如果添加的为右节点,那么进入判断
         *      1、父节点为左节点,那么没人出局
         *      2、父节点为右节点,那么进入判断,父节点是否有上级节点
         *          1、有,则上级节点出局复投,轮数加1,复投逻辑
         *
         */
        //获取一条最老的左右节点未满且生效中的记录
        DbMemberNode dbMemberNodeOld = dbMemberNodeMapper.selectOneByWorkStateAndLeftNodeNullOrRightNodeNull(DbMemberNode.STATE_ONE);
        if(ObjectUtil.isEmpty(dbMemberNodeOld)){
            //生成ROOT节点
            DbMemberNode root = new DbMemberNode();
            root.setMemberId(memberId);
            root.setFundId(fundId);
            root.setAmount(new BigDecimal(nodeType.getNodeAmount()));
            root.setType(nodeType.getNodeType());
            root.setCountFund(1);
            root.setPerkState(1);
            root.setWorkState(1);
            dbMemberNodeMapper.insert(root);
            return;
        }
        //然后生成一条新的记录
        DbMemberNode dbMemberNode = new DbMemberNode();
        dbMemberNode.setMemberId(memberId);
        dbMemberNode.setFundId(fundId);
        dbMemberNode.setAmount(new BigDecimal(nodeType.getNodeAmount()));
        dbMemberNode.setCountFund(1);
        dbMemberNode.setPerkState(1);
        dbMemberNode.setLeftRight(ObjectUtil.isEmpty(dbMemberNodeOld.getLeftNode()) ? 1 : 2);
        dbMemberNode.setParentNode(dbMemberNodeOld.getId());
        dbMemberNode.setWorkState(1);
        dbMemberNodeMapper.insert(dbMemberNode);
        //如果添加的为右节点,那么进入判断
        if(DbMemberNode.STATE_TWO == dbMemberNode.getLeftRight()){
            //父节点为右节点,那么进入判断,父节点是否有上级节点
            int leftRight = ObjectUtil.isEmpty(dbMemberNodeOld.getLeftNode()) ? 1 : 2;
            if(DbMemberNode.STATE_TWO == leftRight){
                if(ObjectUtil.isEmpty(dbMemberNodeOld.getParentNode())){
                    return;
                }
                Long parentNode = dbMemberNodeOld.getParentNode();
                DbMemberNode dbMemberNodeRoot = dbMemberNodeMapper.selectById(parentNode);
                if(ObjectUtil.isEmpty(dbMemberNodeRoot)){
                    return;
                }
                //有,则上级节点出局复投,轮数加1,复投逻辑
                memberNodeNext(dbMemberNodeRoot);
            }else{//父节点为左节点,那么没人出局
                return;
            }
        }else{
            //如果添加的为左节点,那么没人出局
            return;
        }
    }
    /**
     * 有,则上级节点出局复投,轮数加1,复投逻辑
     * @param dbMemberNodeRoot
     */
    public void memberNodeNext(DbMemberNode dbMemberNodeRoot) {
        log.info("进入复投");
    }
    // 完成矩阵树,并重置矩阵且重入
    public void finishMatrixTree(Long memberId) {
@@ -283,4 +379,139 @@
            dappFundFlowDao.insert(profitFlow);
        });
    }
    @Override
    public void invitePerkMsg(Long id) {
        /**
         * 推荐规则:
         * 无直推奖励,推2个3层,3个6层,4个10层。1%见点奖(有效层级内,每个每1%),共10层,共%10。
         */
        DappFundFlowEntity dappFundFlowEntity = dappFundFlowDao.selectById(id);
        if(ObjectUtil.isEmpty(dappFundFlowEntity)){
            return;
        }
        BigDecimal amount = dappFundFlowEntity.getAmount().abs();
        /**
         * 往上循环十层,判断每一层是否有见点奖
         */
        Long memberId = dappFundFlowEntity.getMemberId();
        for(int i = 1;i <= 10;i++){
            DappMemberEntity dappMemberEntity = dappMemberDao.selectById(memberId);
            String refererId = dappMemberEntity.getRefererId();
            //上级不存在,则停止循环。
            QueryWrapper<DappMemberEntity> objectQueryWrapper = new QueryWrapper<>();
            objectQueryWrapper.eq("invite_id",refererId);
            DappMemberEntity dappMemberEntityRef = dappMemberDao.selectOne(objectQueryWrapper);
            if(ObjectUtil.isEmpty(dappMemberEntityRef)){
                return;
            }
            //如果为购买星级激活用户,则跳过
            Integer activeStatus = dappMemberEntityRef.getActiveStatus();
            if(1 != activeStatus){
                memberId = dappMemberEntityRef.getId();
                continue;
            }
            //获取上级全部的直推
            String inviteId = dappMemberEntityRef.getInviteId();
            QueryWrapper<DappMemberEntity> memberInviteQuery = new QueryWrapper<>();
            memberInviteQuery.eq("referer_id",inviteId);
            List<DappMemberEntity> memberInviteList = dappMemberDao.selectList(memberInviteQuery);
            //如果没有直推,则跳过
            if(CollUtil.isEmpty(memberInviteList)){
                memberId = dappMemberEntityRef.getId();
                continue;
            }
            InviteRule rule = InviteRule.LEVEL_1.getRule(i);
            if(ObjectUtil.isEmpty(rule)){
                return;
            }
            //如果直推不满足当前规则需要的人数,则跳过
            if(memberInviteList.size() < rule.getInviteNum()){
                memberId = dappMemberEntityRef.getId();
                continue;
            }
            BigDecimal perkPercent = new BigDecimal(rule.getPerkPercent());
            BigDecimal perkAmount = perkPercent.multiply(amount);
            Long perkMemberId = dappMemberEntityRef.getId();
            //生成一条流水
            DappFundFlowEntity rePutInFlow = new DappFundFlowEntity(
                    perkMemberId,
                    perkAmount,
                    15,
                    2,
                    null,
                    null);
            dappFundFlowDao.insert(rePutInFlow);
            //更新用户的金额
            dappWalletService.updateWalletCoinWithLock(perkAmount, perkMemberId, 1);
        }
    }
    @Override
    public void nodePerkMsg(Long id) {
        DappFundFlowEntity dappFundFlowEntity = dappFundFlowDao.selectById(id);
        if(ObjectUtil.isEmpty(dappFundFlowEntity)){
            return;
        }
        BigDecimal amount = dappFundFlowEntity.getAmount().abs();
        log.info("买入贡献值-平分总金额-{}",amount);
        /**
         * 获取节点平分百分比 perkPercent
         * 获取平分的份数 perKNum
         * 获取每一份的金额 perkAmount
         * 获取节点总数 buyNodeNum
         * 如果perKNum大于buyNodeNum,则每个人获得(amount * perkPercent)/ perKNum = perkAmount
         * 如果超出,再超出的人没有奖励
         */
        DataDictionaryCustom perkPercentDic = dataDictionaryCustomMapper.selectDicDataByTypeAndCode(
                DataDictionaryEnum.PERK_PERCENT.getType(),
                DataDictionaryEnum.PERK_PERCENT.getCode()
        );
        BigDecimal perkPercent = new BigDecimal(ObjectUtil.isEmpty(perkPercentDic) ? "10" : perkPercentDic.getValue()).multiply(new BigDecimal("0.01"));
        DataDictionaryCustom perKNumDic = dataDictionaryCustomMapper.selectDicDataByTypeAndCode(
                DataDictionaryEnum.PERK_NUM.getType(),
                DataDictionaryEnum.PERK_NUM.getCode()
        );
        BigDecimal perKNum = new BigDecimal(ObjectUtil.isEmpty(perkPercentDic) ? "1000" : perKNumDic.getValue());
        BigDecimal perkAmount = amount.multiply(perkPercent).divide(perKNum, 8, BigDecimal.ROUND_DOWN);
        if(BigDecimal.ZERO.compareTo(perkAmount) >= 0){
            return;
        }
        QueryWrapper<DappMemberEntity> objectQueryWrapper = new QueryWrapper<>();
        objectQueryWrapper.ge("buy_node",0);
        List<DappMemberEntity> dappMemberEntities = dappMemberDao.selectList(objectQueryWrapper);
        if(CollUtil.isEmpty(dappMemberEntities)){
            return;
        }
        //奖励总份数
        BigDecimal totalPerkNum = BigDecimal.ZERO;
        for(DappMemberEntity dappMemberEntity : dappMemberEntities){
            BigDecimal buyNode = new BigDecimal(dappMemberEntity.getBuyNode());
            totalPerkNum = totalPerkNum.add(buyNode);
            if(perKNum.compareTo(totalPerkNum) < 0){
                return;
            }
            //奖励金额
            BigDecimal memberPerk = perkPercent.multiply(buyNode);
            dappWalletService.updateWalletCoinWithLock(memberPerk, dappMemberEntity.getId(), 1);
            DappFundFlowEntity fundFlow = new DappFundFlowEntity(
                    dappMemberEntity.getId(),
                    memberPerk,
                    14,
                    2,
                    BigDecimal.ZERO,
                    null);
            dappFundFlowDao.insert(fundFlow);
        }
        log.info("买入贡献值-总人数{},-每人金额{}",dappMemberEntities.size(),perkAmount);
    }
}
src/main/java/cc/mrbird/febs/dapp/service/impl/DappWalletServiceImpl.java
@@ -74,6 +74,13 @@
        );
        BigDecimal buyNodeAmount = new BigDecimal(StrUtil.isEmpty(buyNodeAmountDic.getValue()) ? "100" : buyNodeAmountDic.getValue());
        walletInfo.setBuyNodeAmount(buyNodeAmount);
        DataDictionaryCustom buyNodeCodeCntDic = dataDictionaryCustomMapper.selectDicDataByTypeAndCode(
                DataDictionaryEnum.BUY_NODE_CNT.getType(),
                DataDictionaryEnum.BUY_NODE_CNT.getCode()
        );
        BigDecimal buyNodeCodeCnt = new BigDecimal(StrUtil.isEmpty(buyNodeCodeCntDic.getValue()) ? "3" : buyNodeCodeCntDic.getValue());
        walletInfo.setBuyNodeCnt(buyNodeCodeCnt);
        walletInfo.setBuyNode(ObjectUtil.isEmpty(memberInfo.getBuyNode()) ? 0 : memberInfo.getBuyNode());
        return walletInfo;
    }
@@ -345,7 +352,11 @@
        member = dappMemberDao.selectById(member.getId());
//        int buyNode = ObjectUtil.isEmpty(member.getBuyNode()) ? 0 : 1;
        int buyNode = member.getBuyNode();
        if (1 == buyNode) {
        DataDictionaryCustom buyNodeCodeCntDic = dataDictionaryCustomMapper.selectDicDataByTypeAndCode(
                DataDictionaryEnum.BUY_NODE_CNT.getType(),
                DataDictionaryEnum.BUY_NODE_CNT.getCode()
        );
        if (buyNode >= Integer.parseInt(buyNodeCodeCntDic.getValue())) {
            throw new FebsException("Do not repeat purchase");
        }
src/main/java/cc/mrbird/febs/dapp/vo/WalletInfoVo.java
@@ -41,6 +41,9 @@
    @ApiModelProperty(value = "购买节点的金额")
    private BigDecimal buyNodeAmount;
    @ApiModelProperty(value = "购买节点的最大次数")
    private BigDecimal buyNodeCnt;
    @ApiModelProperty(value = "是否是节点 1-是 0-否")
    private Integer buyNode;
}
src/main/java/cc/mrbird/febs/job/MatrixTreeInit.java
@@ -1,7 +1,9 @@
package cc.mrbird.febs.job;
import cc.mrbird.febs.dapp.entity.DappAchieveTreeEntity;
import cc.mrbird.febs.dapp.entity.DappMemberEntity;
import cc.mrbird.febs.dapp.mapper.DappAchieveTreeDao;
import cc.mrbird.febs.dapp.mapper.DappMemberDao;
import cc.mrbird.febs.tree.MatrixTree;
import cc.mrbird.febs.tree.MemberNode;
import lombok.extern.slf4j.Slf4j;
@@ -24,18 +26,26 @@
    @Autowired
    private DappAchieveTreeDao dappAchieveTreeDao;
    @Autowired
    private DappMemberDao dappMemberDao;
    @PostConstruct
    public void init() {
        List<DappAchieveTreeEntity> tree = dappAchieveTreeDao.selectTreeList();
//        List<DappAchieveTreeEntity> tree = dappAchieveTreeDao.selectTreeList();
        List<DappAchieveTreeEntity> tree = dappAchieveTreeDao.selectTreeListV2();
        MatrixTree instance = MatrixTree.getInstance();
        for (DappAchieveTreeEntity treeNode : tree) {
            Long memberId = treeNode.getMemberId();
            DappMemberEntity dappMemberEntity = dappMemberDao.selectById(memberId);
            MemberNode node = new MemberNode();
            node.setAddress(treeNode.getAddress());
            node.setInviteId(treeNode.getInviteId());
            node.setRefererId(treeNode.getRefererId());
            node.setMemberId(treeNode.getMidNode());
            node.setAddress(dappMemberEntity.getAddress());
            node.setInviteId(dappMemberEntity.getInviteId());
            node.setRefererId(dappMemberEntity.getRefererId());
            node.setMemberId(treeNode.getMemberId());
            node.setFundId(treeNode.getFundId());
            instance.addNode(node);
        }
    }
src/main/java/cc/mrbird/febs/rabbit/QueueConstants.java
@@ -5,6 +5,11 @@
 * @date 2022-05-31
 **/
public class QueueConstants {
    //发送推荐规则奖励
    public static final String TFC_NODE_PERK_QUEEN = "queue_tfc_node_perk";
    //发送推荐规则奖励
    public static final String TFC_INVITE_PERK_QUEEN = "queue_tfc_invite_perk";
    public static final String ONLINE_TRANSFER = "queue_sdm_online_transfer";
    public static final String DISTRIB_PROFIT = "queue_sdm_distrib_profit";
    public static final String USER_BUY_REWARD = "queue_sdm_user_buy_reward";
src/main/java/cc/mrbird/febs/rabbit/QueueEnum.java
@@ -5,6 +5,11 @@
@Getter
public enum QueueEnum {
    //发送推荐规则奖励
    TFC_NODE_PERK("exchange_tfc_node_perk", "route_key_tfc_node_perk", QueueConstants.TFC_NODE_PERK_QUEEN),
    //发送推荐规则奖励
    TFC_INVITE_PERK("exchange_tfc_invite_perk", "route_key_tfc_invite_perk", QueueConstants.TFC_INVITE_PERK_QUEEN),
    ONLINE_TRANSFER("exchange_sdm_online_transfer", "route_key_sdm_online_transfer", "queue_sdm_online_transfer"),
    DISTRIB_PROFIT("exchange_sdm_distrib_profit", "route_key_sdm_distrib_profit", "queue_sdm_distrib_profit"),
    USER_BUY_REWARD("exchange_sdm_user_buy_reward", "route_key_sdm_user_buy_reward", "queue_sdm_user_buy_reward"),
src/main/java/cc/mrbird/febs/rabbit/RabbitConfiguration.java
@@ -101,4 +101,42 @@
        return BindingBuilder.bind(feeDistributeQueue()).to(feeDistributeExchange()).with(QueueEnum.DISTRIB_PROFIT.getRoute());
    }
    // === 手续费分发 end ===
    // === 发送推荐规则奖励 start ===
    @Bean
    public DirectExchange invitePerkExchange() {
        return new DirectExchange(QueueEnum.TFC_INVITE_PERK.getExchange());
    }
    @Bean
    public Queue invitePerkQueue() {
        return new Queue(QueueEnum.TFC_INVITE_PERK.getQueue());
    }
    @Bean
    public Binding invitePerkBind() {
        return BindingBuilder.bind(invitePerkQueue()).to(invitePerkExchange()).with(QueueEnum.TFC_INVITE_PERK.getRoute());
    }
    // === 发送推荐规则奖励 end ===
    // === 发送节点奖励 start ===
    @Bean
    public DirectExchange nodePerkExchange() {
        return new DirectExchange(QueueEnum.TFC_NODE_PERK.getExchange());
    }
    @Bean
    public Queue nodePerkQueue() {
        return new Queue(QueueEnum.TFC_NODE_PERK.getQueue());
    }
    @Bean
    public Binding nodePerkBind() {
        return BindingBuilder.bind(nodePerkQueue()).to(nodePerkExchange()).with(QueueEnum.TFC_NODE_PERK.getRoute());
    }
    // === 发送节点奖励 end ===
}
src/main/java/cc/mrbird/febs/rabbit/consumer/ChainConsumer.java
@@ -42,4 +42,18 @@
    public void feeDistribute(String data) {
        dappSystemService.feeDistribute(data);
    }
    @RabbitListener(queues = QueueConstants.TFC_INVITE_PERK_QUEEN)
    public void invitePerkMsg(Long id) {
        log.info("消费推荐规则奖励,流水ID:{}", id);
        dappSystemService.invitePerkMsg(id);
    }
    @RabbitListener(queues = QueueConstants.TFC_NODE_PERK_QUEEN)
    public void nodePerkMsg(Long id) {
        log.info("消费节点投资,流水ID:{}", id);
        dappSystemService.nodePerkMsg(id);
    }
}
src/main/java/cc/mrbird/febs/rabbit/producer/ChainProducer.java
@@ -60,4 +60,20 @@
        CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
        rabbitTemplate.convertAndSend(QueueEnum.DISTRIB_PROFIT.getExchange(), QueueEnum.DISTRIB_PROFIT.getRoute(), id, correlationData);
    }
    /**
     * 推荐规则:
     * 无直推奖励,推2个3层,3个6层,4个10层。1%见点奖(有效层级内,每个每1%),共10层,共%10。
     * @param id 流水ID
     */
    public void sendInvitePerkMsg(Long id) {
        log.info("发送推荐规则奖励,流水ID:{}", id);
        CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
        rabbitTemplate.convertAndSend(QueueEnum.TFC_INVITE_PERK.getExchange(), QueueEnum.TFC_INVITE_PERK.getRoute(), id, correlationData);
    }
    public void sendNodePerkMsg(Long id) {
        log.info("发送节点投资,流水ID:{}", id);
        CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
        rabbitTemplate.convertAndSend(QueueEnum.TFC_NODE_PERK.getExchange(), QueueEnum.TFC_NODE_PERK.getRoute(), id, correlationData);
    }
}
src/main/java/cc/mrbird/febs/tree/MatrixTree.java
@@ -155,7 +155,7 @@
            return null;
        }
        if (node.getMemberId().equals(param) || node.getAddress().equals(param) || node.getInviteId().equals(param)) {
        if (node.getFundId().equals(param) ||node.getMemberId().equals(param) || node.getAddress().equals(param) || node.getInviteId().equals(param)) {
            return node;
        }
src/main/java/cc/mrbird/febs/tree/MemberNode.java
@@ -2,14 +2,14 @@
import lombok.Data;
import java.util.List;
/**
 * @author wzy
 * @date 2022-08-23
 **/
@Data
public class MemberNode {
    private Long fundId;
    private Long memberId;
@@ -30,5 +30,13 @@
        this.refererId = refererId;
    }
    public MemberNode(Long fundId, Long memberId, String address, String inviteId, String refererId) {
        this.fundId = fundId;
        this.memberId = memberId;
        this.address = address;
        this.inviteId = inviteId;
        this.refererId = refererId;
    }
    public MemberNode() {}
}
src/main/resources/mapper/dapp/DappAchieveTreeDao.xml
@@ -12,6 +12,12 @@
        order by a.id
    </select>
    <select id="selectTreeListV2" resultType="cc.mrbird.febs.dapp.entity.DappAchieveTreeEntity">
        select a.*, b.id fundId,b.member_id memberId from dapp_achieve_tree a
        inner join dapp_fund_flow b on a.mid_node=b.id and valid_state=1
        order by a.id
    </select>
    <select id="selectNewestTreeNode" resultType="cc.mrbird.febs.dapp.entity.DappAchieveTreeEntity">
        select * from dapp_achieve_tree a
        order by a.id desc
src/main/resources/mapper/dapp/DbMemberNodeMapper.xml
New file
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cc.mrbird.febs.dapp.mapper.DbMemberNodeMapper">
    <select id="selectOneByWorkStateAndLeftNodeNullOrRightNodeNull" resultType="cc.mrbird.febs.dapp.entity.DbMemberNode">
        select
               *
        from
             db_member_node
        where work_state = #{workState}
            and (left_node is null or right_node is null)
        ORDER BY create_time ASC
            limit 1
    </select>
    <update id="updateDicValueByTypeAndCode">
        update data_dictionary_custom
        set value=#{value}
        <where>
            1=1
            <if test="code != null and code != ''">
                and code = #{code}
            </if>
            <if test="type != null and type != ''">
                and type = #{type}
            </if>
        </where>
    </update>
</mapper>