From 37f13de311a35f45569397422708dd47dab72178 Mon Sep 17 00:00:00 2001
From: KKSU <15274802129@163.com>
Date: Tue, 11 Jun 2024 17:08:49 +0800
Subject: [PATCH] 增加节点买卖规则 增加推荐规则奖励

---
 src/main/java/cc/mrbird/febs/dapp/service/impl/DappSystemServiceImpl.java |  231 +++++++++++++++++++++++
 src/main/java/cc/mrbird/febs/tree/MemberNode.java                         |   12 +
 src/main/java/cc/mrbird/febs/rabbit/consumer/ChainConsumer.java           |   14 +
 src/main/java/cc/mrbird/febs/dapp/entity/DappAchieveTreeEntity.java       |    6 
 src/main/java/cc/mrbird/febs/dapp/service/impl/DappWalletServiceImpl.java |   13 +
 src/main/java/cc/mrbird/febs/rabbit/QueueConstants.java                   |    5 
 src/main/java/cc/mrbird/febs/dapp/service/impl/DappMemberServiceImpl.java |   20 +
 src/main/java/cc/mrbird/febs/dapp/entity/DappFundFlowEntity.java          |    1 
 src/main/java/cc/mrbird/febs/rabbit/producer/ChainProducer.java           |   16 +
 src/main/java/cc/mrbird/febs/job/MatrixTreeInit.java                      |   20 +
 src/main/java/cc/mrbird/febs/rabbit/RabbitConfiguration.java              |   38 +++
 src/main/java/cc/mrbird/febs/dapp/mapper/DbMemberNodeMapper.java          |   11 +
 src/main/resources/mapper/dapp/DbMemberNodeMapper.xml                     |   30 +++
 src/main/resources/mapper/dapp/DappAchieveTreeDao.xml                     |    6 
 src/main/java/cc/mrbird/febs/dapp/enumerate/InviteRule.java               |   38 +++
 src/main/java/cc/mrbird/febs/dapp/service/impl/BscUsdtContractEvent.java  |   11 
 src/main/java/cc/mrbird/febs/dapp/enumerate/DataDictionaryEnum.java       |    1 
 src/main/java/cc/mrbird/febs/dapp/service/DappSystemService.java          |   12 
 src/main/java/cc/mrbird/febs/dapp/vo/WalletInfoVo.java                    |    3 
 src/main/java/cc/mrbird/febs/rabbit/QueueEnum.java                        |    5 
 src/main/java/cc/mrbird/febs/dapp/entity/DbMemberNode.java                |   28 ++
 src/main/java/cc/mrbird/febs/dapp/mapper/DappAchieveTreeDao.java          |    1 
 src/main/java/cc/mrbird/febs/tree/MatrixTree.java                         |    2 
 src/main/java/cc/mrbird/febs/dapp/enumerate/NodeType.java                 |   56 +++++
 24 files changed, 559 insertions(+), 21 deletions(-)

diff --git a/src/main/java/cc/mrbird/febs/dapp/entity/DappAchieveTreeEntity.java b/src/main/java/cc/mrbird/febs/dapp/entity/DappAchieveTreeEntity.java
index 568cee9..a931425 100644
--- a/src/main/java/cc/mrbird/febs/dapp/entity/DappAchieveTreeEntity.java
+++ b/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;
+
 }
diff --git a/src/main/java/cc/mrbird/febs/dapp/entity/DappFundFlowEntity.java b/src/main/java/cc/mrbird/febs/dapp/entity/DappFundFlowEntity.java
index 5ae6ed3..8a7cfd8 100644
--- a/src/main/java/cc/mrbird/febs/dapp/entity/DappFundFlowEntity.java
+++ b/src/main/java/cc/mrbird/febs/dapp/entity/DappFundFlowEntity.java
@@ -50,6 +50,7 @@
      *
      *  13-节点买入
      *  14-节点返利
+     *  15-见点奖
      */
     private Integer type;
 
diff --git a/src/main/java/cc/mrbird/febs/dapp/entity/DbMemberNode.java b/src/main/java/cc/mrbird/febs/dapp/entity/DbMemberNode.java
new file mode 100644
index 0000000..913c121
--- /dev/null
+++ b/src/main/java/cc/mrbird/febs/dapp/entity/DbMemberNode.java
@@ -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;
+
+}
diff --git a/src/main/java/cc/mrbird/febs/dapp/enumerate/DataDictionaryEnum.java b/src/main/java/cc/mrbird/febs/dapp/enumerate/DataDictionaryEnum.java
index 8c5ddf0..54aa5a5 100644
--- a/src/main/java/cc/mrbird/febs/dapp/enumerate/DataDictionaryEnum.java
+++ b/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"),
diff --git a/src/main/java/cc/mrbird/febs/dapp/enumerate/InviteRule.java b/src/main/java/cc/mrbird/febs/dapp/enumerate/InviteRule.java
new file mode 100644
index 0000000..a264ecd
--- /dev/null
+++ b/src/main/java/cc/mrbird/febs/dapp/enumerate/InviteRule.java
@@ -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;
+    }
+}
diff --git a/src/main/java/cc/mrbird/febs/dapp/enumerate/NodeType.java b/src/main/java/cc/mrbird/febs/dapp/enumerate/NodeType.java
new file mode 100644
index 0000000..cc91e8c
--- /dev/null
+++ b/src/main/java/cc/mrbird/febs/dapp/enumerate/NodeType.java
@@ -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;
+    }
+
+}
diff --git a/src/main/java/cc/mrbird/febs/dapp/mapper/DappAchieveTreeDao.java b/src/main/java/cc/mrbird/febs/dapp/mapper/DappAchieveTreeDao.java
index 5939be1..982b2cb 100644
--- a/src/main/java/cc/mrbird/febs/dapp/mapper/DappAchieveTreeDao.java
+++ b/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();
 
diff --git a/src/main/java/cc/mrbird/febs/dapp/mapper/DbMemberNodeMapper.java b/src/main/java/cc/mrbird/febs/dapp/mapper/DbMemberNodeMapper.java
new file mode 100644
index 0000000..d3baafa
--- /dev/null
+++ b/src/main/java/cc/mrbird/febs/dapp/mapper/DbMemberNodeMapper.java
@@ -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);
+
+}
diff --git a/src/main/java/cc/mrbird/febs/dapp/service/DappSystemService.java b/src/main/java/cc/mrbird/febs/dapp/service/DappSystemService.java
index 48b585c..9ebba4d 100644
--- a/src/main/java/cc/mrbird/febs/dapp/service/DappSystemService.java
+++ b/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);
 }
diff --git a/src/main/java/cc/mrbird/febs/dapp/service/impl/BscUsdtContractEvent.java b/src/main/java/cc/mrbird/febs/dapp/service/impl/BscUsdtContractEvent.java
index 755e2e8..f3bd471 100644
--- a/src/main/java/cc/mrbird/febs/dapp/service/impl/BscUsdtContractEvent.java
+++ b/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{
diff --git a/src/main/java/cc/mrbird/febs/dapp/service/impl/DappMemberServiceImpl.java b/src/main/java/cc/mrbird/febs/dapp/service/impl/DappMemberServiceImpl.java
index eafaa5d..1350b7f 100644
--- a/src/main/java/cc/mrbird/febs/dapp/service/impl/DappMemberServiceImpl.java
+++ b/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;
         }
diff --git a/src/main/java/cc/mrbird/febs/dapp/service/impl/DappSystemServiceImpl.java b/src/main/java/cc/mrbird/febs/dapp/service/impl/DappSystemServiceImpl.java
index a22b602..fc43a7c 100644
--- a/src/main/java/cc/mrbird/febs/dapp/service/impl/DappSystemServiceImpl.java
+++ b/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);
+    }
+
 }
diff --git a/src/main/java/cc/mrbird/febs/dapp/service/impl/DappWalletServiceImpl.java b/src/main/java/cc/mrbird/febs/dapp/service/impl/DappWalletServiceImpl.java
index 7a6f752..dab9070 100644
--- a/src/main/java/cc/mrbird/febs/dapp/service/impl/DappWalletServiceImpl.java
+++ b/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");
         }
 
diff --git a/src/main/java/cc/mrbird/febs/dapp/vo/WalletInfoVo.java b/src/main/java/cc/mrbird/febs/dapp/vo/WalletInfoVo.java
index 4873a7a..561fb3f 100644
--- a/src/main/java/cc/mrbird/febs/dapp/vo/WalletInfoVo.java
+++ b/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;
 }
diff --git a/src/main/java/cc/mrbird/febs/job/MatrixTreeInit.java b/src/main/java/cc/mrbird/febs/job/MatrixTreeInit.java
index 3ac5efa..c4ee5f2 100644
--- a/src/main/java/cc/mrbird/febs/job/MatrixTreeInit.java
+++ b/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);
         }
     }
diff --git a/src/main/java/cc/mrbird/febs/rabbit/QueueConstants.java b/src/main/java/cc/mrbird/febs/rabbit/QueueConstants.java
index de49ff2..99626f0 100644
--- a/src/main/java/cc/mrbird/febs/rabbit/QueueConstants.java
+++ b/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";
diff --git a/src/main/java/cc/mrbird/febs/rabbit/QueueEnum.java b/src/main/java/cc/mrbird/febs/rabbit/QueueEnum.java
index 9ca214a..b0cb0a8 100644
--- a/src/main/java/cc/mrbird/febs/rabbit/QueueEnum.java
+++ b/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"),
diff --git a/src/main/java/cc/mrbird/febs/rabbit/RabbitConfiguration.java b/src/main/java/cc/mrbird/febs/rabbit/RabbitConfiguration.java
index cb11d30..8b6fea9 100644
--- a/src/main/java/cc/mrbird/febs/rabbit/RabbitConfiguration.java
+++ b/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 ===
 }
diff --git a/src/main/java/cc/mrbird/febs/rabbit/consumer/ChainConsumer.java b/src/main/java/cc/mrbird/febs/rabbit/consumer/ChainConsumer.java
index 0b8a848..5d81562 100644
--- a/src/main/java/cc/mrbird/febs/rabbit/consumer/ChainConsumer.java
+++ b/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);
+    }
 }
diff --git a/src/main/java/cc/mrbird/febs/rabbit/producer/ChainProducer.java b/src/main/java/cc/mrbird/febs/rabbit/producer/ChainProducer.java
index c6483d3..43167f1 100644
--- a/src/main/java/cc/mrbird/febs/rabbit/producer/ChainProducer.java
+++ b/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);
+    }
 }
diff --git a/src/main/java/cc/mrbird/febs/tree/MatrixTree.java b/src/main/java/cc/mrbird/febs/tree/MatrixTree.java
index cbe09fb..dbaa294 100644
--- a/src/main/java/cc/mrbird/febs/tree/MatrixTree.java
+++ b/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;
         }
 
diff --git a/src/main/java/cc/mrbird/febs/tree/MemberNode.java b/src/main/java/cc/mrbird/febs/tree/MemberNode.java
index 2bb90ad..ca57f03 100644
--- a/src/main/java/cc/mrbird/febs/tree/MemberNode.java
+++ b/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() {}
 }
diff --git a/src/main/resources/mapper/dapp/DappAchieveTreeDao.xml b/src/main/resources/mapper/dapp/DappAchieveTreeDao.xml
index 7cde4a1..808abae 100644
--- a/src/main/resources/mapper/dapp/DappAchieveTreeDao.xml
+++ b/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
diff --git a/src/main/resources/mapper/dapp/DbMemberNodeMapper.xml b/src/main/resources/mapper/dapp/DbMemberNodeMapper.xml
new file mode 100644
index 0000000..76bac63
--- /dev/null
+++ b/src/main/resources/mapper/dapp/DbMemberNodeMapper.xml
@@ -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>
\ No newline at end of file

--
Gitblit v1.9.1