src/main/java/cc/mrbird/febs/dapp/controller/ApiDappMemberController.java
@@ -56,6 +56,12 @@ return new FebsResponse().success().data(dappWalletService.buyNode(buyNodeDto)); } @ApiOperation(value = "购买星团", notes = "购买星团") @PostMapping(value = "/buyStar") public FebsResponse buyStar(@RequestBody BuyStarDto buyStarDto) { return new FebsResponse().success().data(dappWalletService.buyStar(buyStarDto)); } @ApiOperation(value = "转账", notes = "转账") @PostMapping(value = "/transfer") public FebsResponse transfer(@RequestBody TransferDto transferDto) { src/main/java/cc/mrbird/febs/dapp/dto/BuyStarDto.java
New file @@ -0,0 +1,27 @@ package cc.mrbird.febs.dapp.dto; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.math.BigDecimal; @Data @ApiModel(value = "BuyStarDto", description = "连接参数接收类") public class BuyStarDto { @ApiModelProperty(value = "id", example = "1") private Long id; @ApiModelProperty(value = "星团金额", example = "1") private BigDecimal amount; @ApiModelProperty(value = "success/fail", example = "success") private String flag; @ApiModelProperty(value = "交易hash", example = "123") private String txHash; @ApiModelProperty(value = "星团类型") private Integer nodeType; } src/main/java/cc/mrbird/febs/dapp/entity/DappFundFlowEntity.java
@@ -51,6 +51,9 @@ * 13-节点买入 * 14-节点返利 * 15-见点奖 * 16-复投 * 17-收益 * 18-买入 */ private Integer type; src/main/java/cc/mrbird/febs/dapp/enumerate/DataDictionaryEnum.java
@@ -4,6 +4,8 @@ @Getter public enum DataDictionaryEnum { //直邀人数 INVITE_NUM("INVITE_NUM","INVITE_NUM"), // 奖励百分比 PERK_PERCENT("PERK_PERCENT","PERK_PERCENT"), PERK_NUM("PERK_NUM","PERK_NUM"), src/main/java/cc/mrbird/febs/dapp/enumerate/NodeType.java
@@ -7,6 +7,9 @@ public enum NodeType { /** * 节点类型 投注金额 投注奖励 * 30 * 30*1.4 * 30*1.4*1.4 */ NODE_13(13,"566.9","793.66"), src/main/java/cc/mrbird/febs/dapp/mapper/DbMemberNodeMapper.java
@@ -6,6 +6,6 @@ public interface DbMemberNodeMapper extends BaseMapper<DbMemberNode> { DbMemberNode selectOneByWorkStateAndLeftNodeNullOrRightNodeNull(@Param("workState")int stateOne); DbMemberNode selectOneByWorkStateAndLeftNodeNullOrRightNodeNull(@Param("workState")int stateOne,@Param("type")int type); } src/main/java/cc/mrbird/febs/dapp/service/DappWalletService.java
@@ -43,4 +43,6 @@ DappWalletCoinEntity findByMemberId(Long memberId); Long buyNode(BuyNodeDto buyNodeDto); Long buyStar(BuyStarDto buyStarDto); } src/main/java/cc/mrbird/febs/dapp/service/impl/DappSystemServiceImpl.java
@@ -169,8 +169,13 @@ return; } BigDecimal amount = dappFundFlowEntity.getAmount(); //存放买入新团的类型 String toHash = dappFundFlowEntity.getToHash(); //根据金额判断属于属于购买的哪一个节点 NodeType nodeType = NodeType.NODE_1.getNodeByAmount(amount); NodeType nodeType = NodeType.NODE_1.getNode(Integer.parseInt(toHash)); if(ObjectUtil.isEmpty(nodeType)){ return; } /** * 获取一条最老的左右节点未满的记录 * 然后生成一条新的记录 @@ -182,7 +187,7 @@ * */ //获取一条最老的左右节点未满且生效中的记录 DbMemberNode dbMemberNodeOld = dbMemberNodeMapper.selectOneByWorkStateAndLeftNodeNullOrRightNodeNull(DbMemberNode.STATE_ONE); DbMemberNode dbMemberNodeOld = dbMemberNodeMapper.selectOneByWorkStateAndLeftNodeNullOrRightNodeNull(DbMemberNode.STATE_ONE,nodeType.getNodeType()); if(ObjectUtil.isEmpty(dbMemberNodeOld)){ //生成ROOT节点 DbMemberNode root = new DbMemberNode(); @@ -224,6 +229,10 @@ if(ObjectUtil.isEmpty(dbMemberNodeRoot)){ return; } //每个星团,只复投10轮 if(10 < dbMemberNodeRoot.getCountFund()){ return; } //有,则上级节点出局复投,轮数加1,复投逻辑 memberNodeNext(dbMemberNodeRoot); }else{//父节点为左节点,那么没人出局 @@ -241,6 +250,124 @@ */ public void memberNodeNext(DbMemberNode dbMemberNodeRoot) { log.info("进入复投"); DataDictionaryCustom inviteNumDic = dataDictionaryCustomMapper.selectDicDataByTypeAndCode( DataDictionaryEnum.INVITE_NUM.getType(), DataDictionaryEnum.INVITE_NUM.getCode() ); int inviteNum = Integer.parseInt(inviteNumDic.getValue()); Long memberId = dbMemberNodeRoot.getMemberId(); DappMemberEntity dappMemberEntity = dappMemberDao.selectById(memberId); //必须要有两个直推才能复投,或者获取收益,否则,直接返回 QueryWrapper<DappMemberEntity> inviteQuery = new QueryWrapper<>(); inviteQuery.eq("referer_id",dappMemberEntity.getInviteId()); List<DappMemberEntity> dappMemberEntities = dappMemberDao.selectList(inviteQuery); if(CollUtil.isEmpty(dappMemberEntities)){ return; } if(inviteNum > dappMemberEntities.size()){ return; } Integer countFund = dbMemberNodeRoot.getCountFund(); Integer type = dbMemberNodeRoot.getType(); //如果是13星局,则直接复投产生收益 if(NodeType.NODE_13.getNodeType() == type){ //复投 futouSixTeen(memberId,dbMemberNodeRoot.getAmount(),type,countFund+1); //产生收益 BigDecimal perkAmount = dbMemberNodeRoot.getAmount().multiply(new BigDecimal("1.4")); perkSevenTeen(memberId,perkAmount,countFund); return; } //如果是1到12星团 if(type >=NodeType.NODE_1.getNodeType() && type <= NodeType.NODE_12.getNodeType()){ //需要复投本轮, //如果是第一轮,当下一个星团没有投入时,收益复投下一个新团 //如果是第一轮,下一个新团有投入,则产生收益 //复投或者收益的金额 BigDecimal nodeAmount = dbMemberNodeRoot.getAmount().multiply(new BigDecimal("1.4")); if(1 == countFund){//第一轮 //复投本轮,轮数 +1 futouSixTeen(memberId,dbMemberNodeRoot.getAmount(),type,countFund+1); //收益复投(当前的下一个星团没有已投入),还是收益提出 Integer nextType = type + 1; QueryWrapper<DbMemberNode> nodeQueryWrapper = new QueryWrapper<>(); nodeQueryWrapper.eq("member_id",memberId); nodeQueryWrapper.eq("type", nextType); nodeQueryWrapper.eq("work_state", DbMemberNode.STATE_ONE); DbMemberNode dbMemberNode = dbMemberNodeMapper.selectOne(nodeQueryWrapper); if(ObjectUtil.isEmpty(dbMemberNode)){ futouSixTeen(memberId,nodeAmount,nextType,1); }else{ perkSevenTeen(memberId,nodeAmount,countFund); } }else if(countFund <= 9 && countFund >= 2){//2-9轮 //复投本轮,轮数 +1 futouSixTeen(memberId,dbMemberNodeRoot.getAmount(),type,countFund+1); perkSevenTeen(memberId,nodeAmount,countFund); }else{//10轮,收益本金都返回 BigDecimal add = dbMemberNodeRoot.getAmount().add(nodeAmount); perkSevenTeen(memberId,add,countFund); dbMemberNodeRoot.setWorkState(DbMemberNode.STATE_TWO); dbMemberNodeMapper.updateById(dbMemberNodeRoot); } } } /** * 产生收益 * @param memberId 会员ID * @param amount 收益金额 * @param countFund 轮数 */ public void perkSevenTeen(Long memberId,BigDecimal amount,Integer countFund){ //收益流水 DappFundFlowEntity fundFlow = new DappFundFlowEntity( memberId, amount, 17, 2, BigDecimal.ZERO, countFund.toString()); dappFundFlowDao.insert(fundFlow); //更新用户的金额 dappWalletService.updateWalletCoinWithLock(amount, memberId, 1); } /** * 复投本轮 * 插入流水,产生记录 * @param memberId 会员ID * @param amount 复投金额 * @param type 星团类型 * @param countFund 轮数 */ public void futouSixTeen(Long memberId,BigDecimal amount,Integer type,Integer countFund){ //复投流水 DappFundFlowEntity fundFlow = new DappFundFlowEntity( memberId, amount, 16, 2, BigDecimal.ZERO, null); dappFundFlowDao.insert(fundFlow); DbMemberNode dbMemberNodeOld = dbMemberNodeMapper.selectOneByWorkStateAndLeftNodeNullOrRightNodeNull(DbMemberNode.STATE_ONE,type); //复投 DbMemberNode dbMemberNode = new DbMemberNode(); dbMemberNode.setMemberId(memberId); dbMemberNode.setFundId(fundFlow.getId()); dbMemberNode.setAmount(amount); dbMemberNode.setType(type); dbMemberNode.setCountFund(countFund); dbMemberNode.setPerkState(1); if(ObjectUtil.isNotEmpty(dbMemberNodeOld)){ dbMemberNode.setLeftRight(ObjectUtil.isEmpty(dbMemberNodeOld.getLeftNode()) ? 1 : 2); dbMemberNode.setParentNode(dbMemberNodeOld.getId()); } dbMemberNode.setWorkState(1); dbMemberNodeMapper.insert(dbMemberNode); } @@ -493,6 +620,10 @@ //奖励总份数 BigDecimal totalPerkNum = BigDecimal.ZERO; for(DappMemberEntity dappMemberEntity : dappMemberEntities){ //如果账号未激活,则无法领取收益 if(1 != dappMemberEntity.getActiveStatus()){ continue; } BigDecimal buyNode = new BigDecimal(dappMemberEntity.getBuyNode()); totalPerkNum = totalPerkNum.add(buyNode); if(perKNum.compareTo(totalPerkNum) < 0){ src/main/java/cc/mrbird/febs/dapp/service/impl/DappWalletServiceImpl.java
@@ -13,8 +13,10 @@ import cc.mrbird.febs.dapp.service.DappWalletService; import cc.mrbird.febs.dapp.vo.WalletInfoVo; import cc.mrbird.febs.rabbit.producer.ChainProducer; 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 lombok.RequiredArgsConstructor; @@ -47,6 +49,7 @@ private final ChainProducer chainProducer; private final DappSystemDao dappSystemDao; private final DbMemberNodeMapper dbMemberNodeMapper; @Override public WalletInfoVo walletInfo() { @@ -391,4 +394,54 @@ } return null; } @Override public Long buyStar(BuyStarDto buyStarDto) { DappMemberEntity member = LoginUserUtil.getAppUser(); String upgrade = redisUtils.getString("APP_UPGRADE"); if ("upgrade".equals(upgrade)) { throw new FebsException("功能升级中"); } /** * 买入先验证当前星团是否已经买入 */ Integer nodeType = buyStarDto.getNodeType(); QueryWrapper<DbMemberNode> nodeQueryWrapper = new QueryWrapper<>(); nodeQueryWrapper.eq("member_id",member.getId()); nodeQueryWrapper.eq("type", nodeType); nodeQueryWrapper.eq("work_state", DbMemberNode.STATE_ONE); List<DbMemberNode> dbMemberNodes = dbMemberNodeMapper.selectList(nodeQueryWrapper); if(CollUtil.isNotEmpty(dbMemberNodes)){ throw new FebsException("已购买"); } if (ObjectUtil.isEmpty(buyStarDto.getId())) {//第一次 DappFundFlowEntity fundFlow = new DappFundFlowEntity( member.getId(), buyStarDto.getAmount().negate(), 18, 1, BigDecimal.ZERO, buyStarDto.getTxHash()); dappFundFlowDao.insert(fundFlow); return fundFlow.getId(); } else {//第二次 DappFundFlowEntity flow = dappFundFlowDao.selectById(buyStarDto.getId()); if(ObjectUtil.isEmpty(flow)){ return null; } if ("success".equals(buyStarDto.getFlag())) { flow.setFromHash(buyStarDto.getTxHash()); flow.setToHash(buyStarDto.getNodeType().toString()); dappFundFlowDao.updateById(flow); } else { if (flow.getStatus() == 1) { dappFundFlowDao.deleteById(buyStarDto.getId()); } } } return null; } } src/main/java/cc/mrbird/febs/job/ProfitDailyJob.java
@@ -1,95 +1,77 @@ package cc.mrbird.febs.job; import cc.mrbird.febs.dapp.entity.DappFundFlowEntity; import cc.mrbird.febs.dapp.entity.DappMemberEntity; import cc.mrbird.febs.dapp.entity.DataDictionaryCustom; import cc.mrbird.febs.dapp.enumerate.DataDictionaryEnum; import cc.mrbird.febs.dapp.mapper.DappFundFlowDao; import cc.mrbird.febs.dapp.mapper.DappMemberDao; import cc.mrbird.febs.dapp.mapper.DataDictionaryCustomMapper; import cc.mrbird.febs.dapp.service.DappWalletService; import cc.mrbird.febs.tree.TreeConstants; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ObjectUtil; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.List; @Slf4j @Component @ConditionalOnProperty(prefix = "system", name = "quartz-job", havingValue = "true") public class ProfitDailyJob { @Autowired private DappMemberDao dappMemberDao; @Autowired private DappFundFlowDao dappFundFlowDao; @Autowired private DataDictionaryCustomMapper dataDictionaryCustomMapper; @Autowired private DappWalletService dappWalletService; @Scheduled(cron = "0 0 0 * * ?") public void profitDailyJob() { log.info("每日产矿任务执行"); DataDictionaryCustom symbolPriceDic = dataDictionaryCustomMapper.selectDicDataByTypeAndCode(DataDictionaryEnum.SYMBOL_PRICE.getType(), DataDictionaryEnum.SYMBOL_PRICE.getCode()); if (symbolPriceDic == null) { log.info("未设置币种价格"); return; } DataDictionaryCustom rebateDic = dataDictionaryCustomMapper.selectDicDataByTypeAndCode(DataDictionaryEnum.REBATE_PERCENT.getType(), DataDictionaryEnum.REBATE_PERCENT.getCode()); if (rebateDic == null) { log.info("未设置每日产矿比例"); return; } BigDecimal symbolPrice = new BigDecimal(symbolPriceDic.getValue()); BigDecimal rebateRatio = new BigDecimal(rebateDic.getValue()); QueryWrapper<DappMemberEntity> query = new QueryWrapper<>(); query.eq("active_status", 1); List<DappMemberEntity> members = dappMemberDao.selectList(query); if (CollUtil.isEmpty(members)) { return; } members.forEach(item -> { QueryWrapper<DappFundFlowEntity> fundFlowQuery = new QueryWrapper<>(); fundFlowQuery.eq("member_id", item.getId()); fundFlowQuery.eq("type", 11); List<DappFundFlowEntity> flows = dappFundFlowDao.selectList(fundFlowQuery); BigDecimal sum = BigDecimal.ZERO; if (CollUtil.isNotEmpty(flows)) { double symbolSum = flows.stream().mapToDouble(flow -> flow.getAmount().doubleValue()).sum(); sum = symbolPrice.multiply(new BigDecimal(symbolSum)); } if (CollUtil.isEmpty(flows) || TreeConstants.PUT_IN_AMOUNT.compareTo(sum) > 0) { BigDecimal profitU = TreeConstants.PUT_IN_AMOUNT.multiply(rebateRatio.divide(BigDecimal.valueOf(100), 4, RoundingMode.HALF_DOWN)); BigDecimal remain = TreeConstants.PUT_IN_AMOUNT.subtract(sum); if (remain.compareTo(profitU) < 0) { profitU = remain; } BigDecimal profitSymbol = profitU.divide(symbolPrice, 8, RoundingMode.HALF_DOWN); dappWalletService.updateWalletMineWithLock(profitSymbol, item.getId(), 1); DappFundFlowEntity fundFlow = new DappFundFlowEntity(item.getId(), profitSymbol, 11, 2, null, null); dappFundFlowDao.insert(fundFlow); } }); } // @Autowired // private DappMemberDao dappMemberDao; // @Autowired // private DappFundFlowDao dappFundFlowDao; // @Autowired // private DataDictionaryCustomMapper dataDictionaryCustomMapper; // @Autowired // private DappWalletService dappWalletService; // // @Scheduled(cron = "0 0 0 * * ?") // public void profitDailyJob() { // log.info("每日产矿任务执行"); // DataDictionaryCustom symbolPriceDic = dataDictionaryCustomMapper.selectDicDataByTypeAndCode(DataDictionaryEnum.SYMBOL_PRICE.getType(), DataDictionaryEnum.SYMBOL_PRICE.getCode()); // if (symbolPriceDic == null) { // log.info("未设置币种价格"); // return; // } // // DataDictionaryCustom rebateDic = dataDictionaryCustomMapper.selectDicDataByTypeAndCode(DataDictionaryEnum.REBATE_PERCENT.getType(), DataDictionaryEnum.REBATE_PERCENT.getCode()); // if (rebateDic == null) { // log.info("未设置每日产矿比例"); // return; // } // // BigDecimal symbolPrice = new BigDecimal(symbolPriceDic.getValue()); // BigDecimal rebateRatio = new BigDecimal(rebateDic.getValue()); // // QueryWrapper<DappMemberEntity> query = new QueryWrapper<>(); // query.eq("active_status", 1); // List<DappMemberEntity> members = dappMemberDao.selectList(query); // if (CollUtil.isEmpty(members)) { // return; // } // // members.forEach(item -> { // QueryWrapper<DappFundFlowEntity> fundFlowQuery = new QueryWrapper<>(); // fundFlowQuery.eq("member_id", item.getId()); // fundFlowQuery.eq("type", 11); // List<DappFundFlowEntity> flows = dappFundFlowDao.selectList(fundFlowQuery); // // BigDecimal sum = BigDecimal.ZERO; // if (CollUtil.isNotEmpty(flows)) { // double symbolSum = flows.stream().mapToDouble(flow -> flow.getAmount().doubleValue()).sum(); // sum = symbolPrice.multiply(new BigDecimal(symbolSum)); // } // // if (CollUtil.isEmpty(flows) || TreeConstants.PUT_IN_AMOUNT.compareTo(sum) > 0) { // BigDecimal profitU = TreeConstants.PUT_IN_AMOUNT.multiply(rebateRatio.divide(BigDecimal.valueOf(100), 4, RoundingMode.HALF_DOWN)); // // BigDecimal remain = TreeConstants.PUT_IN_AMOUNT.subtract(sum); // if (remain.compareTo(profitU) < 0) { // profitU = remain; // } // // BigDecimal profitSymbol = profitU.divide(symbolPrice, 8, RoundingMode.HALF_DOWN); // // dappWalletService.updateWalletMineWithLock(profitSymbol, item.getId(), 1); // DappFundFlowEntity fundFlow = new DappFundFlowEntity(item.getId(), profitSymbol, 11, 2, null, null); // dappFundFlowDao.insert(fundFlow); // } // }); // // // } } src/main/resources/mapper/dapp/DbMemberNodeMapper.xml
@@ -8,23 +8,11 @@ from db_member_node where work_state = #{workState} and type = #{type} 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>