Selaa lähdekoodia

fix : 兼容腾讯小游戏媒体SDK回传

bilingfeng 5 kuukautta sitten
vanhempi
commit
4dbd70bcde
14 muutettua tiedostoa jossa 698 lisäystä ja 82 poistoa
  1. 42 0
      game-back/game-back-base/src/main/java/com/zanxiang/game/back/base/pojo/dto/TencentMiniGameOrderBackQueryRpcDTO.java
  2. 24 1
      game-back/game-back-base/src/main/java/com/zanxiang/game/back/base/rpc/ITencentMiniGameBackRpc.java
  3. 1 1
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/GameBackApplication.java
  4. 197 8
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/rpc/impl/TencentMiniGameBackRpcImpl.java
  5. 2 2
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/IGameTencentMiniGameOrderService.java
  6. 2 0
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/IGameTencentMiniGameRoleRegisterService.java
  7. 2 0
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/IGameTencentMiniGameUserService.java
  8. 129 17
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/impl/GameTencentMiniGameOrderServiceImpl.java
  9. 60 0
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/impl/GameTencentMiniGameRoleRegisterServiceImpl.java
  10. 37 0
      game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/impl/GameTencentMiniGameUserServiceImpl.java
  11. 10 0
      game-module/game-module-mybatis/src/main/java/com/zanxiang/game/module/mybatis/entity/GameBackLogMediaSdk.java
  12. 1 1
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/SDKApplication.java
  13. 59 15
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/impl/CallBackServiceImpl.java
  14. 132 37
      game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/impl/GameBackLogMediaSdkServiceImpl.java

+ 42 - 0
game-back/game-back-base/src/main/java/com/zanxiang/game/back/base/pojo/dto/TencentMiniGameOrderBackQueryRpcDTO.java

@@ -0,0 +1,42 @@
+package com.zanxiang.game.back.base.pojo.dto;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * @author : lingfeng
+ * @time : 2024-11-22
+ * @description :
+ */
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+public class TencentMiniGameOrderBackQueryRpcDTO implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 游戏 id
+     */
+    private Long gameId;
+
+    /**
+     * sdk 里面的用户 openId(要求唯一)
+     */
+    private String wechatOpenid;
+
+    /**
+     * 订单编号
+     */
+    private String orderId;
+
+    /**
+     * 渠道标识
+     */
+    private String agentKey;
+}

+ 24 - 1
game-back/game-back-base/src/main/java/com/zanxiang/game/back/base/rpc/ITencentMiniGameBackRpc.java

@@ -1,8 +1,10 @@
 package com.zanxiang.game.back.base.rpc;
 
+import com.zanxiang.game.back.base.pojo.dto.TencentMiniGameOrderBackQueryRpcDTO;
 import com.zanxiang.game.back.base.pojo.dto.TencentOrderDTO;
 import com.zanxiang.game.back.base.pojo.dto.TencentRoleRegisterRpcDTO;
 import com.zanxiang.game.back.base.pojo.dto.TencentUserDTO;
+import com.zanxiang.game.back.base.pojo.vo.OrderBackQueryRpcVO;
 import com.zanxiang.module.util.pojo.ResultVO;
 
 /**
@@ -10,18 +12,39 @@ import com.zanxiang.module.util.pojo.ResultVO;
  * 文档地址:https://docs.qq.com/doc/DRkpGUU5jSFVxQVFN
  */
 public interface ITencentMiniGameBackRpc {
+
+    /**
+     * 订单回传查询-媒体SDK回传
+     */
+    ResultVO<OrderBackQueryRpcVO> orderBackQuery(TencentMiniGameOrderBackQueryRpcDTO dto);
+
     /**
      * 订单回传
      */
     ResultVO<Boolean> backOrder(TencentOrderDTO dto);
 
+    /**
+     * 订单回传-媒体SDK回传
+     */
+    ResultVO<Boolean> callBackOrder(TencentOrderDTO dto);
+
     /**
      * 用户回传
      */
     ResultVO<Boolean> backUser(TencentUserDTO dto);
 
     /**
-     * 用户回传
+     * 用户回传-媒体SDK回传
+     */
+    ResultVO<Boolean> callBackUser(TencentUserDTO dto);
+
+    /**
+     * 角色回传
      */
     ResultVO<Boolean> backRoleRegister(TencentRoleRegisterRpcDTO dto);
+
+    /**
+     * 角色回传-媒体SDK
+     */
+    ResultVO<Boolean> callBackRole(TencentRoleRegisterRpcDTO dto);
 }

+ 1 - 1
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/GameBackApplication.java

@@ -18,7 +18,7 @@ public class GameBackApplication {
 
     public static void main(String[] args) {
         SpringApplication.run(GameBackApplication.class, args);
-        System.out.println("角色新手引导回传bug, 判定条件修改 ( ´・・)ノ(._.`)  \n" +
+        System.out.println("兼容腾讯小游戏媒体SDK回传 ( ´・・)ノ(._.`)  \n" +
                 " ______  __     __     \n" +
                 "/_____/\\/__/\\ /__/\\    \n" +
                 "\\:::__\\/\\ \\::\\\\:.\\ \\   \n" +

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

@@ -2,33 +2,38 @@ package com.zanxiang.game.back.serve.rpc.impl;
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.zanxiang.game.back.base.ServerInfo;
+import com.zanxiang.game.back.base.pojo.dto.TencentMiniGameOrderBackQueryRpcDTO;
 import com.zanxiang.game.back.base.pojo.dto.TencentOrderDTO;
 import com.zanxiang.game.back.base.pojo.dto.TencentRoleRegisterRpcDTO;
 import com.zanxiang.game.back.base.pojo.dto.TencentUserDTO;
 import com.zanxiang.game.back.base.pojo.enums.OrderStatusEnum;
+import com.zanxiang.game.back.base.pojo.vo.OrderBackQueryRpcVO;
 import com.zanxiang.game.back.base.rpc.ITencentMiniGameBackRpc;
-import com.zanxiang.game.back.serve.pojo.entity.GameBackPolicy;
-import com.zanxiang.game.back.serve.pojo.entity.GameTencentMiniGameOrder;
-import com.zanxiang.game.back.serve.pojo.entity.GameTencentMiniGameRoleRegister;
-import com.zanxiang.game.back.serve.pojo.entity.GameTencentMiniGameUser;
+import com.zanxiang.game.back.serve.pojo.entity.*;
 import com.zanxiang.game.back.serve.pojo.enums.BackStatusEnum;
-import com.zanxiang.game.back.serve.service.IGameBackPolicyService;
-import com.zanxiang.game.back.serve.service.IGameTencentMiniGameOrderService;
-import com.zanxiang.game.back.serve.service.IGameTencentMiniGameRoleRegisterService;
-import com.zanxiang.game.back.serve.service.IGameTencentMiniGameUserService;
+import com.zanxiang.game.back.serve.service.*;
 import com.zanxiang.module.util.JsonUtil;
 import com.zanxiang.module.util.pojo.ResultVO;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
 import org.apache.dubbo.config.annotation.DubboService;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
 
 import java.time.LocalDateTime;
+import java.util.Collections;
+import java.util.List;
 import java.util.Objects;
+import java.util.stream.Collectors;
 
 @Slf4j
 @DubboService
 public class TencentMiniGameBackRpcImpl implements ITencentMiniGameBackRpc {
 
+    @Autowired
+    private RedisTemplate<String, Object> redisTemplate;
+
     @Autowired
     private IGameBackPolicyService gameBackPolicyService;
 
@@ -41,6 +46,62 @@ public class TencentMiniGameBackRpcImpl implements ITencentMiniGameBackRpc {
     @Autowired
     private IGameTencentMiniGameRoleRegisterService gameTencentMiniGameRoleRegisterService;
 
+    @Autowired
+    private IGameTencentMiniGameOrderSplitLogService gameTencentMiniGameOrderSplitLogService;
+
+    @Override
+    public ResultVO<OrderBackQueryRpcVO> orderBackQuery(TencentMiniGameOrderBackQueryRpcDTO dto) {
+        log.error("微信小游戏订单媒体SDK回传结果查询:{}", JsonUtil.toString(dto));
+        GameTencentMiniGameOrder orderLog = this.queryOrder(dto);
+        if (orderLog == null) {
+            try {
+                Thread.sleep(15 * 1000L);
+            } catch (Exception e) {
+                log.error(e.getMessage(), e);
+            }
+            orderLog = this.queryOrder(dto);
+        }
+        if (orderLog == null) {
+            return ResultVO.ok(OrderBackQueryRpcVO.builder()
+                    .doBack(Boolean.FALSE)
+                    .backMsg("回传异常,找不到订单:" + dto.getOrderId())
+                    .build());
+        }
+        List<Long> splitMoney = gameTencentMiniGameOrderSplitLogService.list(new LambdaQueryWrapper<GameTencentMiniGameOrderSplitLog>()
+                .eq(GameTencentMiniGameOrderSplitLog::getOrderNo, orderLog.getOrderId())
+                .orderByAsc(GameTencentMiniGameOrderSplitLog::getBackIndex)
+        ).stream().map(GameTencentMiniGameOrderSplitLog::getSplitMoney).collect(Collectors.toList());
+        return ResultVO.ok(OrderBackQueryRpcVO.builder()
+                .doBack(BackStatusEnum.getByValue(orderLog.getBackStatus()) == BackStatusEnum.SUCCESS)
+                .backMoney(CollectionUtils.isEmpty(splitMoney) ? Collections.singletonList(orderLog.getBackMoney()) : splitMoney)
+                .backMsg(orderLog.getBackMsg())
+                .build());
+    }
+
+    private GameTencentMiniGameOrder queryOrder(TencentMiniGameOrderBackQueryRpcDTO dto) {
+        String lockKey = ServerInfo.SERVER_NAME + ":TencentMiniGameBack:" + dto.getGameId() + ":" + dto.getOrderId();
+        int maxCount = 0;
+        while (true) {
+            if (redisTemplate.opsForValue().get(lockKey) == null) {
+                break;
+            }
+            if (maxCount++ >= 120 / 10) {
+                break;
+            }
+            try {
+                Thread.sleep(10 * 1000L);
+            } catch (Exception e) {
+                log.error(e.getMessage(), e);
+            }
+        }
+        return gameTencentMiniGameOrderService.getOne(new LambdaQueryWrapper<GameTencentMiniGameOrder>()
+                .eq(GameTencentMiniGameOrder::getOrderId, dto.getOrderId())
+                .eq(GameTencentMiniGameOrder::getGameId, dto.getGameId())
+                .eq(GameTencentMiniGameOrder::getAgentKey, dto.getAgentKey())
+                .eq(GameTencentMiniGameOrder::getWechatOpenid, dto.getWechatOpenid())
+        );
+    }
+
     @Override
     public ResultVO<Boolean> backOrder(TencentOrderDTO dto) {
         if (Objects.equals(OrderStatusEnum.SUCCESS_PAY.getValue(), dto.getOrderStatus())) {
@@ -97,6 +158,62 @@ public class TencentMiniGameBackRpcImpl implements ITencentMiniGameBackRpc {
         }
     }
 
+    @Override
+    public ResultVO<Boolean> callBackOrder(TencentOrderDTO dto) {
+        if (Objects.equals(OrderStatusEnum.SUCCESS_PAY.getValue(), dto.getOrderStatus())) {
+            log.error("腾讯小游戏订单媒体SDK回传收到:{}。", JsonUtil.toString(dto));
+        } else {
+            log.error("腾讯小游戏订单媒体SDK回传收到:{}。订单未支付,直接过滤", JsonUtil.toString(dto));
+            return ResultVO.ok(true);
+        }
+        boolean isFirstOrder = gameTencentMiniGameOrderService.getOne(new LambdaQueryWrapper<GameTencentMiniGameOrder>()
+                .select(GameTencentMiniGameOrder::getOrderId)
+                .eq(GameTencentMiniGameOrder::getGameId, dto.getGameId())
+                .eq(GameTencentMiniGameOrder::getWechatAppId, dto.getWechatAppId())
+                .eq(GameTencentMiniGameOrder::getAdAccountId, dto.getAdAccountId())
+                .eq(GameTencentMiniGameOrder::getOrderStatus, OrderStatusEnum.SUCCESS_PAY.getValue())
+                .eq(GameTencentMiniGameOrder::getWechatOpenid, dto.getWechatOpenid())
+                .last("limit 1")
+        ) == null;
+        GameTencentMiniGameUser userLog = gameTencentMiniGameUserService.getOne(new LambdaQueryWrapper<GameTencentMiniGameUser>()
+                .select(GameTencentMiniGameUser::getBackStatus, GameTencentMiniGameUser::getClickId)
+                .eq(GameTencentMiniGameUser::getGameId, dto.getGameId())
+                .eq(GameTencentMiniGameUser::getWechatAppId, dto.getWechatAppId())
+                .eq(GameTencentMiniGameUser::getWechatOpenid, dto.getWechatOpenid())
+                .eq(GameTencentMiniGameUser::getAdAccountId, dto.getAdAccountId())
+                .orderByDesc(GameTencentMiniGameUser::getCreateTime)
+                .last("limit 1")
+        );
+        GameTencentMiniGameOrder orderLog = GameTencentMiniGameOrder.builder()
+                .adAccountId(dto.getAdAccountId())
+                .gameId(dto.getGameId())
+                .orderId(dto.getOrderId())
+                .agentKey(dto.getChannel())
+                .rechargeMoney(dto.getRechargeMoney())
+                .rechargeTime(dto.getRechargeTime())
+                .subscribeTime(dto.getSubscribeTime())
+                .registerTime(dto.getRegisterTime())
+                .wechatAppId(dto.getWechatAppId())
+                .wechatOpenid(dto.getWechatOpenid())
+                .orderStatus(dto.getOrderStatus())
+                .payTime(dto.getPayTime())
+                .createTime(LocalDateTime.now())
+                .backStatus(BackStatusEnum.NO.getBackStatus())
+                .backPolicyId(dto.getBackPolicyId())
+                .clickId(userLog == null ? null : userLog.getClickId())
+                .roleId(dto.getRoleId())
+                .roleName(dto.getRoleName())
+                .isFirstOrder(isFirstOrder)
+                .build();
+        gameTencentMiniGameOrderService.save(orderLog);
+        if (userLog == null) {
+            log.error("腾讯小游戏订单媒体SDK回传失败,找不到回传的用户 orderId: {}", orderLog.getOrderId());
+            return ResultVO.fail("找不到回传用户");
+        } else {
+            return ResultVO.ok(gameTencentMiniGameOrderService.callback(orderLog));
+        }
+    }
+
     @Override
     public ResultVO<Boolean> backUser(TencentUserDTO dto) {
         log.error("腾讯小游戏用户回传收到:{}", JsonUtil.toString(dto));
@@ -123,6 +240,24 @@ public class TencentMiniGameBackRpcImpl implements ITencentMiniGameBackRpc {
         return ResultVO.ok(Boolean.TRUE);
     }
 
+    public ResultVO<Boolean> callBackUser(TencentUserDTO dto) {
+        log.error("腾讯小游戏用户媒体SDK回传收到:{}", JsonUtil.toString(dto));
+        GameTencentMiniGameUser userLog = GameTencentMiniGameUser.builder()
+                .adAccountId(dto.getAdAccountId())
+                .gameId(dto.getGameId())
+                .agentKey(dto.getChannel())
+                .subscribeTime(dto.getSubscribeTime())
+                .registerTime(dto.getRegisterTime())
+                .wechatAppId(dto.getWechatAppId())
+                .wechatOpenid(dto.getWechatOpenid())
+                .backStatus(BackStatusEnum.NO.getBackStatus())
+                .clickId(dto.getClickId())
+                .createTime(LocalDateTime.now())
+                .build();
+        gameTencentMiniGameUserService.save(userLog);
+        return ResultVO.ok(gameTencentMiniGameUserService.callback(userLog));
+    }
+
     @Override
     public ResultVO<Boolean> backRoleRegister(TencentRoleRegisterRpcDTO dto) {
         log.error("腾讯小游戏创角回传收到:{}", JsonUtil.toString(dto));
@@ -185,4 +320,58 @@ public class TencentMiniGameBackRpcImpl implements ITencentMiniGameBackRpc {
         }
         return ResultVO.ok(gameTencentMiniGameRoleRegisterService.roleRegisterBack(roleRegisterLog));
     }
+
+    @Override
+    public ResultVO<Boolean> callBackRole(TencentRoleRegisterRpcDTO dto) {
+        log.error("腾讯小游戏创角媒体SDK回传收到:{}", JsonUtil.toString(dto));
+        GameTencentMiniGameRoleRegister roleRegisterLog;
+        GameTencentMiniGameRoleRegister oldRole = gameTencentMiniGameRoleRegisterService.getOne(new LambdaQueryWrapper<GameTencentMiniGameRoleRegister>()
+                .eq(GameTencentMiniGameRoleRegister::getGameId, dto.getGameId())
+                .eq(GameTencentMiniGameRoleRegister::getWechatAppId, dto.getWechatAppId())
+                .eq(GameTencentMiniGameRoleRegister::getWechatOpenid, dto.getWechatOpenid())
+                .eq(GameTencentMiniGameRoleRegister::getRoleId, dto.getRoleId())
+                .last("limit 1")
+        );
+        if (oldRole != null) {
+            roleRegisterLog = oldRole;
+            if (dto.getRoleLevel() != null && (oldRole.getRoleLevel() == null || oldRole.getRoleLevel() < dto.getRoleLevel())) {
+                gameTencentMiniGameRoleRegisterService.update(new LambdaUpdateWrapper<GameTencentMiniGameRoleRegister>()
+                        .set(GameTencentMiniGameRoleRegister::getRoleLevel, dto.getRoleLevel())
+                        .set(GameTencentMiniGameRoleRegister::getRoleName, dto.getRoleName())
+                        .eq(GameTencentMiniGameRoleRegister::getId, oldRole.getId())
+                );
+            }
+            // 创角已回传, 不重复执行回传
+            if (Objects.equals(oldRole.getBackStatus(), BackStatusEnum.SUCCESS.getBackStatus())) {
+                return ResultVO.ok(Boolean.TRUE);
+            }
+        } else {
+            GameTencentMiniGameUser userLog = gameTencentMiniGameUserService.getOne(new LambdaQueryWrapper<GameTencentMiniGameUser>()
+                    .select(GameTencentMiniGameUser::getBackStatus, GameTencentMiniGameUser::getClickId)
+                    .eq(GameTencentMiniGameUser::getGameId, dto.getGameId())
+                    .eq(GameTencentMiniGameUser::getWechatAppId, dto.getWechatAppId())
+                    .eq(GameTencentMiniGameUser::getWechatOpenid, dto.getWechatOpenid())
+                    .eq(GameTencentMiniGameUser::getAdAccountId, dto.getAdAccountId())
+                    .orderByDesc(GameTencentMiniGameUser::getCreateTime)
+                    .last("limit 1")
+            );
+            roleRegisterLog = GameTencentMiniGameRoleRegister.builder()
+                    .backPolicyId(dto.getBackPolicyId())
+                    .agentKey(dto.getChannel())
+                    .gameId(dto.getGameId())
+                    .adAccountId(dto.getAdAccountId())
+                    .wechatAppId(dto.getWechatAppId())
+                    .wechatOpenid(dto.getWechatOpenid())
+                    .clickId(userLog == null ? null : userLog.getClickId())
+                    .registerTime(dto.getRegisterTime())
+                    .backStatus(BackStatusEnum.NO.getBackStatus())
+                    .createTime(LocalDateTime.now())
+                    .roleId(dto.getRoleId())
+                    .roleName(dto.getRoleName())
+                    .roleLevel(dto.getRoleLevel())
+                    .build();
+            gameTencentMiniGameRoleRegisterService.save(roleRegisterLog);
+        }
+        return ResultVO.ok(gameTencentMiniGameRoleRegisterService.callback(roleRegisterLog));
+    }
 }

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

@@ -7,12 +7,12 @@ import com.zanxiang.game.back.serve.pojo.dto.OrderReportDTO;
 import com.zanxiang.game.back.serve.pojo.entity.GameTencentMiniGameOrder;
 import com.zanxiang.game.back.serve.pojo.vo.GameTencentMiniGameOrderVO;
 
-import java.util.List;
-
 public interface IGameTencentMiniGameOrderService extends IService<GameTencentMiniGameOrder> {
 
     boolean orderBack(GameTencentMiniGameOrder orderLog);
 
+    boolean callback(GameTencentMiniGameOrder orderLog);
+
     IPage<GameTencentMiniGameOrderVO> listOfPage(GameTencentMiniGameOrderDTO dto);
 
     boolean doReport(OrderReportDTO dto);

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

@@ -13,6 +13,8 @@ public interface IGameTencentMiniGameRoleRegisterService extends IService<GameTe
 
     boolean roleRegisterBack(GameTencentMiniGameRoleRegister roleRegisterLog);
 
+    boolean callback(GameTencentMiniGameRoleRegister roleRegisterLog);
+
     void tutorialFinishBack(GameTencentMiniGameRoleRegister roleRegisterLog, GameBackPolicy gameBackPolicy);
 
     IPage<GameTencentMiniGameRoleRegisterVO> listOfPage(GameTencentMiniGameRoleRegisterDTO dto);

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

@@ -12,6 +12,8 @@ public interface IGameTencentMiniGameUserService extends IService<GameTencentMin
 
     boolean userBack(GameTencentMiniGameUser userLog);
 
+    boolean callback(GameTencentMiniGameUser userLog);
+
     IPage<GameTencentMiniGameUserVO> listOfPage(GameTencentMiniGameUserDTO dto);
 
     boolean doReport(List<Long> userLogIds);

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

@@ -7,7 +7,6 @@ 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.Tuple2;
-import com.github.sd4324530.jtuple.Tuple3;
 import com.github.sd4324530.jtuple.Tuple4;
 import com.zanxiang.advertising.tencent.base.AdvertisingTencentServer;
 import com.zanxiang.advertising.tencent.base.rpc.IUserActionSetRpc;
@@ -17,20 +16,13 @@ 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.dto.OrderReportDTO;
-import com.zanxiang.game.back.serve.pojo.entity.GameBackPolicy;
-import com.zanxiang.game.back.serve.pojo.entity.GameTencentMiniGameOrder;
-import com.zanxiang.game.back.serve.pojo.entity.GameTencentMiniGameOrderSplitLog;
-import com.zanxiang.game.back.serve.pojo.entity.GameTencentMiniGameUser;
-import com.zanxiang.game.back.serve.pojo.entity.GameTencentOrderSplitLog;
+import com.zanxiang.game.back.serve.pojo.entity.*;
+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.enums.BackUnitEnum;
 import com.zanxiang.game.back.serve.pojo.vo.GameTencentMiniGameOrderVO;
 import com.zanxiang.game.back.serve.pojo.vo.GameTencentMiniOrderSplitLogVO;
-import com.zanxiang.game.back.serve.service.IGameBackPolicyService;
-import com.zanxiang.game.back.serve.service.IGameTencentMiniGameBackLogService;
-import com.zanxiang.game.back.serve.service.IGameTencentMiniGameOrderService;
-import com.zanxiang.game.back.serve.service.IGameTencentMiniGameOrderSplitLogService;
-import com.zanxiang.game.back.serve.service.IGameTencentMiniGameUserService;
+import com.zanxiang.game.back.serve.service.*;
 import com.zanxiang.game.back.serve.utils.BackPolicyUtil;
 import com.zanxiang.game.back.serve.utils.OrderUtil;
 import com.zanxiang.game.module.base.ServerInfo;
@@ -51,12 +43,7 @@ import org.springframework.transaction.annotation.Transactional;
 
 import java.time.LocalDateTime;
 import java.time.LocalTime;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
+import java.util.*;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.function.Function;
 import java.util.stream.Collectors;
@@ -168,6 +155,131 @@ public class GameTencentMiniGameOrderServiceImpl extends ServiceImpl<GameTencent
         );
     }
 
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean callback(GameTencentMiniGameOrder orderLog) {
+        if (!Objects.equals(orderLog.getOrderStatus(), OrderStatusEnum.SUCCESS_PAY.getValue())) {
+            // 只要回传 支付行为
+            return true;
+        }
+        GameTencentMiniGameUser userLog = this.userLog(orderLog);
+        if (userLog == null) {
+            return update(new LambdaUpdateWrapper<GameTencentMiniGameOrder>()
+                    .set(GameTencentMiniGameOrder::getBackStatus, BackStatusEnum.FAILED.getBackStatus())
+                    .set(GameTencentMiniGameOrder::getBackMoney, orderLog.getRechargeMoney())
+                    .set(GameTencentMiniGameOrder::getBackMsg, "回传失败!找不到回传用户")
+                    .eq(GameTencentMiniGameOrder::getId, orderLog.getId())
+            );
+        }
+
+        GameBackPolicy gameBackPolicy = gameBackPolicyService.getById(orderLog.getBackPolicyId());
+        // 此处是否是首单用 limit 2。因为在执行判断之前订单已入库,所以库里只有一笔才是首单
+        Tuple4<Boolean, Long, String, List<Tuple2<Long, LocalDateTime>>> backInfo = BackPolicyUtil.backOrder(orderLog.getOrderId(), gameBackPolicy, orderLog.getRechargeMoney(),
+                orderLog.getIsFirstOrder(),
+                orderLog.getPayTime(),
+                // 此处使用用户最近一次的重新染色时间
+                userLog.getCreateTime(),
+                orderLog.getWechatOpenid(),
+                new TencentMiniGameOrderBackPolicyCheck(this, gameBackPolicy, userLog, orderLog));
+        boolean doBack = backInfo.first;
+        Long backMoney = backInfo.second;
+        String backMsg = backInfo.third;
+
+        if (!doBack) {
+            return update(new LambdaUpdateWrapper<GameTencentMiniGameOrder>()
+                    .set(GameTencentMiniGameOrder::getBackStatus, BackStatusEnum.NO.getBackStatus())
+                    .set(GameTencentMiniGameOrder::getBackMoney, backMoney)
+                    .set(GameTencentMiniGameOrder::getBackMsg, backMsg)
+                    .eq(GameTencentMiniGameOrder::getId, orderLog.getId())
+            );
+        }
+        // 拆单
+        if (CollectionUtils.isNotEmpty(backInfo.fourth)) {
+            // 需要拆单
+            List<GameTencentMiniGameOrderSplitLog> splitOrderLogList = new ArrayList<>(backInfo.fourth.size());
+            for (int i = 0; i < backInfo.fourth.size(); i++) {
+                Tuple2<Long, LocalDateTime> splitOrder = backInfo.fourth.get(i);
+                splitOrderLogList.add(GameTencentMiniGameOrderSplitLog.builder()
+                        .backDay(splitOrder.second.toLocalDate())
+                        .orderNo(orderLog.getOrderId())
+                        .backIndex(i + 1)
+                        .backCount(backInfo.fourth.size())
+                        .splitMoney(splitOrder.first)
+                        .backTime(splitOrder.second)
+                        .backStatus(BackStatusEnum.NO.getBackStatus())
+                        .createTime(LocalDateTime.now())
+                        .build());
+            }
+            gameTencentMiniGameOrderSplitLogService.saveBatch(splitOrderLogList);
+            return update(new LambdaUpdateWrapper<GameTencentMiniGameOrder>()
+                    .set(GameTencentMiniGameOrder::getBackStatus, BackStatusEnum.NO.getBackStatus())
+                    .set(GameTencentMiniGameOrder::getBackMoney, backInfo.second)
+                    .set(GameTencentMiniGameOrder::getBackMsg, backMsg)
+                    .eq(GameTencentMiniGameOrder::getId, orderLog.getId())
+            );
+        }
+
+        Tuple2<BackStatusEnum, String> backResult = this.doCallbackMediaSdk(orderLog, orderLog.getPayTime(), backMoney);
+        if (StringUtils.isNotBlank(backResult.second)) {
+            backMsg = backMsg + ("回传失败:" + backResult.second);
+        }
+        return update(new LambdaUpdateWrapper<GameTencentMiniGameOrder>()
+                .set(GameTencentMiniGameOrder::getBackStatus, backResult.first.getBackStatus())
+                .set(GameTencentMiniGameOrder::getBackMoney, backMoney)
+                .set(GameTencentMiniGameOrder::getBackMsg, backMsg)
+                .eq(GameTencentMiniGameOrder::getId, orderLog.getId())
+        );
+    }
+
+    private Tuple2<BackStatusEnum, String> doCallbackMediaSdk(GameTencentMiniGameOrder orderLog, LocalDateTime backTime, Long backMoney) {
+        GameTencentMiniGameUser userLog = this.userLog(orderLog);
+        String actionType = orderLog.getOrderStatus().equals(OrderStatusEnum.SUCCESS_PAY.getValue()) ?
+                ActionTypeEnum.PURCHASE.getActionType() : ActionTypeEnum.COMPLETE_ORDER.getActionType();
+        if (userLog == null) {
+            gameTencentMiniGameBackLogService.save(GameTencentMiniGameBackLog.builder()
+                    .gameId(orderLog.getGameId())
+                    .adAccountId(orderLog.getAdAccountId())
+                    .clickId(orderLog.getClickId())
+                    .actionTime(backTime)
+                    .wechatOpenid(orderLog.getWechatOpenid())
+                    .wechatAppId(orderLog.getWechatAppId())
+                    .actionType(actionType)
+                    .amount(backMoney)
+                    .orderId(orderLog.getOrderId())
+                    .createTime(LocalDateTime.now())
+                    .backStatus(BackStatusEnum.FAILED.getBackStatus())
+                    .errMsg("找不到用户注册信息")
+                    .build());
+            return Tuple2.with(BackStatusEnum.FAILED, "找不到用户注册信息");
+        }
+        BackStatusEnum backStatus = BackStatusEnum.SUCCESS;
+        gameTencentMiniGameBackLogService.save(GameTencentMiniGameBackLog.builder()
+                .gameId(orderLog.getGameId())
+                .adAccountId(orderLog.getAdAccountId())
+                .clickId(orderLog.getClickId())
+                .actionTime(backTime)
+                .wechatOpenid(orderLog.getWechatOpenid())
+                .wechatAppId(orderLog.getWechatAppId())
+                .actionType(actionType)
+                .amount(backMoney)
+                .orderId(orderLog.getOrderId())
+                .createTime(LocalDateTime.now())
+                .backStatus(backStatus.getBackStatus())
+                .errMsg(null)
+                .build());
+        return Tuple2.with(backStatus, null);
+    }
+
+    private GameTencentMiniGameUser userLog(GameTencentMiniGameOrder orderLog) {
+        return gameTencentMiniGameUserService.getOne(new LambdaQueryWrapper<GameTencentMiniGameUser>()
+                .eq(GameTencentMiniGameUser::getGameId, orderLog.getGameId())
+                .eq(GameTencentMiniGameUser::getWechatAppId, orderLog.getWechatAppId())
+                .eq(GameTencentMiniGameUser::getWechatOpenid, orderLog.getWechatOpenid())
+                .eq(GameTencentMiniGameUser::getAdAccountId, orderLog.getAdAccountId())
+                .orderByDesc(GameTencentMiniGameUser::getCreateTime)
+                .last("limit 1"));
+    }
+
     @Override
     public IPage<GameTencentMiniGameOrderVO> listOfPage(GameTencentMiniGameOrderDTO dto) {
         IPage<GameTencentMiniGameOrder> page = page(dto.toPage(), new LambdaQueryWrapper<GameTencentMiniGameOrder>()

+ 60 - 0
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/impl/GameTencentMiniGameRoleRegisterServiceImpl.java

@@ -71,6 +71,15 @@ public class GameTencentMiniGameRoleRegisterServiceImpl extends ServiceImpl<Game
         );
     }
 
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean callback(GameTencentMiniGameRoleRegister roleRegisterLog) {
+        BackStatusEnum backStatusEnum = this.doCallbackMediaSdk(roleRegisterLog);
+        return update(new LambdaUpdateWrapper<GameTencentMiniGameRoleRegister>()
+                .set(GameTencentMiniGameRoleRegister::getBackStatus, backStatusEnum.getBackStatus())
+                .eq(GameTencentMiniGameRoleRegister::getId, roleRegisterLog.getId())
+        );
+    }
 
     @Override
     public IPage<GameTencentMiniGameRoleRegisterVO> listOfPage(GameTencentMiniGameRoleRegisterDTO dto) {
@@ -209,4 +218,55 @@ public class GameTencentMiniGameRoleRegisterServiceImpl extends ServiceImpl<Game
         }
         return BeanUtil.copy(roleRegisterLog, GameTencentMiniGameRoleRegisterVO.class);
     }
+
+    private BackStatusEnum doCallbackMediaSdk(GameTencentMiniGameRoleRegister roleRegisterLog) {
+        GameTencentMiniGameUser user = gameTencentMiniGameUserService.getOne(new LambdaQueryWrapper<GameTencentMiniGameUser>()
+                .eq(GameTencentMiniGameUser::getGameId, roleRegisterLog.getGameId())
+                .eq(GameTencentMiniGameUser::getWechatAppId, roleRegisterLog.getWechatAppId())
+                .eq(GameTencentMiniGameUser::getWechatOpenid, roleRegisterLog.getWechatOpenid())
+                .eq(GameTencentMiniGameUser::getAdAccountId, roleRegisterLog.getAdAccountId())
+                .orderByDesc(GameTencentMiniGameUser::getCreateTime)
+                .last("limit 1"));
+        if (user == null) {
+            gameTencentMiniGameBackLogService.save(GameTencentMiniGameBackLog.builder()
+                    .gameId(roleRegisterLog.getGameId())
+                    .adAccountId(roleRegisterLog.getAdAccountId())
+                    .clickId(roleRegisterLog.getClickId())
+                    .actionTime(roleRegisterLog.getRegisterTime())
+                    .wechatOpenid(roleRegisterLog.getWechatOpenid())
+                    .wechatAppId(roleRegisterLog.getWechatAppId())
+                    .actionType(ActionTypeEnum.CREATE_ROLE.getActionType())
+                    .createTime(LocalDateTime.now())
+                    .backStatus(BackStatusEnum.FAILED.getBackStatus())
+                    .errMsg("找不到用户注册信息")
+                    .build());
+            return BackStatusEnum.FAILED;
+        }
+        //判断创角是否回传
+        if (gameTencentMiniGameBackLogService.count(new LambdaQueryWrapper<GameTencentMiniGameBackLog>()
+                .eq(GameTencentMiniGameBackLog::getGameId, roleRegisterLog.getGameId())
+                .eq(GameTencentMiniGameBackLog::getWechatAppId, roleRegisterLog.getWechatAppId())
+                .eq(GameTencentMiniGameBackLog::getWechatOpenid, roleRegisterLog.getWechatOpenid())
+                .eq(GameTencentMiniGameBackLog::getAdAccountId, roleRegisterLog.getAdAccountId())
+                .eq(GameTencentMiniGameBackLog::getActionType, ActionTypeEnum.CREATE_ROLE.getActionType())
+                .eq(GameTencentMiniGameBackLog::getBackStatus, BackStatusEnum.SUCCESS.getBackStatus())
+        ) > 0) {
+            //创角已回传
+            return BackStatusEnum.NO;
+        }
+        BackStatusEnum backStatus = BackStatusEnum.SUCCESS;
+        gameTencentMiniGameBackLogService.save(GameTencentMiniGameBackLog.builder()
+                .gameId(roleRegisterLog.getGameId())
+                .adAccountId(roleRegisterLog.getAdAccountId())
+                .clickId(roleRegisterLog.getClickId())
+                .actionTime(roleRegisterLog.getRegisterTime())
+                .wechatOpenid(roleRegisterLog.getWechatOpenid())
+                .wechatAppId(roleRegisterLog.getWechatAppId())
+                .actionType(ActionTypeEnum.CREATE_ROLE.getActionType())
+                .createTime(LocalDateTime.now())
+                .backStatus(backStatus.getBackStatus())
+                .errMsg(null)
+                .build());
+        return backStatus;
+    }
 }

+ 37 - 0
game-back/game-back-serve/src/main/java/com/zanxiang/game/back/serve/service/impl/GameTencentMiniGameUserServiceImpl.java

@@ -61,6 +61,16 @@ public class GameTencentMiniGameUserServiceImpl extends ServiceImpl<GameTencentM
         );
     }
 
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean callback(GameTencentMiniGameUser userLog) {
+        BackStatusEnum backStatus = this.doCallbackMediaSdk(userLog);
+        return update(new LambdaUpdateWrapper<GameTencentMiniGameUser>()
+                .set(GameTencentMiniGameUser::getBackStatus, backStatus.getBackStatus())
+                .eq(GameTencentMiniGameUser::getId, userLog.getId())
+        );
+    }
+
     @Override
     public IPage<GameTencentMiniGameUserVO> listOfPage(GameTencentMiniGameUserDTO dto) {
         IPage<GameTencentMiniGameUser> page = page(dto.toPage(), new LambdaQueryWrapper<GameTencentMiniGameUser>()
@@ -149,4 +159,31 @@ public class GameTencentMiniGameUserServiceImpl extends ServiceImpl<GameTencentM
         }
         return BeanUtil.copy(userLog, GameTencentMiniGameUserVO.class);
     }
+
+    private BackStatusEnum doCallbackMediaSdk(GameTencentMiniGameUser userLog) {
+        if (gameTencentMiniGameBackLogService.count(new LambdaQueryWrapper<GameTencentMiniGameBackLog>()
+                .eq(GameTencentMiniGameBackLog::getGameId, userLog.getGameId())
+                .eq(GameTencentMiniGameBackLog::getWechatAppId, userLog.getWechatAppId())
+                .eq(GameTencentMiniGameBackLog::getWechatOpenid, userLog.getWechatOpenid())
+                .eq(GameTencentMiniGameBackLog::getAdAccountId, userLog.getAdAccountId())
+                .eq(GameTencentMiniGameBackLog::getActionType, ActionTypeEnum.REGISTER.getActionType())
+                .eq(GameTencentMiniGameBackLog::getBackStatus, BackStatusEnum.SUCCESS.getBackStatus())
+        ) > 0) {
+            return BackStatusEnum.NO;
+        }
+        BackStatusEnum backStatus = BackStatusEnum.SUCCESS;
+        gameTencentMiniGameBackLogService.save(GameTencentMiniGameBackLog.builder()
+                .gameId(userLog.getGameId())
+                .adAccountId(userLog.getAdAccountId())
+                .clickId(userLog.getClickId())
+                .actionTime(LocalDateTime.now())
+                .wechatOpenid(userLog.getWechatOpenid())
+                .wechatAppId(userLog.getWechatAppId())
+                .actionType(ActionTypeEnum.REGISTER.getActionType())
+                .createTime(LocalDateTime.now())
+                .backStatus(backStatus.getBackStatus())
+                .errMsg(null)
+                .build());
+        return backStatus;
+    }
 }

+ 10 - 0
game-module/game-module-mybatis/src/main/java/com/zanxiang/game/module/mybatis/entity/GameBackLogMediaSdk.java

@@ -49,6 +49,16 @@ public class GameBackLogMediaSdk implements Serializable {
      */
     private String callBackJudgeResult;
 
+    /**
+     * 角色id
+     */
+    private String roleId;
+
+    /**
+     * 订单id
+     */
+    private String orderId;
+
     /**
      * 媒体sdk回传参数
      */

+ 1 - 1
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/SDKApplication.java

@@ -23,7 +23,7 @@ public class SDKApplication {
 
     public static void main(String[] args) {
         SpringApplication.run(SDKApplication.class, args);
-        System.out.println("赞象SDK服务启动成功 <sdk改版, 兼容小程媒体sdk回传> ( ´・・)ノ(._.`) \n" +
+        System.out.println("赞象SDK服务启动成功 <兼容腾讯小游戏媒体SDK回传> ( ´・・)ノ(._.`) \n" +
                 " ___________ _   __\n" +
                 "/  ___|  _  \\ | / /\n" +
                 "\\ `--.| | | | |/ / \n" +

+ 59 - 15
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/impl/CallBackServiceImpl.java

@@ -229,12 +229,7 @@ public class CallBackServiceImpl implements ICallBackService {
             }
             //腾讯小游戏回传
             if (Objects.equals(agent.getAccountType(), AccountTypeEnum.TENCENT_MINI_GAME.getValue())) {
-                TencentUserDTO tencentUserDTO = this.transform(user, agent, gameApplet);
-                //解析设置clickId
-                Map<String, String> channelMap = agentService.channelTransform(user.getChannel());
-                tencentUserDTO.setClickId(channelMap.get("gdt_vid"));
-                tencentMiniGameBackRpc.backUser(tencentUserDTO);
-                gameBackLogService.addLog(user.getId(), null, "腾讯小游戏用户回传提交", JsonUtil.toString(tencentUserDTO));
+                this.userCallBackTencentMiniGame(user, agent, gameApplet);
             }
             //腾讯APP私域
             if (Objects.equals(agent.getAccountType(), AccountTypeEnum.TENCENT_APP_API.getValue())) {
@@ -263,6 +258,27 @@ public class CallBackServiceImpl implements ICallBackService {
         }
     }
 
+    private void userCallBackTencentMiniGame(User user, Agent agent, GameApplet gameApplet) {
+        //查询游戏信息
+        Game game = gameService.getById(agent.getGameId());
+        //构造回传参数
+        TencentUserDTO tencentUserDTO = this.transform(user, agent, gameApplet);
+        //解析设置clickId
+        Map<String, String> channelMap = agentService.channelTransform(user.getChannel());
+        tencentUserDTO.setClickId(channelMap.get("gdt_vid"));
+        //没有配置媒体SDK, 执行API回传
+        String describe;
+        if (Strings.isBlank(game.getAdSdkConfig())) {
+            tencentMiniGameBackRpc.backUser(tencentUserDTO);
+            describe = "腾讯小游戏用户回传提交";
+        } else {
+            //执行媒体SDK回传
+            tencentMiniGameBackRpc.callBackUser(tencentUserDTO);
+            describe = "腾讯小游戏用户媒体SDK回传提交";
+        }
+        gameBackLogService.addLog(user.getId(), null, describe, JsonUtil.toString(tencentUserDTO));
+    }
+
     @Override
     public void roleCallBack(GameUserRole gameUserRole) {
         //判断游戏是否开启广告回传, 未开启, 不回传
@@ -290,9 +306,7 @@ public class CallBackServiceImpl implements ICallBackService {
             }
             //腾讯小游戏回传
             if (Objects.equals(agent.getAccountType(), AccountTypeEnum.TENCENT_MINI_GAME.getValue())) {
-                TencentRoleRegisterRpcDTO tencentRoleRegisterRpcDTO = this.transform(user, agent, gameApplet, gameUserRole);
-                tencentMiniGameBackRpc.backRoleRegister(tencentRoleRegisterRpcDTO);
-                gameBackLogService.addLog(user.getId(), gameUserRole.getRoleId(), "腾讯小游戏创角回传提交", JsonUtil.toString(tencentRoleRegisterRpcDTO));
+                this.roleCallBackTencentMiniGame(user, agent, gameApplet, gameUserRole);
             }
             //腾讯APP私域
             if (Objects.equals(agent.getAccountType(), AccountTypeEnum.TENCENT_APP_API.getValue())) {
@@ -321,6 +335,22 @@ public class CallBackServiceImpl implements ICallBackService {
         }
     }
 
+    private void roleCallBackTencentMiniGame(User user, Agent agent, GameApplet gameApplet, GameUserRole gameUserRole) {
+        //查询游戏信息
+        Game game = gameService.getById(agent.getGameId());
+        TencentRoleRegisterRpcDTO tencentRoleRegisterRpcDTO = this.transform(user, agent, gameApplet, gameUserRole);
+        //没有配置媒体SDK, 执行API回传
+        String describe;
+        if (Strings.isBlank(game.getAdSdkConfig())) {
+            tencentMiniGameBackRpc.backRoleRegister(tencentRoleRegisterRpcDTO);
+            describe = "腾讯小游戏创角回传提交";
+        } else {
+            tencentMiniGameBackRpc.callBackRole(tencentRoleRegisterRpcDTO);
+            describe = "腾讯小游戏创角媒体SDK回传提交";
+        }
+        gameBackLogService.addLog(user.getId(), gameUserRole.getRoleId(), describe, JsonUtil.toString(tencentRoleRegisterRpcDTO));
+    }
+
     @Override
     public void orderCallBack(PlatformOrderDTO platformOrderDTO) {
         //判断游戏是否开启广告回传, 未开启, 不回传
@@ -349,12 +379,7 @@ public class CallBackServiceImpl implements ICallBackService {
             }
             //腾讯小游戏回传
             if (Objects.equals(agent.getAccountType(), AccountTypeEnum.TENCENT_MINI_GAME.getValue())) {
-                TencentOrderDTO tencentOrderDTO = this.transform(platformOrderDTO, user, agent, gameApplet);
-                //解析设置clickId
-                Map<String, String> channelMap = agentService.channelTransform(user.getChannel());
-                tencentOrderDTO.setClickId(channelMap.get("gdt_vid"));
-                tencentMiniGameBackRpc.backOrder(tencentOrderDTO);
-                gameBackLogService.addLog(user.getId(), platformOrderDTO.getOrderId(), "腾讯小游戏订单回传提交", JsonUtil.toString(tencentOrderDTO));
+                this.orderCallBackTencentMiniGame(user, agent, gameApplet, platformOrderDTO);
             }
             //腾讯APP私域
             if (Objects.equals(agent.getAccountType(), AccountTypeEnum.TENCENT_APP_API.getValue())) {
@@ -383,6 +408,25 @@ public class CallBackServiceImpl implements ICallBackService {
         }
     }
 
+    private void orderCallBackTencentMiniGame(User user, Agent agent, GameApplet gameApplet, PlatformOrderDTO platformOrderDTO) {
+        //查询游戏信息
+        Game game = gameService.getById(agent.getGameId());
+        TencentOrderDTO tencentOrderDTO = this.transform(platformOrderDTO, user, agent, gameApplet);
+        //解析设置clickId
+        Map<String, String> channelMap = agentService.channelTransform(user.getChannel());
+        tencentOrderDTO.setClickId(channelMap.get("gdt_vid"));
+        //没有配置媒体SDK, 执行API回传
+        String describe;
+        if (Strings.isBlank(game.getAdSdkConfig())) {
+            tencentMiniGameBackRpc.backOrder(tencentOrderDTO);
+            describe = "腾讯小游戏订单回传提交";
+        } else {
+            tencentMiniGameBackRpc.callBackOrder(tencentOrderDTO);
+            describe = "腾讯小游戏订单媒体SDK回传提交";
+        }
+        gameBackLogService.addLog(user.getId(), platformOrderDTO.getOrderId(), describe, JsonUtil.toString(tencentOrderDTO));
+    }
+
     private TencentRoleRegisterRpcDTO transform(User user, Agent agent, GameApplet gameApplet, GameUserRole gameUserRole) {
         return TencentRoleRegisterRpcDTO.builder()
                 .backPolicyId(agent.getBackPolicyId())

+ 132 - 37
game-module/game-module-sdk/src/main/java/com/zanxiang/game/module/sdk/service/impl/GameBackLogMediaSdkServiceImpl.java

@@ -4,14 +4,15 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.github.sd4324530.jtuple.Tuple2;
+import com.github.sd4324530.jtuple.Tuple3;
 import com.zanxiang.game.back.base.ServerInfo;
+import com.zanxiang.game.back.base.pojo.dto.TencentMiniGameOrderBackQueryRpcDTO;
 import com.zanxiang.game.back.base.pojo.dto.TtAppOrderBackQueryRpcDTO;
 import com.zanxiang.game.back.base.pojo.vo.OrderBackQueryRpcVO;
+import com.zanxiang.game.back.base.rpc.ITencentMiniGameBackRpc;
 import com.zanxiang.game.back.base.rpc.ITtAppBackRpc;
-import com.zanxiang.game.module.mybatis.entity.Agent;
-import com.zanxiang.game.module.mybatis.entity.GameBackLogMediaSdk;
-import com.zanxiang.game.module.mybatis.entity.User;
-import com.zanxiang.game.module.mybatis.entity.UserEvent;
+import com.zanxiang.game.module.base.pojo.enums.AccountTypeEnum;
+import com.zanxiang.game.module.mybatis.entity.*;
 import com.zanxiang.game.module.mybatis.mapper.GameBackLogMediaSdkMapper;
 import com.zanxiang.game.module.sdk.constant.RedisKeyConstant;
 import com.zanxiang.game.module.sdk.enums.CallBackTypeEnum;
@@ -28,7 +29,10 @@ import org.apache.logging.log4j.util.Strings;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import java.time.LocalDate;
 import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.temporal.ChronoUnit;
 import java.util.*;
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
@@ -45,8 +49,8 @@ public class GameBackLogMediaSdkServiceImpl extends ServiceImpl<GameBackLogMedia
     @DubboReference(providedBy = ServerInfo.SERVER_DUBBO_NAME)
     private ITtAppBackRpc ttAppBackRpc;
 
-    @Autowired
-    private IAgentService agentService;
+    @DubboReference(providedBy = ServerInfo.SERVER_DUBBO_NAME)
+    private ITencentMiniGameBackRpc tencentMiniGameBackRpc;
 
     @Autowired
     private IUserService userService;
@@ -55,11 +59,17 @@ public class GameBackLogMediaSdkServiceImpl extends ServiceImpl<GameBackLogMedia
     private IOrderService orderService;
 
     @Autowired
-    private IDistributedLockComponent distributedLockComponent;
+    private IAgentService agentService;
 
     @Autowired
     private IUserEventService userEventService;
 
+    @Autowired
+    private IUserLoginLogService userLoginLogService;
+
+    @Autowired
+    private IDistributedLockComponent distributedLockComponent;
+
     @Override
     public Map<String, Object> callBackJudge(CallBackControlParam param, UserData userData) {
         Map<String, Object> resultMap = new HashMap<>(7);
@@ -95,13 +105,14 @@ public class GameBackLogMediaSdkServiceImpl extends ServiceImpl<GameBackLogMedia
             log.error("重复请求触发线程锁, 直接返回false, lockKey : {}", lockKey);
             return resultMap;
         }
+        //执行回传判断
         try {
-            //判断回传
-            this.checkCallBack(user.getId(), agent, param.getCallBackTypeEnum(), resultMap, param);
+            this.checkCallBack(user, agent, resultMap, param);
         } catch (Exception e) {
-            log.error("事件回传判断, 出现异常, param : {},  userData : {}, e : {}", JsonUtil.toString(param),
-                    JsonUtil.toString(userData), e.getMessage(), e);
+            log.error("事件回传判断, 出现异常, param : {},  userData : {}, e : {}",
+                    JsonUtil.toString(param), JsonUtil.toString(userData), e.getMessage(), e);
         } finally {
+            //释放线程锁
             distributedLockComponent.unlock(lockKey);
         }
         //返回结果
@@ -124,11 +135,13 @@ public class GameBackLogMediaSdkServiceImpl extends ServiceImpl<GameBackLogMedia
 
     private Tuple2<Boolean, String> callBackParamCheck(CallBackControlParam param, Map<String, Object> resultMap) {
         CallBackTypeEnum callBackTypeEnum = param.getCallBackTypeEnum();
-        //创角和新手引导回传, 必须传角色id
+        //创角, 新手引导, 等级提升回传, 必须传角色id
         if (Objects.equals(callBackTypeEnum, CallBackTypeEnum.CALL_BACK_ACTIVATE)
-                || Objects.equals(callBackTypeEnum, CallBackTypeEnum.CALL_BACK_TUTORIAL_FINISH)) {
+                || Objects.equals(callBackTypeEnum, CallBackTypeEnum.CALL_BACK_CREATE_ROLE)
+                || Objects.equals(callBackTypeEnum, CallBackTypeEnum.CALL_BACK_TUTORIAL_FINISH)
+                || Objects.equals(callBackTypeEnum, CallBackTypeEnum.CALL_BACK_UPDATE_LEVEL)) {
             if (Strings.isBlank(param.getRoleId())) {
-                return Tuple2.with(Boolean.FALSE, "参数错误, 创角或新手引导回传, 必须传角色id");
+                return Tuple2.with(Boolean.FALSE, "参数错误, 创角, 新手引导或者等级提升回传, 必须传角色id");
             }
             resultMap.put("roleId", param.getRoleId());
         }
@@ -168,8 +181,14 @@ public class GameBackLogMediaSdkServiceImpl extends ServiceImpl<GameBackLogMedia
         return Tuple2.with(callBack, amountList);
     }
 
-    private void checkCallBack(Long userId, Agent agent, CallBackTypeEnum callBackTypeEnum, Map<String, Object> resultMap,
-                               CallBackControlParam param) {
+    private void checkCallBack(User user, Agent agent, Map<String, Object> resultMap, CallBackControlParam param) {
+        //玩家id
+        Long userId = user.getId();
+        //游戏id
+        Long gameId = agent.getGameId();
+        //回传类型
+        CallBackTypeEnum callBackTypeEnum = param.getCallBackTypeEnum();
+        //按不同类型判断
         switch (callBackTypeEnum) {
             case CALL_BACK_LOGIN_IN:
                 break;
@@ -185,35 +204,106 @@ public class GameBackLogMediaSdkServiceImpl extends ServiceImpl<GameBackLogMedia
                 resultMap.put("callBack", Boolean.TRUE);
                 break;
             case CALL_BACK_RE_ACTIVE:
-                //沉默唤起
-                resultMap.put("callBack", Boolean.TRUE);
+                Tuple3<Boolean, Long, String> tuple = this.callBackReActiveCheck(param.getRoleId(), userId, gameId);
+                resultMap.put("callBack", tuple.first);
+                resultMap.put("backFlowDay", tuple.second);
+                resultMap.put("backMsg", tuple.third);
                 break;
             case CALL_BACK_TUTORIAL_FINISH:
-                //完成新手引导
-                resultMap.put("callBack", Boolean.TRUE);
+                Tuple2<Boolean, String> tuple2 = this.callBackTutorialFinishCheck(param.getRoleId(), userId, gameId);
+                resultMap.put("callBack", tuple2.first);
+                resultMap.put("backMsg", tuple2.second);
                 break;
             case CALL_BACK_PAY_ORDER:
-                TtAppOrderBackQueryRpcDTO orderTransform = this.transform(userId, param.getOrderId(), agent);
-                OrderBackQueryRpcVO orderBackQueryRpcVO = ttAppBackRpc.orderBackQuery(orderTransform).getData();
-                resultMap.put("orderId", param.getOrderId());
-                resultMap.put("callBack", orderBackQueryRpcVO.getDoBack());
-                resultMap.put("backMsg", orderBackQueryRpcVO.getBackMsg());
-                if (Objects.equals(orderBackQueryRpcVO.getDoBack(), Boolean.TRUE)) {
-                    //传过来的金额是分, 换算成元, 存在小数直接舍弃
-                    List<Long> backMoney = orderBackQueryRpcVO.getBackMoney()
-                            .stream().map(money -> money / 100)
-                            .collect(Collectors.toList());
-                    resultMap.put("amount", backMoney);
-                }
+                Tuple3<Boolean, List<Long>, String> tuple3 = this.callBackOrderCheck(param.getOrderId(), user, agent);
+                resultMap.put("callBack", tuple3.first);
+                resultMap.put("amount", tuple3.second);
+                resultMap.put("backMsg", tuple3.third);
                 break;
             default:
                 resultMap.put("backMsg", "未知的回传类型");
         }
     }
 
+    private Tuple3<Boolean, Long, String> callBackReActiveCheck(String roleId, Long userId, Long gameId) {
+        //判断玩家今日是否已经沉默唤起回传
+        if (super.count(new LambdaQueryWrapper<GameBackLogMediaSdk>()
+                .eq(GameBackLogMediaSdk::getGameId, gameId)
+                .eq(GameBackLogMediaSdk::getUserId, userId)
+                .eq(GameBackLogMediaSdk::getRoleId, roleId)
+                .eq(GameBackLogMediaSdk::getCallBackParam, CallBackTypeEnum.CALL_BACK_RE_ACTIVE)
+                .ge(GameBackLogMediaSdk::getCreateTime, LocalDateTime.of(LocalDate.now(), LocalTime.MIN))
+        ) > 0) {
+            return Tuple3.with(Boolean.FALSE, null, "今日已执行沉默唤起回传, 不重复执行");
+        }
+        //获取玩家今天之前最后一次登录日志
+        UserLoginLog userLoginLog = userLoginLogService.getOne(new LambdaQueryWrapper<UserLoginLog>()
+                .eq(UserLoginLog::getUserId, userId)
+                .le(UserLoginLog::getCreateTime, LocalDateTime.of(LocalDate.now(), LocalTime.MIN))
+                .orderByDesc(UserLoginLog::getCreateTime)
+                .last("limit 1"));
+        if (userLoginLog == null) {
+            return Tuple3.with(Boolean.FALSE, null, "不存在今日之前的登录日志, 不执行沉默唤起回传");
+        }
+        //最长未登录天数, 判断标准暂定 30 天
+        long backFlowDay = 30;
+        long betweenDay = ChronoUnit.DAYS.between(userLoginLog.getCreateTime().toLocalDate(), LocalDate.now());
+        //返回判断结果
+        return Tuple3.with(betweenDay >= backFlowDay, backFlowDay, "沉默唤起判断依据登录日志id: " + userLoginLog.getId());
+    }
+
+    private Tuple2<Boolean, String> callBackTutorialFinishCheck(String roleId, Long userId, Long gameId) {
+        long count = super.count(new LambdaQueryWrapper<GameBackLogMediaSdk>()
+                .eq(GameBackLogMediaSdk::getGameId, gameId)
+                .eq(GameBackLogMediaSdk::getUserId, userId)
+                .eq(GameBackLogMediaSdk::getRoleId, roleId)
+                .eq(GameBackLogMediaSdk::getCallBackParam, CallBackTypeEnum.CALL_BACK_TUTORIAL_FINISH)
+        );
+        return Tuple2.with(count <= 0, count <= 0 ? "执行新手引导回传" : "角色已执行新手引导回传, 不重复执行, count : " + count);
+    }
+
+    private Tuple3<Boolean, List<Long>, String> callBackOrderCheck(String orderId, User user, Agent agent) {
+        Boolean doBack = Boolean.FALSE;
+        List<Long> amount = null;
+        String backMsg = null;
+        //头条APP直投回传
+        if (Objects.equals(agent.getAccountType(), AccountTypeEnum.BYTE_APP.getValue())) {
+            TtAppOrderBackQueryRpcDTO orderQuery = this.transform(user.getId(), orderId, agent);
+            OrderBackQueryRpcVO orderBackQueryRpcVO = ttAppBackRpc.orderBackQuery(orderQuery).getData();
+            //传过来的金额是分, 头条媒体SDK需要换算成元, 存在小数直接舍弃
+            if (Objects.equals(orderBackQueryRpcVO.getDoBack(), Boolean.TRUE)) {
+                amount = orderBackQueryRpcVO.getBackMoney().stream().map(money -> money / 100).collect(Collectors.toList());
+            }
+            doBack = orderBackQueryRpcVO.getDoBack();
+            backMsg = orderBackQueryRpcVO.getBackMsg();
+        }
+        //腾讯小游戏媒体SDK回传
+        if (Objects.equals(agent.getAccountType(), AccountTypeEnum.TENCENT_MINI_GAME.getValue())) {
+            TencentMiniGameOrderBackQueryRpcDTO orderQuery = this.transform(user.getOpenId(), orderId, agent);
+            OrderBackQueryRpcVO orderBackQueryRpcVO = tencentMiniGameBackRpc.orderBackQuery(orderQuery).getData();
+            if (Objects.equals(orderBackQueryRpcVO.getDoBack(), Boolean.TRUE)) {
+                amount = orderBackQueryRpcVO.getBackMoney();
+            }
+            doBack = orderBackQueryRpcVO.getDoBack();
+            backMsg = orderBackQueryRpcVO.getBackMsg();
+        }
+        return Tuple3.with(doBack, amount, Strings.isBlank(backMsg) ? "未知的渠道投放类型" : backMsg);
+    }
+
     @Override
     public boolean addMediaSdkBackLog(BackLogMediaSdkParam param, UserData userData) {
-        return super.save(this.transform(param, userData));
+        GameBackLogMediaSdk gameBackLogMediaSdk = this.transform(param, userData);
+        Map<String, Object> callBackJudgeResult = param.getCallBackJudgeResult();
+        //回传判断结果参数不为空
+        if (!callBackJudgeResult.isEmpty()) {
+            if (callBackJudgeResult.containsKey("roleId")) {
+                gameBackLogMediaSdk.setRoleId(String.valueOf(callBackJudgeResult.get("roleId")));
+            }
+            if (callBackJudgeResult.containsKey("orderId")) {
+                gameBackLogMediaSdk.setOrderId(String.valueOf(callBackJudgeResult.get("orderId")));
+            }
+        }
+        return super.save(gameBackLogMediaSdk);
     }
 
     private GameBackLogMediaSdk transform(BackLogMediaSdkParam param, UserData userData) {
@@ -236,8 +326,13 @@ public class GameBackLogMediaSdkServiceImpl extends ServiceImpl<GameBackLogMedia
                 .agentKey(agent.getAgentKey())
                 .build();
     }
-}
-
-
-
 
+    private TencentMiniGameOrderBackQueryRpcDTO transform(String wechatOpenid, String orderId, Agent agent) {
+        return TencentMiniGameOrderBackQueryRpcDTO.builder()
+                .gameId(agent.getGameId())
+                .wechatOpenid(wechatOpenid)
+                .orderId(orderId)
+                .agentKey(agent.getAgentKey())
+                .build();
+    }
+}