소스 검색

Merge remote-tracking branch 'origin/package' into package

lth 1 년 전
부모
커밋
94507f01e4
23개의 변경된 파일998개의 추가작업 그리고 232개의 파일을 삭제
  1. 45 1
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/controller/BackPolicyController.java
  2. 7 3
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/controller/OceanengineLogController.java
  3. 7 3
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/controller/TencentLogController.java
  4. 7 3
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/controller/TencentMiniGameLogController.java
  5. 36 6
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/pojo/dto/GameBackPolicyDTO.java
  6. 30 2
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/pojo/entity/GameBackPolicy.java
  7. 4 0
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/pojo/entity/GameOceanengineOrderLog.java
  8. 4 0
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/pojo/entity/GameTencentMiniGameOrder.java
  9. 4 0
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/pojo/entity/GameTencentOrder.java
  10. 11 3
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/pojo/enums/BackUnitEnum.java
  11. 47 3
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/pojo/vo/GameBackPolicyVO.java
  12. 1 1
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/rpc/impl/TencentMiniGameBackRpcImpl.java
  13. 1 1
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/rpc/impl/TencentUserActionBackRpcImpl.java
  14. 1 1
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/rpc/impl/TtMiniGameBackRpcImpl.java
  15. 2 2
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/IGameOceanengineOrderLogService.java
  16. 2 2
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/IGameTencentMiniGameOrderService.java
  17. 2 2
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/IGameTencentOrderService.java
  18. 58 2
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/impl/GameBackPolicyServiceImpl.java
  19. 175 29
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/impl/GameOceanengineOrderLogServiceImpl.java
  20. 173 37
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/impl/GameTencentMiniGameOrderServiceImpl.java
  21. 172 35
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/impl/GameTencentOrderServiceImpl.java
  22. 193 90
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/utils/BackPolicyUtil.java
  23. 16 6
      game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/component/DataPowerComponent.java

+ 45 - 1
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/controller/BackPolicyController.java

@@ -10,10 +10,12 @@ import com.zanxiang.module.util.exception.BaseException;
 import com.zanxiang.module.util.pojo.ResultVO;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
+import org.apache.commons.collections4.CollectionUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
+import java.math.BigDecimal;
 import java.util.List;
 
 @RestController
@@ -64,7 +66,7 @@ public class BackPolicyController {
     private void checkDTO(GameBackPolicyDTO dto) {
         BackUnitEnum backUnit = BackUnitEnum.getByValue(dto.getBackUnit());
         if (backUnit == null) {
-            dto.setBackUnit(BackUnitEnum.UNIT_ONCE.getValue());
+            throw new BaseException("错误的回传单位:" + dto.getBackUnit());
         }
         if (dto.getFirstMinMoney().compareTo(dto.getFirstMaxMoney()) >= 0) {
             throw new BaseException("首充的大额金额必须大于小额金额");
@@ -86,5 +88,47 @@ public class BackPolicyController {
                 throw new BaseException("首充的大额金额必须大于小额金额");
             }
         }
+        checkDownLevel(dto.getFirstDownLevel());
+        checkDownLevel(dto.getRechargeDownLevel());
+        checkDownLevel(dto.getMarkUpDownLevel());
+        if (dto.getFirstBackCountOfUser() != null && dto.getFirstBackCountOfUser() < 1) {
+            throw new BaseException("单用户最大回传次数不能小于 1");
+        }
+        if (dto.getRechargeBackCountOfUser() != null && dto.getRechargeBackCountOfUser() < 1) {
+            throw new BaseException("单用户最大回传次数不能小于 1");
+        }
+        if (dto.getMarkUpBackCountOfUser() != null && dto.getMarkUpBackCountOfUser() < 1) {
+            throw new BaseException("单用户最大回传次数不能小于 1");
+        }
+    }
+
+    private void checkDownLevel(List<GameBackPolicyVO.PolicyDownLevel> downLevelList) {
+        if (CollectionUtils.isEmpty(downLevelList)) {
+            return;
+        }
+        downLevelList.sort((val1, val2) -> val1.getMinMoney().compareTo(val2.getMinMoney()));
+        BigDecimal compareMoney = null;
+        for (GameBackPolicyVO.PolicyDownLevel downLevel : downLevelList) {
+            if (downLevel.getMinMoney() == null
+                    || downLevel.getMaxMoney() == null
+                    || downLevel.getBackMoney() == null) {
+                throw new BaseException("降档策略校验失败:金额不能为空");
+            }
+            if (downLevel.getMinMoney().compareTo(BigDecimal.ZERO) <= 0
+                    || downLevel.getMaxMoney().compareTo(BigDecimal.ZERO) <= 0
+                    || downLevel.getBackMoney().compareTo(BigDecimal.ZERO) <= 0) {
+                throw new BaseException("降档策略校验失败:金额必须大于 0");
+            }
+            if (downLevel.getMinMoney().compareTo(downLevel.getMaxMoney()) > 0) {
+                throw new BaseException("降档策略校验失败:最小金额(" + downLevel.getMinMoney() + ")> 最大金额(" + downLevel.getMaxMoney() + ")");
+            }
+            if (compareMoney == null) {
+                compareMoney = downLevel.getMaxMoney();
+            } else {
+                if (compareMoney.compareTo(downLevel.getMinMoney()) >= 0) {
+                    throw new BaseException("降档策略校验失败:金额区间内不能有交集!!!");
+                }
+            }
+        }
     }
 }

+ 7 - 3
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/controller/OceanengineLogController.java

@@ -8,6 +8,7 @@ import com.zanxiang.game.back.serve.pojo.vo.GameOceanengineOrderLogVO;
 import com.zanxiang.game.back.serve.pojo.vo.GameOceanengineUserLogVO;
 import com.zanxiang.game.back.serve.service.IGameOceanengineOrderLogService;
 import com.zanxiang.game.back.serve.service.IGameOceanengineUserLogService;
+import com.zanxiang.module.util.exception.BaseException;
 import com.zanxiang.module.util.pojo.ResultVO;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
@@ -37,10 +38,13 @@ public class OceanengineLogController {
     }
 
     @PreAuthorize(permissionKey = "gameBack:oceanengine:orderReport")
-    @PostMapping("/orderReport/{ids}")
+    @PostMapping("/orderReport/{ids}/{backMoney}")
     @ApiOperation(value = "头条订单手动上报")
-    public ResultVO<Boolean> oceanengineOrderReport(@PathVariable("ids") List<Long> ids) {
-        return ResultVO.ok(oceanengineOrderLogService.oceanengineOrderReport(ids));
+    public ResultVO<Boolean> oceanengineOrderReport(@PathVariable("ids") List<Long> ids, @PathVariable("backMoney") Long backMoney) {
+        if (backMoney < 1) {
+            throw new BaseException("回传金额错误!");
+        }
+        return ResultVO.ok(oceanengineOrderLogService.oceanengineOrderReport(ids, backMoney));
     }
 
     @PreAuthorize(permissionKey = "gameBack:oceanengine:userLogs")

+ 7 - 3
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/controller/TencentLogController.java

@@ -8,6 +8,7 @@ import com.zanxiang.game.back.serve.pojo.vo.GameTencentOrderVO;
 import com.zanxiang.game.back.serve.pojo.vo.GameTencentUserVO;
 import com.zanxiang.game.back.serve.service.IGameTencentOrderService;
 import com.zanxiang.game.back.serve.service.IGameTencentUserService;
+import com.zanxiang.module.util.exception.BaseException;
 import com.zanxiang.module.util.pojo.ResultVO;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
@@ -37,10 +38,13 @@ public class TencentLogController {
     }
 
     @PreAuthorize(permissionKey = "gameBack:tencent:orderReport")
-    @PostMapping("/orderReport/{ids}")
+    @PostMapping("/orderReport/{ids}/{backMoney}")
     @ApiOperation(value = "腾讯订单手动上报")
-    public ResultVO<Boolean> tencentOrderReport(@PathVariable("ids") List<Long> ids) {
-        return ResultVO.ok(tencentOrderService.tencentOrderReport(ids));
+    public ResultVO<Boolean> tencentOrderReport(@PathVariable("ids") List<Long> ids, @PathVariable("backMoney") Long backMoney) {
+        if(backMoney < 1) {
+            throw new BaseException("回传金额错误!");
+        }
+        return ResultVO.ok(tencentOrderService.tencentOrderReport(ids, backMoney));
     }
 
     @PreAuthorize(permissionKey = "gameBack:tencent:userLogs")

+ 7 - 3
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/controller/TencentMiniGameLogController.java

@@ -8,6 +8,7 @@ import com.zanxiang.game.back.serve.pojo.vo.GameTencentMiniGameOrderVO;
 import com.zanxiang.game.back.serve.pojo.vo.GameTencentMiniGameUserVO;
 import com.zanxiang.game.back.serve.service.IGameTencentMiniGameOrderService;
 import com.zanxiang.game.back.serve.service.IGameTencentMiniGameUserService;
+import com.zanxiang.module.util.exception.BaseException;
 import com.zanxiang.module.util.pojo.ResultVO;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
@@ -37,10 +38,13 @@ public class TencentMiniGameLogController {
     }
 
     @PreAuthorize(permissionKey = "gameBack:tencentMiniGame:orderReport")
-    @PostMapping("/orderReport/{ids}")
+    @PostMapping("/orderReport/{ids}/{backMoney}")
     @ApiOperation(value = "腾讯订单手动上报")
-    public ResultVO<Boolean> tencentOrderReport(@PathVariable("ids") List<Long> ids) {
-        return ResultVO.ok(gameTencentMiniGameOrderService.doReport(ids));
+    public ResultVO<Boolean> tencentOrderReport(@PathVariable("ids") List<Long> ids, @PathVariable("backMoney") Long backMoney) {
+        if (backMoney < 1) {
+            throw new BaseException("回传金额错误!");
+        }
+        return ResultVO.ok(gameTencentMiniGameOrderService.doReport(ids, backMoney));
     }
 
     @PreAuthorize(permissionKey = "gameBack:tencentMiniGame:userLogs")

+ 36 - 6
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/pojo/dto/GameBackPolicyDTO.java

@@ -3,6 +3,7 @@ package com.zanxiang.game.back.serve.pojo.dto;
 import com.baomidou.mybatisplus.annotation.IdType;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
+import com.zanxiang.game.back.serve.pojo.vo.GameBackPolicyVO;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.AllArgsConstructor;
 import lombok.Builder;
@@ -14,6 +15,7 @@ import javax.validation.constraints.NotNull;
 import java.io.Serializable;
 import java.math.BigDecimal;
 import java.time.LocalDateTime;
+import java.util.List;
 
 /**
  * <p>
@@ -94,6 +96,17 @@ public class GameBackPolicyDTO implements Serializable {
     @ApiModelProperty("首充-其它金额回传概率/比例")
     private String firstOtherMoneyRate;
 
+    /**
+     * 首充-其它金额回传概率/比例
+     */
+    @ApiModelProperty("首充-降档规则")
+    private List<GameBackPolicyVO.PolicyDownLevel> firstDownLevel;
+    /**
+     * 首充-按用户订单数卡单
+     */
+    @ApiModelProperty("首充-按用户订单数卡单")
+    private Integer firstBackCountOfUser;
+
     /**
      * 次单-小额判定金额(小于等于)
      */
@@ -150,15 +163,20 @@ public class GameBackPolicyDTO implements Serializable {
     @ApiModelProperty("次单-其它金额回传概率/比例")
     private String rechargeOtherMoneyRate;
 
+    @ApiModelProperty("注册充值回传的最大间隔时间(超时不回传)")
+    private Long regPayIntervalTime;
+
     /**
-     * 降档级别
+     * 首充-其它金额回传概率/比例
      */
-    @NotNull
-    @ApiModelProperty("降档级别")
-    private Integer levelDown;
+    @ApiModelProperty("次单-降档规则")
+    private List<GameBackPolicyVO.PolicyDownLevel> rechargeDownLevel;
 
-    @ApiModelProperty("注册充值回传的最大间隔时间(超时不回传)")
-    private Long regPayIntervalTime;
+    /**
+     * 次单-按用户订单数卡单
+     */
+    @ApiModelProperty("次单-按用户订单数卡单")
+    private Integer rechargeBackCountOfUser;
 
     /**
      * 是否补单
@@ -214,5 +232,17 @@ public class GameBackPolicyDTO implements Serializable {
     @ApiModelProperty("补单-其它金额回传概率/比例")
     private String markUpOrderOtherMoneyRate;
 
+    /**
+     * 首充-其它金额回传概率/比例
+     */
+    @ApiModelProperty("补单-降档规则")
+    private List<GameBackPolicyVO.PolicyDownLevel> markUpDownLevel;
+
+    /**
+     * 补单-按用户订单数卡单
+     */
+    @ApiModelProperty("补单-按用户订单数卡单")
+    private Integer markUpBackCountOfUser;
+
 
 }

+ 30 - 2
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/pojo/entity/GameBackPolicy.java

@@ -7,7 +7,10 @@ import com.baomidou.mybatisplus.annotation.TableName;
 import java.io.Serializable;
 import java.math.BigDecimal;
 import java.time.LocalDateTime;
+import java.util.List;
 
+import com.zanxiang.game.back.serve.pojo.vo.GameBackPolicyVO;
+import io.swagger.annotations.ApiModelProperty;
 import lombok.*;
 import lombok.experimental.Accessors;
 
@@ -77,6 +80,16 @@ public class GameBackPolicy implements Serializable {
      */
     private String firstOtherMoneyRate;
 
+    /**
+     * 首单-降档规则
+     */
+    private String firstDownLevel;
+
+    /**
+     * 首充-按用户订单数卡单
+     */
+    private Integer firstBackCountOfUser;
+
     /**
      * 次单/日-小额判定金额(小于等于)
      */
@@ -118,9 +131,14 @@ public class GameBackPolicy implements Serializable {
     private String rechargeOtherMoneyRate;
 
     /**
-     * 降档级别
+     * 次单-降档规则
      */
-    private Integer levelDown;
+    private String rechargeDownLevel;
+
+    /**
+     * 次单-按用户订单数卡单
+     */
+    private Integer rechargeBackCountOfUser;
 
     private LocalDateTime createTime;
 
@@ -181,5 +199,15 @@ public class GameBackPolicy implements Serializable {
      */
     private String markUpOrderOtherMoneyRate;
 
+    /**
+     * 补单-降档规则
+     */
+    private String markUpDownLevel;
+
+    /**
+     * 补单-按用户订单数卡单
+     */
+    private Integer markUpBackCountOfUser;
+
 
 }

+ 4 - 0
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/pojo/entity/GameOceanengineOrderLog.java

@@ -93,4 +93,8 @@ public class GameOceanengineOrderLog implements Serializable {
 
     private Boolean isFirstOrder;
 
+    private Long backMoney;
+
+    private String backMsg;
+
 }

+ 4 - 0
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/pojo/entity/GameTencentMiniGameOrder.java

@@ -106,4 +106,8 @@ public class GameTencentMiniGameOrder implements Serializable {
     private String roleName;
 
     private Boolean isFirstOrder;
+
+    private Long backMoney;
+
+    private String backMsg;
 }

+ 4 - 0
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/pojo/entity/GameTencentOrder.java

@@ -118,4 +118,8 @@ public class GameTencentOrder implements Serializable {
     private String roleName;
 
     private Boolean isFirstOrder;
+
+    private Long backMoney;
+
+    private String backMsg;
 }

+ 11 - 3
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/pojo/enums/BackUnitEnum.java

@@ -7,13 +7,21 @@ import java.util.Objects;
 @Getter
 public enum BackUnitEnum {
     /**
-     * 未回传
+     * 首单/次单
      */
     UNIT_ONCE(1),
     /**
-     * 回传成功
+     * 首日/次日
      */
-    UNIT_DAY(2);
+    UNIT_DAY(2),
+    /**
+     * 24小时、其它时间
+     */
+    UNIT_TIME_DAY(3),
+    /**
+     * 48、其它时间
+     */
+    UNIT_TIME_2DAY(4);
 
     private final Integer value;
 

+ 47 - 3
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/pojo/vo/GameBackPolicyVO.java

@@ -9,6 +9,7 @@ import lombok.NoArgsConstructor;
 import java.io.Serializable;
 import java.math.BigDecimal;
 import java.time.LocalDateTime;
+import java.util.List;
 
 /**
  * <p>
@@ -82,6 +83,18 @@ public class GameBackPolicyVO implements Serializable {
     @ApiModelProperty("首充-其它金额回传概率/比例")
     private String firstOtherMoneyRate;
 
+    /**
+     * 首充-降档规则
+     */
+    @ApiModelProperty("首充-降档规则")
+    private List<PolicyDownLevel> firstDownLevel;
+
+    /**
+     * 首充-按用户订单数卡单
+     */
+    @ApiModelProperty("首充-按用户订单数卡单")
+    private Integer firstBackCountOfUser;
+
     /**
      * 次单-小额判定金额(小于等于)
      */
@@ -131,10 +144,16 @@ public class GameBackPolicyVO implements Serializable {
     private String rechargeOtherMoneyRate;
 
     /**
-     * 降档级别
+     * 次单-降档规则
      */
-    @ApiModelProperty("降档级别")
-    private Integer levelDown;
+    @ApiModelProperty("次单-降档规则")
+    private List<PolicyDownLevel> rechargeDownLevel;
+
+    /**
+     * 次单-按用户订单数卡单
+     */
+    @ApiModelProperty("次单-按用户订单数卡单")
+    private Integer rechargeBackCountOfUser;
 
     private LocalDateTime createTime;
 
@@ -199,5 +218,30 @@ public class GameBackPolicyVO implements Serializable {
     @ApiModelProperty("补单-其它金额回传概率/比例")
     private String markUpOrderOtherMoneyRate;
 
+    /**
+     * 补单-降档规则
+     */
+    @ApiModelProperty("补单-降档规则")
+    private List<PolicyDownLevel> markUpDownLevel;
+
+    /**
+     * 补单-按用户订单数卡单
+     */
+    @ApiModelProperty("补单-按用户订单数卡单")
+    private Integer markUpBackCountOfUser;
+
+    @Data
+    @NoArgsConstructor
+    @AllArgsConstructor
+    @Builder
+    public static class PolicyDownLevel {
+
+        private BigDecimal minMoney;
+
+        private BigDecimal maxMoney;
+
+        private BigDecimal backMoney;
+    }
+
 
 }

+ 1 - 1
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/rpc/impl/TencentMiniGameBackRpcImpl.java

@@ -61,7 +61,7 @@ public class TencentMiniGameBackRpcImpl implements ITencentMiniGameBackRpc {
                 .isFirstOrder(isFirstOrder)
                 .build();
         gameTencentMiniGameOrderService.save(orderLog);
-        return ResultVO.ok(gameTencentMiniGameOrderService.orderBack(orderLog, false));
+        return ResultVO.ok(gameTencentMiniGameOrderService.orderBack(orderLog, false, null));
     }
 
     @Override

+ 1 - 1
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/rpc/impl/TencentUserActionBackRpcImpl.java

@@ -64,7 +64,7 @@ public class TencentUserActionBackRpcImpl implements ITencentUserActionBackRpc {
                 .isFirstOrder(isFirstOrder)
                 .build();
         gameTencentOrderService.save(gameTencentOrder);
-        return ResultVO.ok(gameTencentOrderService.orderBack(gameTencentOrder, false));
+        return ResultVO.ok(gameTencentOrderService.orderBack(gameTencentOrder, false, null));
     }
 
     @Override

+ 1 - 1
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/rpc/impl/TtMiniGameBackRpcImpl.java

@@ -83,6 +83,6 @@ public class TtMiniGameBackRpcImpl implements ITtMiniGameBackRpc {
         ) == null;
         orderLog.setIsFirstOrder(isFirstOrder);
         gameOceanengineOrderLogService.save(orderLog);
-        return ResultVO.ok(gameOceanengineOrderLogService.callback(orderLog, false));
+        return ResultVO.ok(gameOceanengineOrderLogService.callback(orderLog, false, null));
     }
 }

+ 2 - 2
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/IGameOceanengineOrderLogService.java

@@ -10,9 +10,9 @@ import java.util.List;
 
 public interface IGameOceanengineOrderLogService extends IService<GameOceanengineOrderLog> {
 
-    boolean callback(GameOceanengineOrderLog orderLog, boolean mustBack);
+    boolean callback(GameOceanengineOrderLog orderLog, boolean mustBack, Long backMoneyOfInput);
 
     IPage<GameOceanengineOrderLogVO> oceanengineOrderLogList(GameOceanengineOrderLogDTO dto);
 
-    boolean oceanengineOrderReport(List<Long> ids);
+    boolean oceanengineOrderReport(List<Long> ids, Long backMoney);
 }

+ 2 - 2
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/IGameTencentMiniGameOrderService.java

@@ -10,9 +10,9 @@ import java.util.List;
 
 public interface IGameTencentMiniGameOrderService extends IService<GameTencentMiniGameOrder> {
 
-    boolean orderBack(GameTencentMiniGameOrder orderLog, boolean mustBack);
+    boolean orderBack(GameTencentMiniGameOrder orderLog, boolean mustBack, Long backMoneyOfInput);
 
     IPage<GameTencentMiniGameOrderVO> listOfPage(GameTencentMiniGameOrderDTO dto);
 
-    boolean doReport(List<Long> orderLogIds);
+    boolean doReport(List<Long> orderLogIds, Long backMoney);
 }

+ 2 - 2
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/IGameTencentOrderService.java

@@ -19,9 +19,9 @@ import java.util.List;
  */
 public interface IGameTencentOrderService extends IService<GameTencentOrder> {
 
-    boolean orderBack(GameTencentOrder tencentOrder, boolean mustBack);
+    boolean orderBack(GameTencentOrder tencentOrder, boolean mustBack, Long backMoneyOfInput);
 
     IPage<GameTencentOrderVO> tencentOrderLogList(GameTencentOrderDTO dto);
 
-    boolean tencentOrderReport(List<Long> ids);
+    boolean tencentOrderReport(List<Long> ids, Long backMoney);
 }

+ 58 - 2
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/impl/GameBackPolicyServiceImpl.java

@@ -21,6 +21,7 @@ import com.zanxiang.module.util.NumberUtil;
 import com.zanxiang.module.util.bean.BeanUtil;
 import com.zanxiang.module.util.exception.BaseException;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.dubbo.config.annotation.DubboReference;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -28,7 +29,11 @@ import org.springframework.stereotype.Service;
 
 import java.math.BigDecimal;
 import java.time.LocalDateTime;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
 import java.util.List;
+import java.util.function.Function;
 import java.util.stream.Collectors;
 
 /**
@@ -87,6 +92,8 @@ public class GameBackPolicyServiceImpl extends ServiceImpl<GameBackPolicyMapper,
                 .firstMaxMoneyRate(dto.getFirstMaxMoneyRate())
                 .firstOtherMoneyType(dto.getFirstOtherMoneyType())
                 .firstOtherMoneyRate(dto.getFirstOtherMoneyRate())
+                .firstDownLevel(downLevelToString(dto.getFirstDownLevel()))
+                .firstBackCountOfUser(dto.getFirstBackCountOfUser())
                 .rechargeMinMoney(NumberUtil.multiply100(dto.getRechargeMinMoney()).longValue())
                 .rechargeMinMoneyType(dto.getRechargeMinMoneyType())
                 .rechargeMinMoneyRate(dto.getRechargeMinMoneyRate())
@@ -95,7 +102,8 @@ public class GameBackPolicyServiceImpl extends ServiceImpl<GameBackPolicyMapper,
                 .rechargeMaxMoneyRate(dto.getRechargeMaxMoneyRate())
                 .rechargeOtherMoneyType(dto.getRechargeOtherMoneyType())
                 .rechargeOtherMoneyRate(dto.getRechargeOtherMoneyRate())
-                .levelDown(dto.getLevelDown())
+                .rechargeDownLevel(downLevelToString(dto.getRechargeDownLevel()))
+                .rechargeBackCountOfUser(dto.getRechargeBackCountOfUser())
                 .createBy(SecurityUtil.getUserId())
                 .createTime(LocalDateTime.now())
                 .regPayIntervalTime(dto.getRegPayIntervalTime())
@@ -109,6 +117,8 @@ public class GameBackPolicyServiceImpl extends ServiceImpl<GameBackPolicyMapper,
                 .markUpOrderMaxMoneyRate(dto.getMarkUpOrderMaxMoneyRate())
                 .markUpOrderOtherMoneyType(dto.getFirstOtherMoneyType())
                 .markUpOrderOtherMoneyRate(dto.getMarkUpOrderMaxMoneyRate())
+                .markUpDownLevel(downLevelToString(dto.getMarkUpDownLevel()))
+                .markUpBackCountOfUser(dto.getMarkUpBackCountOfUser())
                 .build();
         return gameBackPolicyService.save(backPolicy);
     }
@@ -130,6 +140,8 @@ public class GameBackPolicyServiceImpl extends ServiceImpl<GameBackPolicyMapper,
                 .firstMaxMoneyRate(dto.getFirstMaxMoneyRate())
                 .firstOtherMoneyType(dto.getFirstOtherMoneyType())
                 .firstOtherMoneyRate(dto.getFirstOtherMoneyRate())
+                .firstDownLevel(downLevelToString(dto.getFirstDownLevel()))
+                .firstBackCountOfUser(dto.getFirstBackCountOfUser())
                 .rechargeMinMoney(NumberUtil.multiply100(dto.getRechargeMinMoney()).longValue())
                 .rechargeMinMoneyType(dto.getRechargeMinMoneyType())
                 .rechargeMinMoneyRate(dto.getRechargeMinMoneyRate())
@@ -138,7 +150,8 @@ public class GameBackPolicyServiceImpl extends ServiceImpl<GameBackPolicyMapper,
                 .rechargeMaxMoneyRate(dto.getRechargeMaxMoneyRate())
                 .rechargeOtherMoneyType(dto.getRechargeOtherMoneyType())
                 .rechargeOtherMoneyRate(dto.getRechargeOtherMoneyRate())
-                .levelDown(dto.getLevelDown())
+                .rechargeDownLevel(downLevelToString(dto.getRechargeDownLevel()))
+                .rechargeBackCountOfUser(dto.getRechargeBackCountOfUser())
                 .regPayIntervalTime(dto.getRegPayIntervalTime())
                 .createBy(old.getCreateBy())
                 .createTime(old.getCreateTime())
@@ -154,6 +167,8 @@ public class GameBackPolicyServiceImpl extends ServiceImpl<GameBackPolicyMapper,
                 .markUpOrderMaxMoneyRate(dto.getMarkUpOrderMaxMoneyRate())
                 .markUpOrderOtherMoneyType(dto.getFirstOtherMoneyType())
                 .markUpOrderOtherMoneyRate(dto.getMarkUpOrderMaxMoneyRate())
+                .markUpDownLevel(downLevelToString(dto.getMarkUpDownLevel()))
+                .markUpBackCountOfUser(dto.getMarkUpBackCountOfUser())
                 .build();
 
         return gameBackPolicyService.updateById(backPolicy);
@@ -187,6 +202,24 @@ public class GameBackPolicyServiceImpl extends ServiceImpl<GameBackPolicyMapper,
         if (gameBackPolicy.getMarkUpOrderMaxMoney() != null) {
             vo.setMarkUpOrderMaxMoney(NumberUtil.divide100(new BigDecimal(gameBackPolicy.getMarkUpOrderMaxMoney())));
         }
+        if (StringUtils.isNotBlank(gameBackPolicy.getFirstDownLevel())) {
+            vo.setFirstDownLevel(Arrays.stream(gameBackPolicy.getFirstDownLevel().split(","))
+                    .map(this::transformDownLevel)
+                    .collect(Collectors.toList())
+            );
+        }
+        if (StringUtils.isNotBlank(gameBackPolicy.getRechargeDownLevel())) {
+            vo.setRechargeDownLevel(Arrays.stream(gameBackPolicy.getRechargeDownLevel().split(","))
+                    .map(this::transformDownLevel)
+                    .collect(Collectors.toList())
+            );
+        }
+        if (StringUtils.isNotBlank(gameBackPolicy.getMarkUpDownLevel())) {
+            vo.setMarkUpDownLevel(Arrays.stream(gameBackPolicy.getMarkUpDownLevel().split(","))
+                    .map(this::transformDownLevel)
+                    .collect(Collectors.toList())
+            );
+        }
         return vo;
     }
 
@@ -198,4 +231,27 @@ public class GameBackPolicyServiceImpl extends ServiceImpl<GameBackPolicyMapper,
         vo.setCreateName(sysUserRpc.getById(gameBackPolicy.getCreateBy()).getData().getNickname());
         return vo;
     }
+
+    private 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();
+    }
+
+    private String downLevelToString(List<GameBackPolicyVO.PolicyDownLevel> downLevelList) {
+        if (CollectionUtils.isEmpty(downLevelList)) {
+            return null;
+        }
+        downLevelList.sort((val1, val2) -> val1.getMinMoney().compareTo(val2.getMinMoney()));
+        return StringUtils.join(downLevelList.stream().map(this::downLevelToString).collect(Collectors.toList()), ",");
+    }
+
+    private String downLevelToString(GameBackPolicyVO.PolicyDownLevel downLevel) {
+        return NumberUtil.multiply100(downLevel.getMinMoney()).longValue() + "_" +
+                NumberUtil.multiply100(downLevel.getMaxMoney()).longValue() + "_" +
+                NumberUtil.multiply100(downLevel.getBackMoney()).longValue();
+    }
 }

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

@@ -5,6 +5,8 @@ import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.github.sd4324530.jtuple.Tuple3;
+import com.github.sd4324530.jtuple.Tuples;
 import com.zanxiang.game.back.base.pojo.enums.OrderStatusEnum;
 import com.zanxiang.game.back.serve.dao.mapper.GameOceanengineOrderLogMapper;
 import com.zanxiang.game.back.serve.oceanengine.MiniGameCallback;
@@ -12,6 +14,7 @@ import com.zanxiang.game.back.serve.oceanengine.OceanengineCallbackException;
 import com.zanxiang.game.back.serve.pojo.dto.GameOceanengineOrderLogDTO;
 import com.zanxiang.game.back.serve.pojo.entity.*;
 import com.zanxiang.game.back.serve.pojo.enums.BackStatusEnum;
+import com.zanxiang.game.back.serve.pojo.enums.BackUnitEnum;
 import com.zanxiang.game.back.serve.pojo.vo.GameOceanengineOrderLogVO;
 import com.zanxiang.game.back.serve.service.IGameBackPolicyService;
 import com.zanxiang.game.back.serve.service.IGameOceanengineBackLogService;
@@ -58,50 +61,191 @@ public class GameOceanengineOrderLogServiceImpl extends ServiceImpl<GameOceaneng
 
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public boolean callback(GameOceanengineOrderLog orderLog, boolean mustBack) {
+    public boolean callback(GameOceanengineOrderLog orderLog, boolean mustBack, Long backMoneyOfInput) {
         boolean doBack = false;
+        Long backMoney;
+        String backMsg;
         if (mustBack) {
             doBack = true;
+            backMoney = backMoneyOfInput;
+            backMsg = "手动触发的回传";
         } else {
             if (!Objects.equals(orderLog.getOrderStatus(), OrderStatusEnum.SUCCESS_PAY.getValue())) {
                 // 头条只要回传支付订单
-                return false;
+                return true;
             }
-            if (orderLog.getBackPolicyId() == null) {
-                // 没有回传策略,则直接全量回传
-                doBack = true;
-            } else {
-                GameBackPolicy gameBackPolicy = gameBackPolicyService.getById(orderLog.getBackPolicyId());
-                doBack = BackPolicyUtil.backOrder(orderLog.getOrderNo(), gameBackPolicy, orderLog.getAmount(),
-                        orderLog.getIsFirstOrder(),
-                        orderLog.getPayTime(), orderLog.getRegTime(),
-                        (backUnit, isFirstOrder, firstDay, markUpTime) -> Long.valueOf(list(new LambdaQueryWrapper<GameOceanengineOrderLog>()
+            GameBackPolicy gameBackPolicy = gameBackPolicyService.getById(orderLog.getBackPolicyId());
+            Tuple3<Boolean, Long, String> backInfo = BackPolicyUtil.backOrder(orderLog.getOrderNo(), gameBackPolicy, orderLog.getAmount(),
+                    orderLog.getIsFirstOrder(),
+                    orderLog.getPayTime(), orderLog.getRegTime(),
+                    orderLog.getOpenId(),
+                    new BackPolicyUtil.IBackPolicyCheck() {
+                        @Override
+                        public long backCountForFixedRate(int numberOfRound, BackUnitEnum backUnit, Boolean firstPolicy) {
+                            numberOfRound = numberOfRound - 1;
+                            if (backUnit == BackUnitEnum.UNIT_ONCE) {
+                                return list(new LambdaQueryWrapper<GameOceanengineOrderLog>()
                                         .eq(GameOceanengineOrderLog::getGameId, orderLog.getGameId())
                                         .eq(GameOceanengineOrderLog::getAppId, orderLog.getAppId())
                                         .eq(GameOceanengineOrderLog::getAccountId, orderLog.getAccountId())
                                         .eq(GameOceanengineOrderLog::getBackPolicyId, gameBackPolicy.getId())
                                         .eq(GameOceanengineOrderLog::getOrderStatus, OrderStatusEnum.SUCCESS_PAY.getValue())
-                                        .eq(isFirstOrder != null, GameOceanengineOrderLog::getIsFirstOrder, isFirstOrder)
-                                        .apply(firstDay != null && firstDay, "date(reg_time) = date(pay_time)")
-                                        .apply(firstDay != null && !firstDay, "date(reg_time) != date(pay_time)")
-                                        .apply(markUpTime != null, "TIMESTAMPDIFF(MINUTE, reg_time, pay_time) > {0}", markUpTime)
+                                        .eq(GameOceanengineOrderLog::getIsFirstOrder, firstPolicy)
                                         .ne(GameOceanengineOrderLog::getOrderNo, orderLog.getOrderNo())
                                         .orderByDesc(GameOceanengineOrderLog::getCreateTime)
-                                        .last("limit " + backUnit)
-                                ).stream().filter(log -> log.getBackStatus().equals(BackStatusEnum.SUCCESS.getBackStatus())).count()
-                        ).intValue());
-                orderLog.setAmount(BackPolicyUtil.lowRechargeLevel(orderLog.getAmount(), gameBackPolicy.getLevelDown()));
-            }
+                                        .last("limit " + numberOfRound)
+                                ).stream().filter(log -> log.getBackStatus().equals(BackStatusEnum.SUCCESS.getBackStatus())).count();
+                            } else if (backUnit == BackUnitEnum.UNIT_DAY) {
+                                return list(new LambdaQueryWrapper<GameOceanengineOrderLog>()
+                                        .eq(GameOceanengineOrderLog::getGameId, orderLog.getGameId())
+                                        .eq(GameOceanengineOrderLog::getAppId, orderLog.getAppId())
+                                        .eq(GameOceanengineOrderLog::getAccountId, orderLog.getAccountId())
+                                        .eq(GameOceanengineOrderLog::getBackPolicyId, gameBackPolicy.getId())
+                                        .eq(GameOceanengineOrderLog::getOrderStatus, OrderStatusEnum.SUCCESS_PAY.getValue())
+                                        .apply(firstPolicy, "date(reg_time) = date(pay_time)")
+                                        .apply(!firstPolicy, "date(reg_time) != date(pay_time)")
+                                        .ne(GameOceanengineOrderLog::getOrderNo, orderLog.getOrderNo())
+                                        .orderByDesc(GameOceanengineOrderLog::getCreateTime)
+                                        .last("limit " + numberOfRound)
+                                ).stream().filter(log -> log.getBackStatus().equals(BackStatusEnum.SUCCESS.getBackStatus())).count();
+                            } else if (backUnit == BackUnitEnum.UNIT_TIME_DAY) {
+                                return list(new LambdaQueryWrapper<GameOceanengineOrderLog>()
+                                        .eq(GameOceanengineOrderLog::getGameId, orderLog.getGameId())
+                                        .eq(GameOceanengineOrderLog::getAppId, orderLog.getAppId())
+                                        .eq(GameOceanengineOrderLog::getAccountId, orderLog.getAccountId())
+                                        .eq(GameOceanengineOrderLog::getBackPolicyId, gameBackPolicy.getId())
+                                        .eq(GameOceanengineOrderLog::getOrderStatus, OrderStatusEnum.SUCCESS_PAY.getValue())
+                                        .apply(firstPolicy, "TIMESTAMPDIFF(HOUR, reg_time, pay_time) < 24")
+                                        .apply(!firstPolicy, "TIMESTAMPDIFF(HOUR, reg_time, pay_time) >= 24")
+                                        .ne(GameOceanengineOrderLog::getOrderNo, orderLog.getOrderNo())
+                                        .orderByDesc(GameOceanengineOrderLog::getCreateTime)
+                                        .last("limit " + numberOfRound)
+                                ).stream().filter(log -> log.getBackStatus().equals(BackStatusEnum.SUCCESS.getBackStatus())).count();
+                            } else if (backUnit == BackUnitEnum.UNIT_TIME_2DAY) {
+                                return list(new LambdaQueryWrapper<GameOceanengineOrderLog>()
+                                        .eq(GameOceanengineOrderLog::getGameId, orderLog.getGameId())
+                                        .eq(GameOceanengineOrderLog::getAppId, orderLog.getAppId())
+                                        .eq(GameOceanengineOrderLog::getAccountId, orderLog.getAccountId())
+                                        .eq(GameOceanengineOrderLog::getBackPolicyId, gameBackPolicy.getId())
+                                        .eq(GameOceanengineOrderLog::getOrderStatus, OrderStatusEnum.SUCCESS_PAY.getValue())
+                                        .apply(firstPolicy, "TIMESTAMPDIFF(HOUR, reg_time, pay_time) < 48")
+                                        .apply(!firstPolicy, "TIMESTAMPDIFF(HOUR, reg_time, pay_time) >= 48")
+                                        .ne(GameOceanengineOrderLog::getOrderNo, orderLog.getOrderNo())
+                                        .orderByDesc(GameOceanengineOrderLog::getCreateTime)
+                                        .last("limit " + numberOfRound)
+                                ).stream().filter(log -> log.getBackStatus().equals(BackStatusEnum.SUCCESS.getBackStatus())).count();
+                            } else {
+                                throw new RuntimeException("不支持的回传单位[" + backUnit.getValue() + "]");
+                            }
+                        }
+
+                        @Override
+                        public long backCountForUser(BackUnitEnum backUnit, String userId, Boolean firstPolicy) {
+                            if (backUnit == BackUnitEnum.UNIT_ONCE) {
+                                if (firstPolicy) {
+                                    // 首单直接返回 0,必定回传
+                                    return 0;
+                                }
+                                return count(new LambdaQueryWrapper<GameOceanengineOrderLog>()
+                                        .eq(GameOceanengineOrderLog::getGameId, orderLog.getGameId())
+                                        .eq(GameOceanengineOrderLog::getAppId, orderLog.getAppId())
+                                        .eq(GameOceanengineOrderLog::getAccountId, orderLog.getAccountId())
+                                        .eq(GameOceanengineOrderLog::getBackPolicyId, gameBackPolicy.getId())
+                                        .eq(GameOceanengineOrderLog::getOrderStatus, OrderStatusEnum.SUCCESS_PAY.getValue())
+                                        .eq(GameOceanengineOrderLog::getBackStatus, BackStatusEnum.SUCCESS.getBackStatus())
+                                        .eq(GameOceanengineOrderLog::getOpenId, userId)
+                                        .eq(GameOceanengineOrderLog::getIsFirstOrder, firstPolicy)
+                                        .ne(GameOceanengineOrderLog::getOrderNo, orderLog.getOrderNo())
+                                );
+                            } else if (backUnit == BackUnitEnum.UNIT_DAY) {
+                                return count(new LambdaQueryWrapper<GameOceanengineOrderLog>()
+                                        .eq(GameOceanengineOrderLog::getGameId, orderLog.getGameId())
+                                        .eq(GameOceanengineOrderLog::getAppId, orderLog.getAppId())
+                                        .eq(GameOceanengineOrderLog::getAccountId, orderLog.getAccountId())
+                                        .eq(GameOceanengineOrderLog::getBackPolicyId, gameBackPolicy.getId())
+                                        .eq(GameOceanengineOrderLog::getOrderStatus, OrderStatusEnum.SUCCESS_PAY.getValue())
+                                        .eq(GameOceanengineOrderLog::getBackStatus, BackStatusEnum.SUCCESS.getBackStatus())
+                                        .eq(GameOceanengineOrderLog::getOpenId, userId)
+                                        .apply(firstPolicy, "date(reg_time) = date(pay_time)")
+                                        .apply(!firstPolicy, "date(reg_time) != date(pay_time)")
+                                        .ne(GameOceanengineOrderLog::getOrderNo, orderLog.getOrderNo())
+                                );
+                            } else if (backUnit == BackUnitEnum.UNIT_TIME_DAY) {
+                                return count(new LambdaQueryWrapper<GameOceanengineOrderLog>()
+                                        .eq(GameOceanengineOrderLog::getGameId, orderLog.getGameId())
+                                        .eq(GameOceanengineOrderLog::getAppId, orderLog.getAppId())
+                                        .eq(GameOceanengineOrderLog::getAccountId, orderLog.getAccountId())
+                                        .eq(GameOceanengineOrderLog::getBackPolicyId, gameBackPolicy.getId())
+                                        .eq(GameOceanengineOrderLog::getOrderStatus, OrderStatusEnum.SUCCESS_PAY.getValue())
+                                        .eq(GameOceanengineOrderLog::getBackStatus, BackStatusEnum.SUCCESS.getBackStatus())
+                                        .eq(GameOceanengineOrderLog::getOpenId, userId)
+                                        .apply(firstPolicy, "TIMESTAMPDIFF(HOUR, reg_time, pay_time) < 24")
+                                        .apply(!firstPolicy, "TIMESTAMPDIFF(HOUR, reg_time, pay_time) >= 24")
+                                        .ne(GameOceanengineOrderLog::getOrderNo, orderLog.getOrderNo())
+                                );
+                            } else if (backUnit == BackUnitEnum.UNIT_TIME_2DAY) {
+                                return count(new LambdaQueryWrapper<GameOceanengineOrderLog>()
+                                        .eq(GameOceanengineOrderLog::getGameId, orderLog.getGameId())
+                                        .eq(GameOceanengineOrderLog::getAppId, orderLog.getAppId())
+                                        .eq(GameOceanengineOrderLog::getAccountId, orderLog.getAccountId())
+                                        .eq(GameOceanengineOrderLog::getBackPolicyId, gameBackPolicy.getId())
+                                        .eq(GameOceanengineOrderLog::getOrderStatus, OrderStatusEnum.SUCCESS_PAY.getValue())
+                                        .eq(GameOceanengineOrderLog::getBackStatus, BackStatusEnum.SUCCESS.getBackStatus())
+                                        .eq(GameOceanengineOrderLog::getOpenId, userId)
+                                        .apply(firstPolicy, "TIMESTAMPDIFF(HOUR, reg_time, pay_time) < 48")
+                                        .apply(!firstPolicy, "TIMESTAMPDIFF(HOUR, reg_time, pay_time) >= 48")
+                                        .ne(GameOceanengineOrderLog::getOrderNo, orderLog.getOrderNo())
+                                );
+                            } else {
+                                throw new RuntimeException("不支持的回传单位[" + backUnit.getValue() + "]");
+                            }
+                        }
+
+                        @Override
+                        public long markUpOfFixedRate(int numberOfRound, Long markUpTime) {
+                            numberOfRound = numberOfRound - 1;
+                            return list(new LambdaQueryWrapper<GameOceanengineOrderLog>()
+                                    .eq(GameOceanengineOrderLog::getGameId, orderLog.getGameId())
+                                    .eq(GameOceanengineOrderLog::getAppId, orderLog.getAppId())
+                                    .eq(GameOceanengineOrderLog::getAccountId, orderLog.getAccountId())
+                                    .eq(GameOceanengineOrderLog::getBackPolicyId, gameBackPolicy.getId())
+                                    .eq(GameOceanengineOrderLog::getOrderStatus, OrderStatusEnum.SUCCESS_PAY.getValue())
+                                    .apply("TIMESTAMPDIFF(MINUTE, reg_time, pay_time) > {0}", markUpTime)
+                                    .ne(GameOceanengineOrderLog::getOrderNo, orderLog.getOrderNo())
+                                    .orderByDesc(GameOceanengineOrderLog::getCreateTime)
+                                    .last("limit " + numberOfRound)
+                            ).stream().filter(log -> log.getBackStatus().equals(BackStatusEnum.SUCCESS.getBackStatus())).count();
+                        }
+
+                        @Override
+                        public long markUpForUser(String userId, Long markUpTime) {
+                            return count(new LambdaQueryWrapper<GameOceanengineOrderLog>()
+                                    .eq(GameOceanengineOrderLog::getGameId, orderLog.getGameId())
+                                    .eq(GameOceanengineOrderLog::getAppId, orderLog.getAppId())
+                                    .eq(GameOceanengineOrderLog::getAccountId, orderLog.getAccountId())
+                                    .eq(GameOceanengineOrderLog::getBackPolicyId, gameBackPolicy.getId())
+                                    .eq(GameOceanengineOrderLog::getOrderStatus, OrderStatusEnum.SUCCESS_PAY.getValue())
+                                    .eq(GameOceanengineOrderLog::getBackStatus, BackStatusEnum.SUCCESS.getBackStatus())
+                                    .eq(GameOceanengineOrderLog::getOpenId, userId)
+                                    .apply("TIMESTAMPDIFF(MINUTE, reg_time, pay_time) > {0}", markUpTime)
+                                    .ne(GameOceanengineOrderLog::getOrderNo, orderLog.getOrderNo())
+                            );
+                        }
+                    });
+            doBack = backInfo.first;
+            backMoney = backInfo.second;
+            backMsg = backInfo.third;
         }
+        BackStatusEnum backStatus = BackStatusEnum.NO;
         if (doBack) {
-            BackStatusEnum backStatus = doCallback(orderLog);
-            update(new LambdaUpdateWrapper<GameOceanengineOrderLog>()
-                    .set(GameOceanengineOrderLog::getBackStatus, backStatus.getBackStatus())
-                    .eq(GameOceanengineOrderLog::getId, orderLog.getId())
-            );
-            return true;
+            backStatus = doCallback(orderLog);
         }
-        return false;
+        return update(new LambdaUpdateWrapper<GameOceanengineOrderLog>()
+                .set(GameOceanengineOrderLog::getBackStatus, backStatus.getBackStatus())
+                .set(GameOceanengineOrderLog::getBackMoney, backMoney)
+                .set(GameOceanengineOrderLog::getBackMsg, backMsg)
+                .eq(GameOceanengineOrderLog::getId, orderLog.getId())
+        );
     }
 
     @Override
@@ -159,8 +303,10 @@ public class GameOceanengineOrderLogServiceImpl extends ServiceImpl<GameOceaneng
     }
 
     @Override
-    public boolean oceanengineOrderReport(List<Long> ids) {
-        listByIds(ids).forEach(orderLog -> callback(orderLog, true));
+    public boolean oceanengineOrderReport(List<Long> ids, Long backMoney) {
+        listByIds(ids).stream()
+                .filter(order -> !Objects.equals(order.getBackStatus(), BackStatusEnum.SUCCESS.getBackStatus()))
+                .forEach(orderLog -> callback(orderLog, true, backMoney));
         return true;
     }
 

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

@@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.github.sd4324530.jtuple.Tuple3;
 import com.zanxiang.advertising.tencent.base.AdvertisingTencentServer;
 import com.zanxiang.advertising.tencent.base.rpc.IUserActionSetRpc;
 import com.zanxiang.erp.base.ErpServer;
@@ -13,9 +14,9 @@ import com.zanxiang.game.back.base.pojo.enums.OrderStatusEnum;
 import com.zanxiang.game.back.serve.dao.mapper.GameTencentMiniGameOrderMapper;
 import com.zanxiang.game.back.serve.pojo.dto.GameTencentMiniGameOrderDTO;
 import com.zanxiang.game.back.serve.pojo.entity.GameBackPolicy;
-import com.zanxiang.game.back.serve.pojo.entity.GameOceanengineOrderLog;
 import com.zanxiang.game.back.serve.pojo.entity.GameTencentMiniGameOrder;
 import com.zanxiang.game.back.serve.pojo.enums.BackStatusEnum;
+import com.zanxiang.game.back.serve.pojo.enums.BackUnitEnum;
 import com.zanxiang.game.back.serve.pojo.vo.GameTencentMiniGameOrderVO;
 import com.zanxiang.game.back.serve.service.IGameBackPolicyService;
 import com.zanxiang.game.back.serve.service.IGameTencentMiniGameBackLogService;
@@ -61,57 +62,196 @@ public class GameTencentMiniGameOrderServiceImpl extends ServiceImpl<GameTencent
 
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public boolean orderBack(GameTencentMiniGameOrder orderLog, boolean mustBack) {
+    public boolean orderBack(GameTencentMiniGameOrder orderLog, boolean mustBack, Long backMoneyOfInput) {
         if (StringUtils.isBlank(orderLog.getClickId())) {
             // 没有点击 id(之后做监测链接,从监测链接里面找)
             return false;
         }
         boolean doBack = false;
+        Long backMoney;
+        String backMsg;
         if (mustBack) {
             doBack = true;
+            backMoney = backMoneyOfInput;
+            backMsg = "手动触发的回传";
         } else {
             if (!Objects.equals(orderLog.getOrderStatus(), OrderStatusEnum.SUCCESS_PAY.getValue())) {
                 // 只要回传 支付行为
-                return false;
+                return true;
             }
-            if (orderLog.getBackPolicyId() == null) {
-                // 没有回传策略,则直接全量回传
-                doBack = true;
-            } else {
-                GameBackPolicy gameBackPolicy = gameBackPolicyService.getById(orderLog.getBackPolicyId());
-                // 此处是否是首单用 limit 2。因为在执行判断之前订单已入库,所以库里只有一笔才是首单
-                doBack = BackPolicyUtil.backOrder(orderLog.getOrderId(), gameBackPolicy, orderLog.getRechargeMoney(),
-                        orderLog.getIsFirstOrder(), orderLog.getPayTime(), orderLog.getRegisterTime(),
-                        (backUnit, isFirstOrder, firstDay, markUpTime) -> Long.valueOf(list(new LambdaQueryWrapper<GameTencentMiniGameOrder>()
+            GameBackPolicy gameBackPolicy = gameBackPolicyService.getById(orderLog.getBackPolicyId());
+            // 此处是否是首单用 limit 2。因为在执行判断之前订单已入库,所以库里只有一笔才是首单
+            Tuple3<Boolean, Long, String> backInfo = BackPolicyUtil.backOrder(orderLog.getOrderId(), gameBackPolicy, orderLog.getRechargeMoney(),
+                    orderLog.getIsFirstOrder(), orderLog.getPayTime(), orderLog.getRegisterTime(), orderLog.getWechatOpenid(),
+                    new BackPolicyUtil.IBackPolicyCheck() {
+                        @Override
+                        public long backCountForFixedRate(int numberOfRound, BackUnitEnum backUnit, Boolean firstPolicy) {
+                            numberOfRound = numberOfRound - 1;
+                            if (backUnit == BackUnitEnum.UNIT_ONCE) {
+                                return list(new LambdaQueryWrapper<GameTencentMiniGameOrder>()
                                         .eq(GameTencentMiniGameOrder::getGameId, orderLog.getGameId())
                                         .eq(GameTencentMiniGameOrder::getWechatAppId, orderLog.getWechatAppId())
                                         .eq(GameTencentMiniGameOrder::getAdAccountId, orderLog.getAdAccountId())
+                                        .eq(GameTencentMiniGameOrder::getBackPolicyId, gameBackPolicy.getId())
                                         .eq(GameTencentMiniGameOrder::getOrderStatus, OrderStatusEnum.SUCCESS_PAY.getValue())
+                                        .eq(GameTencentMiniGameOrder::getIsFirstOrder, firstPolicy)
+                                        .ne(GameTencentMiniGameOrder::getOrderId, orderLog.getOrderId())
+                                        .orderByDesc(GameTencentMiniGameOrder::getCreateTime)
+                                        .last("limit " + numberOfRound)
+                                ).stream().filter(log -> log.getBackStatus().equals(BackStatusEnum.SUCCESS.getBackStatus())).count();
+                            } else if (backUnit == BackUnitEnum.UNIT_DAY) {
+                                return list(new LambdaQueryWrapper<GameTencentMiniGameOrder>()
+                                        .eq(GameTencentMiniGameOrder::getGameId, orderLog.getGameId())
+                                        .eq(GameTencentMiniGameOrder::getWechatAppId, orderLog.getWechatAppId())
+                                        .eq(GameTencentMiniGameOrder::getAdAccountId, orderLog.getAdAccountId())
                                         .eq(GameTencentMiniGameOrder::getBackPolicyId, gameBackPolicy.getId())
-                                        .eq(isFirstOrder != null, GameTencentMiniGameOrder::getIsFirstOrder, isFirstOrder)
-                                        .apply(firstDay != null && firstDay, "date(register_time) = date(pay_time)")
-                                        .apply(firstDay != null && !firstDay, "date(register_time) != date(pay_time)")
-                                        .apply(markUpTime != null, "TIMESTAMPDIFF(MINUTE, register_time, pay_time) > {0}", markUpTime)
+                                        .eq(GameTencentMiniGameOrder::getOrderStatus, OrderStatusEnum.SUCCESS_PAY.getValue())
+                                        .apply(firstPolicy, "date(recharge_time) = date(pay_time)")
+                                        .apply(!firstPolicy, "date(recharge_time) != date(pay_time)")
                                         .ne(GameTencentMiniGameOrder::getOrderId, orderLog.getOrderId())
                                         .orderByDesc(GameTencentMiniGameOrder::getCreateTime)
-                                        .last("limit " + backUnit)
-                                ).stream().filter(log -> log.getBackStatus().equals(BackStatusEnum.SUCCESS.getBackStatus())).count()
-                        ).intValue());
-                orderLog.setRechargeMoney(BackPolicyUtil.lowRechargeLevel(orderLog.getRechargeMoney(), gameBackPolicy.getLevelDown()));
-            }
+                                        .last("limit " + numberOfRound)
+                                ).stream().filter(log -> log.getBackStatus().equals(BackStatusEnum.SUCCESS.getBackStatus())).count();
+                            } else if (backUnit == BackUnitEnum.UNIT_TIME_DAY) {
+                                return list(new LambdaQueryWrapper<GameTencentMiniGameOrder>()
+                                        .eq(GameTencentMiniGameOrder::getGameId, orderLog.getGameId())
+                                        .eq(GameTencentMiniGameOrder::getWechatAppId, orderLog.getWechatAppId())
+                                        .eq(GameTencentMiniGameOrder::getAdAccountId, orderLog.getAdAccountId())
+                                        .eq(GameTencentMiniGameOrder::getBackPolicyId, gameBackPolicy.getId())
+                                        .eq(GameTencentMiniGameOrder::getOrderStatus, OrderStatusEnum.SUCCESS_PAY.getValue())
+                                        .apply(firstPolicy, "TIMESTAMPDIFF(HOUR, recharge_time, pay_time) < 24")
+                                        .apply(!firstPolicy, "TIMESTAMPDIFF(HOUR, recharge_time, pay_time) >= 24")
+                                        .ne(GameTencentMiniGameOrder::getOrderId, orderLog.getOrderId())
+                                        .orderByDesc(GameTencentMiniGameOrder::getCreateTime)
+                                        .last("limit " + numberOfRound)
+                                ).stream().filter(log -> log.getBackStatus().equals(BackStatusEnum.SUCCESS.getBackStatus())).count();
+                            } else if (backUnit == BackUnitEnum.UNIT_TIME_2DAY) {
+                                return list(new LambdaQueryWrapper<GameTencentMiniGameOrder>()
+                                        .eq(GameTencentMiniGameOrder::getGameId, orderLog.getGameId())
+                                        .eq(GameTencentMiniGameOrder::getWechatAppId, orderLog.getWechatAppId())
+                                        .eq(GameTencentMiniGameOrder::getAdAccountId, orderLog.getAdAccountId())
+                                        .eq(GameTencentMiniGameOrder::getBackPolicyId, gameBackPolicy.getId())
+                                        .eq(GameTencentMiniGameOrder::getOrderStatus, OrderStatusEnum.SUCCESS_PAY.getValue())
+                                        .apply(firstPolicy, "TIMESTAMPDIFF(HOUR, recharge_time, pay_time) < 48")
+                                        .apply(!firstPolicy, "TIMESTAMPDIFF(HOUR, recharge_time, pay_time) >= 48")
+                                        .ne(GameTencentMiniGameOrder::getOrderId, orderLog.getOrderId())
+                                        .orderByDesc(GameTencentMiniGameOrder::getCreateTime)
+                                        .last("limit " + numberOfRound)
+                                ).stream().filter(log -> log.getBackStatus().equals(BackStatusEnum.SUCCESS.getBackStatus())).count();
+                            } else {
+                                throw new RuntimeException("不支持的回传单位[" + backUnit.getValue() + "]");
+                            }
+                        }
+
+                        @Override
+                        public long backCountForUser(BackUnitEnum backUnit, String userId, Boolean firstPolicy) {
+                            if (backUnit == BackUnitEnum.UNIT_ONCE) {
+                                if (firstPolicy) {
+                                    // 首单直接返回 0,必定回传
+                                    return 0;
+                                }
+                                return count(new LambdaQueryWrapper<GameTencentMiniGameOrder>()
+                                        .eq(GameTencentMiniGameOrder::getGameId, orderLog.getGameId())
+                                        .eq(GameTencentMiniGameOrder::getWechatAppId, orderLog.getWechatAppId())
+                                        .eq(GameTencentMiniGameOrder::getAdAccountId, orderLog.getAdAccountId())
+                                        .eq(GameTencentMiniGameOrder::getBackPolicyId, gameBackPolicy.getId())
+                                        .eq(GameTencentMiniGameOrder::getOrderStatus, OrderStatusEnum.SUCCESS_PAY.getValue())
+                                        .eq(GameTencentMiniGameOrder::getBackStatus, BackStatusEnum.SUCCESS.getBackStatus())
+                                        .eq(GameTencentMiniGameOrder::getWechatOpenid, userId)
+                                        .eq(GameTencentMiniGameOrder::getIsFirstOrder, firstPolicy)
+                                        .ne(GameTencentMiniGameOrder::getOrderId, orderLog.getOrderId())
+                                );
+                            } else if (backUnit == BackUnitEnum.UNIT_DAY) {
+                                return count(new LambdaQueryWrapper<GameTencentMiniGameOrder>()
+                                        .eq(GameTencentMiniGameOrder::getGameId, orderLog.getGameId())
+                                        .eq(GameTencentMiniGameOrder::getWechatAppId, orderLog.getWechatAppId())
+                                        .eq(GameTencentMiniGameOrder::getAdAccountId, orderLog.getAdAccountId())
+                                        .eq(GameTencentMiniGameOrder::getBackPolicyId, gameBackPolicy.getId())
+                                        .eq(GameTencentMiniGameOrder::getOrderStatus, OrderStatusEnum.SUCCESS_PAY.getValue())
+                                        .eq(GameTencentMiniGameOrder::getBackStatus, BackStatusEnum.SUCCESS.getBackStatus())
+                                        .eq(GameTencentMiniGameOrder::getWechatOpenid, userId)
+                                        .apply(firstPolicy, "date(recharge_time) = date(pay_time)")
+                                        .apply(!firstPolicy, "date(recharge_time) != date(pay_time)")
+                                        .ne(GameTencentMiniGameOrder::getOrderId, orderLog.getOrderId())
+                                );
+                            } else if (backUnit == BackUnitEnum.UNIT_TIME_DAY) {
+                                return count(new LambdaQueryWrapper<GameTencentMiniGameOrder>()
+                                        .eq(GameTencentMiniGameOrder::getGameId, orderLog.getGameId())
+                                        .eq(GameTencentMiniGameOrder::getWechatAppId, orderLog.getWechatAppId())
+                                        .eq(GameTencentMiniGameOrder::getAdAccountId, orderLog.getAdAccountId())
+                                        .eq(GameTencentMiniGameOrder::getBackPolicyId, gameBackPolicy.getId())
+                                        .eq(GameTencentMiniGameOrder::getOrderStatus, OrderStatusEnum.SUCCESS_PAY.getValue())
+                                        .eq(GameTencentMiniGameOrder::getBackStatus, BackStatusEnum.SUCCESS.getBackStatus())
+                                        .eq(GameTencentMiniGameOrder::getWechatOpenid, userId)
+                                        .apply(firstPolicy, "TIMESTAMPDIFF(HOUR, recharge_time, pay_time) < 24")
+                                        .apply(!firstPolicy, "TIMESTAMPDIFF(HOUR, recharge_time, pay_time) >= 24")
+                                        .ne(GameTencentMiniGameOrder::getOrderId, orderLog.getOrderId())
+                                );
+                            } else if (backUnit == BackUnitEnum.UNIT_TIME_2DAY) {
+                                return count(new LambdaQueryWrapper<GameTencentMiniGameOrder>()
+                                        .eq(GameTencentMiniGameOrder::getGameId, orderLog.getGameId())
+                                        .eq(GameTencentMiniGameOrder::getWechatAppId, orderLog.getWechatAppId())
+                                        .eq(GameTencentMiniGameOrder::getAdAccountId, orderLog.getAdAccountId())
+                                        .eq(GameTencentMiniGameOrder::getBackPolicyId, gameBackPolicy.getId())
+                                        .eq(GameTencentMiniGameOrder::getOrderStatus, OrderStatusEnum.SUCCESS_PAY.getValue())
+                                        .eq(GameTencentMiniGameOrder::getBackStatus, BackStatusEnum.SUCCESS.getBackStatus())
+                                        .eq(GameTencentMiniGameOrder::getWechatOpenid, userId)
+                                        .apply(firstPolicy, "TIMESTAMPDIFF(HOUR, recharge_time, pay_time) < 48")
+                                        .apply(!firstPolicy, "TIMESTAMPDIFF(HOUR, recharge_time, pay_time) >= 48")
+                                        .ne(GameTencentMiniGameOrder::getOrderId, orderLog.getOrderId())
+                                );
+                            } else {
+                                throw new RuntimeException("不支持的回传单位[" + backUnit.getValue() + "]");
+                            }
+                        }
+
+                        @Override
+                        public long markUpOfFixedRate(int numberOfRound, Long markUpTime) {
+                            numberOfRound = numberOfRound - 1;
+                            return list(new LambdaQueryWrapper<GameTencentMiniGameOrder>()
+                                    .eq(GameTencentMiniGameOrder::getGameId, orderLog.getGameId())
+                                    .eq(GameTencentMiniGameOrder::getWechatAppId, orderLog.getWechatAppId())
+                                    .eq(GameTencentMiniGameOrder::getAdAccountId, orderLog.getAdAccountId())
+                                    .eq(GameTencentMiniGameOrder::getBackPolicyId, gameBackPolicy.getId())
+                                    .eq(GameTencentMiniGameOrder::getOrderStatus, OrderStatusEnum.SUCCESS_PAY.getValue())
+                                    .apply("TIMESTAMPDIFF(MINUTE, recharge_time, pay_time) > {0}", markUpTime)
+                                    .ne(GameTencentMiniGameOrder::getOrderId, orderLog.getOrderId())
+                                    .orderByDesc(GameTencentMiniGameOrder::getCreateTime)
+                                    .last("limit " + numberOfRound)
+                            ).stream().filter(log -> log.getBackStatus().equals(BackStatusEnum.SUCCESS.getBackStatus())).count();
+                        }
+
+                        @Override
+                        public long markUpForUser(String userId, Long markUpTime) {
+                            return count(new LambdaQueryWrapper<GameTencentMiniGameOrder>()
+                                    .eq(GameTencentMiniGameOrder::getGameId, orderLog.getGameId())
+                                    .eq(GameTencentMiniGameOrder::getWechatAppId, orderLog.getWechatAppId())
+                                    .eq(GameTencentMiniGameOrder::getAdAccountId, orderLog.getAdAccountId())
+                                    .eq(GameTencentMiniGameOrder::getBackPolicyId, gameBackPolicy.getId())
+                                    .eq(GameTencentMiniGameOrder::getOrderStatus, OrderStatusEnum.SUCCESS_PAY.getValue())
+                                    .eq(GameTencentMiniGameOrder::getBackStatus, BackStatusEnum.SUCCESS.getBackStatus())
+                                    .eq(GameTencentMiniGameOrder::getWechatOpenid, userId)
+                                    .apply("TIMESTAMPDIFF(MINUTE, recharge_time, pay_time) > {0}", markUpTime)
+                                    .ne(GameTencentMiniGameOrder::getOrderId, orderLog.getOrderId())
+                            );
+                        }
+                    });
+            doBack = backInfo.first;
+            backMoney = backInfo.second;
+            backMsg = backInfo.third;
         }
+        BackStatusEnum backStatus = BackStatusEnum.NO;
         if (doBack) {
-            BackStatusEnum backStatus = gameTencentMiniGameBackLogService.orderBack(orderLog);
-            update(new LambdaUpdateWrapper<GameTencentMiniGameOrder>()
-                    .set(GameTencentMiniGameOrder::getBackStatus, backStatus.getBackStatus())
-                    .eq(GameTencentMiniGameOrder::getId, orderLog.getId())
-            );
-            return true;
+            backStatus = gameTencentMiniGameBackLogService.orderBack(orderLog);
         }
-        return false;
+        return update(new LambdaUpdateWrapper<GameTencentMiniGameOrder>()
+                .set(GameTencentMiniGameOrder::getBackStatus, backStatus.getBackStatus())
+                .set(GameTencentMiniGameOrder::getBackMoney, backMoney)
+                .set(GameTencentMiniGameOrder::getBackMsg, backMsg)
+                .eq(GameTencentMiniGameOrder::getId, orderLog.getId())
+        );
     }
 
-
     @Override
     public IPage<GameTencentMiniGameOrderVO> listOfPage(GameTencentMiniGameOrderDTO dto) {
         IPage<GameTencentMiniGameOrder> page = page(dto.toPage(), new LambdaQueryWrapper<GameTencentMiniGameOrder>()
@@ -138,14 +278,10 @@ public class GameTencentMiniGameOrderServiceImpl extends ServiceImpl<GameTencent
     }
 
     @Override
-    public boolean doReport(List<Long> orderLogIds) {
-        listByIds(orderLogIds).forEach(orderLog -> {
-            BackStatusEnum backStatus = gameTencentMiniGameBackLogService.orderBack(orderLog);
-            update(new LambdaUpdateWrapper<GameTencentMiniGameOrder>()
-                    .set(GameTencentMiniGameOrder::getBackStatus, backStatus.getBackStatus())
-                    .eq(GameTencentMiniGameOrder::getId, orderLog.getId())
-            );
-        });
+    public boolean doReport(List<Long> orderLogIds, Long backMoney) {
+        listByIds(orderLogIds).stream()
+                .filter(order -> !Objects.equals(order.getBackStatus(), BackStatusEnum.SUCCESS.getBackStatus()))
+                .forEach(orderLog -> orderBack(orderLog, true, backMoney));
         return true;
     }
 

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

@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.github.sd4324530.jtuple.Tuple3;
 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;
@@ -14,12 +15,11 @@ import com.zanxiang.game.back.base.pojo.enums.OrderStatusEnum;
 import com.zanxiang.game.back.serve.pojo.dto.GameTencentOrderDTO;
 import com.zanxiang.game.back.serve.pojo.entity.GameBackPolicy;
 import com.zanxiang.game.back.serve.pojo.entity.GameTencentBackLog;
-import com.zanxiang.game.back.serve.pojo.entity.GameTencentMiniGameOrder;
 import com.zanxiang.game.back.serve.pojo.entity.GameTencentOrder;
 import com.zanxiang.game.back.serve.dao.mapper.GameTencentOrderMapper;
 import com.zanxiang.game.back.serve.pojo.enums.ActionTypeEnum;
 import com.zanxiang.game.back.serve.pojo.enums.BackStatusEnum;
-import com.zanxiang.game.back.serve.pojo.vo.GameTencentMiniGameOrderVO;
+import com.zanxiang.game.back.serve.pojo.enums.BackUnitEnum;
 import com.zanxiang.game.back.serve.pojo.vo.GameTencentOrderVO;
 import com.zanxiang.game.back.serve.service.IGameBackPolicyService;
 import com.zanxiang.game.back.serve.service.IGameTencentBackLogService;
@@ -75,49 +75,190 @@ public class GameTencentOrderServiceImpl extends ServiceImpl<GameTencentOrderMap
 
     @Override
     @Transactional(rollbackFor = Exception.class)
-    public boolean orderBack(GameTencentOrder orderLog, boolean mustBack) {
+    public boolean orderBack(GameTencentOrder orderLog, boolean mustBack, Long backMoneyOfInput) {
         boolean doBack = false;
+        Long backMoney;
+        String backMsg;
         if (mustBack) {
             doBack = true;
+            backMoney = backMoneyOfInput;
+            backMsg = "手动触发的回传";
         } else {
             if (!Objects.equals(orderLog.getOrderStatus(), OrderStatusEnum.SUCCESS_PAY.getValue())) {
                 // 只要回传 支付行为
                 return false;
             }
-            if (orderLog.getBackPolicyId() == null) {
-                // 没有回传策略,则直接全量回传
-                doBack = true;
-            } else {
-                GameBackPolicy gameBackPolicy = gameBackPolicyService.getById(orderLog.getBackPolicyId());
-                doBack = BackPolicyUtil.backOrder(orderLog.getOrderId(), gameBackPolicy, orderLog.getRechargeMoney(),
-                        orderLog.getIsFirstOrder(), orderLog.getPayTime(), orderLog.getRegisterTime(),
-                        (backUnit, isFirstOrder, firstDay, markUpTime) -> Long.valueOf(list(new LambdaQueryWrapper<GameTencentOrder>()
+            GameBackPolicy gameBackPolicy = gameBackPolicyService.getById(orderLog.getBackPolicyId());
+            Tuple3<Boolean, Long, String> backInfo = BackPolicyUtil.backOrder(orderLog.getOrderId(), gameBackPolicy, orderLog.getRechargeMoney(),
+                    orderLog.getIsFirstOrder(), orderLog.getPayTime(), orderLog.getRegisterTime(),
+                    orderLog.getWechatOpenid(),
+                    new BackPolicyUtil.IBackPolicyCheck() {
+                        @Override
+                        public long backCountForFixedRate(int numberOfRound, BackUnitEnum backUnit, Boolean firstPolicy) {
+                            numberOfRound = numberOfRound - 1;
+                            if (backUnit == BackUnitEnum.UNIT_ONCE) {
+                                return list(new LambdaQueryWrapper<GameTencentOrder>()
                                         .eq(GameTencentOrder::getGameId, orderLog.getGameId())
                                         .eq(GameTencentOrder::getWechatAppId, orderLog.getWechatAppId())
                                         .eq(GameTencentOrder::getAdAccountId, orderLog.getAdAccountId())
                                         .eq(GameTencentOrder::getBackPolicyId, gameBackPolicy.getId())
                                         .eq(GameTencentOrder::getOrderStatus, OrderStatusEnum.SUCCESS_PAY.getValue())
-                                        .eq(isFirstOrder != null, GameTencentOrder::getIsFirstOrder, isFirstOrder)
-                                        .apply(firstDay != null && firstDay, "date(register_time) = date(pay_time)")
-                                        .apply(firstDay != null && !firstDay, "date(register_time) != date(pay_time)")
-                                        .apply(markUpTime != null, "TIMESTAMPDIFF(MINUTE, register_time, pay_time) > {0}", markUpTime)
+                                        .eq(GameTencentOrder::getIsFirstOrder, firstPolicy)
                                         .ne(GameTencentOrder::getOrderId, orderLog.getOrderId())
                                         .orderByDesc(GameTencentOrder::getCreateTime)
-                                        .last("limit " + backUnit)
-                                ).stream().filter(log -> log.getIsBack().equals(BackStatusEnum.SUCCESS.getBackStatus())).count()
-                        ).intValue());
-                orderLog.setRechargeMoney(BackPolicyUtil.lowRechargeLevel(orderLog.getRechargeMoney(), gameBackPolicy.getLevelDown()));
-            }
+                                        .last("limit " + numberOfRound)
+                                ).stream().filter(log -> log.getIsBack().equals(BackStatusEnum.SUCCESS.getBackStatus())).count();
+                            } else if (backUnit == BackUnitEnum.UNIT_DAY) {
+                                return list(new LambdaQueryWrapper<GameTencentOrder>()
+                                        .eq(GameTencentOrder::getGameId, orderLog.getGameId())
+                                        .eq(GameTencentOrder::getWechatAppId, orderLog.getWechatAppId())
+                                        .eq(GameTencentOrder::getAdAccountId, orderLog.getAdAccountId())
+                                        .eq(GameTencentOrder::getBackPolicyId, gameBackPolicy.getId())
+                                        .eq(GameTencentOrder::getOrderStatus, OrderStatusEnum.SUCCESS_PAY.getValue())
+                                        .apply(firstPolicy, "date(recharge_time) = date(pay_time)")
+                                        .apply(!firstPolicy, "date(recharge_time) != date(pay_time)")
+                                        .ne(GameTencentOrder::getOrderId, orderLog.getOrderId())
+                                        .orderByDesc(GameTencentOrder::getCreateTime)
+                                        .last("limit " + numberOfRound)
+                                ).stream().filter(log -> log.getIsBack().equals(BackStatusEnum.SUCCESS.getBackStatus())).count();
+                            } else if (backUnit == BackUnitEnum.UNIT_TIME_DAY) {
+                                return list(new LambdaQueryWrapper<GameTencentOrder>()
+                                        .eq(GameTencentOrder::getGameId, orderLog.getGameId())
+                                        .eq(GameTencentOrder::getWechatAppId, orderLog.getWechatAppId())
+                                        .eq(GameTencentOrder::getAdAccountId, orderLog.getAdAccountId())
+                                        .eq(GameTencentOrder::getBackPolicyId, gameBackPolicy.getId())
+                                        .eq(GameTencentOrder::getOrderStatus, OrderStatusEnum.SUCCESS_PAY.getValue())
+                                        .apply(firstPolicy, "TIMESTAMPDIFF(HOUR, recharge_time, pay_time) < 24")
+                                        .apply(!firstPolicy, "TIMESTAMPDIFF(HOUR, recharge_time, pay_time) >= 24")
+                                        .ne(GameTencentOrder::getOrderId, orderLog.getOrderId())
+                                        .orderByDesc(GameTencentOrder::getCreateTime)
+                                        .last("limit " + numberOfRound)
+                                ).stream().filter(log -> log.getIsBack().equals(BackStatusEnum.SUCCESS.getBackStatus())).count();
+                            } else if (backUnit == BackUnitEnum.UNIT_TIME_2DAY) {
+                                return list(new LambdaQueryWrapper<GameTencentOrder>()
+                                        .eq(GameTencentOrder::getGameId, orderLog.getGameId())
+                                        .eq(GameTencentOrder::getWechatAppId, orderLog.getWechatAppId())
+                                        .eq(GameTencentOrder::getAdAccountId, orderLog.getAdAccountId())
+                                        .eq(GameTencentOrder::getBackPolicyId, gameBackPolicy.getId())
+                                        .eq(GameTencentOrder::getOrderStatus, OrderStatusEnum.SUCCESS_PAY.getValue())
+                                        .apply(firstPolicy, "TIMESTAMPDIFF(HOUR, recharge_time, pay_time) < 48")
+                                        .apply(!firstPolicy, "TIMESTAMPDIFF(HOUR, recharge_time, pay_time) >= 48")
+                                        .ne(GameTencentOrder::getOrderId, orderLog.getOrderId())
+                                        .orderByDesc(GameTencentOrder::getCreateTime)
+                                        .last("limit " + numberOfRound)
+                                ).stream().filter(log -> log.getIsBack().equals(BackStatusEnum.SUCCESS.getBackStatus())).count();
+                            } else {
+                                throw new RuntimeException("不支持的回传单位[" + backUnit.getValue() + "]");
+                            }
+                        }
+
+                        @Override
+                        public long backCountForUser(BackUnitEnum backUnit, String userId, Boolean firstPolicy) {
+                            if (backUnit == BackUnitEnum.UNIT_ONCE) {
+                                if (firstPolicy) {
+                                    // 首单直接返回 0,必定回传
+                                    return 0;
+                                }
+                                return count(new LambdaQueryWrapper<GameTencentOrder>()
+                                        .eq(GameTencentOrder::getGameId, orderLog.getGameId())
+                                        .eq(GameTencentOrder::getWechatAppId, orderLog.getWechatAppId())
+                                        .eq(GameTencentOrder::getAdAccountId, orderLog.getAdAccountId())
+                                        .eq(GameTencentOrder::getBackPolicyId, gameBackPolicy.getId())
+                                        .eq(GameTencentOrder::getOrderStatus, OrderStatusEnum.SUCCESS_PAY.getValue())
+                                        .eq(GameTencentOrder::getIsBack, BackStatusEnum.SUCCESS.getBackStatus())
+                                        .eq(GameTencentOrder::getWechatOpenid, userId)
+                                        .eq(GameTencentOrder::getIsFirstOrder, firstPolicy)
+                                        .ne(GameTencentOrder::getOrderId, orderLog.getOrderId())
+                                );
+                            } else if (backUnit == BackUnitEnum.UNIT_DAY) {
+                                return count(new LambdaQueryWrapper<GameTencentOrder>()
+                                        .eq(GameTencentOrder::getGameId, orderLog.getGameId())
+                                        .eq(GameTencentOrder::getWechatAppId, orderLog.getWechatAppId())
+                                        .eq(GameTencentOrder::getAdAccountId, orderLog.getAdAccountId())
+                                        .eq(GameTencentOrder::getBackPolicyId, gameBackPolicy.getId())
+                                        .eq(GameTencentOrder::getOrderStatus, OrderStatusEnum.SUCCESS_PAY.getValue())
+                                        .eq(GameTencentOrder::getIsBack, BackStatusEnum.SUCCESS.getBackStatus())
+                                        .eq(GameTencentOrder::getWechatOpenid, userId)
+                                        .apply(firstPolicy, "date(recharge_time) = date(pay_time)")
+                                        .apply(!firstPolicy, "date(recharge_time) != date(pay_time)")
+                                        .ne(GameTencentOrder::getOrderId, orderLog.getOrderId())
+                                );
+                            } else if (backUnit == BackUnitEnum.UNIT_TIME_DAY) {
+                                return count(new LambdaQueryWrapper<GameTencentOrder>()
+                                        .eq(GameTencentOrder::getGameId, orderLog.getGameId())
+                                        .eq(GameTencentOrder::getWechatAppId, orderLog.getWechatAppId())
+                                        .eq(GameTencentOrder::getAdAccountId, orderLog.getAdAccountId())
+                                        .eq(GameTencentOrder::getBackPolicyId, gameBackPolicy.getId())
+                                        .eq(GameTencentOrder::getOrderStatus, OrderStatusEnum.SUCCESS_PAY.getValue())
+                                        .eq(GameTencentOrder::getIsBack, BackStatusEnum.SUCCESS.getBackStatus())
+                                        .eq(GameTencentOrder::getWechatOpenid, userId)
+                                        .apply(firstPolicy, "TIMESTAMPDIFF(HOUR, recharge_time, pay_time) < 24")
+                                        .apply(!firstPolicy, "TIMESTAMPDIFF(HOUR, recharge_time, pay_time) >= 24")
+                                        .ne(GameTencentOrder::getOrderId, orderLog.getOrderId())
+                                );
+                            } else if (backUnit == BackUnitEnum.UNIT_TIME_2DAY) {
+                                return count(new LambdaQueryWrapper<GameTencentOrder>()
+                                        .eq(GameTencentOrder::getGameId, orderLog.getGameId())
+                                        .eq(GameTencentOrder::getWechatAppId, orderLog.getWechatAppId())
+                                        .eq(GameTencentOrder::getAdAccountId, orderLog.getAdAccountId())
+                                        .eq(GameTencentOrder::getBackPolicyId, gameBackPolicy.getId())
+                                        .eq(GameTencentOrder::getOrderStatus, OrderStatusEnum.SUCCESS_PAY.getValue())
+                                        .eq(GameTencentOrder::getIsBack, BackStatusEnum.SUCCESS.getBackStatus())
+                                        .eq(GameTencentOrder::getWechatOpenid, userId)
+                                        .apply(firstPolicy, "TIMESTAMPDIFF(HOUR, recharge_time, pay_time) < 48")
+                                        .apply(!firstPolicy, "TIMESTAMPDIFF(HOUR, recharge_time, pay_time) >= 48")
+                                        .ne(GameTencentOrder::getOrderId, orderLog.getOrderId())
+                                );
+                            } else {
+                                throw new RuntimeException("不支持的回传单位[" + backUnit.getValue() + "]");
+                            }
+                        }
+
+                        @Override
+                        public long markUpOfFixedRate(int numberOfRound, Long markUpTime) {
+                            numberOfRound = numberOfRound - 1;
+                            return list(new LambdaQueryWrapper<GameTencentOrder>()
+                                    .eq(GameTencentOrder::getGameId, orderLog.getGameId())
+                                    .eq(GameTencentOrder::getWechatAppId, orderLog.getWechatAppId())
+                                    .eq(GameTencentOrder::getAdAccountId, orderLog.getAdAccountId())
+                                    .eq(GameTencentOrder::getBackPolicyId, gameBackPolicy.getId())
+                                    .eq(GameTencentOrder::getOrderStatus, OrderStatusEnum.SUCCESS_PAY.getValue())
+                                    .apply("TIMESTAMPDIFF(MINUTE, recharge_time, pay_time) > {0}", markUpTime)
+                                    .ne(GameTencentOrder::getOrderId, orderLog.getOrderId())
+                                    .orderByDesc(GameTencentOrder::getCreateTime)
+                                    .last("limit " + numberOfRound)
+                            ).stream().filter(log -> log.getIsBack().equals(BackStatusEnum.SUCCESS.getBackStatus())).count();
+                        }
+
+                        @Override
+                        public long markUpForUser(String userId, Long markUpTime) {
+                            return count(new LambdaQueryWrapper<GameTencentOrder>()
+                                    .eq(GameTencentOrder::getGameId, orderLog.getGameId())
+                                    .eq(GameTencentOrder::getWechatAppId, orderLog.getWechatAppId())
+                                    .eq(GameTencentOrder::getAdAccountId, orderLog.getAdAccountId())
+                                    .eq(GameTencentOrder::getBackPolicyId, gameBackPolicy.getId())
+                                    .eq(GameTencentOrder::getOrderStatus, OrderStatusEnum.SUCCESS_PAY.getValue())
+                                    .eq(GameTencentOrder::getIsBack, BackStatusEnum.SUCCESS.getBackStatus())
+                                    .eq(GameTencentOrder::getWechatOpenid, userId)
+                                    .apply("TIMESTAMPDIFF(MINUTE, recharge_time, pay_time) > {0}", markUpTime)
+                                    .ne(GameTencentOrder::getOrderId, orderLog.getOrderId())
+                            );
+                        }
+                    });
+            doBack = backInfo.first;
+            backMoney = backInfo.second;
+            backMsg = backInfo.third;
         }
+        BackStatusEnum backStatus = BackStatusEnum.NO;
         if (doBack) {
-            BackStatusEnum backStatus = doCallback(orderLog);
-            update(new LambdaUpdateWrapper<GameTencentOrder>()
-                    .set(GameTencentOrder::getIsBack, backStatus.getBackStatus())
-                    .eq(GameTencentOrder::getId, orderLog.getId())
-            );
-            return true;
+            backStatus = doCallback(orderLog);
         }
-        return false;
+        return update(new LambdaUpdateWrapper<GameTencentOrder>()
+                .set(GameTencentOrder::getIsBack, backStatus.getBackStatus())
+                .set(GameTencentOrder::getBackMoney, backMoney)
+                .set(GameTencentOrder::getBackMsg, backMsg)
+                .eq(GameTencentOrder::getId, orderLog.getId())
+        );
     }
 
 
@@ -175,14 +316,10 @@ public class GameTencentOrderServiceImpl extends ServiceImpl<GameTencentOrderMap
     }
 
     @Override
-    public boolean tencentOrderReport(List<Long> ids) {
-        listByIds(ids).forEach(orderLog -> {
-            BackStatusEnum backStatus = doCallback(orderLog);
-            update(new LambdaUpdateWrapper<GameTencentOrder>()
-                    .set(GameTencentOrder::getIsBack, backStatus.getBackStatus())
-                    .eq(GameTencentOrder::getId, orderLog.getId())
-            );
-        });
+    public boolean tencentOrderReport(List<Long> ids, Long backMoney) {
+        listByIds(ids).stream()
+                .filter(order -> !Objects.equals(order.getIsBack(), BackStatusEnum.SUCCESS.getBackStatus()))
+                .forEach(orderLog -> orderBack(orderLog, true, backMoney));
         return true;
     }
 

+ 193 - 90
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/utils/BackPolicyUtil.java

@@ -1,18 +1,23 @@
 package com.zanxiang.game.back.serve.utils;
 
 import com.github.sd4324530.jtuple.Tuple2;
+import com.github.sd4324530.jtuple.Tuple3;
 import com.github.sd4324530.jtuple.Tuples;
 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 lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
 import org.apache.commons.lang3.RandomUtils;
+import org.apache.commons.lang3.StringUtils;
 
 import java.math.BigDecimal;
 import java.time.LocalDateTime;
 import java.util.Arrays;
+import java.util.List;
 import java.util.Objects;
 import java.util.function.Function;
 
@@ -27,24 +32,26 @@ public class BackPolicyUtil {
     /**
      * 订单回传
      *
-     * @param gameBackPolicy   回传策略
-     * @param rechargeMoney    充值金额
-     * @param lastBackFunction 在指定最近订单数量内是否有订单回传过
-     * @return <是否回传, 回传金额>
+     * @return <是否回传,回传金额,回传描述>
      */
-    public static boolean backOrder(String orderId, GameBackPolicy gameBackPolicy, long rechargeMoney, boolean isFirstOrder, LocalDateTime payTime, LocalDateTime regTime, LastBackFunction lastBackFunction) {
+    public static Tuple3<Boolean, Long, String> backOrder(String orderId, GameBackPolicy gameBackPolicy,
+                                                          long rechargeMoney, boolean isFirstOrder,
+                                                          LocalDateTime payTime, LocalDateTime regTime,
+                                                          String userId, IBackPolicyCheck backPolicyCheck) {
         if (null == gameBackPolicy) {
-            log.error("订单 id[{}]通过回传策略[null]判断后,是否回传:{}.", orderId, true);
-            return true;
+            log.error("订单 id[{}]找不到回传策略,默认回传", orderId);
+            return Tuples.tuple(Boolean.TRUE, rechargeMoney, "没有回传策略");
         }
         BackUnitEnum backUnit = gameBackPolicy.getBackUnit() == null ? BackUnitEnum.UNIT_ONCE : BackUnitEnum.getByValue(gameBackPolicy.getBackUnit());
 
-        Boolean firstPolicy = null, firstDay = null;
+        Boolean firstPolicy = null;
         Long markUpTime = null;
         Integer backType;
         String backRate;
         if (gameBackPolicy.getRegPayIntervalTime() != null
                 && ((DateUtil.localDateTimeToSecond(payTime) - DateUtil.localDateTimeToSecond(regTime)) / 60) > gameBackPolicy.getRegPayIntervalTime()) {
+            // 补单
+            log.error("订单 id[{}]通过回传策略[{}]判断后,超过注册充值间隔时间,走补单逻辑 {}.", orderId, gameBackPolicy.getId(), gameBackPolicy.getRegPayIntervalTime());
             if (gameBackPolicy.getMarkUpOrder() != null && gameBackPolicy.getMarkUpOrder()) {
                 markUpTime = gameBackPolicy.getRegPayIntervalTime();
                 if (rechargeMoney <= gameBackPolicy.getMarkUpOrderMinMoney()) {
@@ -59,93 +66,153 @@ public class BackPolicyUtil {
                     backType = gameBackPolicy.getMarkUpOrderOtherMoneyType();
                     backRate = gameBackPolicy.getMarkUpOrderOtherMoneyRate();
                 }
-                log.error("订单 id[{}]通过回传策略[{}]判断后,超过注册充值间隔时间,走补单逻辑 {}.", orderId, gameBackPolicy.getId(), gameBackPolicy.getRegPayIntervalTime());
-            } else {
-                log.error("订单 id[{}]通过回传策略[{}]判断后,超过注册充值间隔时间,不回穿 {}.", orderId, gameBackPolicy.getId(), gameBackPolicy.getRegPayIntervalTime());
-                return false;
-            }
-        } else {
-            if (backUnit == BackUnitEnum.UNIT_ONCE) {
-                if (isFirstOrder) {
-                    firstPolicy = true;
-                    if (rechargeMoney <= gameBackPolicy.getFirstMinMoney()) {
-                        // 小额
-                        backType = gameBackPolicy.getFirstMinMoneyType();
-                        backRate = gameBackPolicy.getFirstMinMoneyRate();
-                    } else if (rechargeMoney >= gameBackPolicy.getFirstMaxMoney()) {
-                        // 大额
-                        backType = gameBackPolicy.getFirstMaxMoneyType();
-                        backRate = gameBackPolicy.getFirstMaxMoneyRate();
-                    } else {
-                        backType = gameBackPolicy.getFirstOtherMoneyType();
-                        backRate = gameBackPolicy.getFirstOtherMoneyRate();
+                String backMsg = "";
+                if (Objects.equals(backType, GameBackPolicy.POLICY_TYPE_FIXED_RATE)) {
+                    // 固定比例回传
+                    String[] temp = backRate.split(":");
+                    int backCount = Integer.parseInt(temp[0]);
+                    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,全部不回传");
                     }
-                    log.error("订单 id[{}]通过回传策略[{}]判断后,正常回传. 首单:{}, backType: {}, backRate: {}", orderId, gameBackPolicy.getId(), true, backType, backRate);
-                } else {
-                    firstPolicy = false;
-                    if (rechargeMoney <= gameBackPolicy.getRechargeMinMoney()) {
-                        // 小额
-                        backType = gameBackPolicy.getRechargeMinMoneyType();
-                        backRate = gameBackPolicy.getRechargeMinMoneyRate();
-                    } else if (rechargeMoney >= gameBackPolicy.getRechargeMaxMoney()) {
-                        // 大额
-                        backType = gameBackPolicy.getRechargeMaxMoneyType();
-                        backRate = gameBackPolicy.getRechargeMaxMoneyRate();
-                    } else {
-                        backType = gameBackPolicy.getRechargeOtherMoneyType();
-                        backRate = gameBackPolicy.getRechargeOtherMoneyRate();
+                    if (ignoreCount == 0) {
+                        log.error("订单 id[{}]通过回传策略[{}]判断后,回传,原因:回传比例 {}", orderId, gameBackPolicy.getId(), backRate);
+                        return Tuples.tuple(Boolean.TRUE, downLevel(rechargeMoney, gameBackPolicy.getMarkUpDownLevel()), "补单-按比例回传,忽略比例为 0,全部回传");
                     }
-                    log.error("订单 id[{}]通过回传策略[{}]判断后,正常回传. 首单:{}, backType: {}, backRate: {}", orderId, gameBackPolicy.getId(), false, backType, backRate);
-                }
-            } else if (backUnit == BackUnitEnum.UNIT_DAY) {
-                long intervalDays = DateUtil.intervalOfDays(regTime.toLocalDate(), payTime.toLocalDate());
-                if (intervalDays == 0) {
-                    firstDay = true;
-                    if (rechargeMoney <= gameBackPolicy.getFirstMinMoney()) {
-                        // 小额
-                        backType = gameBackPolicy.getFirstMinMoneyType();
-                        backRate = gameBackPolicy.getFirstMinMoneyRate();
-                    } else if (rechargeMoney >= gameBackPolicy.getFirstMaxMoney()) {
-                        // 大额
-                        backType = gameBackPolicy.getFirstMaxMoneyType();
-                        backRate = gameBackPolicy.getFirstMaxMoneyRate();
-                    } else {
-                        backType = gameBackPolicy.getFirstOtherMoneyType();
-                        backRate = gameBackPolicy.getFirstOtherMoneyRate();
+                    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);
                     }
-                    log.error("订单 id[{}]通过回传策略[{}]判断后,正常回传. 首日:{}, backType: {}, backRate: {}", orderId, gameBackPolicy.getId(), true, backType, backRate);
-                } else {
-                    firstDay = false;
-                    if (rechargeMoney <= gameBackPolicy.getRechargeMinMoney()) {
-                        // 小额
-                        backType = gameBackPolicy.getRechargeMinMoneyType();
-                        backRate = gameBackPolicy.getRechargeMinMoneyRate();
-                    } else if (rechargeMoney >= gameBackPolicy.getRechargeMaxMoney()) {
-                        // 大额
-                        backType = gameBackPolicy.getRechargeMaxMoneyType();
-                        backRate = gameBackPolicy.getRechargeMaxMoneyRate();
-                    } else {
-                        backType = gameBackPolicy.getRechargeOtherMoneyType();
-                        backRate = gameBackPolicy.getRechargeOtherMoneyRate();
+                } else if (Objects.equals(backType, GameBackPolicy.POLICY_TYPE_RANDOM_RATE)) {
+                    // 随机概率回传
+                    boolean isBack = RandomUtils.nextInt(0, 100) < NumberUtil.multiply100(new BigDecimal(backRate)).intValue();
+                    backMsg = "补单-随机概率回传(" + backRate + ")";
+                    if (!isBack) {
+                        log.error("订单 id[{}]通过回传策略[{}]判断后,不回传,原因:{}", orderId, gameBackPolicy.getId(), backMsg);
+                        return Tuples.tuple(Boolean.FALSE, downLevel(rechargeMoney, gameBackPolicy.getMarkUpDownLevel()), backMsg);
                     }
-                    log.error("订单 id[{}]通过回传策略[{}]判断后,正常回传. 首日:{}, backType: {}, backRate: {}", orderId, gameBackPolicy.getId(), false, backType, backRate);
+                } else {
+                    throw new RuntimeException("回传策略[" + gameBackPolicy.getId() + "]配置错误,未知的回传类型:" + backType);
+                }
+                if (gameBackPolicy.getMarkUpBackCountOfUser() == null) {
+                    backMsg = backMsg + ",未配置单用户最大回传笔数";
+                    log.error("订单 id[{}]通过回传策略[{}]判断后,回传,原因:回传概率 {}", orderId, gameBackPolicy.getId(), backMsg);
+                    return Tuples.tuple(Boolean.TRUE, downLevel(rechargeMoney, gameBackPolicy.getMarkUpDownLevel()), 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);
+            } else {
+                log.error("订单 id[{}]通过回传策略[{}]判断后,不回传,原因:超过注册充值间隔时间但是未开启补单", orderId, gameBackPolicy.getId());
+                return Tuples.tuple(Boolean.FALSE, downLevel(rechargeMoney, gameBackPolicy.getMarkUpDownLevel()), "回传策略未开启补单");
+            }
+        }
+
+        // 正常判断
+        if (backUnit == BackUnitEnum.UNIT_ONCE) {
+            firstPolicy = isFirstOrder;
+        } else if (backUnit == BackUnitEnum.UNIT_DAY) {
+            long intervalDays = DateUtil.intervalOfDays(regTime.toLocalDate(), payTime.toLocalDate());
+            firstPolicy = intervalDays == 0;
+        } else if (backUnit == BackUnitEnum.UNIT_TIME_DAY) {
+            long intervalHours = DateUtil.intervalOfHour(regTime, payTime);
+            firstPolicy = intervalHours < 24;
+        } else if (backUnit == BackUnitEnum.UNIT_TIME_2DAY) {
+            long intervalHours = DateUtil.intervalOfHour(regTime, payTime);
+            firstPolicy = intervalHours < 48;
+        } else {
+            throw new RuntimeException("未知的回传单位:" + backUnit);
+        }
+        if (firstPolicy) {
+            if (rechargeMoney <= gameBackPolicy.getFirstMinMoney()) {
+                // 小额
+                backType = gameBackPolicy.getFirstMinMoneyType();
+                backRate = gameBackPolicy.getFirstMinMoneyRate();
+            } else if (rechargeMoney >= gameBackPolicy.getFirstMaxMoney()) {
+                // 大额
+                backType = gameBackPolicy.getFirstMaxMoneyType();
+                backRate = gameBackPolicy.getFirstMaxMoneyRate();
+            } else {
+                backType = gameBackPolicy.getFirstOtherMoneyType();
+                backRate = gameBackPolicy.getFirstOtherMoneyRate();
+            }
+            log.error("订单 id[{}]通过回传策略[{}]判断后走首日逻辑:backType: {}, backRate: {}", orderId, gameBackPolicy.getId(), backType, backRate);
+        } else {
+            if (rechargeMoney <= gameBackPolicy.getRechargeMinMoney()) {
+                // 小额
+                backType = gameBackPolicy.getRechargeMinMoneyType();
+                backRate = gameBackPolicy.getRechargeMinMoneyRate();
+            } else if (rechargeMoney >= gameBackPolicy.getRechargeMaxMoney()) {
+                // 大额
+                backType = gameBackPolicy.getRechargeMaxMoneyType();
+                backRate = gameBackPolicy.getRechargeMaxMoneyRate();
             } else {
-                throw new RuntimeException("未知的回传单位:" + backUnit);
+                backType = gameBackPolicy.getRechargeOtherMoneyType();
+                backRate = gameBackPolicy.getRechargeOtherMoneyRate();
             }
+            log.error("订单 id[{}]通过回传策略[{}]判断后走次日逻辑, backType: {}, backRate: {}", orderId, gameBackPolicy.getId(), backType, backRate);
         }
+        Integer maxBackCountOfUser = firstPolicy ? gameBackPolicy.getFirstBackCountOfUser() : gameBackPolicy.getRechargeBackCountOfUser();
+        String backMsg = firstPolicy ? "首-" : "次-";
+        String downLevelString = firstPolicy ? gameBackPolicy.getFirstDownLevel() : gameBackPolicy.getRechargeDownLevel();
         if (Objects.equals(backType, GameBackPolicy.POLICY_TYPE_FIXED_RATE)) {
+            // 固定比例回传
+            String[] temp = backRate.split(":");
+            int backCount = Integer.parseInt(temp[0]);
+            int ignoreCount = Integer.parseInt(temp[1]);
+            if (backCount == 0) {
+                backMsg = backMsg + "按比例回传,回传比例为 0,全部不回传";
+                log.error("订单 id[{}]通过回传策略[{}]判断后,不回传,原因:{}", orderId, gameBackPolicy.getId(), backMsg);
+                return Tuples.tuple(Boolean.FALSE, downLevel(rechargeMoney, downLevelString), backMsg);
+            }
+            if (ignoreCount == 0) {
+                backMsg = backMsg + "按比例回传,忽略比例为 0,全部回传";
+                log.error("订单 id[{}]通过回传策略[{}]判断后,回传,原因:{}", orderId, gameBackPolicy.getId(), backMsg);
+                return Tuples.tuple(Boolean.TRUE, downLevel(rechargeMoney, downLevelString), 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);
+            }
+        } else if (Objects.equals(backType, GameBackPolicy.POLICY_TYPE_RANDOM_RATE)) {
+            // 随机概率回传
+            boolean isBack = RandomUtils.nextInt(0, 100) < NumberUtil.multiply100(new BigDecimal(backRate)).intValue();
+            backMsg = backMsg + "补单-随机概率回传(" + backRate + ")";
+            if (!isBack) {
+                log.error("订单 id[{}]通过回传策略[{}]判断后,不回传,原因:{}", orderId, gameBackPolicy.getId(), backMsg);
+                return Tuples.tuple(Boolean.FALSE, downLevel(rechargeMoney, downLevelString), backMsg);
+            }
+        } else {
+            throw new RuntimeException("回传策略[" + gameBackPolicy.getId() + "]配置错误,未知的回传类型:" + backType);
+        }
+
+        if (maxBackCountOfUser == null) {
+            backMsg = backMsg + ",未配置单用户最大回传笔数";
+            log.error("订单 id[{}]通过回传策略[{}]判断后,回传,原因:回传概率 {}", orderId, gameBackPolicy.getId(), backMsg);
+            return Tuples.tuple(Boolean.TRUE, downLevel(rechargeMoney, downLevelString), 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);
+        /*if (Objects.equals(backType, GameBackPolicy.POLICY_TYPE_FIXED_RATE)) {
             // 固定比例回传
             String[] temp = backRate.split(":");
             int backCount = Integer.parseInt(temp[0]);
             int ignoreCount = Integer.parseInt(temp[1]);
             if (backCount == 0) {
                 log.error("订单 id[{}]通过回传策略[{}]判断后,是否回传:{}.", orderId, gameBackPolicy.getId(), false);
-                return false;
+                return Tuples.tuple(Boolean.FALSE, rechargeMoney, "按比例回传,回传比例为 0,全部不回传");
             }
             if (ignoreCount == 0) {
                 log.error("订单 id[{}]通过回传策略[{}]判断后,是否回传:{}.", orderId, gameBackPolicy.getId(), true);
-                return true;
+                return Tuples.tuple(Boolean.TRUE, rechargeMoney, "按比例回传,忽略比例为 0,全部回传");
             }
             int isBackCount = lastBackFunction.getLastBackCount(backCount + ignoreCount - 1, firstPolicy, firstDay, markUpTime);
             log.error("订单 id[{}]通过回传策略[{}]判断后,是否回传:{}.", orderId, gameBackPolicy.getId(), (isBackCount < backCount));
@@ -154,10 +221,27 @@ public class BackPolicyUtil {
             // 随机概率回传
             boolean isBack = RandomUtils.nextInt(0, 100) < NumberUtil.multiply100(new BigDecimal(backRate)).intValue();
             log.error("订单 id[{}]通过回传策略[{}]判断后,是否回传:{}.", orderId, gameBackPolicy.getId(), isBack);
-            return isBack;
+            return Tuples.tuple(isBack, rechargeMoney, "按概率 " + backRate + "判断");
         } else {
             throw new RuntimeException("回传策略[" + gameBackPolicy.getId() + "]配置错误,未知的回传类型:" + backType);
+        }*/
+    }
+
+    private static Long downLevel(Long rechargeMoney, String downLevelStr) {
+        if (StringUtils.isBlank(downLevelStr)) {
+            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;
+            }
+        }
+        return rechargeMoney;
     }
 
     private static Tuple2<Integer, Integer> approximate(int molecular, int denominator) {
@@ -180,23 +264,42 @@ public class BackPolicyUtil {
     /**
      * 降档
      */
-    public static long lowRechargeLevel(long rechargeMoney, Integer levelDown) {
-        if (levelDown == null || levelDown == 0) {
+    public static long lowRechargeLevel(long rechargeMoney, String levelDownStr) {
+        if (StringUtils.isBlank(levelDownStr)) {
+            // 无需降档
             return rechargeMoney;
         }
-        int level = RECHARGE_LEVEL.length - 1;
-        for (int i = 0; i < RECHARGE_LEVEL.length; i++) {
-            if (rechargeMoney <= RECHARGE_LEVEL[i]) {
-                level = i;
-                break;
+        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;
             }
         }
-        level = level - levelDown;
-        level = level < 0 ? 0 : Math.min(level, RECHARGE_LEVEL.length - 1);
-        return RECHARGE_LEVEL[level];
+        // 没有匹配金额规则,直接返回
+        return rechargeMoney;
     }
 
-    public interface LastBackFunction {
-        int getLastBackCount(int backUnit, Boolean isFirstOrder, Boolean firstDay, Long markUpTime);
+    public interface IBackPolicyCheck {
+        /**
+         * 按比例回传时单次循环已经回传的人数
+         */
+        long backCountForFixedRate(int numberOfRound, BackUnitEnum backUnit, Boolean firstPolicy);
+
+        /**
+         * 单个用户已回传订单数
+         */
+        long backCountForUser(BackUnitEnum backUnit, String userId, Boolean firstPolicy);
+
+        /**
+         * 补单,按比例回传时单次循环已经回传的人数
+         */
+        long markUpOfFixedRate(int numberOfRound, Long markUpTime);
+
+        /**
+         * 补单,单个用户已回传订单数
+         */
+        long markUpForUser(String userId, Long markUpTime);
     }
 }

+ 16 - 6
game-data/game-data-serve/src/main/java/com/zanxiang/game/data/serve/component/DataPowerComponent.java

@@ -1,14 +1,19 @@
 package com.zanxiang.game.data.serve.component;
 
 import com.zanxiang.erp.base.ErpServer;
-import com.zanxiang.erp.base.rpc.ISysUserGroupRpc;
+import com.zanxiang.erp.base.rpc.ISysGameUserGroupRpc;
 import com.zanxiang.erp.security.util.SecurityUtil;
 import com.zanxiang.game.module.base.ServerInfo;
 import com.zanxiang.game.module.base.rpc.GameAuthRpc;
+import com.zanxiang.module.util.JsonUtil;
+import com.zanxiang.module.util.exception.BaseException;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
 import org.apache.dubbo.config.annotation.DubboReference;
 import org.springframework.stereotype.Component;
 
+import java.util.ArrayList;
+import java.util.Collection;
 import java.util.List;
 
 @Slf4j
@@ -16,7 +21,7 @@ import java.util.List;
 public class DataPowerComponent {
 
     @DubboReference(providedBy = ErpServer.SERVER_DUBBO_NAME)
-    private ISysUserGroupRpc sysUserGroupRpc;
+    private ISysGameUserGroupRpc sysGameUserGroupRpc;
 
     @DubboReference(providedBy = ServerInfo.SERVER_DUBBO_NAME)
     private GameAuthRpc gameAuthRpc;
@@ -24,7 +29,7 @@ public class DataPowerComponent {
     /**
      * 获取当前登录用户有权限查看的用户列表
      * 1:普通用户-投手:自己
-     * 1:普通用户-运营:自己
+     * 1:普通用户-运营:null-->表示不按权限做
      * 2:投手组长:自己+组员
      * 3:管理员:自己+组员
      * 4:超管:null-->有权限看所有数据
@@ -33,12 +38,13 @@ public class DataPowerComponent {
         if (SecurityUtil.isAdmin()) {
             return null;
         }
-        List<Long> subUserIds = sysUserGroupRpc.memberUserId(SecurityUtil.getCompanyId(), SecurityUtil.getUserId()).getData();
+        Collection<Long> subUserIds = sysGameUserGroupRpc.memberUserIds(SecurityUtil.getCompanyId(), SecurityUtil.getUserId()).getData();
         if (subUserIds.size() > 1) {
             // 自然量
             subUserIds.add(-2L);
         }
-        return subUserIds;
+        log.error("1111--------->" + JsonUtil.toString(subUserIds));
+        return new ArrayList<>(subUserIds);
     }
 
 
@@ -54,6 +60,10 @@ public class DataPowerComponent {
         if (SecurityUtil.isAdmin()) {
             return null;
         }
-        return gameAuthRpc.getGameAuthByUserIds().getData().getGameIdList();
+        List<Long> gameIdList = gameAuthRpc.getGameAuthByUserIds().getData().getGameIdList();
+        if(CollectionUtils.isEmpty(gameIdList)) {
+            throw new BaseException("没有游戏查看权限,请联系管理员指派游戏权限");
+        }
+        return gameIdList;
     }
 }