Parcourir la source

回传策略优化

wcc il y a 7 mois
Parent
commit
998aa1f135

+ 45 - 10
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/impl/GameOceanengineAppOrderLogServiceImpl.java

@@ -8,6 +8,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.github.sd4324530.jtuple.Tuple2;
 import com.github.sd4324530.jtuple.Tuple3;
+import com.github.sd4324530.jtuple.Tuple4;
 import com.zanxiang.game.back.base.pojo.enums.OrderStatusEnum;
 import com.zanxiang.game.back.serve.dao.mapper.GameOceanengineAppOrderLogMapper;
 import com.zanxiang.game.back.serve.oceanengine.MiniGameCallback;
@@ -28,6 +29,7 @@ import com.zanxiang.module.util.ObjectUtil;
 import com.zanxiang.module.util.bean.BeanUtil;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.MapUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.dubbo.config.annotation.DubboReference;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -75,13 +77,13 @@ public class GameOceanengineAppOrderLogServiceImpl extends ServiceImpl<GameOcean
         }
 
         GameBackPolicy gameBackPolicy = gameBackPolicyService.getById(orderLog.getBackPolicyId());
-        Tuple3<Boolean, Long, String> backInfo = BackPolicyUtil.backOrder(orderLog.getOrderNo(), gameBackPolicy, orderLog.getAmount(),
+        Tuple4<Boolean, Long, String, List<Tuple2<Long, LocalDateTime>>> backInfo = BackPolicyUtil.backOrder(orderLog.getOrderNo(), gameBackPolicy, orderLog.getAmount(),
                 orderLog.getIsFirstOrder(),
                 orderLog.getPayTime(),
                 // 此处使用用户最近一次的重新染色时间
                 userLog.getCreateTime(),
                 orderLog.getUserId(),
-                new OceanengineOrderBackPolicyCheck(this, userLog, orderLog, gameBackPolicy)
+                new OceanengineOrderBackPolicyCheck(this, gameOceanengineAppOrderSplitLogService, userLog, orderLog, gameBackPolicy)
         );
         boolean doBack = backInfo.first;
         Long backMoney = backInfo.second;
@@ -97,17 +99,16 @@ public class GameOceanengineAppOrderLogServiceImpl extends ServiceImpl<GameOcean
             );
         }
         // 拆单
-        Tuple3<Boolean, Long, List<Tuple2<Long, LocalDateTime>>> splitResult = BackPolicyUtil.splitOrder(gameBackPolicy, backMoney);
-        if (splitResult.first) {
+        if (CollectionUtils.isNotEmpty(backInfo.fourth)) {
             // 需要拆单
-            List<GameOceanengineAppOrderSplitLog> splitOrderLogList = new ArrayList<>(splitResult.third.size());
-            for (int i = 0; i < splitResult.third.size(); i++) {
-                Tuple2<Long, LocalDateTime> splitOrder = splitResult.third.get(i);
+            List<GameOceanengineAppOrderSplitLog> splitOrderLogList = new ArrayList<>(backInfo.fourth.size());
+            for (int i = 0; i < backInfo.fourth.size(); i++) {
+                Tuple2<Long, LocalDateTime> splitOrder = backInfo.fourth.get(i);
                 splitOrderLogList.add(GameOceanengineAppOrderSplitLog.builder()
                         .backDay(splitOrder.second.toLocalDate())
                         .orderNo(orderLog.getOrderNo())
                         .backIndex(i + 1)
-                        .backCount(splitResult.third.size())
+                        .backCount(backInfo.fourth.size())
                         .splitMoney(splitOrder.first)
                         .backTime(splitOrder.second)
                         .backStatus(BackStatusEnum.SUCCESS.getBackStatus())
@@ -118,7 +119,7 @@ public class GameOceanengineAppOrderLogServiceImpl extends ServiceImpl<GameOcean
             gameOceanengineAppOrderSplitLogService.saveBatch(splitOrderLogList);
             return update(new LambdaUpdateWrapper<GameOceanengineAppOrderLog>()
                     .set(GameOceanengineAppOrderLog::getBackStatus, BackStatusEnum.SUCCESS.getBackStatus())
-                    .set(GameOceanengineAppOrderLog::getBackMoney, splitResult.second)
+                    .set(GameOceanengineAppOrderLog::getBackMoney, backInfo.second)
                     .set(GameOceanengineAppOrderLog::getBackMsg, backMsg)
                     .eq(GameOceanengineAppOrderLog::getId, orderLog.getId())
             );
@@ -260,17 +261,51 @@ public class GameOceanengineAppOrderLogServiceImpl extends ServiceImpl<GameOcean
 
     public static class OceanengineOrderBackPolicyCheck implements BackPolicyUtil.IBackPolicyCheck {
         private final IGameOceanengineAppOrderLogService gameOceanengineAppOrderLogService;
+        private final IGameOceanengineAppOrderSplitLogService gameOceanengineAppOrderSplitLogService;
         private final GameBackPolicy gameBackPolicy;
         private final GameOceanengineAppUserLog userLog;
         private final GameOceanengineAppOrderLog orderLog;
 
-        public OceanengineOrderBackPolicyCheck(IGameOceanengineAppOrderLogService gameOceanengineAppOrderLogService, GameOceanengineAppUserLog userLog, GameOceanengineAppOrderLog orderLog, GameBackPolicy gameBackPolicy) {
+        public OceanengineOrderBackPolicyCheck(IGameOceanengineAppOrderLogService gameOceanengineAppOrderLogService, IGameOceanengineAppOrderSplitLogService gameOceanengineAppOrderSplitLogService, GameOceanengineAppUserLog userLog, GameOceanengineAppOrderLog orderLog, GameBackPolicy gameBackPolicy) {
             this.gameOceanengineAppOrderLogService = gameOceanengineAppOrderLogService;
+            this.gameOceanengineAppOrderSplitLogService = gameOceanengineAppOrderSplitLogService;
             this.gameBackPolicy = gameBackPolicy;
             this.userLog = userLog;
             this.orderLog = orderLog;
         }
 
+        public Tuple2<Long, Long> backCountForUserWithSplitOrder(String userId) {
+            Map<String, Long> orderMap = gameOceanengineAppOrderLogService.list(new LambdaQueryWrapper<GameOceanengineAppOrderLog>()
+                    .select(GameOceanengineAppOrderLog::getOrderNo, GameOceanengineAppOrderLog::getBackMoney)
+                    .eq(GameOceanengineAppOrderLog::getGameId, orderLog.getGameId())
+                    .eq(GameOceanengineAppOrderLog::getAccountId, orderLog.getAccountId())
+                    .eq(GameOceanengineAppOrderLog::getBackPolicyId, gameBackPolicy.getId())
+                    .eq(GameOceanengineAppOrderLog::getOrderStatus, OrderStatusEnum.SUCCESS_PAY.getValue())
+                    .eq(GameOceanengineAppOrderLog::getBackStatus, BackStatusEnum.SUCCESS.getBackStatus())
+                    .eq(GameOceanengineAppOrderLog::getUserId, userId)
+                    .ne(GameOceanengineAppOrderLog::getOrderNo, orderLog.getOrderNo())
+            ).stream().collect(Collectors.toMap(GameOceanengineAppOrderLog::getOrderNo, GameOceanengineAppOrderLog::getBackMoney));
+            if (MapUtils.isEmpty(orderMap)) {
+                return Tuple2.with(0L, 0L);
+            }
+            Map<String, Integer> splitBackCountMap = gameOceanengineAppOrderSplitLogService.list(new LambdaQueryWrapper<GameOceanengineAppOrderSplitLog>()
+                    .select(GameOceanengineAppOrderSplitLog::getOrderNo, GameOceanengineAppOrderSplitLog::getBackIndex, GameOceanengineAppOrderSplitLog::getBackCount)
+                    .in(GameOceanengineAppOrderSplitLog::getOrderNo, orderMap.keySet())
+            ).stream().collect(Collectors.toMap(GameOceanengineAppOrderSplitLog::getOrderNo, GameOceanengineAppOrderSplitLog::getBackCount, (obj1, obj2) -> obj1));
+            long count = 0;
+            long backMoney = 0;
+            for (Map.Entry<String, Long> entry : orderMap.entrySet()) {
+                Integer splitBackCount = splitBackCountMap.get(entry.getKey());
+                backMoney += entry.getValue();
+                if (splitBackCount != null) {
+                    count += splitBackCount;
+                } else {
+                    count += 1;
+                }
+            }
+            return Tuple2.with(count, backMoney);
+        }
+
         @Override
         public long backCountForFixedRate(int numberOfRound, BackUnitEnum backUnit, Boolean firstPolicy) {
             numberOfRound = numberOfRound - 1;

+ 8 - 8
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/impl/GameOceanengineOrderLogServiceImpl.java

@@ -8,6 +8,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.github.sd4324530.jtuple.Tuple2;
 import com.github.sd4324530.jtuple.Tuple3;
+import com.github.sd4324530.jtuple.Tuple4;
 import com.github.sd4324530.jtuple.Tuples;
 import com.zanxiang.game.back.base.pojo.enums.OrderStatusEnum;
 import com.zanxiang.game.back.serve.config.NacosDynamicParamConfig;
@@ -97,7 +98,7 @@ public class GameOceanengineOrderLogServiceImpl extends ServiceImpl<GameOceaneng
         }
 
         GameBackPolicy gameBackPolicy = gameBackPolicyService.getById(orderLog.getBackPolicyId());
-        Tuple3<Boolean, Long, String> backInfo = BackPolicyUtil.backOrder(orderLog.getOrderNo(), gameBackPolicy, orderLog.getAmount(),
+        Tuple4<Boolean, Long, String, List<Tuple2<Long, LocalDateTime>>> backInfo = BackPolicyUtil.backOrder(orderLog.getOrderNo(), gameBackPolicy, orderLog.getAmount(),
                 orderLog.getIsFirstOrder(),
                 orderLog.getPayTime(),
                 // 此处使用用户最近一次的重新染色时间
@@ -119,17 +120,16 @@ public class GameOceanengineOrderLogServiceImpl extends ServiceImpl<GameOceaneng
             );
         }
         // 拆单
-        Tuple3<Boolean, Long, List<Tuple2<Long, LocalDateTime>>> splitResult = BackPolicyUtil.splitOrder(gameBackPolicy, backMoney);
-        if (splitResult.first) {
+        if (CollectionUtils.isNotEmpty(backInfo.fourth)) {
             // 需要拆单
-            List<GameOceanengineOrderSplitLog> splitOrderLogList = new ArrayList<>(splitResult.third.size());
-            for (int i = 0; i < splitResult.third.size(); i++) {
-                Tuple2<Long, LocalDateTime> splitOrder = splitResult.third.get(i);
+            List<GameOceanengineOrderSplitLog> splitOrderLogList = new ArrayList<>(backInfo.fourth.size());
+            for (int i = 0; i < backInfo.fourth.size(); i++) {
+                Tuple2<Long, LocalDateTime> splitOrder = backInfo.fourth.get(i);
                 splitOrderLogList.add(GameOceanengineOrderSplitLog.builder()
                         .backDay(splitOrder.second.toLocalDate())
                         .orderNo(orderLog.getOrderNo())
                         .backIndex(i + 1)
-                        .backCount(splitResult.third.size())
+                        .backCount(backInfo.fourth.size())
                         .splitMoney(splitOrder.first)
                         .backTime(splitOrder.second)
                         .backStatus(BackStatusEnum.NO.getBackStatus())
@@ -140,7 +140,7 @@ public class GameOceanengineOrderLogServiceImpl extends ServiceImpl<GameOceaneng
             gameOceanengineOrderSplitLogService.saveBatch(splitOrderLogList);
             return update(new LambdaUpdateWrapper<GameOceanengineOrderLog>()
                     .set(GameOceanengineOrderLog::getBackStatus, BackStatusEnum.NO.getBackStatus())
-                    .set(GameOceanengineOrderLog::getBackMoney, splitResult.second)
+                    .set(GameOceanengineOrderLog::getBackMoney, backInfo.second)
                     .set(GameOceanengineOrderLog::getBackMsg, backMsg)
                     .eq(GameOceanengineOrderLog::getId, orderLog.getId())
             );

+ 9 - 12
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/impl/GameTencentAppApiOrderServiceImpl.java

@@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.github.sd4324530.jtuple.Tuple2;
 import com.github.sd4324530.jtuple.Tuple3;
+import com.github.sd4324530.jtuple.Tuple4;
 import com.zanxiang.advertising.tencent.base.AdvertisingTencentServer;
 import com.zanxiang.advertising.tencent.base.pojo.dto.DataReportOfAccountIdRpcDTO;
 import com.zanxiang.advertising.tencent.base.pojo.dto.DataReportOfAccountIdV3RpcDTO;
@@ -23,19 +24,16 @@ import com.zanxiang.game.back.serve.pojo.enums.BackStatusEnum;
 import com.zanxiang.game.back.serve.pojo.enums.BackUnitEnum;
 import com.zanxiang.game.back.serve.service.*;
 import com.zanxiang.game.back.serve.utils.BackPolicyUtil;
-import com.zanxiang.module.util.DateUtil;
 import com.zanxiang.module.util.NumberUtil;
 import com.zanxiang.module.util.ObjectUtil;
-import com.zanxiang.module.util.URIUtil;
-import com.zanxiang.module.util.encryption.Md5Util;
 import com.zanxiang.module.util.exception.BaseException;
 import com.zanxiang.module.util.pojo.ResultVO;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.lang3.RandomUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.dubbo.config.annotation.DubboReference;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.http.ResponseEntity;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.client.RestTemplate;
@@ -88,7 +86,7 @@ implements IGameTencentAppApiOrderService {
         }
 
         GameBackPolicy gameBackPolicy = gameBackPolicyService.getById(orderLog.getBackPolicyId());
-        Tuple3<Boolean, Long, String> backInfo = BackPolicyUtil.backOrder(orderLog.getOrderId(), gameBackPolicy, orderLog.getRechargeMoney(),
+        Tuple4<Boolean, Long, String, List<Tuple2<Long, LocalDateTime>>> backInfo = BackPolicyUtil.backOrder(orderLog.getOrderId(), gameBackPolicy, orderLog.getRechargeMoney(),
                 orderLog.getIsFirstOrder(),
                 orderLog.getPayTime(),
                 // 此处使用用户最近一次的重新染色时间
@@ -107,17 +105,16 @@ implements IGameTencentAppApiOrderService {
             );
         }
         // 拆单
-        Tuple3<Boolean, Long, List<Tuple2<Long, LocalDateTime>>> splitResult = BackPolicyUtil.splitOrder(gameBackPolicy, backMoney);
-        if (splitResult.first) {
+        if (CollectionUtils.isNotEmpty(backInfo.fourth)) {
             // 需要拆单
-            List<GameTencentAppApiOrderSplitLog> splitOrderLogList = new ArrayList<>(splitResult.third.size());
-            for (int i = 0; i < splitResult.third.size(); i++) {
-                Tuple2<Long, LocalDateTime> splitOrder = splitResult.third.get(i);
+            List<GameTencentAppApiOrderSplitLog> splitOrderLogList = new ArrayList<>(backInfo.fourth.size());
+            for (int i = 0; i < backInfo.fourth.size(); i++) {
+                Tuple2<Long, LocalDateTime> splitOrder = backInfo.fourth.get(i);
                 splitOrderLogList.add(GameTencentAppApiOrderSplitLog.builder()
                         .backDay(splitOrder.second.toLocalDate())
                         .orderNo(orderLog.getOrderId())
                         .backIndex(i + 1)
-                        .backCount(splitResult.third.size())
+                        .backCount(backInfo.fourth.size())
                         .splitMoney(splitOrder.first)
                         .backTime(splitOrder.second)
                         .backStatus(BackStatusEnum.NO.getBackStatus())
@@ -127,7 +124,7 @@ implements IGameTencentAppApiOrderService {
             gameTencentAppApiOrderSplitLogService.saveBatch(splitOrderLogList);
             return update(new LambdaUpdateWrapper<GameTencentAppApiOrder>()
                     .set(GameTencentAppApiOrder::getIsBack, BackStatusEnum.NO.getBackStatus())
-                    .set(GameTencentAppApiOrder::getBackMoney, splitResult.second)
+                    .set(GameTencentAppApiOrder::getBackMoney, backInfo.second)
                     .set(GameTencentAppApiOrder::getBackMsg, backMsg)
                     .eq(GameTencentAppApiOrder::getId, orderLog.getId())
             );

+ 8 - 8
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/impl/GameTencentMiniGameOrderServiceImpl.java

@@ -8,6 +8,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.github.sd4324530.jtuple.Tuple2;
 import com.github.sd4324530.jtuple.Tuple3;
+import com.github.sd4324530.jtuple.Tuple4;
 import com.zanxiang.advertising.tencent.base.AdvertisingTencentServer;
 import com.zanxiang.advertising.tencent.base.rpc.IUserActionSetRpc;
 import com.zanxiang.erp.base.ErpServer;
@@ -110,7 +111,7 @@ public class GameTencentMiniGameOrderServiceImpl extends ServiceImpl<GameTencent
 
         GameBackPolicy gameBackPolicy = gameBackPolicyService.getById(orderLog.getBackPolicyId());
         // 此处是否是首单用 limit 2。因为在执行判断之前订单已入库,所以库里只有一笔才是首单
-        Tuple3<Boolean, Long, String> backInfo = BackPolicyUtil.backOrder(orderLog.getOrderId(), gameBackPolicy, orderLog.getRechargeMoney(),
+        Tuple4<Boolean, Long, String, List<Tuple2<Long, LocalDateTime>>> backInfo = BackPolicyUtil.backOrder(orderLog.getOrderId(), gameBackPolicy, orderLog.getRechargeMoney(),
                 orderLog.getIsFirstOrder(),
                 orderLog.getPayTime(),
                 // 此处使用用户最近一次的重新染色时间
@@ -130,17 +131,16 @@ public class GameTencentMiniGameOrderServiceImpl extends ServiceImpl<GameTencent
             );
         }
         // 拆单
-        Tuple3<Boolean, Long, List<Tuple2<Long, LocalDateTime>>> splitResult = BackPolicyUtil.splitOrder(gameBackPolicy, backMoney);
-        if (splitResult.first) {
+        if (CollectionUtils.isNotEmpty(backInfo.fourth)) {
             // 需要拆单
-            List<GameTencentMiniGameOrderSplitLog> splitOrderLogList = new ArrayList<>(splitResult.third.size());
-            for (int i = 0; i < splitResult.third.size(); i++) {
-                Tuple2<Long, LocalDateTime> splitOrder = splitResult.third.get(i);
+            List<GameTencentMiniGameOrderSplitLog> splitOrderLogList = new ArrayList<>(backInfo.fourth.size());
+            for (int i = 0; i < backInfo.fourth.size(); i++) {
+                Tuple2<Long, LocalDateTime> splitOrder = backInfo.fourth.get(i);
                 splitOrderLogList.add(GameTencentMiniGameOrderSplitLog.builder()
                         .backDay(splitOrder.second.toLocalDate())
                         .orderNo(orderLog.getOrderId())
                         .backIndex(i + 1)
-                        .backCount(splitResult.third.size())
+                        .backCount(backInfo.fourth.size())
                         .splitMoney(splitOrder.first)
                         .backTime(splitOrder.second)
                         .backStatus(BackStatusEnum.NO.getBackStatus())
@@ -150,7 +150,7 @@ public class GameTencentMiniGameOrderServiceImpl extends ServiceImpl<GameTencent
             gameTencentMiniGameOrderSplitLogService.saveBatch(splitOrderLogList);
             return update(new LambdaUpdateWrapper<GameTencentMiniGameOrder>()
                     .set(GameTencentMiniGameOrder::getBackStatus, BackStatusEnum.NO.getBackStatus())
-                    .set(GameTencentMiniGameOrder::getBackMoney, splitResult.second)
+                    .set(GameTencentMiniGameOrder::getBackMoney, backInfo.second)
                     .set(GameTencentMiniGameOrder::getBackMsg, backMsg)
                     .eq(GameTencentMiniGameOrder::getId, orderLog.getId())
             );

+ 8 - 8
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/impl/GameTencentOrderServiceImpl.java

@@ -7,6 +7,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.github.sd4324530.jtuple.Tuple2;
 import com.github.sd4324530.jtuple.Tuple3;
+import com.github.sd4324530.jtuple.Tuple4;
 import com.zanxiang.advertising.tencent.base.AdvertisingTencentServer;
 import com.zanxiang.advertising.tencent.base.pojo.dto.DataReportOfAppIdRpcDTO;
 import com.zanxiang.advertising.tencent.base.pojo.dto.UserActionRpcDTO;
@@ -118,7 +119,7 @@ public class GameTencentOrderServiceImpl extends ServiceImpl<GameTencentOrderMap
         }
 
         GameBackPolicy gameBackPolicy = gameBackPolicyService.getById(orderLog.getBackPolicyId());
-        Tuple3<Boolean, Long, String> backInfo = BackPolicyUtil.backOrder(orderLog.getOrderId(), gameBackPolicy, orderLog.getRechargeMoney(),
+        Tuple4<Boolean, Long, String, List<Tuple2<Long, LocalDateTime>>> backInfo = BackPolicyUtil.backOrder(orderLog.getOrderId(), gameBackPolicy, orderLog.getRechargeMoney(),
                 orderLog.getIsFirstOrder(),
                 orderLog.getPayTime(),
                 // 此处使用用户最近一次的重新染色时间
@@ -137,17 +138,16 @@ public class GameTencentOrderServiceImpl extends ServiceImpl<GameTencentOrderMap
             );
         }
         // 拆单
-        Tuple3<Boolean, Long, List<Tuple2<Long, LocalDateTime>>> splitResult = BackPolicyUtil.splitOrder(gameBackPolicy, backMoney);
-        if (splitResult.first) {
+        if (CollectionUtils.isNotEmpty(backInfo.fourth)) {
             // 需要拆单
-            List<GameTencentOrderSplitLog> splitOrderLogList = new ArrayList<>(splitResult.third.size());
-            for (int i = 0; i < splitResult.third.size(); i++) {
-                Tuple2<Long, LocalDateTime> splitOrder = splitResult.third.get(i);
+            List<GameTencentOrderSplitLog> splitOrderLogList = new ArrayList<>(backInfo.fourth.size());
+            for (int i = 0; i < backInfo.fourth.size(); i++) {
+                Tuple2<Long, LocalDateTime> splitOrder = backInfo.fourth.get(i);
                 splitOrderLogList.add(GameTencentOrderSplitLog.builder()
                         .backDay(splitOrder.second.toLocalDate())
                         .orderNo(orderLog.getOrderId())
                         .backIndex(i + 1)
-                        .backCount(splitResult.third.size())
+                        .backCount(backInfo.fourth.size())
                         .splitMoney(splitOrder.first)
                         .backTime(splitOrder.second)
                         .backStatus(BackStatusEnum.NO.getBackStatus())
@@ -157,7 +157,7 @@ public class GameTencentOrderServiceImpl extends ServiceImpl<GameTencentOrderMap
             gameTencentOrderSplitLogService.saveBatch(splitOrderLogList);
             return update(new LambdaUpdateWrapper<GameTencentOrder>()
                     .set(GameTencentOrder::getIsBack, BackStatusEnum.NO.getBackStatus())
-                    .set(GameTencentOrder::getBackMoney, splitResult.second)
+                    .set(GameTencentOrder::getBackMoney, backInfo.second)
                     .set(GameTencentOrder::getBackMsg, backMsg)
                     .eq(GameTencentOrder::getId, orderLog.getId())
             );

+ 230 - 102
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/utils/BackPolicyUtil.java

@@ -2,13 +2,17 @@ package com.zanxiang.game.back.serve.utils;
 
 import com.github.sd4324530.jtuple.Tuple2;
 import com.github.sd4324530.jtuple.Tuple3;
+import com.github.sd4324530.jtuple.Tuple4;
 import com.github.sd4324530.jtuple.Tuples;
+import com.zanxiang.game.back.serve.pojo.BackPolicyOfSplitLevel;
+import com.zanxiang.game.back.serve.pojo.BackPolicyOfSumRecharge;
 import com.zanxiang.game.back.serve.pojo.entity.GameBackPolicy;
 import com.zanxiang.game.back.serve.pojo.enums.BackUnitEnum;
 import com.zanxiang.game.back.serve.pojo.vo.GameBackPolicyVO;
 import com.zanxiang.module.util.DateUtil;
 import com.zanxiang.module.util.JsonUtil;
 import com.zanxiang.module.util.NumberUtil;
+import com.zanxiang.module.util.exception.BaseException;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.lang3.RandomUtils;
@@ -23,28 +27,205 @@ import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
 import java.util.function.Function;
+import java.util.stream.Collectors;
 
 @Slf4j
 public class BackPolicyUtil {
-    private static final long[] RECHARGE_LEVEL = {12 * 100L, 30 * 100L, 50 * 100L, 98 * 100L, 198 * 100L, 328 * 100L, 649 * 100L, 998 * 100L, 2998 * 100L};
-
-    static {
-        Arrays.sort(RECHARGE_LEVEL);
-    }
 
     /**
      * 订单回传
      *
      * @return <是否回传,回传金额,回传描述>
      */
-    public static Tuple3<Boolean, Long, String> backOrder(String orderId, GameBackPolicy gameBackPolicy,
-                                                          long rechargeMoney, boolean isFirstOrder,
-                                                          LocalDateTime payTime, LocalDateTime regTime,
-                                                          String userId, IBackPolicyCheck backPolicyCheck) {
+    public static Tuple4<Boolean, Long, String, List<Tuple2<Long, LocalDateTime>>> backOrder(String orderId, GameBackPolicy gameBackPolicy,
+                                                                                             long rechargeMoney, boolean isFirstOrder,
+                                                                                             LocalDateTime payTime, LocalDateTime regTime,
+                                                                                             String userId, IBackPolicyCheck backPolicyCheck) {
         if (null == gameBackPolicy) {
             log.error("订单 id[{}]找不到回传策略,默认回传", orderId);
-            return Tuples.tuple(Boolean.TRUE, rechargeMoney, "没有回传策略");
+            return Tuples.tuple(Boolean.TRUE, rechargeMoney, "没有回传策略", null);
+        }
+        if (gameBackPolicy.getPolicyType() == null || Objects.equals(gameBackPolicy.getPolicyType(), GameBackPolicy.TYPE_DEFAULT)) {
+            Tuple3<Boolean, Long, String> backInfo = policyOfDefault(orderId, gameBackPolicy, rechargeMoney, isFirstOrder, payTime, regTime, userId, backPolicyCheck);
+            if (backInfo.first) {
+                Collection<GameBackPolicyVO.SplitStrategy> splitStrategyList = StringUtils.isBlank(gameBackPolicy.getSplitStrategy()) ? Collections.emptyList() : JsonUtil.toList(gameBackPolicy.getSplitStrategy(), List.class, GameBackPolicyVO.SplitStrategy.class);
+                Tuple3<Boolean, Long, List<Tuple2<Long, LocalDateTime>>> splitInfo = splitOrder(splitStrategyList, backInfo.second);
+                if (splitInfo.first) {
+                    return Tuple4.with(backInfo.first, backInfo.second, backInfo.third, splitInfo.third);
+                } else {
+                    return Tuple4.with(backInfo.first, backInfo.second, backInfo.third, null);
+                }
+            } else {
+                return Tuple4.with(backInfo.first, backInfo.second, backInfo.third, null);
+            }
+        } else if (Objects.equals(gameBackPolicy.getPolicyType(), GameBackPolicy.TYPE_SPLIT_LEVEL)) {
+            // 按策略判断
+            BackPolicyOfSplitLevel policyOfSplitLevel = JsonUtil.toObj(gameBackPolicy.getTypeOfSplitLevelJson(), BackPolicyOfSplitLevel.class);
+            Tuple3<Boolean, Long, String> backInfo = policyOfSplitLevel(orderId, gameBackPolicy.getId(), policyOfSplitLevel, rechargeMoney, isFirstOrder, payTime, regTime, userId, backPolicyCheck);
+
+            if (backInfo.first) {
+                Tuple3<Boolean, Long, List<Tuple2<Long, LocalDateTime>>> splitInfo = splitOrder(policyOfSplitLevel.getSplitStrategy(), backInfo.second);
+                if (splitInfo.first) {
+                    return Tuple4.with(backInfo.first, backInfo.second, backInfo.third, splitInfo.third);
+                } else {
+                    return Tuple4.with(backInfo.first, backInfo.second, backInfo.third, null);
+                }
+            } else {
+                return Tuple4.with(backInfo.first, backInfo.second, backInfo.third, null);
+            }
+        } else if (Objects.equals(gameBackPolicy.getPolicyType(), GameBackPolicy.TYPE_SUM_RECHARGE)) {
+            // 按累充判断
+            BackPolicyOfSumRecharge policyOfSumRecharge = JsonUtil.toObj(gameBackPolicy.getTypeOfSumRechargeJson(), BackPolicyOfSumRecharge.class);
+            return policyOfSumRecharge(orderId, gameBackPolicy.getId(), policyOfSumRecharge, rechargeMoney, isFirstOrder, payTime, regTime, userId, backPolicyCheck);
+        }
+        throw new BaseException("未知的回传策略类型:" + gameBackPolicy.getPolicyType());
+
+    }
+
+    /**
+     * 拆单逻辑
+     */
+    public static Tuple3<Boolean, Long, List<Tuple2<Long, LocalDateTime>>> splitOrder(Collection<GameBackPolicyVO.SplitStrategy> splitStrategyList, Long backMoney) {
+        if (CollectionUtils.isEmpty(splitStrategyList)) {
+            return Tuple3.with(false, backMoney, null);
+        }
+        GameBackPolicyVO.SplitStrategy backSplitStrategy = null;
+        for (GameBackPolicyVO.SplitStrategy splitStrategy : splitStrategyList) {
+            if (NumberUtil.multiply100(splitStrategy.getPayMoney()).longValue() == backMoney) {
+                backSplitStrategy = splitStrategy;
+                break;
+            }
+        }
+        if (backSplitStrategy == null) {
+            return Tuple3.with(false, backMoney, null);
+        }
+        List<Tuple2<Long, LocalDateTime>> result = new ArrayList<>();
+        LocalDateTime beginTime = LocalDateTime.now();
+        long sumMoney = 0L;
+        for (BigDecimal splitMoney : backSplitStrategy.getSplitList()) {
+            long money = NumberUtil.multiply100(splitMoney).longValue();
+            sumMoney += money;
+            result.add(Tuple2.with(money, beginTime));
+            int randomMinute = RandomUtils.nextInt(backSplitStrategy.getBetweenMinuteMin(), backSplitStrategy.getBetweenMinuteMax());
+            beginTime = beginTime.plusMinutes(randomMinute);
+        }
+        return Tuple3.with(true, sumMoney, result);
+    }
+
+    private static Tuple3<Boolean, Long, String> policyOfSplitLevel(String orderId, Long policyId, BackPolicyOfSplitLevel policyOfSplitLevel,
+                                                                    long rechargeMoney, boolean isFirstOrder,
+                                                                    LocalDateTime payTime, LocalDateTime regTime,
+                                                                    String userId, IBackPolicyCheck backPolicyCheck) {
+        BigDecimal rechargeAmount = NumberUtil.divide100(new BigDecimal(rechargeMoney));
+        if (policyOfSplitLevel.getRegPayIntervalTime() != null
+                && ((DateUtil.localDateTimeToSecond(payTime) - DateUtil.localDateTimeToSecond(regTime)) / 60) > policyOfSplitLevel.getRegPayIntervalTime()) {
+            log.error("订单 id[{}]通过回传策略[{}]判断后,超过注册充值间隔时间({}),不回传", orderId, policyId, policyOfSplitLevel.getRegPayIntervalTime());
+            return Tuples.tuple(Boolean.FALSE, rechargeMoney, "超过注册充值间隔时间(" + policyOfSplitLevel.getRegPayIntervalTime() + "),不回传");
+        }
+        if (policyOfSplitLevel.getBackCountOfUser() != null) {
+            long userBackCount = backPolicyCheck.backCountForUser(BackUnitEnum.LARGE_AMOUNT, userId, false);
+            if (userBackCount > policyOfSplitLevel.getBackCountOfUser()) {
+                return Tuples.tuple(Boolean.FALSE, rechargeMoney, "单用户最大回传 " + policyOfSplitLevel.getBackCountOfUser() + "笔,当前已回传 " + userBackCount + "笔");
+            }
+        }
+        BackPolicyOfSplitLevel.RechargeLevel rechargeLevel = null;
+        for (BackPolicyOfSplitLevel.RechargeLevel item : policyOfSplitLevel.getRechargeLevelList()) {
+            if (rechargeAmount.compareTo(item.getMinAmount()) >= 0 && rechargeAmount.compareTo(item.getMaxAmount()) < 0) {
+                rechargeLevel = item;
+                break;
+            }
+        }
+        if (rechargeLevel == null) {
+            log.error("订单 id[{}]通过回传策略[{}]判断后,找不到对应的充值挡位,不回传", orderId, policyId);
+            return Tuples.tuple(Boolean.FALSE, rechargeMoney, "充值金额(" + rechargeAmount + ")未找到对应的挡位,默认不回传");
+        }
+        if (Objects.equals(rechargeLevel.getBackType(), GameBackPolicy.POLICY_TYPE_FIXED_RATE)) {
+            // 固定比例回传
+            String[] temp = rechargeLevel.getBackRate().split(":");
+            int backCount = Integer.parseInt(temp[0]);
+            int ignoreCount = Integer.parseInt(temp[1]);
+            if (backCount == 0) {
+                String backMsg = "按比例回传,回传比例为 0,全部不回传";
+                log.error("订单 id[{}]通过回传策略[{}]判断后,不回传,原因:{}", orderId, policyId, backMsg);
+                return Tuples.tuple(Boolean.FALSE, rechargeMoney, backMsg);
+            }
+            if (ignoreCount == 0) {
+                String backMsg = "按比例回传,忽略比例为 0,全部回传";
+                log.error("订单 id[{}]通过回传策略[{}]判断后,回传,原因:{}", orderId, policyId, backMsg);
+                return Tuples.tuple(Boolean.TRUE, downLevel(rechargeMoney, policyOfSplitLevel.getDownLevel()), backMsg);
+            }
+            long isBackCount = backPolicyCheck.backCountForFixedRate(backCount + ignoreCount, BackUnitEnum.LARGE_AMOUNT, false);
+            String backMsg = "按比例回传,每 " + (backCount + ignoreCount) + "笔回传 " + backCount + "笔,当前第 " + (isBackCount + 1) + "笔";
+            if (isBackCount >= backCount) {
+                log.error("订单 id[{}]通过回传策略[{}]判断后,不回传,原因:{}", orderId, policyId, backMsg);
+                return Tuples.tuple(Boolean.FALSE, downLevel(rechargeMoney, policyOfSplitLevel.getDownLevel()), backMsg);
+            } else {
+                log.error("订单 id[{}]通过回传策略[{}]判断后,回传,原因:{}", orderId, policyId, backMsg);
+                return Tuples.tuple(Boolean.TRUE, downLevel(rechargeMoney, policyOfSplitLevel.getDownLevel()), backMsg);
+            }
+        } else if (Objects.equals(rechargeLevel.getBackType(), GameBackPolicy.POLICY_TYPE_RANDOM_RATE)) {
+            // 随机概率回传
+            boolean isBack = RandomUtils.nextInt(0, 100) < NumberUtil.multiply100(new BigDecimal(rechargeLevel.getBackRate())).intValue();
+            String backMsg = "随机概率回传(" + NumberUtil.multiply100(new BigDecimal(rechargeLevel.getBackRate())) + "%)";
+            if (!isBack) {
+                log.error("订单 id[{}]通过回传策略[{}]判断后,不回传,原因:{}", orderId, policyId, backMsg);
+                return Tuples.tuple(Boolean.FALSE, downLevel(rechargeMoney, policyOfSplitLevel.getDownLevel()), backMsg);
+            } else {
+                log.error("订单 id[{}]通过回传策略[{}]判断后,回传,原因:{}", orderId, policyId, backMsg);
+                return Tuples.tuple(Boolean.TRUE, downLevel(rechargeMoney, policyOfSplitLevel.getDownLevel()), backMsg);
+            }
+        } else {
+            throw new RuntimeException("回传策略[" + policyId + "]配置错误,未知的回传类型:" + rechargeLevel.getBackType());
+        }
+
+    }
+
+    private static Tuple4<Boolean, Long, String, List<Tuple2<Long, LocalDateTime>>> policyOfSumRecharge(String orderId, Long policyId, BackPolicyOfSumRecharge policyOfSumRecharge,
+                                                                                                        long rechargeMoney, boolean isFirstOrder,
+                                                                                                        LocalDateTime payTime, LocalDateTime regTime,
+                                                                                                        String userId, IBackPolicyCheck backPolicyCheck) {
+        BigDecimal rechargeAmount = NumberUtil.divide100(new BigDecimal(rechargeMoney));
+        if (policyOfSumRecharge.getRegPayIntervalTime() != null
+                && ((DateUtil.localDateTimeToSecond(payTime) - DateUtil.localDateTimeToSecond(regTime)) / 60) > policyOfSumRecharge.getRegPayIntervalTime()) {
+            log.error("订单 id[{}]通过回传策略[{}]判断后,超过注册充值间隔时间({}),不回传", orderId, policyId, policyOfSumRecharge.getRegPayIntervalTime());
+            return Tuples.tuple(Boolean.FALSE, rechargeMoney, "超过注册充值间隔时间(" + policyOfSumRecharge.getRegPayIntervalTime() + "),不回传", null);
+        }
+        BackPolicyOfSumRecharge.RechargeLevel rechargeLevel = null;
+        for (BackPolicyOfSumRecharge.RechargeLevel item : policyOfSumRecharge.getRechargeLevelList()) {
+            if (rechargeAmount.compareTo(item.getMinAmount()) >= 0 && rechargeAmount.compareTo(item.getMaxAmount()) < 0) {
+                rechargeLevel = item;
+                break;
+            }
+        }
+        if (rechargeLevel == null) {
+            log.error("订单 id[{}]通过回传策略[{}]判断后,找不到对应的累充挡位,不回传", orderId, policyId);
+            return Tuples.tuple(Boolean.FALSE, rechargeMoney, "充值金额(" + rechargeAmount + ")未找到对应的挡位,默认不回传", null);
+        }
+        Tuple2<Long, Long> backInfo = backPolicyCheck.backCountForUserWithSplitOrder(userId);
+        if (rechargeLevel.getBackCountOfUser() <= backInfo.first) {
+            log.error("订单 id[{}]通过回传策略[{}]判断后,已达到回传的订单数,不回传", orderId, policyId);
+            return Tuples.tuple(Boolean.FALSE, rechargeMoney, "充值金额(" + rechargeAmount + ")已达到回传的订单数(已回传:" + backInfo.first + "笔,当前挡位:" + rechargeLevel.getBackCountOfUser() + "笔),不回传", null);
         }
+
+        long backCount = rechargeLevel.getBackCountOfUser() - backInfo.first;
+        long backMoney = backInfo.second - NumberUtil.multiply100(rechargeLevel.getMinAmount()).longValue();
+        if (backMoney <= 0) {
+            // 最低回传一分钱
+            backMoney = 1;
+        }
+        List<Tuple2<Long, LocalDateTime>> splitOrder = new ArrayList<>();
+        for (int i = 0; i < backCount; i++) {
+            splitOrder.add(Tuple2.with(backMoney, LocalDateTime.now()));
+        }
+        String backMsg = "充值金额(" + rechargeAmount + ") 已回传:" + backInfo.first + "笔,当前挡位:" + rechargeLevel.getBackCountOfUser() + "笔,回传(" + backCount + "-" + backMoney + ")笔";
+        log.error("订单 id[{}]通过回传策略[{}]判断后,回传。回传日志:{}", orderId, policyId, backMsg);
+        return Tuples.tuple(Boolean.TRUE, rechargeMoney, backMsg, splitOrder);
+    }
+
+    private static Tuple3<Boolean, Long, String> policyOfDefault(String orderId, GameBackPolicy gameBackPolicy,
+                                                                 long rechargeMoney, boolean isFirstOrder,
+                                                                 LocalDateTime payTime, LocalDateTime regTime,
+                                                                 String userId, IBackPolicyCheck backPolicyCheck) {
         if (gameBackPolicy.getSupperSmallAmount() != null && gameBackPolicy.getSupperSmallAmount() >= rechargeMoney) {
             log.error("订单 id[{}]被判定为超小额订单({}),默认不回传", orderId, gameBackPolicy.getSupperSmallAmount());
             return Tuples.tuple(Boolean.FALSE, rechargeMoney, "超小额订单(<=" + gameBackPolicy.getSupperSmallAmount() + "),不回传");
@@ -64,6 +245,9 @@ public class BackPolicyUtil {
                 && ((DateUtil.localDateTimeToSecond(payTime) - DateUtil.localDateTimeToSecond(regTime)) / 60) > gameBackPolicy.getRegPayIntervalTime()) {
             // 补单
             log.error("订单 id[{}]通过回传策略[{}]判断后,超过注册充值间隔时间,走补单逻辑 {}, money: {}.", orderId, gameBackPolicy.getId(), gameBackPolicy.getRegPayIntervalTime(), totalRechargeAmount);
+
+            List<GameBackPolicyVO.PolicyDownLevel> downLevels = StringUtils.isEmpty(gameBackPolicy.getMarkUpDownLevel()) ? Collections.emptyList()
+                    : Arrays.stream(gameBackPolicy.getMarkUpDownLevel().split(",")).map(BackPolicyUtil::transformDownLevel).collect(Collectors.toList());
             if (gameBackPolicy.getMarkUpOrder() != null && gameBackPolicy.getMarkUpOrder()) {
                 long money = backUnit == BackUnitEnum.LARGE_AMOUNT ? totalRechargeAmount : rechargeMoney;
                 markUpTime = gameBackPolicy.getRegPayIntervalTime();
@@ -87,17 +271,17 @@ public class BackPolicyUtil {
                     int ignoreCount = Integer.parseInt(temp[1]);
                     if (backCount == 0) {
                         log.error("订单 id[{}]通过回传策略[{}]判断后,不回传,原因:回传比例 {}", orderId, gameBackPolicy.getId(), backRate);
-                        return Tuples.tuple(Boolean.FALSE, downLevel(rechargeMoney, gameBackPolicy.getMarkUpDownLevel()), "补单-按比例回传,回传比例为 0,全部不回传");
+                        return Tuples.tuple(Boolean.FALSE, downLevel(rechargeMoney, downLevels), "补单-按比例回传,回传比例为 0,全部不回传");
                     }
                     if (ignoreCount == 0) {
                         log.error("订单 id[{}]通过回传策略[{}]判断后,回传,原因:回传比例 {}", orderId, gameBackPolicy.getId(), backRate);
-                        return Tuples.tuple(Boolean.TRUE, downLevel(rechargeMoney, gameBackPolicy.getMarkUpDownLevel()), "补单-按比例回传,忽略比例为 0,全部回传");
+                        return Tuples.tuple(Boolean.TRUE, downLevel(rechargeMoney, downLevels), "补单-按比例回传,忽略比例为 0,全部回传");
                     }
                     long isBackCount = backPolicyCheck.markUpOfFixedRate(backCount + ignoreCount, markUpTime);
                     backMsg = "补单-按比例回传,每 " + (backCount + ignoreCount) + "笔回传 " + backCount + "笔,当前第 " + (isBackCount + 1) + "笔";
                     if (isBackCount >= backCount) {
                         log.error("订单 id[{}]通过回传策略[{}]判断后,不回传,原因:{}", orderId, gameBackPolicy.getId(), backMsg);
-                        return Tuples.tuple(Boolean.FALSE, downLevel(rechargeMoney, gameBackPolicy.getMarkUpDownLevel()), backMsg);
+                        return Tuples.tuple(Boolean.FALSE, downLevel(rechargeMoney, downLevels), backMsg);
                     }
                 } else if (Objects.equals(backType, GameBackPolicy.POLICY_TYPE_RANDOM_RATE)) {
                     // 随机概率回传
@@ -105,22 +289,22 @@ public class BackPolicyUtil {
                     backMsg = "补单-随机概率回传(" + NumberUtil.multiply100(new BigDecimal(backRate)) + "%)";
                     if (!isBack) {
                         log.error("订单 id[{}]通过回传策略[{}]判断后,不回传,原因:{}", orderId, gameBackPolicy.getId(), backMsg);
-                        return Tuples.tuple(Boolean.FALSE, downLevel(rechargeMoney, gameBackPolicy.getMarkUpDownLevel()), backMsg);
+                        return Tuples.tuple(Boolean.FALSE, downLevel(rechargeMoney, downLevels), backMsg);
                     }
                 } else {
                     throw new RuntimeException("回传策略[" + gameBackPolicy.getId() + "]配置错误,未知的回传类型:" + backType);
                 }
                 if (gameBackPolicy.getMarkUpBackCountOfUser() == null) {
                     log.error("订单 id[{}]通过回传策略[{}]判断后,回传,原因:回传概率 {}", orderId, gameBackPolicy.getId(), backMsg);
-                    return Tuples.tuple(Boolean.TRUE, downLevel(rechargeMoney, gameBackPolicy.getMarkUpDownLevel()), backMsg);
+                    return Tuples.tuple(Boolean.TRUE, downLevel(rechargeMoney, downLevels), backMsg);
                 }
                 long userBackCount = backPolicyCheck.markUpForUser(userId, markUpTime);
                 backMsg = backMsg + ",单用户最大回传 " + gameBackPolicy.getMarkUpBackCountOfUser() + "笔,当前已回传 " + userBackCount + "笔";
                 log.error("订单 id[{}]通过回传策略[{}]判断后,是否回传:{},原因:{}", orderId, gameBackPolicy.getId(), userBackCount < gameBackPolicy.getMarkUpBackCountOfUser(), backMsg);
-                return Tuples.tuple(userBackCount < gameBackPolicy.getMarkUpBackCountOfUser(), downLevel(rechargeMoney, gameBackPolicy.getMarkUpDownLevel()), backMsg);
+                return Tuples.tuple(userBackCount < gameBackPolicy.getMarkUpBackCountOfUser(), downLevel(rechargeMoney, downLevels), backMsg);
             } else {
                 log.error("订单 id[{}]通过回传策略[{}]判断后,不回传,原因:超过注册充值间隔时间但是未开启补单", orderId, gameBackPolicy.getId());
-                return Tuples.tuple(Boolean.FALSE, downLevel(rechargeMoney, gameBackPolicy.getMarkUpDownLevel()), "补单-未开启补单");
+                return Tuples.tuple(Boolean.FALSE, downLevel(rechargeMoney, downLevels), "补单-未开启补单");
             }
         }
 
@@ -176,6 +360,8 @@ public class BackPolicyUtil {
         Integer maxBackCountOfUser = firstPolicy ? gameBackPolicy.getFirstBackCountOfUser() : gameBackPolicy.getRechargeBackCountOfUser();
         String backMsg = firstPolicy ? "首-" : "次-";
         String downLevelString = firstPolicy ? gameBackPolicy.getFirstDownLevel() : gameBackPolicy.getRechargeDownLevel();
+        List<GameBackPolicyVO.PolicyDownLevel> downLevels = StringUtils.isEmpty(downLevelString) ? Collections.emptyList()
+                : Arrays.stream(downLevelString.split(",")).map(BackPolicyUtil::transformDownLevel).collect(Collectors.toList());
         if (Objects.equals(backType, GameBackPolicy.POLICY_TYPE_FIXED_RATE)) {
             // 固定比例回传
             String[] temp = backRate.split(":");
@@ -184,18 +370,18 @@ public class BackPolicyUtil {
             if (backCount == 0) {
                 backMsg = backMsg + "按比例回传,回传比例为 0,全部不回传";
                 log.error("订单 id[{}]通过回传策略[{}]判断后,不回传,原因:{}", orderId, gameBackPolicy.getId(), backMsg);
-                return Tuples.tuple(Boolean.FALSE, downLevel(rechargeMoney, downLevelString), backMsg);
+                return Tuples.tuple(Boolean.FALSE, downLevel(rechargeMoney, downLevels), backMsg);
             }
             if (ignoreCount == 0) {
                 backMsg = backMsg + "按比例回传,忽略比例为 0,全部回传";
                 log.error("订单 id[{}]通过回传策略[{}]判断后,回传,原因:{}", orderId, gameBackPolicy.getId(), backMsg);
-                return Tuples.tuple(Boolean.TRUE, downLevel(rechargeMoney, downLevelString), backMsg);
+                return Tuples.tuple(Boolean.TRUE, downLevel(rechargeMoney, downLevels), backMsg);
             }
             long isBackCount = backPolicyCheck.backCountForFixedRate(backCount + ignoreCount, backUnit, firstPolicy);
             backMsg = backMsg + "按比例回传,每 " + (backCount + ignoreCount) + "笔回传 " + backCount + "笔,当前第 " + (isBackCount + 1) + "笔";
             if (isBackCount >= backCount) {
                 log.error("订单 id[{}]通过回传策略[{}]判断后,不回传,原因:{}", orderId, gameBackPolicy.getId(), backMsg);
-                return Tuples.tuple(Boolean.FALSE, downLevel(rechargeMoney, downLevelString), backMsg);
+                return Tuples.tuple(Boolean.FALSE, downLevel(rechargeMoney, downLevels), backMsg);
             }
         } else if (Objects.equals(backType, GameBackPolicy.POLICY_TYPE_RANDOM_RATE)) {
             // 随机概率回传
@@ -203,7 +389,7 @@ public class BackPolicyUtil {
             backMsg = backMsg + "随机概率回传(" + NumberUtil.multiply100(new BigDecimal(backRate)) + "%)";
             if (!isBack) {
                 log.error("订单 id[{}]通过回传策略[{}]判断后,不回传,原因:{}", orderId, gameBackPolicy.getId(), backMsg);
-                return Tuples.tuple(Boolean.FALSE, downLevel(rechargeMoney, downLevelString), backMsg);
+                return Tuples.tuple(Boolean.FALSE, downLevel(rechargeMoney, downLevels), backMsg);
             }
         } else {
             throw new RuntimeException("回传策略[" + gameBackPolicy.getId() + "]配置错误,未知的回传类型:" + backType);
@@ -211,100 +397,34 @@ public class BackPolicyUtil {
 
         if (maxBackCountOfUser == null) {
             log.error("订单 id[{}]通过回传策略[{}]判断后,回传,原因:回传概率 {}", orderId, gameBackPolicy.getId(), backMsg);
-            return Tuples.tuple(Boolean.TRUE, downLevel(rechargeMoney, downLevelString), backMsg);
+            return Tuples.tuple(Boolean.TRUE, downLevel(rechargeMoney, downLevels), backMsg);
         }
         long userBackCount = backPolicyCheck.backCountForUser(backUnit, userId, firstPolicy);
         backMsg = backMsg + ",单用户最大回传 " + maxBackCountOfUser + "笔,当前已回传 " + userBackCount + "笔";
         log.error("订单 id[{}]通过回传策略[{}]判断后,是否回传:{},原因:{}", orderId, gameBackPolicy.getId(), userBackCount < maxBackCountOfUser, backMsg);
-        return Tuples.tuple(userBackCount < maxBackCountOfUser, downLevel(rechargeMoney, downLevelString), backMsg);
-    }
-
-    /**
-     * 拆单逻辑
-     */
-    public static Tuple3<Boolean, Long, List<Tuple2<Long, LocalDateTime>>> splitOrder(GameBackPolicy gameBackPolicy, Long backMoney) {
-        if (gameBackPolicy == null || StringUtils.isBlank(gameBackPolicy.getSplitStrategy())) {
-            return Tuple3.with(false, backMoney, null);
-        }
-        Collection<GameBackPolicyVO.SplitStrategy> splitStrategyList = JsonUtil.toList(gameBackPolicy.getSplitStrategy(), List.class, GameBackPolicyVO.SplitStrategy.class);
-        if (CollectionUtils.isEmpty(splitStrategyList)) {
-            return Tuple3.with(false, backMoney, null);
-        }
-        GameBackPolicyVO.SplitStrategy backSplitStrategy = null;
-        for (GameBackPolicyVO.SplitStrategy splitStrategy : splitStrategyList) {
-            if (NumberUtil.multiply100(splitStrategy.getPayMoney()).longValue() == backMoney) {
-                backSplitStrategy = splitStrategy;
-                break;
-            }
-        }
-        if (backSplitStrategy == null) {
-            return Tuple3.with(false, backMoney, null);
-        }
-        List<Tuple2<Long, LocalDateTime>> result = new ArrayList<>();
-        LocalDateTime beginTime = LocalDateTime.now();
-        long sumMoney = 0L;
-        for (BigDecimal splitMoney : backSplitStrategy.getSplitList()) {
-            long money = NumberUtil.multiply100(splitMoney).longValue();
-            sumMoney += money;
-            result.add(Tuple2.with(money, beginTime));
-            int randomMinute = RandomUtils.nextInt(backSplitStrategy.getBetweenMinuteMin(), backSplitStrategy.getBetweenMinuteMax());
-            beginTime = beginTime.plusMinutes(randomMinute);
-        }
-        return Tuple3.with(true, sumMoney, result);
+        return Tuples.tuple(userBackCount < maxBackCountOfUser, downLevel(rechargeMoney, downLevels), backMsg);
     }
 
-    private static Long downLevel(Long rechargeMoney, String downLevelStr) {
-        if (StringUtils.isBlank(downLevelStr)) {
+    private static Long downLevel(Long rechargeMoney, List<GameBackPolicyVO.PolicyDownLevel> downLevels) {
+        if (CollectionUtils.isEmpty(downLevels)) {
             return rechargeMoney;
         }
-        String[] downLevelList = downLevelStr.split(",");
-        for (String downLevel : downLevelList) {
-            String[] tmp = downLevel.split("_");
-            long minMoney = Long.parseLong(tmp[0]);
-            long maxMoney = Long.parseLong(tmp[1]);
-            Long backMoney = Long.parseLong(tmp[2]);
-            if (rechargeMoney >= minMoney && rechargeMoney <= maxMoney) {
-                return backMoney;
+        BigDecimal rechargeAmount = NumberUtil.divide100(new BigDecimal(rechargeMoney));
+        for (GameBackPolicyVO.PolicyDownLevel downLevel : downLevels) {
+            if (rechargeAmount.compareTo(downLevel.getMinMoney()) >= 0 && rechargeAmount.compareTo(downLevel.getMaxMoney()) <= 0) {
+                return NumberUtil.multiply100(downLevel.getBackMoney()).longValue();
             }
         }
         return rechargeMoney;
     }
 
-    private static Tuple2<Integer, Integer> approximate(int molecular, int denominator) {
-        if (molecular % denominator == 0) {
-            int temp = molecular / denominator;
-            return Tuples.tuple(temp, temp);
-        }
-        int model = 2;
-        do {
-            if (molecular % model == 0 && denominator % model == 0) {
-                molecular = molecular / model;
-                denominator = denominator / model;
-                continue;
-            }
-            model++;
-        } while (model <= denominator / 2);
-        return Tuples.tuple(molecular, denominator);
-    }
-
-    /**
-     * 降档
-     */
-    public static long lowRechargeLevel(long rechargeMoney, String levelDownStr) {
-        if (StringUtils.isBlank(levelDownStr)) {
-            // 无需降档
-            return rechargeMoney;
-        }
-        String[] levelDownStrList = levelDownStr.split(",");
-        for (String levelDown : levelDownStrList) {
-            String[] tmp = levelDown.split("_");
-            long min = Long.parseLong(tmp[0]), max = Long.parseLong(tmp[1]), back = Long.parseLong(tmp[2]);
-            if (rechargeMoney >= min && rechargeMoney <= max) {
-                return back;
-            }
-        }
-        // 没有匹配金额规则,直接返回
-        return rechargeMoney;
+    private static GameBackPolicyVO.PolicyDownLevel transformDownLevel(String downLevel) {
+        String[] tmp = downLevel.split("_");
+        return GameBackPolicyVO.PolicyDownLevel.builder()
+                .minMoney(NumberUtil.divide100(new BigDecimal(Long.parseLong(tmp[0]))))
+                .maxMoney(NumberUtil.divide100(new BigDecimal(Long.parseLong(tmp[1]))))
+                .backMoney(NumberUtil.divide100(new BigDecimal(Long.parseLong(tmp[2]))))
+                .build();
     }
 
     public interface IBackPolicyCheck {
@@ -332,5 +452,13 @@ public class BackPolicyUtil {
          * 获取用户的累充金额
          */
         Long totalRechargeAmount();
+
+        /**
+         * 单个用户已回传订单数(包含拆单的订单数)
+         * Tuple2<回传订单数、回传金额>
+         */
+        default Tuple2<Long, Long> backCountForUserWithSplitOrder(String userId) {
+            throw new RuntimeException("暂不支持!!");
+        }
     }
 }