diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3151277 --- /dev/null +++ b/.gitignore @@ -0,0 +1,49 @@ +###################################################################### +# Build Tools + +.gradle +/build/ +!gradle/wrapper/gradle-wrapper.jar + +target/ +!.mvn/wrapper/maven-wrapper.jar + +###################################################################### +# IDE + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### JRebel ### +rebel.xml + +### NetBeans ### +nbproject/private/ +build/* +nbbuild/ +dist/ +nbdist/ +.nb-gradle/ + +###################################################################### +# Others +*.log +*.xml.versionsBackup +*.swp + +!*/build/*.java +!*/build/*.html +!*/build/*.xml +logs/ +.idea/ \ No newline at end of file diff --git a/ff-base/src/main/java/com/ff/base/constant/CacheConstants.java b/ff-base/src/main/java/com/ff/base/constant/CacheConstants.java index 676af5f..01d8620 100644 --- a/ff-base/src/main/java/com/ff/base/constant/CacheConstants.java +++ b/ff-base/src/main/java/com/ff/base/constant/CacheConstants.java @@ -5,8 +5,7 @@ package com.ff.base.constant; * * @author ff */ -public class CacheConstants -{ +public class CacheConstants { /** * 登录用户 redis key */ @@ -45,43 +44,103 @@ public class CacheConstants /** * jili 游戏 */ - public static final String JILI_GAMES= "jili_games:"; + public static final String JILI_GAMES = "jili_games:"; /** * xk 游戏 */ - public static final String XK_GAMES= "xk_games:"; + public static final String XK_GAMES = "xk_games:"; + + /** + * ae游戏 + */ + public static final String AE_GAMES = "ae_games:"; + /** + * km游戏 + */ + public static final String KM_GAMES = "km_games:"; + /** * pgx游戏 */ - public static final String PGX_GAMES= "pgx_games:"; + public static final String PGX_GAMES = "pgx_games:"; /** * pg游戏 */ - public static final String PG_GAMES= "pg_games:"; + public static final String PG_GAMES = "pg_games:"; + + /** + * pgt游戏 + */ + public static final String PGT_GAMES = "pgt_games:"; /** * fc游戏 */ - public static final String FC_GAMES= "fc_games:"; + public static final String FC_GAMES = "fc_games:"; /** * sa游戏 */ - public static final String SA_GAMES= "sa_games:"; + public static final String SA_GAMES = "sa_games:"; /** * dg游戏 */ - public static final String DG_GAMES= "dg_games:"; + public static final String DG_GAMES = "dg_games:"; + /** + * fb体育 + */ + public static final String FB_Sports = "fp_sports:"; + + /** + * db体育 + */ + public static final String DB_Sports = "db_sports:"; /** * pg游戏投注货币 */ - public static final String PG_GAMES_BET_CURRENCY= "pg_games:bet:currency"; + public static final String PG_GAMES_BET_CURRENCY = "pg_games:bet:currency"; + + + /** + * pgt下一个id + */ + public static final String PGT_NEXT_ID = "pgt_next:id:"; + + /** + * ae时间从 + */ + public static final String AE_TIME_FROM= "ae:time:from"; + + /** + * 美天棋牌游戏 + */ + public static final String MeiTian_GAMES = "meitian_games:"; + + + public static final String Platform = "platform:"; + + /** + * km用户令牌 + */ + public static final String KM_USER_TOKEN = "km:user:token:"; + + + /** + * ae时间从 + */ + public static final String SV388_TIME_FROM= "sv388:time:from"; + + public static final String SV388_GAMES = "sv388_games:"; } + + + + diff --git a/ff-base/src/main/java/com/ff/base/constant/Constants.java b/ff-base/src/main/java/com/ff/base/constant/Constants.java index bb32cc1..cc76992 100644 --- a/ff-base/src/main/java/com/ff/base/constant/Constants.java +++ b/ff-base/src/main/java/com/ff/base/constant/Constants.java @@ -178,51 +178,6 @@ public class Constants { */ public static final String PASS_PREFIX = "FF_"; - /** - * jili 接口请求前缀 - */ - public static final String JILI_API_BASE_URL = "jili.api.base.url"; - - /** - * ng 接口请求前缀 - */ - public static final String NG_API_BASE_URL = "ng.api.base.url"; - - /** - * fc-api基本url - */ - public static final String FC_API_BASE_URL = "fc.api.base.url"; - - /** - * 吉利测试地址 - */ - public static final String JILI_GAME_DOME = "jili.game.dome"; - - /** - * xk 接口请求前缀 - */ - public static final String XK_API_BASE_URL = "xk.api.base.url"; - - /** - * pt-api基本url - */ - public static final String PT_API_BASE_URL = "pt.api.base.url"; - - /** - * pgx-api基本url - */ - public static final String PGX_API_BASE_URL = "gpx.api.base.url"; - - /** - * dg-api基本url - */ - public static final String DG_API_BASE_URL = "dg.api.base.url"; - - - /** - * sa-api基本url - */ - public static final String SA_API_BASE_URL = "sa.api.base.url"; /** * 服务 @@ -235,15 +190,12 @@ public class Constants { public static final String SYSTEM = "system"; - - /** * 主 数据源 */ public static final String DATA_SOURCE = "master"; - /** * 租户id */ @@ -297,5 +249,5 @@ public class Constants { /** * 一百 */ - public static final BigDecimal HUNDRED =new BigDecimal("100") ; + public static final BigDecimal HUNDRED = new BigDecimal("100"); } diff --git a/ff-base/src/main/java/com/ff/base/enums/ErrorCode.java b/ff-base/src/main/java/com/ff/base/enums/ErrorCode.java index b4c841e..a2df09e 100644 --- a/ff-base/src/main/java/com/ff/base/enums/ErrorCode.java +++ b/ff-base/src/main/java/com/ff/base/enums/ErrorCode.java @@ -13,15 +13,15 @@ import java.util.stream.Stream; */ @Getter public enum ErrorCode { - ERROR(500, "系统业务异常"), + ERROR(500, "业务异常"), GAME_ACCOUNT_CREATION_FAILED(1001, "当前游戏账号已存在"), ACCOUNT_NOT_EXIST(1002, "当前游戏账号不存在"), PLATFORM_NOT_EXIST(1003, "游戏平台不存在"), CURRENCY_NOT_EXIST(1004, "游戏平台不支持的货币"), GAME_NOT_EXIST(1005, "游戏不存在"), CURRENCY_EXCHANGE(1006, "不支持币种的汇率"), - FREQUENT_INTERFACE_REQUESTS (1007, "接口请求频繁"), - BALANCE_TRANSFER_FAILED (1008, "余额转移失败"), + FREQUENT_INTERFACE_REQUESTS(1007, "接口请求频繁"), + BALANCE_TRANSFER_FAILED(1008, "余额转移失败"), LANG_NOT_EXIST(1009, "游戏平台不支持的语言"), ORDER_NOT_EXIST(1010, "订单不存在"), PLAYERS_ARE_PLAYING(1011, "玩家游玩中"), @@ -30,6 +30,14 @@ public enum ErrorCode { ACCOUNT_NOT_ONLINE(1014, "账号不在线"), FREQUENT_BALANCE_TRANSFER(1015, "当前游戏账号余额转移频繁"), PLATFORM_NOT_METHODS(1016, "游戏平台不支持的方法"), + Create_Member_Failure(1017, "创建会员失败"), + Transfer_In_Failure(1018, "转入失败"), + Transfer_Out_Failure(1019, "转出失败"), + Get_Member_Info_Failure(1020, "获取会员信息失败"), + Transfer_Not_Exist(1021, "转帐操作不存在"), + Get_Url_Failure(1022, "获取URL失败"), + Miss_Config(1023, "缺少配置"), + DUPLICATE_ORDER_ID (1024, "重复的订单id"), ; // 获取错误码 diff --git a/ff-base/src/main/java/com/ff/base/enums/FBSportsType.java b/ff-base/src/main/java/com/ff/base/enums/FBSportsType.java new file mode 100644 index 0000000..f3fff75 --- /dev/null +++ b/ff-base/src/main/java/com/ff/base/enums/FBSportsType.java @@ -0,0 +1,60 @@ +package com.ff.base.enums; + + +import lombok.Getter; + +import java.util.Optional; +import java.util.stream.Stream; + + +/** + * xkgame类型 + * + * @author shi + * @date 2024/11/13 + */ +@Getter +public enum FBSportsType { + + Sports("8", 8,"FB体育"), + ; + + private final String code; + private final Integer systemCode; + private final String info; + FBSportsType(String code, Integer systemCode, String info) + { + this.code = code; + this.systemCode = systemCode; + this.info = info; + } + + + /** + * 按代码查找系统 + * + * @param code 代码 + * @return {@link String } + */ + public static Integer findSystemByCode(String code) { + Optional system = Stream.of(FBSportsType.values()) + .filter(gameType -> gameType.getCode().equals(code)) + .map(FBSportsType::getSystemCode) + .findFirst(); + return system.orElse(null); + } + + /** + * 按代码查找信息 + * + * @param code 代码 + * @return {@link String } + */ + public static String findInfoByCode(String code) { + Optional system = Stream.of(FBSportsType.values()) + .filter(gameType -> gameType.getCode().equals(code)) + .map(FBSportsType::getInfo) + .findFirst(); + return system.orElse(null); + } +} diff --git a/ff-base/src/main/java/com/ff/base/enums/GameExchangeStep.java b/ff-base/src/main/java/com/ff/base/enums/GameExchangeStep.java new file mode 100644 index 0000000..31257c4 --- /dev/null +++ b/ff-base/src/main/java/com/ff/base/enums/GameExchangeStep.java @@ -0,0 +1,34 @@ +package com.ff.base.enums; + + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.Getter; + +/** + * 游戏交换步骤 + * + * @author shi + * @date 2025/04/08 + */ +@Getter +@AllArgsConstructor +public enum GameExchangeStep { + CREATE_ORDER(1, "创建订单"), + DEDUCT_BALANCE(2, "转入提前扣租户余额"), + PLATFORM_TRANSACTION(3, "平台交易成功"), + TENANT_QUOTA_DEDUCTED(4, "转出租户额度增加成功"); + + private final Integer code; + private final String description; + + // 根据 code 获取对应的枚举 + public static GameExchangeStep getByCode(int code) { + for (GameExchangeStep step : GameExchangeStep.values()) { + if (step.getCode() == code) { + return step; + } + } + return null; + } +} diff --git a/ff-base/src/main/java/com/ff/base/enums/GameExchangeStepStatus.java b/ff-base/src/main/java/com/ff/base/enums/GameExchangeStepStatus.java new file mode 100644 index 0000000..fd70790 --- /dev/null +++ b/ff-base/src/main/java/com/ff/base/enums/GameExchangeStepStatus.java @@ -0,0 +1,21 @@ +package com.ff.base.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 游戏交换步骤状态 + * + * @author shi + * @date 2025/04/08 + */ +@Getter +@AllArgsConstructor +public enum GameExchangeStepStatus { + IN_PROGRESS(0, "进行中"), + SUCCESS(1, "成功"), + FAILURE(2, "失败"); + + private final int code; + private final String description; +} diff --git a/ff-base/src/main/java/com/ff/base/enums/GamePlatforms.java b/ff-base/src/main/java/com/ff/base/enums/GamePlatforms.java index 6ad30a8..b231529 100644 --- a/ff-base/src/main/java/com/ff/base/enums/GamePlatforms.java +++ b/ff-base/src/main/java/com/ff/base/enums/GamePlatforms.java @@ -1,5 +1,7 @@ package com.ff.base.enums; +import com.ff.base.exception.base.ApiException; + import java.util.ArrayList; import java.util.List; @@ -11,22 +13,41 @@ public enum GamePlatforms { FC("FC", "FC"), SA("SA", "SA"), DG("DG", "DG"), + MT("MT", "美天棋牌"), + AE("AE", "AE"), + KM("KM", "KM"), + PGT("PGT", "PGT"), + FBSports("FBSports", "FB体育"), + SV388("SV388", "SV388真人"), + DBSports("DBSports", "DB体育"), PT("PT", "PT"), ; private final String code; private final String info; - GamePlatforms(String code, String info) - { + GamePlatforms(String code, String info) { this.code = code; this.info = info; } + /** + * 通过代码获取 + * + * @param code 代码 + * @return {@link GamePlatforms } + */ + public static GamePlatforms getByCode(String code) { + for (GamePlatforms platform : GamePlatforms.values()) { + if (platform.getCode().equals(code)) { + return platform; + } + } + throw new ApiException(ErrorCode.PLATFORM_NOT_EXIST.getCode()); + } - public static List getCodes() - { - List result=new ArrayList<>(); + public static List getCodes() { + List result = new ArrayList<>(); GamePlatforms[] values = GamePlatforms.values(); for (GamePlatforms value : values) { result.add(value.getCode()); @@ -34,13 +55,11 @@ public enum GamePlatforms { return result; } - public String getCode() - { + public String getCode() { return code; } - public String getInfo() - { + public String getInfo() { return info; } diff --git a/ff-base/src/main/java/com/ff/base/enums/KMGameType.java b/ff-base/src/main/java/com/ff/base/enums/KMGameType.java new file mode 100644 index 0000000..460795c --- /dev/null +++ b/ff-base/src/main/java/com/ff/base/enums/KMGameType.java @@ -0,0 +1,70 @@ +package com.ff.base.enums; + + +import java.util.Optional; +import java.util.stream.Stream; + + +/** + * xkgame类型 + * + * @author shi + * @date 2024/11/13 + */ +public enum KMGameType { + + ELECTRON("KMQM", 1,"电子") + + ; + + private final String code; + private final Integer systemCode; + private final String info; + KMGameType(String code, Integer systemCode, String info) + { + this.code = code; + this.systemCode = systemCode; + this.info = info; + } + + public String getCode() + { + return code; + } + + public Integer getSystemCode() + { + return systemCode; + } + public String getInfo() + { + return info; + } + /** + * 按代码查找系统 + * + * @param code 代码 + * @return {@link String } + */ + public static Integer findSystemByCode(String code) { + Optional system = Stream.of(KMGameType.values()) + .filter(gameType -> gameType.getCode().equals(code)) + .map(KMGameType::getSystemCode) + .findFirst(); + return system.orElse(null); + } + + /** + * 按代码查找信息 + * + * @param code 代码 + * @return {@link String } + */ + public static String findInfoByCode(String code) { + Optional system = Stream.of(KMGameType.values()) + .filter(gameType -> gameType.getCode().equals(code)) + .map(KMGameType::getInfo) + .findFirst(); + return system.orElse(null); + } +} diff --git a/ff-base/src/main/java/com/ff/base/enums/MeiTianGameType.java b/ff-base/src/main/java/com/ff/base/enums/MeiTianGameType.java new file mode 100644 index 0000000..ee7ada5 --- /dev/null +++ b/ff-base/src/main/java/com/ff/base/enums/MeiTianGameType.java @@ -0,0 +1,53 @@ +package com.ff.base.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.Optional; +import java.util.stream.Stream; + +/** + * @author cengy + */ +@Getter +@AllArgsConstructor +public enum MeiTianGameType { + ELECTRON(4, 1, "电子"), + CHESS(2, 2, "棋牌"), + GAME_HALL(0, 3, "游戏大厅"), + CATCH_FISH(3, 4, "捕鱼"), + bai_ren(1, 5,"百人场") + , + ; + private final Integer code; + private final Integer systemCode; + private final String info; + + /** + * 按代码查找系统 + * + * @param code 代码 + * @return {@link String } + */ + public static Integer findSystemByCode(Integer code) { + Optional system = Stream.of(MeiTianGameType.values()) + .filter(gameType -> gameType.getCode().equals(code)) + .map(MeiTianGameType::getSystemCode) + .findFirst(); + return system.orElse(null); + } + + /** + * 按代码查找信息 + * + * @param code 代码 + * @return {@link String } + */ + public static String findInfoByCode(Integer code) { + Optional system = Stream.of(MeiTianGameType.values()) + .filter(gameType -> gameType.getCode().equals(code)) + .map(MeiTianGameType::getInfo) + .findFirst(); + return system.orElse(null); + } +} diff --git a/ff-base/src/main/java/com/ff/base/enums/PGTBetStatus.java b/ff-base/src/main/java/com/ff/base/enums/PGTBetStatus.java new file mode 100644 index 0000000..f5537c2 --- /dev/null +++ b/ff-base/src/main/java/com/ff/base/enums/PGTBetStatus.java @@ -0,0 +1,24 @@ +package com.ff.base.enums; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.Getter; + +/** + * 完成 + * + * @author shi + * @date 2025/04/07 + */ +@Getter +@AllArgsConstructor +public enum PGTBetStatus { + OPEN(1, "打开 或 未结算", "OPEN"), + SETTLED(2, "已结算", "SETTLED"), + UNSETTLED(1, "未结算", "UNSETTLED"), + VOID(3, "作废 或 无效", "VOID"); + + private final int code; + private final String description; + private final String type; +} diff --git a/ff-base/src/main/java/com/ff/base/enums/PGTGameType.java b/ff-base/src/main/java/com/ff/base/enums/PGTGameType.java new file mode 100644 index 0000000..94ebdb1 --- /dev/null +++ b/ff-base/src/main/java/com/ff/base/enums/PGTGameType.java @@ -0,0 +1,43 @@ +package com.ff.base.enums; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.Getter; + +import java.util.Optional; +import java.util.stream.Stream; + +/** + * pgt名称类型 + * + * @author shi + * @date 2025/04/07 + */ +@Getter +@AllArgsConstructor +public enum PGTGameType { + EGAMES("EGAMES",1, "游戏老虎机"), + LIVECASINO("LIVECASINO",2, "现场赌场"), + SPORT("SPORT",8, "体育"), + POKER("POKER",2, "扑克"), + TRADING("TRADING",1, "贸易"); + + // 枚举字段 + private final String code; + private final Integer systemCode; + private final String description; + + /** + * 按代码查找系统 + * + * @param code 代码 + * @return {@link Integer } + */ + public static Integer findSystemByCode(String code) { + Optional system = Stream.of(PGTGameType.values()) + .filter(gameType -> gameType.getCode().equals(code)) + .map(PGTGameType::getSystemCode) + .findFirst(); + return system.orElse(null); + } +} diff --git a/ff-base/src/main/java/com/ff/base/enums/PGTPayoutStatus.java b/ff-base/src/main/java/com/ff/base/enums/PGTPayoutStatus.java new file mode 100644 index 0000000..7c62692 --- /dev/null +++ b/ff-base/src/main/java/com/ff/base/enums/PGTPayoutStatus.java @@ -0,0 +1,35 @@ +package com.ff.base.enums; + +import com.dtflys.forest.annotation.Get; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.Getter; + +/** + * pgtplayout状态 + * + * @author shi + * @date 2025/04/07 + */ +@Getter +@AllArgsConstructor +public enum PGTPayoutStatus { + + LOSE("LOSE", 2, "输"), + WIN("WIN",1, "赢"), + DRAW("DRAW",3, "平"), + UNKNOWN("UNKNOWN",4, "未知"); + + private final String code; + private final Integer systemCode; + private final String description; + + public static PGTPayoutStatus getByCode(String code) { + for (PGTPayoutStatus status : PGTPayoutStatus.values()) { + if (status.getCode().equals(code)) { + return status; + } + } + return UNKNOWN; + } +} diff --git a/ff-base/src/main/java/com/ff/base/enums/PlatformType.java b/ff-base/src/main/java/com/ff/base/enums/PlatformType.java index 272c646..530d9e6 100644 --- a/ff-base/src/main/java/com/ff/base/enums/PlatformType.java +++ b/ff-base/src/main/java/com/ff/base/enums/PlatformType.java @@ -18,10 +18,11 @@ public enum PlatformType { GAME_HALL(3, "游戏大厅"), FISHING(4, "捕鱼"), BETTING_MACHINE(5, "押分机 (含宾果)"), - VIDEO(6, "视讯"), + VIDEO(6, "真人视讯"), LOTTERY(7, "彩票"), SPORTS(8, "体育"), - HUNTING(9, "捕猎"); + HUNTING(9, "捕猎"), + BaiRen(10, "百人场"); private final int code; private final String name; diff --git a/ff-base/src/main/java/com/ff/base/enums/TimeOutType.java b/ff-base/src/main/java/com/ff/base/enums/TimeOutType.java new file mode 100644 index 0000000..d1ea786 --- /dev/null +++ b/ff-base/src/main/java/com/ff/base/enums/TimeOutType.java @@ -0,0 +1,25 @@ +package com.ff.base.enums; + +import com.alibaba.druid.filter.AutoLoad; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 超时类型 + * + * @author shi + * @date 2025/04/09 + */ +@AllArgsConstructor +@Getter +public enum TimeOutType { + GAME_EXCHANGE_MONEY("gameExchangeMoney", "游戏余额转移"); + /** + * 代码 + */ + private final String code; + /** + * 信息 + */ + private final String info; +} diff --git a/ff-base/src/main/java/com/ff/base/enums/TransferType.java b/ff-base/src/main/java/com/ff/base/enums/TransferType.java index 6ebbfac..8d110ab 100644 --- a/ff-base/src/main/java/com/ff/base/enums/TransferType.java +++ b/ff-base/src/main/java/com/ff/base/enums/TransferType.java @@ -9,7 +9,8 @@ package com.ff.base.enums; */ public enum TransferType { ALL(1, "从游戏商转移额度到平台商(不看amount值,全部转出"), - GAMES(2, "从平台商转移额度到游戏商"); + GAMES(2, "从平台商转移额度到游戏商"), + ; private final Integer code; private final String info; diff --git a/ff-base/src/main/java/com/ff/base/enums/TriggerType.java b/ff-base/src/main/java/com/ff/base/enums/TriggerType.java new file mode 100644 index 0000000..86edf54 --- /dev/null +++ b/ff-base/src/main/java/com/ff/base/enums/TriggerType.java @@ -0,0 +1,21 @@ +package com.ff.base.enums; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.Getter; + +/** + * 触发类型 + * + * @author shi + * @date 2025/04/09 + */ +@Getter +@AllArgsConstructor +public enum TriggerType { + MANUAL(1, "用户调用手动触发"), + TIMER(2, "定时器触发"); + + private final int code; + private final String description; +} diff --git a/ff-base/src/main/java/com/ff/base/handler/JsonHandler.java b/ff-base/src/main/java/com/ff/base/handler/JsonHandler.java new file mode 100644 index 0000000..df3da7b --- /dev/null +++ b/ff-base/src/main/java/com/ff/base/handler/JsonHandler.java @@ -0,0 +1,59 @@ +package com.ff.base.handler; + +import com.alibaba.fastjson2.JSON; +import org.apache.ibatis.type.BaseTypeHandler; +import org.apache.ibatis.type.JdbcType; + +import java.sql.CallableStatement; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; + +/** + * mybatis json字段转换 + * + * @author cengy + */ +public class JsonHandler extends BaseTypeHandler { + private final Class type; + + + public JsonHandler(Class type) { + if (type == null) { + throw new IllegalArgumentException("Type argument cannot be null"); + } + this.type = type; + } + + @Override + public void setNonNullParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException { + ps.setString(i, JSON.toJSONString(parameter)); + } + + @Override + public T getNullableResult(ResultSet rs, String columnName) throws SQLException { + String json = rs.getString(columnName); + if (json != null) { + return JSON.parseObject(json, type); + } + return null; + } + + @Override + public T getNullableResult(ResultSet rs, int columnIndex) throws SQLException { + String json = rs.getString(columnIndex); + if (json != null) { + return JSON.parseObject(json, type); + } + return null; + } + + @Override + public T getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { + String json = cs.getString(columnIndex); + if (json != null) { + return JSON.parseObject(json, type); + } + return null; + } +} diff --git a/ff-base/src/main/java/com/ff/base/handler/JsonListHandler.java b/ff-base/src/main/java/com/ff/base/handler/JsonListHandler.java new file mode 100644 index 0000000..da2d651 --- /dev/null +++ b/ff-base/src/main/java/com/ff/base/handler/JsonListHandler.java @@ -0,0 +1,64 @@ +package com.ff.base.handler; + +import com.alibaba.fastjson2.JSON; +import org.apache.ibatis.type.BaseTypeHandler; +import org.apache.ibatis.type.JdbcType; + +import java.sql.CallableStatement; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.List; + +/** + * mybatis json字段转换 + * + * @author cengy + */ +public class JsonListHandler extends BaseTypeHandler> { + private final Class type; + + public JsonListHandler(Class type) { + if (type == null) { + throw new IllegalArgumentException("Type argument cannot be null"); + } + this.type = type; + } + + @Override + public void setNonNullParameter(PreparedStatement ps, int i, List parameter, JdbcType jdbcType) throws SQLException { + // Convert the List to JSON string + String json = JSON.toJSONString(parameter); + ps.setString(i, json); + + } + + @Override + public List getNullableResult(ResultSet rs, String columnName) throws SQLException { + + String json = rs.getString(columnName); + if (json == null) { + return null; + } + return JSON.parseArray(json, type); + } + + @Override + public List getNullableResult(ResultSet rs, int columnIndex) throws SQLException { + String json = rs.getString(columnIndex); + if (json == null) { + return null; + } + return JSON.parseArray(json, type); + + } + + @Override + public List getNullableResult(CallableStatement cs, int columnIndex) throws SQLException { + String json = cs.getString(columnIndex); + if (json == null) { + return null; + } + return JSON.parseArray(json, type); + } +} diff --git a/ff-base/src/main/java/com/ff/base/manager/AsyncManager.java b/ff-base/src/main/java/com/ff/base/manager/AsyncManager.java index 4e2458f..c68be3c 100644 --- a/ff-base/src/main/java/com/ff/base/manager/AsyncManager.java +++ b/ff-base/src/main/java/com/ff/base/manager/AsyncManager.java @@ -2,11 +2,12 @@ package com.ff.base.manager; import com.ff.base.utils.Threads; import com.ff.base.utils.spring.SpringUtils; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +import java.util.ArrayList; +import java.util.List; import java.util.TimerTask; -import java.util.concurrent.Callable; -import java.util.concurrent.Future; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; +import java.util.concurrent.*; /** * 异步任务管理器 @@ -24,10 +25,33 @@ public class AsyncManager { */ private ScheduledExecutorService executor = SpringUtils.getBean("scheduledExecutorService"); + + /** + * 顺序执行线程池 + */ + private List orderedExecutor = new ArrayList<>(); + /** + * 最大线程数 + */ + public static final int MAX_THREAD_COUNT = 16; + + /** + * 线程池 + */ + private ThreadPoolTaskExecutor taskExecutor; + + + /** * 单例模式 */ private AsyncManager() { + for (int i = 0; i < MAX_THREAD_COUNT; i++) { + orderedExecutor.add(Executors.newSingleThreadExecutor()); + } + executor = SpringUtils.getBean("scheduledExecutorService"); + taskExecutor = SpringUtils.getBean("threadPoolTaskExecutor"); + } private static AsyncManager me = new AsyncManager(); @@ -36,6 +60,22 @@ public class AsyncManager { return me; } + + + + public void executeOrdered(String key, Runnable task) { + + if (null == key || key.isEmpty()) { + taskExecutor.execute(task); + return; + } + + int hash = key.hashCode(); + int index = Math.abs(hash % MAX_THREAD_COUNT); + orderedExecutor.get(index).execute(task); + } + + /** * 执行任务 * diff --git a/ff-base/src/main/java/com/ff/base/system/service/ISysConfigService.java b/ff-base/src/main/java/com/ff/base/system/service/ISysConfigService.java index 36cb477..46ba6c6 100644 --- a/ff-base/src/main/java/com/ff/base/system/service/ISysConfigService.java +++ b/ff-base/src/main/java/com/ff/base/system/service/ISysConfigService.java @@ -11,6 +11,8 @@ import java.util.List; */ public interface ISysConfigService { + + SysConfig getByConfigKey(String configKey); /** * 查询参数配置信息 * diff --git a/ff-base/src/main/java/com/ff/base/system/service/impl/SysConfigServiceImpl.java b/ff-base/src/main/java/com/ff/base/system/service/impl/SysConfigServiceImpl.java index db717dc..b3b5b1b 100644 --- a/ff-base/src/main/java/com/ff/base/system/service/impl/SysConfigServiceImpl.java +++ b/ff-base/src/main/java/com/ff/base/system/service/impl/SysConfigServiceImpl.java @@ -32,6 +32,12 @@ public class SysConfigServiceImpl implements ISysConfigService { @Autowired private RedisCache redisCache; + @Override + public SysConfig getByConfigKey(String configKey) { + SysConfig config = new SysConfig(); + config.setConfigKey(configKey); + return configMapper.selectConfig(config); + } /** * 查询参数配置信息 diff --git a/ff-base/src/main/java/com/ff/base/utils/DateUtils.java b/ff-base/src/main/java/com/ff/base/utils/DateUtils.java index 49e7441..a473e18 100644 --- a/ff-base/src/main/java/com/ff/base/utils/DateUtils.java +++ b/ff-base/src/main/java/com/ff/base/utils/DateUtils.java @@ -38,6 +38,12 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils { public static String DAY_END_TIME = "23:59:59"; + public static final String ISO_8601_FORMAT = "yyyy-MM-dd'T'HH:mm:ss"; + + + public static final String ISO_8601_FORMAT_Z = "yyyy-MM-dd'T'HH:mm:ss'Z'"; + + /** * 获取当前Date型日期 * @@ -202,6 +208,28 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils { return zdt.format(formatter); } + /** + * 将时间戳转换为指定格式的时间字符串 + * + * @param timestamp 时间戳(毫秒) + * @param format 目标时间格式,例如:yyyy-MM-dd'T'HH:mm:ssXXX + * @param timeZone 时区,例如:GMT+8,UTC等 + * @return 格式化后的时间字符串 + */ + public static String convertTimestampToFormattedDate(long timestamp, String format, String timeZone) { + // 创建日期格式化对象 + SimpleDateFormat sdf = new SimpleDateFormat(format); + + // 设置时区为GMT+8 + sdf.setTimeZone(TimeZone.getTimeZone(timeZone)); + + // 转换为 Date 对象 + Date date = new Date(timestamp); + + // 返回格式化后的时间字符串 + return sdf.format(date); + } + /** * 将毫秒时间戳转换为指定时区的时间,并按指定格式输出 * @@ -222,7 +250,6 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils { } - /** * 增加 LocalDate ==> Date */ @@ -914,4 +941,38 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils { public static boolean isBetween(Long value, Long minValue, Long maxValue) { return value >= minValue && value <= maxValue; } + + /** + * 将日期字符串转换为指定时区的毫秒时间戳 + * + * @param dateString 日期字符串,格式为 "yyyy-MM-dd'T'HH:mm:ss.SSS" + * @param timezone 时区(如 UTC、Asia/Shanghai) + * @return 时区下的毫秒时间戳 + * @throws Exception 日期解析异常 + */ + public static long convertToMillisWithTimezone(String dateString, String timezone) { + try { + // 设置日期格式 + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS"); + + // 设置解析时使用的时区 + sdf.setTimeZone(TimeZone.getTimeZone(timezone)); + + // 解析日期字符串为 Date 对象 + Date date = sdf.parse(dateString); + + // 获取项目默认时区 + TimeZone defaultTimeZone = TimeZone.getDefault(); + + // 使用默认时区的 Calendar 计算 + Calendar calendar = Calendar.getInstance(defaultTimeZone); + calendar.setTime(date); + + // 返回该时区对应的毫秒时间戳 + return calendar.getTimeInMillis(); + } catch (Exception e) { + return 0; + } + + } } diff --git a/ff-base/src/main/java/com/ff/base/utils/JsonUtil.java b/ff-base/src/main/java/com/ff/base/utils/JsonUtil.java index f87c94e..b760170 100644 --- a/ff-base/src/main/java/com/ff/base/utils/JsonUtil.java +++ b/ff-base/src/main/java/com/ff/base/utils/JsonUtil.java @@ -108,7 +108,7 @@ public class JsonUtil { * * @param map 地图 * @return {@link String } - */// 将LinkedHashMap转换为查询字符串 + */ // 将LinkedHashMap转换为查询字符串 public static String mapToQueryString(Map map) { return map.entrySet().stream() .map(entry -> entry.getKey() + "=" + entry.getValue()) diff --git a/ff-base/src/main/java/com/ff/base/utils/NumberUtils.java b/ff-base/src/main/java/com/ff/base/utils/NumberUtils.java index bfc3134..0ea20e8 100644 --- a/ff-base/src/main/java/com/ff/base/utils/NumberUtils.java +++ b/ff-base/src/main/java/com/ff/base/utils/NumberUtils.java @@ -9,7 +9,6 @@ import java.util.concurrent.ThreadLocalRandom; public class NumberUtils { - /** * 计算比例 * @@ -68,17 +67,13 @@ public class NumberUtils { Random random = new Random(); StringBuilder sb = new StringBuilder(); - // 每位字符可以是字母(A-Z, a-z)或数字(0-9) - for (int i = 0; i - + org.springframework.boot diff --git a/ff-game/src/main/java/com/ff/api/controller/ApiGameController.java b/ff-game/src/main/java/com/ff/api/controller/ApiGameController.java index cfaa77b..f393575 100644 --- a/ff-game/src/main/java/com/ff/api/controller/ApiGameController.java +++ b/ff-game/src/main/java/com/ff/api/controller/ApiGameController.java @@ -1,7 +1,7 @@ package com.ff.api.controller; -import cn.hutool.core.util.NumberUtil; +import cn.hutool.core.util.IdUtil; import com.ff.annotation.CheckHeader; import com.ff.api.request.*; import com.ff.api.response.*; @@ -11,27 +11,29 @@ import com.ff.base.core.domain.AjaxResult; import com.ff.base.core.page.TableDataInfo; import com.ff.base.enums.*; import com.ff.base.exception.base.ApiException; -import com.ff.base.exception.base.BaseException; +import com.ff.base.manager.AsyncManager; +import com.ff.base.system.domain.TenantSecretKey; import com.ff.base.utils.StringUtils; import com.ff.base.utils.bean.BeanUtils; -import com.ff.base.system.domain.TenantSecretKey; import com.ff.common.dto.GameBalanceExchange; import com.ff.common.service.ITenantGameQuotaFlowService; import com.ff.common.service.ITenantGameQuotaService; import com.ff.config.KeyConfig; import com.ff.game.api.IGamesService; +import com.ff.game.api.exchange.StepProcessorFactory; +import com.ff.game.api.exchange.dto.GameExchangeDTO; import com.ff.game.api.request.*; import com.ff.game.domain.*; import com.ff.game.dto.GameBettingDetailsDTO; -import com.ff.game.dto.GameSecretKeyCurrencyDTO; -import com.ff.game.dto.GameSecretKeyLangDTO; import com.ff.game.service.*; import com.ff.member.domain.Member; import com.ff.member.service.IMemberService; import com.github.pagehelper.PageHelper; +import lombok.Data; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.http.ResponseEntity; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.Assert; @@ -42,13 +44,14 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.context.request.async.DeferredResult; import javax.annotation.Resource; import java.math.BigDecimal; -import java.util.*; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.Future; -import java.util.stream.Collectors; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; /** * api控制器 @@ -74,22 +77,12 @@ public class ApiGameController extends BaseController { @Resource private KeyConfig keyConfig; - @Resource - private IGameSecretKeyService gameSecretKeyService; - @Resource private IMemberService memberService; - @Resource - private IGamePlatformService gamePlatformService; - - @Resource private ITenantGameQuotaService tenantGameQuotaService; - @Resource - private ITenantGameQuotaFlowService tenantGameQuotaFlowService; - @Resource private IGameBettingDetailsService gameBettingDetailsService; @@ -98,17 +91,16 @@ public class ApiGameController extends BaseController { @Resource private IGameExchangeMoneyService gameExchangeMoneyService; - @Resource - private IGameSecretKeyCurrencyService gameSecretKeyCurrencyService; - - - @Resource - private IGameSecretKeyLangService gameSecretKeyLangService; - @Autowired @Qualifier("threadPoolTaskExecutor") private ThreadPoolTaskExecutor threadPoolTaskExecutor; + @Resource + private IPlatformService platformService; + + + @Resource + private StepProcessorFactory stepProcessorFactory; /** * 列表 @@ -118,11 +110,15 @@ public class ApiGameController extends BaseController { @PostMapping("/list") public AjaxResult list() { List gameResponses = gameService.selectGameResponseList(); - for (GameResponse gameRespons : gameResponses) { + for (GameResponse gameResponse : gameResponses) { + Platform platform = platformService.get(gameResponse.getPlatformCode()); + if (null == platform) { + continue; + } + + List currencyCode = new ArrayList<>(platform.getCurrencyInfo().keySet()); + gameResponse.setCurrencyCode(currencyCode); - List gameSecretKeyCurrencies = gameSecretKeyCurrencyService.findByGameSecretKeyCurrencyDTOList(GameSecretKeyCurrencyDTO.builder().platformCode(gameRespons.getPlatformCode()).build()); - List currencyCode = gameSecretKeyCurrencies.stream().map(GameSecretKeyCurrencyDTO::getSystemCurrency).collect(Collectors.toList()); - gameRespons.setCurrencyCode(currencyCode); } return AjaxResult.success(gameResponses); } @@ -131,49 +127,57 @@ public class ApiGameController extends BaseController { /** * 登录 * - * @param memberCreateApiRequest 成员创建api请求 + * @param loginRequest 登入游戏 * @return {@link AjaxResult } */ @PostMapping("/login") - public AjaxResult login(@Validated @RequestBody GameLoginRequest memberCreateApiRequest) { + public AjaxResult login(@Validated @RequestBody GameLoginRequest loginRequest) { - Game game = gameService.selectGameById(memberCreateApiRequest.getGameId()); + Game game = gameService.selectGameByGameId(loginRequest.getGameId()); ApiException.notNull(game, ErrorCode.GAME_NOT_EXIST.getCode()); - GamePlatform gamePlatform = gamePlatformService.selectGamePlatformById(game.getPlatformId()); - ApiException.notNull(gamePlatform, ErrorCode.PLATFORM_NOT_EXIST.getCode()); + Platform platform = platformService.get(game.getPlatformCode()); + ApiException.notNull(platform, ErrorCode.PLATFORM_NOT_EXIST.getCode()); + IGamesService iGamesService = gamesService.get(platform.getPlatformCode() + Constants.SERVICE); + ApiException.notNull(iGamesService, ErrorCode.PLATFORM_NOT_EXIST.getCode()); + + String targetCurrency = platform.getCurrencyInfo().get(loginRequest.getCurrencyCode()); + ApiException.notNull(targetCurrency, ErrorCode.CURRENCY_NOT_EXIST.getCode()); + + KeyInfo keyInfo = null; + for (KeyInfo keyData : platform.getKeyInfo()) { + if (StringUtils.isNotEmpty(loginRequest.getCurrencyCode())) { + if (keyData.getCurrency().equalsIgnoreCase(loginRequest.getCurrencyCode())) { + keyInfo = keyData; + break; + } + } + } + ApiException.notNull(keyInfo, ErrorCode.CURRENCY_NOT_EXIST.getCode()); + + String targetLang = platform.getLangInfo().get(loginRequest.getLangCode()); + ApiException.notNull(targetLang, ErrorCode.LANG_NOT_EXIST.getCode()); - IGamesService iGamesService = gamesService.get(gamePlatform.getPlatformCode() + Constants.SERVICE); - - - TenantSecretKey tenantSecretKey = keyConfig.get(); - GameSecretKeyCurrencyDTO secretKeyCurrencyDTO = gameSecretKeyCurrencyService.findByGameSecretKeyCurrencyDTO(GameSecretKeyCurrencyDTO.builder() - .platformCode(gamePlatform.getPlatformCode()) - .systemCurrency(memberCreateApiRequest.getCurrencyCode()).build()); - ApiException.notNull(secretKeyCurrencyDTO, ErrorCode.CURRENCY_NOT_EXIST.getCode()); - - GameSecretKeyLangDTO gameSecretKeyLangDTO = gameSecretKeyLangService.findGameSecretKeyLangDTO(GameSecretKeyLangDTO.builder() - .platformCode(gamePlatform.getPlatformCode()) - .systemLangCode(memberCreateApiRequest.getLangCode()) - .build()); - ApiException.notNull(gameSecretKeyLangDTO, ErrorCode.LANG_NOT_EXIST.getCode()); - - - Member member = memberService.selectMemberByAccount(memberCreateApiRequest.getAccount(), memberCreateApiRequest.getCurrencyCode(), gamePlatform.getPlatformCode()); + Member member = memberService.selectMemberByAccount(loginRequest.getAccount(), loginRequest.getCurrencyCode(), platform.getPlatformCode()); ApiException.notNull(member, ErrorCode.ACCOUNT_NOT_EXIST.getCode()); GamesLogin gamesLogin = GamesLogin.builder() - .agentId(secretKeyCurrencyDTO.getCode()) - .agentKey(secretKeyCurrencyDTO.getKey()) + .agentId(keyInfo.getCode()) + .agentKey(keyInfo.getKey()) .account(member.getGameAccount()) .gameType(game.getGameSourceType()) - .currency(secretKeyCurrencyDTO.getCurrency()) + .currency(/*secretKeyCurrencyDTO.getCurrency()*/targetCurrency) .gameId(game.getGameCode()) - .homeUrl(memberCreateApiRequest.getHomeUrl()) - .platform(memberCreateApiRequest.getPlatform()) - .disableFullScreen(memberCreateApiRequest.getDisableFullScreen()) - .lang(gameSecretKeyLangDTO.getLang()) + .homeUrl(loginRequest.getHomeUrl()) + .betLimit(loginRequest.getBetLimit()) + .platform(loginRequest.getPlatform()) + .disableFullScreen(loginRequest.getDisableFullScreen()) + .lang(/*gameSecretKeyLangDTO.getLang()*/ targetLang) + .vendor(platform) + .keyInfo(keyInfo) + .systemCurrency(loginRequest.getCurrencyCode()) + .build(); String login = iGamesService.loginWithoutRedirect(gamesLogin); @@ -189,53 +193,101 @@ public class ApiGameController extends BaseController { * @return {@link AjaxResult } */ @PostMapping("/exchange/balance") - @Transactional - public AjaxResult exchangeBalance(@Validated @RequestBody GameExchangeBalanceRequest gameExchangeBalanceRequest) { - + public DeferredResult exchangeBalance(@Validated @RequestBody GameExchangeBalanceRequest gameExchangeBalanceRequest) { IGamesService iGamesService = gamesService.get(gameExchangeBalanceRequest.getPlatformCode() + Constants.SERVICE); ApiException.notNull(iGamesService, ErrorCode.PLATFORM_NOT_EXIST.getCode()); TenantSecretKey tenantSecretKey = keyConfig.get(); - GameSecretKeyCurrencyDTO gameSecretKey = gameSecretKeyCurrencyService.findByGameSecretKeyCurrencyDTO(GameSecretKeyCurrencyDTO.builder() - .platformCode(gameExchangeBalanceRequest.getPlatformCode()) - .systemCurrency(gameExchangeBalanceRequest.getCurrencyCode()).build()); - ApiException.notNull(gameSecretKey, ErrorCode.CURRENCY_NOT_EXIST.getCode()); + Platform platform = platformService.get(gameExchangeBalanceRequest.getPlatformCode()); + ApiException.notNull(platform, ErrorCode.PLATFORM_NOT_EXIST.getCode()); - BigDecimal quota = tenantGameQuotaService.gameBalanceExchange(GameBalanceExchange.builder() - .platformCode(gameExchangeBalanceRequest.getPlatformCode()) - .sourceId(gameExchangeBalanceRequest.getOrderId()) - .currencyCode(gameExchangeBalanceRequest.getCurrencyCode()) - .transferType(gameExchangeBalanceRequest.getTransferType()) - .amount(gameExchangeBalanceRequest.getAmount()) - .account(gameExchangeBalanceRequest.getAccount()) - .tenantKey(tenantSecretKey.getTenantKey()) - .build()); + String targetCurrency = platform.getCurrencyInfo().get(gameExchangeBalanceRequest.getCurrencyCode()); + ApiException.notNull(targetCurrency, ErrorCode.CURRENCY_NOT_EXIST.getCode()); + + KeyInfo keyInfo = null; + for (KeyInfo keyData : platform.getKeyInfo()) { + if (StringUtils.isNotEmpty(gameExchangeBalanceRequest.getCurrencyCode())) { + if (keyData.getCurrency().equalsIgnoreCase(gameExchangeBalanceRequest.getCurrencyCode())) { + keyInfo = keyData; + break; + } + } + } + ApiException.notNull(keyInfo, ErrorCode.CURRENCY_NOT_EXIST.getCode()); // 获取用户信息 Member member = memberService.selectMemberByAccount(gameExchangeBalanceRequest.getAccount(), gameExchangeBalanceRequest.getCurrencyCode(), gameExchangeBalanceRequest.getPlatformCode()); ApiException.notNull(member, ErrorCode.ACCOUNT_NOT_EXIST.getCode()); + List gameExchangeMonies = gameExchangeMoneyService.selectGameExchangeMoneyList( + GameExchangeMoney.builder() + .tenantKey(tenantSecretKey.getTenantKey()) + .orderId(gameExchangeBalanceRequest.getOrderId()) + .build() + ); - //操作第三方额度接口 - ExchangeTransferMoneyRequestDTO exchangeTransferMoneyRequestDTO = ExchangeTransferMoneyRequestDTO.builder() - .agentId(gameSecretKey.getCode()) - .agentKey(gameSecretKey.getKey()) - .orderId(gameExchangeBalanceRequest.getOrderId()) - .account(member.getGameAccount()) - .currency(gameSecretKey.getCurrency()) + ApiException.isTrue(CollectionUtils.isEmpty(gameExchangeMonies), ErrorCode.DUPLICATE_ORDER_ID.getCode()); + + + Long gameExchangeMoneyId = IdUtil.getSnowflakeNextId(); + GameExchangeDTO exchangeMoney = GameExchangeDTO.builder() + .id(gameExchangeMoneyId) .tenantKey(tenantSecretKey.getTenantKey()) - .quota(quota) - .amount(gameExchangeBalanceRequest.getAmount()) - .transferType(gameExchangeBalanceRequest.getTransferType()) - .build(); - Long exchangeTransferId = iGamesService.exchangeTransferByAgentId(exchangeTransferMoneyRequestDTO); - GameExchangeMoney gameExchangeMoney = gameExchangeMoneyService.selectGameExchangeMoneyById(exchangeTransferId); - GameExchangeBalanceResponse gameExchangeBalanceResponse = new GameExchangeBalanceResponse(); - BeanUtils.copyProperties(gameExchangeMoney, gameExchangeBalanceResponse); - return AjaxResult.success(gameExchangeBalanceResponse); + .memberId(member.getId()) + .gameAccount(member.getGameAccount()) + .memberAccount(member.getMemberAccount()) + .exchangeType(gameExchangeBalanceRequest.getTransferType()) + .currencyCode(gameExchangeBalanceRequest.getCurrencyCode()) + .orderId(gameExchangeBalanceRequest.getOrderId()) + .balance(gameExchangeBalanceRequest.getAmount()) + .triggerType(TriggerType.MANUAL.getCode()) + .platformCode(gameExchangeBalanceRequest.getPlatformCode()).build(); + + + //转出设置转出金额为0 + if (TransferType.ALL.getCode().equals(gameExchangeBalanceRequest.getTransferType())){ + exchangeMoney.setBalance(BigDecimal.ZERO); + } + + + ExtInfo extInfo = platform.getExtInfo(); + Long timeout = 5000L; + if (extInfo != null) { + timeout = extInfo.getTimeout(TimeOutType.GAME_EXCHANGE_MONEY.getCode()); + } + + + DeferredResult output = new DeferredResult<>(timeout); + AsyncManager.me().executeOrdered( + exchangeMoney.getOrderId(), + () -> { + try { + stepProcessorFactory.getStepProcessor(GameExchangeStep.CREATE_ORDER).process(exchangeMoney); + + GameExchangeMoney gameExchangeMoney = gameExchangeMoneyService.selectGameExchangeMoneyById(gameExchangeMoneyId); + GameExchangeBalanceResponse gameExchangeBalanceResponse = new GameExchangeBalanceResponse(); + BeanUtils.copyProperties(gameExchangeMoney, gameExchangeBalanceResponse); + output.setResult(AjaxResult.success(gameExchangeBalanceResponse)); + + } catch (Exception e) { + log.error("ApiGameController [exchangeBalance] 余额转移失败 gameExchangeMoneyId {}", gameExchangeMoneyId,e); + stepProcessorFactory.getStepProcessor(GameExchangeStep.getByCode(exchangeMoney.getStep())).rollBack(exchangeMoney); + output.setErrorResult(AjaxResult.error(ErrorCode.BALANCE_TRANSFER_FAILED.getCode(), ErrorCode.BALANCE_TRANSFER_FAILED.getMessage())); + } + + } + ); + // 超时时间处理逻辑 + output.onTimeout(() -> { + GameExchangeMoney gameExchangeMoney = gameExchangeMoneyService.selectGameExchangeMoneyById(gameExchangeMoneyId); + GameExchangeBalanceResponse gameExchangeBalanceResponse = new GameExchangeBalanceResponse(); + BeanUtils.copyProperties(gameExchangeMoney, gameExchangeBalanceResponse); + output.setErrorResult(AjaxResult.success(gameExchangeBalanceResponse)); + }); + return output; } @@ -275,12 +327,22 @@ public class ApiGameController extends BaseController { ApiException.notNull(iGamesService, ErrorCode.PLATFORM_NOT_EXIST.getCode()); - TenantSecretKey tenantSecretKey = keyConfig.get(); - GameSecretKeyCurrencyDTO gameSecretKey = gameSecretKeyCurrencyService.findByGameSecretKeyCurrencyDTO(GameSecretKeyCurrencyDTO.builder() - .platformCode(gameCreateFreeSpinRequest.getPlatformCode()) - .systemCurrency(gameCreateFreeSpinRequest.getCurrencyCode()).build()); - ApiException.notNull(gameSecretKey, ErrorCode.CURRENCY_NOT_EXIST.getCode()); + Platform platform = platformService.get(gameCreateFreeSpinRequest.getPlatformCode()); + ApiException.notNull(platform, ErrorCode.PLATFORM_NOT_EXIST.getCode()); + String targetCurrency = platform.getCurrencyInfo().get(gameCreateFreeSpinRequest.getCurrencyCode()); + ApiException.notNull(targetCurrency, ErrorCode.CURRENCY_NOT_EXIST.getCode()); + + KeyInfo keyInfo = null; + for (KeyInfo keyData : platform.getKeyInfo()) { + if (StringUtils.isNotEmpty(gameCreateFreeSpinRequest.getCurrencyCode())) { + if (keyData.getCurrency().equalsIgnoreCase(gameCreateFreeSpinRequest.getCurrencyCode())) { + keyInfo = keyData; + break; + } + } + } + ApiException.notNull(keyInfo, ErrorCode.CURRENCY_NOT_EXIST.getCode()); Member member = memberService.selectMemberByAccount(gameCreateFreeSpinRequest.getAccount(), gameCreateFreeSpinRequest.getCurrencyCode(), gameCreateFreeSpinRequest.getPlatformCode()); ApiException.notNull(member, ErrorCode.ACCOUNT_NOT_EXIST.getCode()); @@ -288,15 +350,18 @@ public class ApiGameController extends BaseController { CreateFreeSpinRequestDTO createFreeSpinRequestDTO = CreateFreeSpinRequestDTO.builder() .account(member.getGameAccount()) - .currency(gameCreateFreeSpinRequest.getCurrencyCode()) - .agentId(gameSecretKey.getCode()) - .agentKey(gameSecretKey.getKey()) + .currency(/*gameCreateFreeSpinRequest.getCurrencyCode()*/targetCurrency) + .agentId(keyInfo.getCode()) + .agentKey(keyInfo.getKey()) .referenceId(gameCreateFreeSpinRequest.getReferenceId()) .freeSpinValidity(gameCreateFreeSpinRequest.getFreeSpinValidity()) .numberOfRounds(gameCreateFreeSpinRequest.getNumberOfRounds()) .gameIds(gameCreateFreeSpinRequest.getGameIds()) .betValue(gameCreateFreeSpinRequest.getBetValue()) .startTime(gameCreateFreeSpinRequest.getStartTime()) + .vendor(platform) + .keyInfo(keyInfo) + .systemCurrency(gameCreateFreeSpinRequest.getCurrencyCode()) .build(); @@ -349,32 +414,53 @@ public class ApiGameController extends BaseController { */ @PostMapping("/get/detail") public AjaxResult getDetail(@Validated @RequestBody GameGetDetailRequest gameGetDetailRequest) { + Platform platform = platformService.get(gameGetDetailRequest.getPlatformCode()); + ApiException.notNull(platform, ErrorCode.PLATFORM_NOT_EXIST.getCode()); + + String targetCurrency = platform.getCurrencyInfo().get(gameGetDetailRequest.getCurrencyCode()); + ApiException.notNull(targetCurrency, ErrorCode.CURRENCY_NOT_EXIST.getCode()); + + KeyInfo keyInfo = null; + for (KeyInfo keyData : platform.getKeyInfo()) { + if (StringUtils.isNotEmpty(gameGetDetailRequest.getCurrencyCode())) { + if (keyData.getCurrency().equalsIgnoreCase(gameGetDetailRequest.getCurrencyCode())) { + keyInfo = keyData; + break; + } + } + } + ApiException.notNull(keyInfo, ErrorCode.CURRENCY_NOT_EXIST.getCode()); + + String targetLang = platform.getLangInfo().get(gameGetDetailRequest.getLangCode()); + ApiException.notNull(targetLang, ErrorCode.LANG_NOT_EXIST.getCode()); + +// GameSecretKeyCurrencyDTO gameSecretKey = gameSecretKeyCurrencyService.findByGameSecretKeyCurrencyDTO(GameSecretKeyCurrencyDTO.builder() +// .platformCode(gameGetDetailRequest.getPlatformCode()) +// .systemCurrency(gameGetDetailRequest.getCurrencyCode()).build()); - GameSecretKeyCurrencyDTO gameSecretKey = gameSecretKeyCurrencyService.findByGameSecretKeyCurrencyDTO(GameSecretKeyCurrencyDTO.builder() - .platformCode(gameGetDetailRequest.getPlatformCode()) - .systemCurrency(gameGetDetailRequest.getCurrencyCode()).build()); - - - ApiException.notNull(gameSecretKey, ErrorCode.CURRENCY_NOT_EXIST.getCode()); +// ApiException.notNull(gameSecretKey, ErrorCode.CURRENCY_NOT_EXIST.getCode()); IGamesService iGamesService = gamesService.get(gameGetDetailRequest.getPlatformCode() + Constants.SERVICE); ApiException.notNull(iGamesService, ErrorCode.PLATFORM_NOT_EXIST.getCode()); - GameSecretKeyLangDTO gameSecretKeyLang = gameSecretKeyLangService.findGameSecretKeyLangDTO(GameSecretKeyLangDTO.builder() - .platformCode(gameGetDetailRequest.getPlatformCode()) - .systemLangCode(gameGetDetailRequest.getLangCode()) - .build()); - ApiException.notNull(gameSecretKeyLang, ErrorCode.LANG_NOT_EXIST.getCode()); +// GameSecretKeyLangDTO gameSecretKeyLang = gameSecretKeyLangService.findGameSecretKeyLangDTO(GameSecretKeyLangDTO.builder() +// .platformCode(gameGetDetailRequest.getPlatformCode()) +// .systemLangCode(gameGetDetailRequest.getLangCode()) +// .build()); +// ApiException.notNull(gameSecretKeyLang, ErrorCode.LANG_NOT_EXIST.getCode()); GetGameDetailResponseDTO gameDetail = iGamesService.getGameDetail(GetGameDetailRequestDTO.builder() .wagersId(gameGetDetailRequest.getWagersId()) - .lang(gameSecretKeyLang.getLang()) - .agentId(gameSecretKey.getCode()) - .agentKey(gameSecretKey.getKey()) + .lang(/*gameSecretKeyLang.getLang()*/targetLang) + .agentId(keyInfo.getCode()) + .agentKey(keyInfo.getKey()) + .vendor(platform) + .keyInfo(keyInfo) + .systemCurrency(gameGetDetailRequest.getCurrencyCode()) .build()); return AjaxResult.success(gameDetail); } @@ -387,45 +473,82 @@ public class ApiGameController extends BaseController { */ @PostMapping("/kick/member") public AjaxResult kickMember(@Validated @RequestBody GameKickMemeberRequest gameKickMemeberRequest) { - GameSecretKeyCurrencyDTO gameSecretKey = gameSecretKeyCurrencyService.findByGameSecretKeyCurrencyDTO(GameSecretKeyCurrencyDTO.builder() - .platformCode(gameKickMemeberRequest.getPlatformCode()) - .systemCurrency(gameKickMemeberRequest.getCurrencyCode()).build()); - ApiException.notNull(gameSecretKey, ErrorCode.CURRENCY_NOT_EXIST.getCode()); +// GameSecretKeyCurrencyDTO gameSecretKey = gameSecretKeyCurrencyService.findByGameSecretKeyCurrencyDTO(GameSecretKeyCurrencyDTO.builder() +// .platformCode(gameKickMemeberRequest.getPlatformCode()) +// .systemCurrency(gameKickMemeberRequest.getCurrencyCode()).build()); +// ApiException.notNull(gameSecretKey, ErrorCode.CURRENCY_NOT_EXIST.getCode()); + Platform platform = platformService.get(gameKickMemeberRequest.getPlatformCode()); + ApiException.notNull(platform, ErrorCode.PLATFORM_NOT_EXIST.getCode()); - Member member = memberService.selectMemberByAccount(gameKickMemeberRequest.getAccount(), gameKickMemeberRequest.getCurrencyCode(), gameKickMemeberRequest.getPlatformCode()); - ApiException.notNull(member, ErrorCode.ACCOUNT_NOT_EXIST.getCode()); + String targetCurrency = platform.getCurrencyInfo().get(gameKickMemeberRequest.getCurrencyCode()); + ApiException.notNull(targetCurrency, ErrorCode.CURRENCY_NOT_EXIST.getCode()); + + KeyInfo keyInfo = null; + for (KeyInfo keyData : platform.getKeyInfo()) { + if (StringUtils.isNotEmpty(gameKickMemeberRequest.getCurrencyCode())) { + if (keyData.getCurrency().equalsIgnoreCase(gameKickMemeberRequest.getCurrencyCode())) { + keyInfo = keyData; + break; + } + } + } + ApiException.notNull(keyInfo, ErrorCode.CURRENCY_NOT_EXIST.getCode()); IGamesService iGamesService = gamesService.get(gameKickMemeberRequest.getPlatformCode() + Constants.SERVICE); ApiException.notNull(iGamesService, ErrorCode.PLATFORM_NOT_EXIST.getCode()); + Member member = memberService.selectMemberByAccount(gameKickMemeberRequest.getAccount(), gameKickMemeberRequest.getCurrencyCode(), gameKickMemeberRequest.getPlatformCode()); + ApiException.notNull(member, ErrorCode.ACCOUNT_NOT_EXIST.getCode()); + return AjaxResult.success(iGamesService.kickMember(KickMemberRequestDTO.builder() .account(member.getGameAccount()) - .agentId(gameSecretKey.getCode()) - .currency(gameSecretKey.getCurrency()) - .agentKey(gameSecretKey.getKey()) + .agentId(keyInfo.getCode()) + .currency(targetCurrency) + .agentKey(keyInfo.getKey()) + .vendor(platform) + .keyInfo(keyInfo) + .systemCurrency(gameKickMemeberRequest.getCurrencyCode()) .build())); } @PostMapping("/kick/member/all") public AjaxResult kickMemberAll(@Validated @RequestBody GameKickMemeberAllRequest gameKickMemeberAllRequest) { - GameSecretKeyCurrencyDTO gameSecretKey = gameSecretKeyCurrencyService.findByGameSecretKeyCurrencyDTO(GameSecretKeyCurrencyDTO.builder() - .platformCode(gameKickMemeberAllRequest.getPlatformCode()) - .systemCurrency(gameKickMemeberAllRequest.getCurrencyCode()).build()); +// GameSecretKeyCurrencyDTO gameSecretKey = gameSecretKeyCurrencyService.findByGameSecretKeyCurrencyDTO(GameSecretKeyCurrencyDTO.builder() +// .platformCode(gameKickMemeberAllRequest.getPlatformCode()) +// .systemCurrency(gameKickMemeberAllRequest.getCurrencyCode()).build()); +// +// ApiException.notNull(gameSecretKey, ErrorCode.CURRENCY_NOT_EXIST.getCode()); + Platform platform = platformService.get(gameKickMemeberAllRequest.getPlatformCode()); + ApiException.notNull(platform, ErrorCode.PLATFORM_NOT_EXIST.getCode()); - ApiException.notNull(gameSecretKey, ErrorCode.CURRENCY_NOT_EXIST.getCode()); + String targetCurrency = platform.getCurrencyInfo().get(gameKickMemeberAllRequest.getCurrencyCode()); + ApiException.notNull(targetCurrency, ErrorCode.CURRENCY_NOT_EXIST.getCode()); + + KeyInfo keyInfo = null; + for (KeyInfo keyData : platform.getKeyInfo()) { + if (StringUtils.isNotEmpty(gameKickMemeberAllRequest.getCurrencyCode())) { + if (keyData.getCurrency().equalsIgnoreCase(gameKickMemeberAllRequest.getCurrencyCode())) { + keyInfo = keyData; + break; + } + } + } + ApiException.notNull(keyInfo, ErrorCode.CURRENCY_NOT_EXIST.getCode()); IGamesService iGamesService = gamesService.get(gameKickMemeberAllRequest.getPlatformCode() + Constants.SERVICE); ApiException.notNull(iGamesService, ErrorCode.PLATFORM_NOT_EXIST.getCode()); - KickMemberAllDTO kickMemberAllDTO = KickMemberAllDTO.builder() - .agentId(gameSecretKey.getCode()) - .agentKey(gameSecretKey.getKey()) - .currency(gameSecretKey.getCurrency()) + .agentId(keyInfo.getCode()) + .agentKey(keyInfo.getKey()) + .currency(/*gameSecretKey.getCurrency()*/targetCurrency) + .vendor(platform) + .keyInfo(keyInfo) + .systemCurrency(gameKickMemeberAllRequest.getCurrencyCode()) .build(); if (!ObjectUtils.isEmpty(gameKickMemeberAllRequest.getGameId())) { Game game = gameService.selectGameById(gameKickMemeberAllRequest.getGameId()); @@ -474,23 +597,43 @@ public class ApiGameController extends BaseController { /** * 取消自由旋转 * - * @param gameGetFreeSpinDashflowRequest 游戏获得免费旋转dashflow请求 + * @param request 游戏获得免费旋转dashflow请求 * @return {@link TableDataInfo } */ @PostMapping("/cancel/free/spin") - public AjaxResult cancelFreeSpin(@Validated @RequestBody GameCancelFreeSpinRequest gameGetFreeSpinDashflowRequest) { - GameSecretKeyCurrencyDTO gameSecretKey = gameSecretKeyCurrencyService.findByGameSecretKeyCurrencyDTO(GameSecretKeyCurrencyDTO.builder() - .platformCode(gameGetFreeSpinDashflowRequest.getPlatformCode()) - .systemCurrency(gameGetFreeSpinDashflowRequest.getCurrencyCode()).build()); - ApiException.notNull(gameSecretKey, ErrorCode.CURRENCY_NOT_EXIST.getCode()); + public AjaxResult cancelFreeSpin(@Validated @RequestBody GameCancelFreeSpinRequest request) { +// GameSecretKeyCurrencyDTO gameSecretKey = gameSecretKeyCurrencyService.findByGameSecretKeyCurrencyDTO(GameSecretKeyCurrencyDTO.builder() +// .platformCode(gameGetFreeSpinDashflowRequest.getPlatformCode()) +// .systemCurrency(gameGetFreeSpinDashflowRequest.getCurrencyCode()).build()); +// ApiException.notNull(gameSecretKey, ErrorCode.CURRENCY_NOT_EXIST.getCode()); - IGamesService iGamesService = gamesService.get(gameGetFreeSpinDashflowRequest.getPlatformCode() + Constants.SERVICE); + Platform platform = platformService.get(request.getPlatformCode()); + ApiException.notNull(platform, ErrorCode.PLATFORM_NOT_EXIST.getCode()); + + String targetCurrency = platform.getCurrencyInfo().get(request.getCurrencyCode()); + ApiException.notNull(targetCurrency, ErrorCode.CURRENCY_NOT_EXIST.getCode()); + + KeyInfo keyInfo = null; + for (KeyInfo keyData : platform.getKeyInfo()) { + if (StringUtils.isNotEmpty(request.getCurrencyCode())) { + if (keyData.getCurrency().equalsIgnoreCase(request.getCurrencyCode())) { + keyInfo = keyData; + break; + } + } + } + ApiException.notNull(keyInfo, ErrorCode.CURRENCY_NOT_EXIST.getCode()); + + IGamesService iGamesService = gamesService.get(request.getPlatformCode() + Constants.SERVICE); ApiException.notNull(iGamesService, ErrorCode.PLATFORM_NOT_EXIST.getCode()); Boolean cancelFreeSpin = iGamesService.cancelFreeSpin(CancelFreeSpinRequestDTO.builder() - .agentId(gameSecretKey.getCode()) - .agentKey(gameSecretKey.getKey()) - .referenceId(gameGetFreeSpinDashflowRequest.getReferenceId()) + .agentId(keyInfo.getCode()) + .agentKey(keyInfo.getKey()) + .referenceId(request.getReferenceId()) + .vendor(platform) + .keyInfo(keyInfo) + .systemCurrency(request.getCurrencyCode()) .build()); return AjaxResult.success(cancelFreeSpin); } @@ -498,45 +641,80 @@ public class ApiGameController extends BaseController { /** * 信息全部 * - * @param gameExchangeBalanceAllRequest 成员信息所有api请求 + * @param request 成员信息所有api请求 * @return {@link AjaxResult } - */ + *//* @PostMapping("/exchange/balance/all") - public AjaxResult exchangeBalanceAll(@Validated @RequestBody GameExchangeBalanceAllRequest gameExchangeBalanceAllRequest) { + public AjaxResult exchangeBalanceAll(@Validated @RequestBody GameExchangeBalanceAllRequest request) { TenantSecretKey tenantSecretKey = keyConfig.get(); +// List gameSecretKeys = gameSecretKeyCurrencyService.findByGameSecretKeyCurrencyDTOList(GameSecretKeyCurrencyDTO.builder() +// .systemCurrency(gameExchangeBalanceAllRequest.getCurrencyCode()).build()); - List gameSecretKeys = gameSecretKeyCurrencyService.findByGameSecretKeyCurrencyDTOList(GameSecretKeyCurrencyDTO.builder() - .systemCurrency(gameExchangeBalanceAllRequest.getCurrencyCode()).build()); + List keys = new ArrayList<>(); + for (GamePlatforms platformEnum : GamePlatforms.values()) { + + Platform platform = platformService.get(platformEnum.getCode()); + String targetCurrency = platform.getCurrencyInfo().get(request.getCurrencyCode()); + if (StringUtils.isEmpty(targetCurrency)) { + continue; + } + KeyInfo keyInfo = null; + for (KeyInfo keyData : platform.getKeyInfo()) { + if (StringUtils.isNotEmpty(request.getCurrencyCode())) { + if (keyData.getCurrency().equalsIgnoreCase(request.getCurrencyCode())) { + keyInfo = keyData; + break; + } + } + } + if (null == keyInfo) { + continue; + } + + Key key = new Key(); + key.setPlatformCode(platform.getPlatformCode()); + key.setCode(keyInfo.getCode()); + key.setKey(keyInfo.getKey()); + key.setCurrency(targetCurrency); + key.setPlatform(platform); + key.setKeyInfo(keyInfo); + key.setSystemCurrency(request.getCurrencyCode()); + keys.add(key); + } // 创建线程池 Map balanceMap = new LinkedHashMap<>(); - CountDownLatch latch = new CountDownLatch(gameSecretKeys.size()); + CountDownLatch latch = new CountDownLatch(keys.size()); // 使用List存储Future对象,用于获取异步执行的结果 List> futures = new ArrayList<>(); // 提交异步任务到线程池 - for (GameSecretKeyCurrencyDTO gameSecretKeyCurrencyDTO : gameSecretKeys) { +// for (GameSecretKeyCurrencyDTO gameSecretKeyCurrencyDTO : gameSecretKeys) { + for (Key key : keys) { futures.add(threadPoolTaskExecutor.submit(() -> { try { - IGamesService iGamesService = gamesService.get(gameSecretKeyCurrencyDTO.getPlatformCode() + Constants.SERVICE); + IGamesService iGamesService = gamesService.get(key.getPlatformCode() + Constants.SERVICE); - Member member = memberService.selectMemberByAccount(gameExchangeBalanceAllRequest.getAccount(), gameExchangeBalanceAllRequest.getCurrencyCode(), gameSecretKeyCurrencyDTO.getPlatformCode()); + Member member = memberService.selectMemberByAccount(request.getAccount(), request.getCurrencyCode(), key.getPlatformCode()); ApiException.notNull(member, ErrorCode.ACCOUNT_NOT_EXIST.getCode()); //操作第三方钱包 ExchangeTransferMoneyRequestDTO exchangeTransferMoneyRequestDTO = ExchangeTransferMoneyRequestDTO.builder() - .agentId(gameSecretKeyCurrencyDTO.getCode()) - .agentKey(gameSecretKeyCurrencyDTO.getKey()) - .orderId(gameExchangeBalanceAllRequest.getOrderId()) + .agentId(key.getCode()) + .agentKey(key.getKey()) + .orderId(request.getOrderId()) .amount(BigDecimal.ONE) - .currency(gameSecretKeyCurrencyDTO.getCurrency()) + .currency(*//*gameSecretKeyCurrencyDTO.getCurrency()*//*key.currency) .tenantKey(tenantSecretKey.getTenantKey()) .account(member.getGameAccount()) + .vendor(key.getPlatform()) + .keyInfo(key.getKeyInfo()) + .systemCurrency(key.systemCurrency) .transferType(TransferType.ALL.getCode()) .build(); return iGamesService.exchangeTransferByAgentId(exchangeTransferMoneyRequestDTO); @@ -571,11 +749,15 @@ public class ApiGameController extends BaseController { tenantGameQuotaService.gameBalanceExchange(GameBalanceExchange.builder() .platformCode(gameExchangeMoney.getPlatformCode()) .currencyCode(gameExchangeMoney.getCurrencyCode()) - .sourceId(gameExchangeBalanceAllRequest.getOrderId()) + .sourceId(request.getOrderId()) .transferType(TransferType.ALL.getCode()) .amount(gameExchangeMoney.getBalance()) .account(member.getMemberAccount()) .tenantKey(tenantSecretKey.getTenantKey()) + .currency() + .systemCurrency(gameExchangeMoney.getCurrencyCode()) + .agentId() + .agentKey() .build()); } @@ -587,5 +769,77 @@ public class ApiGameController extends BaseController { return AjaxResult.success(balanceMap); + }*/ + + + /** + * 演示登录 + * + * @param request 游戏演示登录请求 + * @return {@link AjaxResult } + */ + @PostMapping("/demo/login") + public AjaxResult demoLogin(@Validated @RequestBody GameDemoLoginRequest request) { + + Game game = gameService.selectGameById(request.getGameId()); + ApiException.notNull(game, ErrorCode.GAME_NOT_EXIST.getCode()); + + //GamePlatform gamePlatform = gamePlatformService.selectGamePlatformById(game.getPlatformId()); + //ApiException.notNull(gamePlatform, ErrorCode.PLATFORM_NOT_EXIST.getCode()); + + Platform platform = platformService.get(game.getPlatformCode()); + ApiException.notNull(platform, ErrorCode.PLATFORM_NOT_EXIST.getCode()); + + IGamesService iGamesService = gamesService.get(platform.getPlatformCode() + Constants.SERVICE); + ApiException.notNull(iGamesService, ErrorCode.PLATFORM_NOT_EXIST.getCode()); + + String targetCurrency = platform.getCurrencyInfo().get(request.getCurrencyCode()); + ApiException.notNull(targetCurrency, ErrorCode.CURRENCY_NOT_EXIST.getCode()); + + KeyInfo keyInfo = null; + for (KeyInfo keyData : platform.getKeyInfo()) { + if (StringUtils.isNotEmpty(request.getCurrencyCode())) { + if (keyData.getCurrency().equalsIgnoreCase(request.getCurrencyCode())) { + keyInfo = keyData; + break; + } + } + } + ApiException.notNull(keyInfo, ErrorCode.CURRENCY_NOT_EXIST.getCode()); + + String targetLang = platform.getLangInfo().get(request.getLangCode()); + ApiException.notNull(targetLang, ErrorCode.LANG_NOT_EXIST.getCode()); + +// GameSecretKeyLangDTO gameSecretKeyLangDTO = gameSecretKeyLangService.findGameSecretKeyLangDTO(GameSecretKeyLangDTO.builder() +// .platformCode(gamePlatform.getPlatformCode()) +// .systemLangCode(gameDemoLoginRequest.getLangCode()) +// .build()); +// ApiException.notNull(gameSecretKeyLangDTO, ErrorCode.LANG_NOT_EXIST.getCode()); + + + GameDemoLoginRequestDTO gamesLogin = GameDemoLoginRequestDTO.builder() + .gameId(game.getGameCode()) + .gameType(game.getGameSourceType()) + .lang(/*gameSecretKeyLangDTO.getLang()*/targetLang) + .vendor(platform) + .keyInfo(keyInfo) + .systemCurrency(request.getCurrencyCode()) + .build(); + + GameDemoLoginResponseDTO gameDemoLoginResponseDTO = iGamesService.gameDemoLogin(gamesLogin); + GameDemoLoginResponse gameDemoLoginResponse = new GameDemoLoginResponse(); + BeanUtils.copyProperties(gameDemoLoginResponseDTO, gameDemoLoginResponse); + return AjaxResult.success(gameDemoLoginResponse); + } + + @Data + class Key { + private String platformCode; + private String code; + private String currency; + private String key; + private Platform platform; + private KeyInfo keyInfo; + private String systemCurrency; } } diff --git a/ff-game/src/main/java/com/ff/api/controller/ApiMemberController.java b/ff-game/src/main/java/com/ff/api/controller/ApiMemberController.java index e82fc57..56bd037 100644 --- a/ff-game/src/main/java/com/ff/api/controller/ApiMemberController.java +++ b/ff-game/src/main/java/com/ff/api/controller/ApiMemberController.java @@ -11,20 +11,22 @@ import com.ff.base.constant.Constants; import com.ff.base.core.controller.BaseController; import com.ff.base.core.domain.AjaxResult; import com.ff.base.enums.ErrorCode; +import com.ff.base.enums.GamePlatforms; import com.ff.base.exception.base.ApiException; import com.ff.base.exception.base.BaseException; -import com.ff.base.utils.StringUtils; import com.ff.base.system.domain.TenantSecretKey; +import com.ff.base.utils.StringUtils; import com.ff.config.KeyConfig; import com.ff.game.api.IGamesService; -import com.ff.game.api.request.*; -import com.ff.game.domain.GameSecretKey; -import com.ff.game.dto.GameSecretKeyCurrencyDTO; -import com.ff.game.service.IGameSecretKeyCurrencyService; -import com.ff.game.service.IGameSecretKeyService; -import com.ff.game.service.IGameService; +import com.ff.game.api.request.CreateMemberRequestDTO; +import com.ff.game.api.request.MemberInfoRequestDTO; +import com.ff.game.api.request.MemberInfoResponseDTO; +import com.ff.game.domain.KeyInfo; +import com.ff.game.domain.Platform; +import com.ff.game.service.IPlatformService; import com.ff.member.domain.Member; import com.ff.member.service.IMemberService; +import lombok.Data; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -32,10 +34,12 @@ import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.Assert; -import org.springframework.util.CollectionUtils; import org.springframework.util.ObjectUtils; import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.*; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; import java.math.BigDecimal; @@ -58,31 +62,21 @@ import java.util.concurrent.Future; @Slf4j public class ApiMemberController extends BaseController { - @Autowired private Map gamesService; - - @Resource - private IGameService gameService; - - @Resource private KeyConfig keyConfig; - @Resource - private IGameSecretKeyService gameSecretKeyService; - @Resource private IMemberService memberService; - @Autowired @Qualifier("threadPoolTaskExecutor") private ThreadPoolTaskExecutor threadPoolTaskExecutor; @Resource - private IGameSecretKeyCurrencyService gameSecretKeyCurrencyService; + private IPlatformService platformService; /** * 创建成员 @@ -98,24 +92,33 @@ public class ApiMemberController extends BaseController { ApiException.notNull(iGamesService, ErrorCode.PLATFORM_NOT_EXIST.getCode()); TenantSecretKey tenantSecretKey = keyConfig.get(); - GameSecretKeyCurrencyDTO gameSecretKey = gameSecretKeyCurrencyService.findByGameSecretKeyCurrencyDTO(GameSecretKeyCurrencyDTO.builder() - .platformCode(memberCreateApiRequest.getPlatformCode()) - .systemCurrency(memberCreateApiRequest.getCurrencyCode()).build()); - ApiException.notNull(gameSecretKey, ErrorCode.CURRENCY_NOT_EXIST.getCode()); + Platform platform = platformService.get(memberCreateApiRequest.getPlatformCode()); + ApiException.notNull(platform, ErrorCode.CURRENCY_NOT_EXIST.getCode()); + String targetCurrency = platform.getCurrencyInfo().get(memberCreateApiRequest.getCurrencyCode()); + ApiException.notNull(targetCurrency, ErrorCode.CURRENCY_NOT_EXIST.getCode()); - String gameAccount = StringUtils.addSuffix(memberService.getMemberGameAccount(memberCreateApiRequest.getPlatformCode()), tenantSecretKey.getTenantSn()); + KeyInfo keyInfo = null; + for (KeyInfo keyData : platform.getKeyInfo()) { + if (StringUtils.isNotEmpty(memberCreateApiRequest.getCurrencyCode())) { + if (keyData.getCurrency().equalsIgnoreCase(memberCreateApiRequest.getCurrencyCode())) { + keyInfo = keyData; + break; + } + } + } + ApiException.notNull(keyInfo, ErrorCode.CURRENCY_NOT_EXIST.getCode()); + + String gameAccount =memberService.getMemberGameAccount(memberCreateApiRequest.getPlatformCode(), tenantSecretKey.getTenantSn()); // 获取用户信息 Member gameMember = memberService.selectMemberByAccount(memberCreateApiRequest.getAccount(), memberCreateApiRequest.getCurrencyCode(), memberCreateApiRequest.getPlatformCode()); - if (!ObjectUtils.isEmpty(gameMember)){ + if (!ObjectUtils.isEmpty(gameMember)) { throw new ApiException(ErrorCode.GAME_ACCOUNT_CREATION_FAILED.getCode()); } - - //注册本地账号 Member member = Member.builder() .tenantKey(tenantSecretKey.getTenantKey()) @@ -130,12 +133,21 @@ public class ApiMemberController extends BaseController { //向第三方注册账号 CreateMemberRequestDTO gamesBaseRequestDTO = CreateMemberRequestDTO.builder() .account(gameAccount) - .agentId(gameSecretKey.getCode()) - .agentKey(gameSecretKey.getKey()) - .currency(gameSecretKey.getCurrency()) + .agentId(keyInfo.getCode()) + .agentKey(keyInfo.getKey()) + .betLimit(memberCreateApiRequest.getBetLimit()) + .platformType(memberCreateApiRequest.getPlatformType()) + .currency(targetCurrency) + .vendor(platform) + .keyInfo(keyInfo) + .systemCurrency(memberCreateApiRequest.getCurrencyCode()) .build(); Boolean result = iGamesService.createMember(gamesBaseRequestDTO); Assert.isTrue(result, "建立游戏账号失败"); + + + + return toAjax(Boolean.TRUE); } @@ -144,35 +156,46 @@ public class ApiMemberController extends BaseController { /** * 获取会员信息 * - * @param memberInfoApiRequest 成员信息api请求 + * @param request 成员信息api请求 * @return {@link AjaxResult } */ @PostMapping("/info") - public AjaxResult getMemberInfo(@Validated @RequestBody MemberInfoApiRequest memberInfoApiRequest) { - IGamesService iGamesService = gamesService.get(memberInfoApiRequest.getPlatformCode() + Constants.SERVICE); + public AjaxResult getMemberInfo(@Validated @RequestBody MemberInfoApiRequest request) { + IGamesService iGamesService = gamesService.get(request.getPlatformCode() + Constants.SERVICE); ApiException.notNull(iGamesService, ErrorCode.PLATFORM_NOT_EXIST.getCode()); - TenantSecretKey tenantSecretKey = keyConfig.get(); - GameSecretKeyCurrencyDTO gameSecretKey = gameSecretKeyCurrencyService.findByGameSecretKeyCurrencyDTO(GameSecretKeyCurrencyDTO.builder() - .platformCode(memberInfoApiRequest.getPlatformCode()) - .systemCurrency(memberInfoApiRequest.getCurrencyCode()).build()); + Platform platform = platformService.get(request.getPlatformCode()); + ApiException.notNull(platform, ErrorCode.PLATFORM_NOT_EXIST.getCode()); - ApiException.notNull(gameSecretKey, ErrorCode.CURRENCY_NOT_EXIST.getCode()); + String targetCurrency = platform.getCurrencyInfo().get(request.getCurrencyCode()); + ApiException.notNull(targetCurrency, ErrorCode.CURRENCY_NOT_EXIST.getCode()); + KeyInfo keyInfo = null; + for (KeyInfo keyData : platform.getKeyInfo()) { + if (StringUtils.isNotEmpty(request.getCurrencyCode())) { + if (keyData.getCurrency().equalsIgnoreCase(request.getCurrencyCode())) { + keyInfo = keyData; + break; + } + } + } + ApiException.notNull(keyInfo, ErrorCode.CURRENCY_NOT_EXIST.getCode()); // 获取用户信息 - Member member = memberService.selectMemberByAccount(memberInfoApiRequest.getAccount(), memberInfoApiRequest.getCurrencyCode(), memberInfoApiRequest.getPlatformCode()); + Member member = memberService.selectMemberByAccount(request.getAccount(), request.getCurrencyCode(), request.getPlatformCode()); ApiException.notNull(member, ErrorCode.ACCOUNT_NOT_EXIST.getCode()); - //向第三方查询账号 MemberInfoRequestDTO gamesBaseRequestDTO = MemberInfoRequestDTO.builder() .accounts(member.getGameAccount()) - .agentId(gameSecretKey.getCode()) - .currency(gameSecretKey.getCurrency()) - .agentKey(gameSecretKey.getKey()) + .agentId(keyInfo.getCode()) + .currency(targetCurrency) + .agentKey(keyInfo.getKey()) + .vendor(platform) + .keyInfo(keyInfo) + .systemCurrency(request.getCurrencyCode()) .build(); MemberInfoResponseDTO memberInfo = iGamesService.getMemberInfo(gamesBaseRequestDTO); MemberInfoResponse memberInfoResponse = new MemberInfoResponse(); @@ -191,22 +214,50 @@ public class ApiMemberController extends BaseController { public AjaxResult infoAll(@Validated @RequestBody MemberInfoAllApiRequest memberInfoAllApiRequest) { +// List gameSecretKeys = gameSecretKeyCurrencyService.findByGameSecretKeyCurrencyDTOList( +// GameSecretKeyCurrencyDTO.builder() +// .systemCurrency(memberInfoAllApiRequest.getCurrencyCode()).build()); + List keys = new ArrayList<>(); + for (GamePlatforms platformEnum : GamePlatforms.values()) { + Platform platform = platformService.get(platformEnum.getCode()); + String targetCurrency = platform.getCurrencyInfo().get(memberInfoAllApiRequest.getCurrencyCode()); + if (StringUtils.isEmpty(targetCurrency)) { + continue; + } + KeyInfo keyInfo = null; + for (KeyInfo keyData : platform.getKeyInfo()) { + if (StringUtils.isNotEmpty(memberInfoAllApiRequest.getCurrencyCode())) { + if (keyData.getCurrency().equalsIgnoreCase(memberInfoAllApiRequest.getCurrencyCode())) { + keyInfo = keyData; + break; + } + } + } + if (null == keyInfo) { + continue; + } - - List gameSecretKeys = gameSecretKeyCurrencyService.findByGameSecretKeyCurrencyDTOList(GameSecretKeyCurrencyDTO.builder() - .systemCurrency(memberInfoAllApiRequest.getCurrencyCode()).build()); - + Key key = new Key(); + key.setPlatformCode(platform.getPlatformCode()); + key.setCode(keyInfo.getCode()); + key.setKey(keyInfo.getKey()); + key.setCurrency(targetCurrency); + key.setSystemCurrency(memberInfoAllApiRequest.getCurrencyCode()); + keys.add(key); + } // 创建线程池 Map balanceMap = new LinkedHashMap<>(); - CountDownLatch latch = new CountDownLatch(gameSecretKeys.size()); + CountDownLatch latch = new CountDownLatch(keys.size()); // 使用List存储Future对象,用于获取异步执行的结果 List> futures = new ArrayList<>(); // 提交异步任务到线程池 - for (GameSecretKeyCurrencyDTO gameSecretKey : gameSecretKeys) { + for (Key gameSecretKey : keys) { + futures.add(threadPoolTaskExecutor.submit(() -> { + try { IGamesService iGamesService = gamesService.get(gameSecretKey.getPlatformCode() + Constants.SERVICE); @@ -219,6 +270,7 @@ public class ApiMemberController extends BaseController { .accounts(member.getGameAccount()) .agentId(gameSecretKey.getCode()) .currency(gameSecretKey.getCurrency()) + .systemCurrency(gameSecretKey.getSystemCurrency()) .agentKey(gameSecretKey.getKey()) .build(); //查询余额 @@ -254,5 +306,13 @@ public class ApiMemberController extends BaseController { return AjaxResult.success(balanceMap); } + @Data + class Key { + private String platformCode; + private String code; + private String currency; + private String key; + private String systemCurrency; + } } diff --git a/ff-game/src/main/java/com/ff/api/request/GameDemoLoginRequest.java b/ff-game/src/main/java/com/ff/api/request/GameDemoLoginRequest.java new file mode 100644 index 0000000..e1c116c --- /dev/null +++ b/ff-game/src/main/java/com/ff/api/request/GameDemoLoginRequest.java @@ -0,0 +1,59 @@ +package com.ff.api.request; + +import lombok.Data; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.io.Serializable; +import java.util.Map; + +/** + * 游戏登录请求 + * + * @author shi + * @date 2025/02/11 + */ +@Data +public class GameDemoLoginRequest implements Serializable { + private final static long serialVersionUID = 7699430372422335056L; + + + + + /** + * 语种id + */ + @NotBlank(message = "langCode不能为空") + @Length(max = 32, message = "langCode长度不能超过32个字符") + private String langCode; + + + /** + * 游戏id + */ + @NotNull(message = "gameId不能为空") + private Long gameId; + + + /** + * 游戏回主页功能导向位置 + */ + private String homeUrl; + /** + * 带入 web 或是 app + */ + private String platform; + /** + * 带入 1 即关闭全屏幕模式 + */ + private Integer disableFullScreen; + + /** + * 币种 + */ + @NotBlank(message = "currencyCode不能为空") + @Length(max = 32, message = "currencyCode长度不能超过32个字符") + private String currencyCode; + +} diff --git a/ff-game/src/main/java/com/ff/api/request/GameLoginRequest.java b/ff-game/src/main/java/com/ff/api/request/GameLoginRequest.java index cc85df7..9c2d5f4 100644 --- a/ff-game/src/main/java/com/ff/api/request/GameLoginRequest.java +++ b/ff-game/src/main/java/com/ff/api/request/GameLoginRequest.java @@ -6,6 +6,7 @@ import org.hibernate.validator.constraints.Length; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; import java.io.Serializable; +import java.util.Map; /** * 游戏登录请求 @@ -43,8 +44,8 @@ public class GameLoginRequest implements Serializable { /** * 游戏id */ - @NotNull(message = "gameId不能为空") - private Long gameId; + @NotBlank(message = "gameId不能为空") + private String gameId; /** @@ -59,4 +60,9 @@ public class GameLoginRequest implements Serializable { * 带入 1 即关闭全屏幕模式 */ private Integer disableFullScreen; + + /** + * ae 平台 投注限额 + */ + private Map>> betLimit; } diff --git a/ff-game/src/main/java/com/ff/api/request/MemberCreateApiRequest.java b/ff-game/src/main/java/com/ff/api/request/MemberCreateApiRequest.java index 249d3f7..83af3f7 100644 --- a/ff-game/src/main/java/com/ff/api/request/MemberCreateApiRequest.java +++ b/ff-game/src/main/java/com/ff/api/request/MemberCreateApiRequest.java @@ -8,6 +8,7 @@ import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotNull; import javax.validation.constraints.Pattern; import java.io.Serializable; +import java.util.Map; /** * 创建成员请求 @@ -34,4 +35,13 @@ public class MemberCreateApiRequest implements Serializable{ @Length(max = 32, message = "currencyCode长度不能超过32个字符") private String currencyCode; + /** + * 投注限额 + */ + private Map>> betLimit; + + /** + * 平台类型 0 桌面 1 移动 + */ + private Integer platformType; } diff --git a/ff-game/src/main/java/com/ff/api/response/GameBettingDetailsResponse.java b/ff-game/src/main/java/com/ff/api/response/GameBettingDetailsResponse.java index 8e6b3b5..4ad32de 100644 --- a/ff-game/src/main/java/com/ff/api/response/GameBettingDetailsResponse.java +++ b/ff-game/src/main/java/com/ff/api/response/GameBettingDetailsResponse.java @@ -38,7 +38,7 @@ public class GameBettingDetailsResponse implements Serializable /** 游戏id */ - private Long gameId; + private String gameId; /** 游戏类型 ff_game_type 字典 */ private Integer gameType; diff --git a/ff-game/src/main/java/com/ff/api/response/GameDemoLoginResponse.java b/ff-game/src/main/java/com/ff/api/response/GameDemoLoginResponse.java new file mode 100644 index 0000000..1978ee0 --- /dev/null +++ b/ff-game/src/main/java/com/ff/api/response/GameDemoLoginResponse.java @@ -0,0 +1,28 @@ +package com.ff.api.response; + +import lombok.Data; +import org.hibernate.validator.constraints.Length; + +import javax.validation.constraints.NotBlank; +import javax.validation.constraints.NotNull; +import java.io.Serializable; + + +/** + * 游戏演示登录响应 + * + * @author shi + * @date 2025/04/03 + */ +@Data +public class GameDemoLoginResponse implements Serializable { + private final static long serialVersionUID = 7699430372422335056L; + + + + /** + * 网址 + */ + private String url; + +} diff --git a/ff-game/src/main/java/com/ff/api/response/GameResponse.java b/ff-game/src/main/java/com/ff/api/response/GameResponse.java index 8f4eee3..4b24077 100644 --- a/ff-game/src/main/java/com/ff/api/response/GameResponse.java +++ b/ff-game/src/main/java/com/ff/api/response/GameResponse.java @@ -1,5 +1,6 @@ package com.ff.api.response; +import com.ff.game.domain.NameInfo; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -27,7 +28,7 @@ public class GameResponse implements Serializable { /** * 游戏id */ - private Long id; + private String id; /** * 游戏名称 @@ -60,5 +61,8 @@ public class GameResponse implements Serializable { * 支持货币代码 */ private List currencyCode; - + /** + * 名称 + */ + private List nameInfo; } diff --git a/ff-game/src/main/java/com/ff/common/dto/GameBalanceExchange.java b/ff-game/src/main/java/com/ff/common/dto/GameBalanceExchange.java index 5935c43..ae9260b 100644 --- a/ff-game/src/main/java/com/ff/common/dto/GameBalanceExchange.java +++ b/ff-game/src/main/java/com/ff/common/dto/GameBalanceExchange.java @@ -1,5 +1,6 @@ package com.ff.common.dto; +import com.ff.game.api.request.GamesBaseRequestDTO; import io.swagger.models.auth.In; import lombok.AllArgsConstructor; import lombok.Builder; @@ -21,7 +22,7 @@ import java.math.BigDecimal; @AllArgsConstructor @NoArgsConstructor @SuperBuilder -public class GameBalanceExchange implements Serializable { +public class GameBalanceExchange extends GamesBaseRequestDTO implements Serializable { private final static long serialVersionUID = 3452954102791311247L; @@ -46,6 +47,12 @@ public class GameBalanceExchange implements Serializable { */ private BigDecimal amount; + + /** + * + */ + private BigDecimal amountActual; + /** * 账户 */ @@ -60,4 +67,9 @@ public class GameBalanceExchange implements Serializable { */ private String sourceId; + /** + * 就是全部 + */ + private Boolean isAll; + } diff --git a/ff-game/src/main/java/com/ff/common/service/impl/TenantGameQuotaServiceImpl.java b/ff-game/src/main/java/com/ff/common/service/impl/TenantGameQuotaServiceImpl.java index 3186d9e..31eced5 100644 --- a/ff-game/src/main/java/com/ff/common/service/impl/TenantGameQuotaServiceImpl.java +++ b/ff-game/src/main/java/com/ff/common/service/impl/TenantGameQuotaServiceImpl.java @@ -26,13 +26,8 @@ import com.ff.common.service.ITenantQuotaExchangeService; import com.ff.base.system.service.ITenantSecretKeyService; import com.ff.game.api.IGamesService; import com.ff.game.api.request.MemberInfoRequestDTO; -import com.ff.game.domain.GameSecretKey; -import com.ff.game.dto.GameSecretKeyCurrencyDTO; -import com.ff.game.service.IGameSecretKeyCurrencyService; -import com.ff.game.service.IGameSecretKeyService; import com.ff.member.domain.Member; import com.ff.member.service.IMemberService; -import nonapi.io.github.classgraph.json.Id; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.ff.common.mapper.TenantGameQuotaMapper; @@ -61,30 +56,18 @@ public class TenantGameQuotaServiceImpl implements ITenantGameQuotaService { @Resource private ITenantSecretKeyService tenantSecretKeyService; - @Resource private IMemberService memberService; - - @Resource - private IGameSecretKeyService gameSecretKeyService; - - @Autowired private Map gamesService; - @Resource private ITenantQuotaExchangeService tenantQuotaExchangeService; @Resource private ITenantPlatformService tenantPlatformService; - - @Resource - private IGameSecretKeyCurrencyService gameSecretKeyCurrencyService; - - /** * 查询租户游戏配额 * @@ -169,7 +152,7 @@ public class TenantGameQuotaServiceImpl implements ITenantGameQuotaService { BigDecimal balance = balanceChangesDTO.getBalance(); //如果有汇率 则需要计算真实扣除额度 if (!ObjectUtils.isEmpty(balanceChangesDTO.getActualBalance())) { - balance = NumberUtil.div(balance, balanceChangesDTO.getActualBalance(), 2, RoundingMode.FLOOR); + balance = NumberUtil.div(balance, balanceChangesDTO.getActualBalance(), 5, RoundingMode.FLOOR); } if (BigDecimal.ZERO.compareTo(balance) >= 0) { @@ -239,7 +222,7 @@ public class TenantGameQuotaServiceImpl implements ITenantGameQuotaService { BigDecimal balance = balanceRealChangesDTO.getBalance(); //如果有汇率 则需要计算真实扣除额度 if (!ObjectUtils.isEmpty(balanceRealChangesDTO.getActualBalance())) { - balance = NumberUtil.div(balance, balanceRealChangesDTO.getActualBalance(), 2, RoundingMode.FLOOR); + balance = NumberUtil.div(balance, balanceRealChangesDTO.getActualBalance(), 5, RoundingMode.FLOOR); } if (BigDecimal.ZERO.compareTo(balance) >= 0) { @@ -288,13 +271,6 @@ public class TenantGameQuotaServiceImpl implements ITenantGameQuotaService { */ @Override public BigDecimal gameBalanceExchange(GameBalanceExchange gameBalanceExchange) { - // 获取平台接口密钥 - GameSecretKeyCurrencyDTO gameSecretKey = gameSecretKeyCurrencyService.findByGameSecretKeyCurrencyDTO(GameSecretKeyCurrencyDTO.builder() - .platformCode(gameBalanceExchange.getPlatformCode()) - .systemCurrency(gameBalanceExchange.getCurrencyCode()).build()); - - // 检查平台密钥是否存在,否则抛出异常 - ApiException.notNull(gameSecretKey, ErrorCode.CURRENCY_NOT_EXIST.getCode()); TenantQuotaExchange tenantQuotaExchange = tenantQuotaExchangeService.getTenantQuotaExchange(Constants.USDT, gameBalanceExchange.getCurrencyCode()); ApiException.notNull(tenantQuotaExchange, ErrorCode.CURRENCY_EXCHANGE.getCode()); @@ -313,14 +289,11 @@ public class TenantGameQuotaServiceImpl implements ITenantGameQuotaService { ApiException.notNull(tenantPlatform, ErrorCode.PLATFORM_NOT_EXIST.getCode()); - // 获取用户信息 Member member = memberService.selectMemberByAccount(gameBalanceExchange.getAccount(), gameBalanceExchange.getCurrencyCode(), gameBalanceExchange.getPlatformCode()); ApiException.notNull(member, ErrorCode.ACCOUNT_NOT_EXIST.getCode()); - - // 检查用户是否存在,否则抛出异常 ApiException.notNull(member, ErrorCode.ACCOUNT_NOT_EXIST.getCode()); @@ -341,14 +314,21 @@ public class TenantGameQuotaServiceImpl implements ITenantGameQuotaService { // 如果是出账操作 if (isOut) { - // 获取第三方钱包余额 - MemberInfoRequestDTO gamesBaseRequestDTO = MemberInfoRequestDTO.builder() - .accounts(member.getGameAccount()) - .agentId(gameSecretKey.getCode()) - .currency(gameSecretKey.getCurrency()) - .agentKey(gameSecretKey.getKey()) - .build(); - balanceRequestAmount = iGamesService.getMemberInfo(gamesBaseRequestDTO).getBalance(); + if (ObjectUtils.isEmpty(gameBalanceExchange.getIsAll())||gameBalanceExchange.getIsAll()){ + // 获取第三方钱包余额 + MemberInfoRequestDTO gamesBaseRequestDTO = MemberInfoRequestDTO.builder() + .accounts(member.getGameAccount()) + .agentId(gameBalanceExchange.getAgentId()) + .currency(gameBalanceExchange.getCurrency()) + .agentKey(gameBalanceExchange.getAgentKey()) + .build(); + balanceRequestAmount = iGamesService.getMemberInfo(gamesBaseRequestDTO).getBalance(); + if (balanceRequestAmount.compareTo(BigDecimal.ZERO) <= 0) { + throw new ApiException(ErrorCode.INSUFFICIENT_PLAYER_BALANCE.getCode()); + } + } + + balanceRequestAmount = NumberUtil.add(balanceRequestAmount, NumberUtil.mul(balanceRequestAmount, NumberUtil.div(tenantPlatform.getUseCost(), Constants.HUNDRED))); // 计算累计转入和转出金额 @@ -410,12 +390,10 @@ public class TenantGameQuotaServiceImpl implements ITenantGameQuotaService { // 如果是扣账操作,首先处理假额度 String falseTenantQuotaType = QuotaUtils.getFalseTenantQuota(gameBalanceExchange.getPlatformCode(), gameBalanceExchange.getCurrencyCode()); TenantGameQuota falseTenantQuota = selectTenantGameQuotaByTenantKey(tenantSecretKey.getTenantKey(), falseTenantQuotaType); - balanceRequestAmount = NumberUtil.add(gameBalanceExchange.getAmount(), NumberUtil.mul(gameBalanceExchange.getAmount(), NumberUtil.div(tenantPlatform.getUseCost(), Constants.HUNDRED))); + balanceRequestAmount = NumberUtil.add(gameBalanceExchange.getAmount(), NumberUtil.mul(gameBalanceExchange.getAmount(), NumberUtil.div(tenantPlatform.getUseCost(), Constants.HUNDRED))); if (falseTenantQuota.getBalance().compareTo(BigDecimal.ZERO) > 0) { - - BigDecimal falseQuotaBalance = falseTenantQuota.getBalance(); if (falseQuotaBalance.compareTo(balanceRequestAmount) >= 0) { // 假额度足够扣除本次所需金额 diff --git a/ff-game/src/main/java/com/ff/config/ContentRefreshedEventListener.java b/ff-game/src/main/java/com/ff/config/ContentRefreshedEventListener.java index 0b0d82b..a1964ef 100644 --- a/ff-game/src/main/java/com/ff/config/ContentRefreshedEventListener.java +++ b/ff-game/src/main/java/com/ff/config/ContentRefreshedEventListener.java @@ -5,6 +5,7 @@ import com.ff.base.system.domain.SysDatasource; import com.ff.base.system.mapper.SysDatasourceMapper; import com.ff.base.system.service.ISysConfigService; import com.ff.base.system.service.ISysDictTypeService; +import com.ff.game.service.IPlatformService; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; import org.springframework.context.ApplicationListener; @@ -34,6 +35,9 @@ public class ContentRefreshedEventListener implements ApplicationListener delayQueue = new DelayQueue<>(); + + private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); + + public void addTask(DelayTask delayTask) { + delayQueue.put(delayTask); + } + + // 启动延迟队列任务处理 + @PostConstruct + public void startProcessing() { + // 每 1 秒钟执行一次任务检查 + scheduler.scheduleAtFixedRate(this::processTasks, 10, 1, TimeUnit.SECONDS); + } + + // 处理过期任务 + private void processTasks() { + DelayTask task = null; // 阻塞,直到队列中有任务到期 + try { + task = delayQueue.take(); + } catch (InterruptedException e) { + log.error("获取过期任务失败", e); + } + if (null == task) { + return; + } + AsyncManager.me().execute(new DelayRunnable(task)); + } + + public static class DelayRunnable implements Runnable { + + DelayTask delayTask; + + public DelayRunnable(DelayTask delayTask) { + this.delayTask = delayTask; + } + + @Override + public void run() { + try { + delayTask.execute(); + } catch (Exception e) { + log.error("处理过期任务出错", e); + } + } + } +} diff --git a/ff-game/src/main/java/com/ff/delay/DelayTask.java b/ff-game/src/main/java/com/ff/delay/DelayTask.java new file mode 100644 index 0000000..e32cc7d --- /dev/null +++ b/ff-game/src/main/java/com/ff/delay/DelayTask.java @@ -0,0 +1,44 @@ +package com.ff.delay; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.concurrent.Delayed; +import java.util.concurrent.TimeUnit; + +/** + * @author cengy + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public abstract class DelayTask implements Delayed { + private long delayTime; + private long expireTime; + + public DelayTask(long delayTime) { + this.delayTime = delayTime; + this.expireTime = System.currentTimeMillis() + delayTime; // 设置过期时间 + } + + @Override + public long getDelay(TimeUnit unit) { + long diff = expireTime - System.currentTimeMillis(); + return unit.convert(diff, TimeUnit.MILLISECONDS); + } + + @Override + public int compareTo(Delayed o) { + if (this.expireTime < ((DelayTask) o).expireTime) { + return -1; + } + if (this.expireTime > ((DelayTask) o).expireTime) { + return 1; + } + return 0; + } + + abstract public void execute(); +} + diff --git a/ff-game/src/main/java/com/ff/game/api/IGamesService.java b/ff-game/src/main/java/com/ff/game/api/IGamesService.java index 4d7c6f3..00585dd 100644 --- a/ff-game/src/main/java/com/ff/game/api/IGamesService.java +++ b/ff-game/src/main/java/com/ff/game/api/IGamesService.java @@ -52,6 +52,14 @@ public interface IGamesService { */ String getGameList(GamesBaseRequestDTO gamesBaseRequestDTO); + /** + * 获取交易id + * + * @param transactionIdRequestDTO 事务id请求dto + * @return {@link String } + */ + String getTransactionId(TransactionIdRequestDTO transactionIdRequestDTO); + /** * 按代理id进行交换转账 @@ -66,9 +74,9 @@ public interface IGamesService { * 汇兑转移状态确认 * * @param exchangeTransferMoneyRequestDTO 兑换转账请求dto - * @return {@link Boolean } + * @return {@link ExchangeTransferStatusResponseDTO } */ - Boolean exchangeTransferStatus(ExchangeTransferStatusRequestDTO exchangeTransferMoneyRequestDTO); + ExchangeTransferStatusResponseDTO exchangeTransferStatus(ExchangeTransferStatusRequestDTO exchangeTransferMoneyRequestDTO); /** @@ -96,6 +104,8 @@ public interface IGamesService { */ Boolean createFreeSpin(CreateFreeSpinRequestDTO createFreeSpinRequest); + + /** * 获取游戏详细信息 * @@ -136,6 +146,13 @@ public interface IGamesService { */ Boolean cancelFreeSpin(CancelFreeSpinRequestDTO cancelFreeSpinRequestDTO); + /** + * 游戏演示登录 + * + * @param gameDemoLoginRequestDTO 游戏演示登录请求dto + * @return {@link GameDemoLoginResponseDTO } + */ + GameDemoLoginResponseDTO gameDemoLogin(GameDemoLoginRequestDTO gameDemoLoginRequestDTO); /** diff --git a/ff-game/src/main/java/com/ff/game/api/ae/address/MyAEAddressSource.java b/ff-game/src/main/java/com/ff/game/api/ae/address/MyAEAddressSource.java new file mode 100644 index 0000000..01a76ab --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/ae/address/MyAEAddressSource.java @@ -0,0 +1,31 @@ +package com.ff.game.api.ae.address; + +import com.dtflys.forest.callback.AddressSource; +import com.dtflys.forest.http.ForestAddress; +import com.dtflys.forest.http.ForestRequest; +import com.ff.base.enums.GamePlatforms; +import com.ff.game.service.IPlatformService; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + + +/** + * 我jili address来源 + * + * @author shi + * @date 2025/02/10 + */ +@Component +public class MyAEAddressSource implements AddressSource { + + @Resource + private IPlatformService platformService; + + @Override + public ForestAddress getAddress(ForestRequest request) { + String apiBaseUrl = platformService.get(GamePlatforms.AE.getCode()) + .getUrlInfo().getUrl(); + return new ForestAddress("https", apiBaseUrl, 443, ""); + } +} \ No newline at end of file diff --git a/ff-game/src/main/java/com/ff/game/api/ae/client/AEClient.java b/ff-game/src/main/java/com/ff/game/api/ae/client/AEClient.java new file mode 100644 index 0000000..032cc08 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/ae/client/AEClient.java @@ -0,0 +1,132 @@ +package com.ff.game.api.ae.client; + +import com.dtflys.forest.annotation.*; +import com.ff.game.api.ae.address.MyAEAddressSource; +import com.ff.game.api.ae.dto.*; +import com.ff.game.api.jili.dto.*; +import com.ff.game.api.xk.dto.XKKickMemberAllDTO; +import com.ff.game.api.xk.dto.XKKickMemberDTO; + +import java.util.Map; + +/** + * xk 请求 + * + * @author shi + * @date 2025/02/10 + */ +@Address(source = MyAEAddressSource.class) +public interface AEClient { + /** + * 创建成员 + * + * @param params 参数 + * @return {@link String } + */ + @Post(url ="/wallet/createMember", + headers = { + "Content-type: application/x-www-form-urlencoded" + }) + AEResponse createMember(@Body Map params); + + /** + * 获取会员信息 + * + * @param params 参数 + * @return {@link AEMemberInfo } + */ + @Post(url ="/wallet/getBalance", + headers = { + "Content-type: application/x-www-form-urlencoded" + }) + AEMemberInfo getMemberInfo(@Body Map params); + + /** + * 无重定向登录 + * + * @param params 参数 + * @return {@link AELoginResponse } + */ + @Post("/wallet/login") + AELoginResponse loginWithoutRedirect(@Body Map params); + + + + /** + * 按代理id进行交换转账 + * + * @param params 参数 + * @return {@link JILIExchangeMoneyResponseDTO } + */ + @Post(url ="/wallet/deposit", + headers = { + "Content-type: application/x-www-form-urlencoded" + }) + AETransactionResponse deposit(@Body Map params); + + + @Post(url ="/wallet/withdraw", + headers = { + "Content-type: application/x-www-form-urlencoded" + }) + AETransactionResponse withdraw(@Body Map params); + + + /** + * 汇兑转移状态 + * + * @param params 参数 + * @return {@link AEExchangeTransferStatusResponse } + */ + @Post(url ="/wallet/checkTransferOperation", + headers = { + "Content-type: application/x-www-form-urlencoded" + }) + AEExchangeTransferStatusResponse exchangeTransferStatus(@Body Map params); + + /** + * 按时间获取投注记录 + * + * @param params 参数 + * @return {@link AEBetRecordResponse } + */ + @Post(url ="https://tttfetch.apihub55.com/fetch/gzip/getTransactionByUpdateDate", + headers = { + "Content-type: application/x-www-form-urlencoded" + }) + AEBetRecordResponse getBetRecordByTime(@Body Map params); + + /** + * 按时间获取投注历史记录 + * + * @param params 参数 + * @return {@link AEBetRecordResponse } + */ + @Post(url ="https://tttfetch.apihub55.com/fetch/gzip/getTransactionByTxTime", + headers = { + "Content-type: application/x-www-form-urlencoded" + }) + AEBetRecordResponse getBetHistoryRecordByTime(@Body Map params); + /** + * 踢出队员 + * + * @param params 参数 + * @return {@link JILIKickMemberDTO } + */ + @Post(url ="/wallet/logout", + headers = { + "Content-type: application/x-www-form-urlencoded" + }) + XKKickMemberDTO kickMember(@Body Map params); + + /** + * 踢出所有队员 + * + * @param params 参数 + * @return {@link JILIKickMemberAllDTO } + */ + @Get("/kickMemberAll") + XKKickMemberAllDTO kickMemberAll(@JSONBody Map params); + + +} diff --git a/ff-game/src/main/java/com/ff/game/api/ae/dto/AEBetRecordResponse.java b/ff-game/src/main/java/com/ff/game/api/ae/dto/AEBetRecordResponse.java new file mode 100644 index 0000000..a288b22 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/ae/dto/AEBetRecordResponse.java @@ -0,0 +1,186 @@ +package com.ff.game.api.ae.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.math.BigDecimal; +import java.util.Date; +import java.util.List; + +/** + * aebet记录响应 + * + * @author shi + * @date 2025/04/01 + */ +@Data +public class AEBetRecordResponse { + + /** + * 状态代码 + */ + @JsonProperty("status") + private Integer status; + + /** + * 描述信息 (String类型) + * "Success" - 请求成功 + * 其他 - 错误信息 + */ + private String desc; + /** + * 交易记录 + */ + @JsonProperty("transactions") + private List transactions; + + @Data + public static class Transaction { + + /** + * 游戏类型 + */ + @JsonProperty("gameType") + private String gameType; + + /** + * 返还金额(包含下注金额) + */ + @JsonProperty("winAmount") + private BigDecimal winAmount; + + /** + * 交易时间 + */ + @JsonProperty("txTime") + private Date txTime; + + /** + * 结算状态 + */ + @JsonProperty("settleStatus") + private Integer settleStatus; + + /** + * 游戏信息 + */ + @JsonProperty("gameInfo") + private String gameInfo; + + /** + * 真实返还金额 + */ + @JsonProperty("realWinAmount") + private BigDecimal realWinAmount; + + /** + * 更新时间 + */ + @JsonProperty("updateTime") + private String updateTime; + + /** + * 真实下注金额 + */ + @JsonProperty("realBetAmount") + private BigDecimal realBetAmount; + + /** + * 用户ID + */ + @JsonProperty("userId") + private String userId; + + /** + * 下注类型 + */ + @JsonProperty("betType") + private String betType; + + /** + * 平台名称 + */ + @JsonProperty("platform") + private String platform; + + /** + * 交易状态 + */ + @JsonProperty("txStatus") + private Integer txStatus; + + /** + * 下注金额 + */ + @JsonProperty("betAmount") + private BigDecimal betAmount; + + /** + * 游戏名称 + */ + @JsonProperty("gameName") + private String gameName; + + /** + * 平台注单号 + */ + @JsonProperty("platformTxId") + private String platformTxId; + + /** + * 下注时间 + */ + @JsonProperty("betTime") + private Date betTime; + + /** + * 平台游戏代码 + */ + @JsonProperty("gameCode") + private String gameCode; + + /** + * 玩家货币代码 + */ + @JsonProperty("currency") + private String currency; + + /** + * 累积奖金的获胜金额 + */ + @JsonProperty("jackpotWinAmount") + private BigDecimal jackpotWinAmount; + + /** + * 累积奖金贡献金额 + */ + @JsonProperty("jackpotBetAmount") + private BigDecimal jackpotBetAmount; + + /** + * 平台有效投注 + */ + @JsonProperty("turnover") + private BigDecimal turnover; + + /** + * 游戏商的回合识别码 + */ + @JsonProperty("roundId") + private String roundId; + + + + /** + * 子注单号 + */ + @JsonProperty("refPlatformTxId") + private String refPlatformTxId; + + /** + * 是否为特殊收费游戏 + */ + @JsonProperty("isPremium") + private Boolean isPremium; + } +} diff --git a/ff-game/src/main/java/com/ff/game/api/ae/dto/AEExchangeTransferStatusResponse.java b/ff-game/src/main/java/com/ff/game/api/ae/dto/AEExchangeTransferStatusResponse.java new file mode 100644 index 0000000..8e68c0f --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/ae/dto/AEExchangeTransferStatusResponse.java @@ -0,0 +1,56 @@ +package com.ff.game.api.ae.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.math.BigDecimal; + + +/** + * aeexchange传输状态响应 + * + * @author shi + * @date 2025/04/01 + */ +@Data +public class AEExchangeTransferStatusResponse { + + /** + * 响应状态 + */ + @JsonProperty("status") + private String status; + + /** + * 情境 1:响应 status = 0000 & txStatus = 1 表示存款/提款成功 + * 情境 2:响应 status = 0000 & txStatus = 0 表示存款/提款失败 + * 情境 3:响应 status = 0000 & txStatus = 2 表示存款/提款处理中,可 3 秒后调用 checkTransferOperation API 确认回覆直到 txStatus = 0 或 1 的回覆 + * 情境 4:响应 status = 1017 表示交易不存在 + */ + @JsonProperty("txStatus") + private String txStatus; + + /** + * 当前余额 + */ + @JsonProperty("balance") + private BigDecimal balance; + + /** + * 转账金额 + */ + @JsonProperty("transferAmount") + private BigDecimal transferAmount; + + /** + * 转账类型(如:DEPOSIT 或 WITHDRAW) + */ + @JsonProperty("transferType") + private String transferType; + + /** + * 交易代码 + */ + @JsonProperty("txCode") + private String txCode; +} diff --git a/ff-game/src/main/java/com/ff/game/api/ae/dto/AELoginResponse.java b/ff-game/src/main/java/com/ff/game/api/ae/dto/AELoginResponse.java new file mode 100644 index 0000000..76b33ed --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/ae/dto/AELoginResponse.java @@ -0,0 +1,41 @@ +package com.ff.game.api.ae.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.util.List; + +/** + * aelogin回应 + * + * @author shi + * @date 2025/04/01 + */ +@Data +public class AELoginResponse { + /** + * 响应状态 + */ + @JsonProperty("status") + private Integer status; + + + /** + * 描述信息 (String类型) + * "Success" - 请求成功 + * 其他 - 错误信息 + */ + private String desc; + + /** + * 登录 URL + */ + @JsonProperty("url") + private String url; + + /** + * 扩展字段,类型为列表,可以存储多项数据 + */ + @JsonProperty("extension") + private List extension; +} diff --git a/ff-game/src/main/java/com/ff/game/api/ae/dto/AELogoutUserResponse.java b/ff-game/src/main/java/com/ff/game/api/ae/dto/AELogoutUserResponse.java new file mode 100644 index 0000000..7451bce --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/ae/dto/AELogoutUserResponse.java @@ -0,0 +1,33 @@ +package com.ff.game.api.ae.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.util.List; + +/** + * 注销用户响应 + * + * @author shi + * @date 2025/04/01 + */ +@Data +public class AELogoutUserResponse { + /** + * 状态代码 + */ + @JsonProperty("status") + private String status; + + /** + * 已注销的用户列表 + */ + @JsonProperty("logoutUsers") + private List logoutUsers; + + /** + * 用户数量 + */ + @JsonProperty("count") + private Integer count; +} diff --git a/ff-game/src/main/java/com/ff/game/api/ae/dto/AEMemberInfo.java b/ff-game/src/main/java/com/ff/game/api/ae/dto/AEMemberInfo.java new file mode 100644 index 0000000..5b51159 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/ae/dto/AEMemberInfo.java @@ -0,0 +1,65 @@ +package com.ff.game.api.ae.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.ZonedDateTime; +import java.util.Date; +import java.util.List; + +/** + * AEMEMBER信息 + * + * @author shi + * @date 2025/03/31 + */ +@Data +public class AEMemberInfo { + /** + * 响应结果列表,包含用户信息 + */ + @JsonProperty("results") + private List result; + + /** + * 记录数量 + */ + @JsonProperty("count") + private int count; + + /** + * 查询时间 + */ + @JsonProperty("querytime") + private Date queryTime; + + /** + * 响应状态 + */ + @JsonProperty("status") + private Integer status; + + @Data + public static class UserInfo { + + /** + * 用户ID + */ + @JsonProperty("userId") + private String userId; + + /** + * 用户余额 + */ + @JsonProperty("balance") + private BigDecimal balance; + + /** + * 最后修改时间 + */ + @JsonProperty("lastModified") + private Date lastModified; + } + +} diff --git a/ff-game/src/main/java/com/ff/game/api/ae/dto/AEResponse.java b/ff-game/src/main/java/com/ff/game/api/ae/dto/AEResponse.java new file mode 100644 index 0000000..499a484 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/ae/dto/AEResponse.java @@ -0,0 +1,26 @@ +package com.ff.game.api.ae.dto; + +import lombok.Data; + +/** + * 航空响应 + * + * @author shi + * @date 2025/03/28 + */ +@Data +public class AEResponse { + /** + * 状态码 (String类型) + * 0000 - 成功 + * 其他 - 错误状态码 + */ + private String status; + + /** + * 描述信息 (String类型) + * "Success" - 请求成功 + * 其他 - 错误信息 + */ + private String desc; +} diff --git a/ff-game/src/main/java/com/ff/game/api/ae/dto/AETransactionResponse.java b/ff-game/src/main/java/com/ff/game/api/ae/dto/AETransactionResponse.java new file mode 100644 index 0000000..397d5ea --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/ae/dto/AETransactionResponse.java @@ -0,0 +1,60 @@ +package com.ff.game.api.ae.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.ZonedDateTime; + +/** + * 电子交易响应 + * + * @author shi + * @date 2025/04/01 + */ +@Data +public class AETransactionResponse { + + /** + * 响应状态 + */ + @JsonProperty("status") + private String status; + + + /** + * 金额 + */ + @JsonProperty("amount") + private BigDecimal amount; + + /** + * 交易方法(如:DEPOSIT, WITHDRAW) + */ + @JsonProperty("method") + private String method; + + /** + * 数据库ID + */ + @JsonProperty("databaseId") + private int databaseId; + + /** + * 当前余额 + */ + @JsonProperty("currentBalance") + private BigDecimal currentBalance; + + /** + * 最后修改时间 + */ + @JsonProperty("lastModified") + private ZonedDateTime lastModified; + + /** + * 交易代码 + */ + @JsonProperty("txCode") + private String txCode; +} diff --git a/ff-game/src/main/java/com/ff/game/api/ae/impl/GamesAEServiceImpl.java b/ff-game/src/main/java/com/ff/game/api/ae/impl/GamesAEServiceImpl.java new file mode 100644 index 0000000..7804bda --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/ae/impl/GamesAEServiceImpl.java @@ -0,0 +1,646 @@ +package com.ff.game.api.ae.impl; + +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.NumberUtil; +import com.ff.base.constant.CacheConstants; +import com.ff.base.constant.Constants; +import com.ff.base.core.redis.RedisCache; +import com.ff.base.enums.*; +import com.ff.base.exception.base.ApiException; +import com.ff.base.exception.base.BaseException; +import com.ff.base.system.service.ISysConfigService; +import com.ff.base.utils.DateUtils; +import com.ff.base.utils.JsonUtil; +import com.ff.base.utils.StringUtils; +import com.ff.base.utils.uuid.IdUtils; +import com.ff.common.dto.GameBalanceExchange; +import com.ff.common.service.ITenantGameQuotaService; +import com.ff.config.KeyConfig; +import com.ff.delay.DelayService; +import com.ff.delay.DelayTask; +import com.ff.game.api.IGamesService; +import com.ff.game.api.ae.client.AEClient; +import com.ff.game.api.ae.dto.*; +import com.ff.game.api.request.*; +import com.ff.game.api.sv388.impl.SV388GamesServiceImpl; +import com.ff.game.api.xk.dto.XKKickMemberDTO; +import com.ff.game.domain.*; +import com.ff.game.service.IGameBettingDetailsService; +import com.ff.game.service.IGameExchangeMoneyService; +import com.ff.game.service.IGameService; +import com.ff.member.domain.Member; +import com.ff.member.service.IMemberService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.Assert; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ObjectUtils; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.util.*; +import java.util.stream.Collectors; + + +/** + * AE 游戏 impl + * + * @author shi + * @date 2024/11/12 + */ +@Service("AEService") +@Slf4j +public class GamesAEServiceImpl implements IGamesService { + + + @Resource + private ISysConfigService configService; + + @Resource + private RedisCache redisCache; + + @Resource + private IGameExchangeMoneyService gameExchangeMoneyService; + + + @Resource + private IGameService gameService; + @Resource + private ITenantGameQuotaService tenantGameQuotaService; + + @Resource + private IMemberService memberService; + + @Resource + private AEClient AEClient; + + + @Resource + private KeyConfig keyConfig; + + @Resource + private IGameBettingDetailsService gameBettingDetailsService; + + @Resource + private DelayService delayService; + + /** + * 游戏id + */ + private static final Long GAME_ID = 1904452832756013817L; + + + /** + * 获得就是成功 + * + * @param errorCode 错误代码 + * @return {@link Boolean } + */ + private Boolean getIsSuccess(Integer errorCode) { + return 0 == errorCode; + } + + + /** + * 获取密钥 + * + * @param gamesBaseRequestDTO 游戏请求dto + * @return {@link Map }<{@link String }, {@link Object }> + */ + private Map getKey(GamesBaseRequestDTO gamesBaseRequestDTO) { + Map params = new LinkedHashMap<>(); + params.put("cert", gamesBaseRequestDTO.getAgentKey()); + params.put("agentId", gamesBaseRequestDTO.getAgentId()); + return params; + } + + /** + * 创建成员 + * + * @param createMemberRequestDTO 创建成员请求dto + * @return {@link Boolean } + */ + @Override + public Boolean createMember(CreateMemberRequestDTO createMemberRequestDTO) { + log.info("GamesAEServiceImpl [createMember] 请求参数 {}", createMemberRequestDTO); + + Map params = this.getKey(createMemberRequestDTO); + params.put("userId", createMemberRequestDTO.getAccount()); + params.put("currency", createMemberRequestDTO.getCurrency()); + params.put("betLimit", JsonUtil.objToString(createMemberRequestDTO.getBetLimit())); + AEResponse aeResponse = AEClient.createMember(params); + String errorCode = aeResponse.getStatus(); + if (this.getIsSuccess(Integer.valueOf(errorCode))) { + return Boolean.TRUE; + } + //判断是否获取成功 + return Boolean.FALSE; + } + + + /** + * 获取会员信息 + * + * @param memberInfoRequestDTO 会员信息请求dto + * @return {@link MemberInfoResponseDTO } + */ + @Override + public MemberInfoResponseDTO getMemberInfo(MemberInfoRequestDTO memberInfoRequestDTO) { + log.info("GamesAEServiceImpl [getMemberInfo] 请求参数 {}", memberInfoRequestDTO); + Map params = this.getKey(memberInfoRequestDTO); + params.put("alluser", 0); + params.put("userIds", memberInfoRequestDTO.getAccounts()); + AEMemberInfo memberInfo = AEClient.getMemberInfo(params); + //判断是否获取成功 + if (this.getIsSuccess(memberInfo.getStatus())) { + AEMemberInfo.UserInfo userInfo = memberInfo.getResult().get(0); + return MemberInfoResponseDTO.builder() + .status(GameMemberStatus.UNKNOWN.getCode()) + .balance(userInfo.getBalance()) + .account(memberInfoRequestDTO.getAccounts()) + .build(); + } else { + throw new ApiException(ErrorCode.ERROR.getCode()); + } + } + + /** + * 无重定向登录 + * + * @param gamesLogin 游戏登录 + * @return {@link String } + */ + @Override + public String loginWithoutRedirect(GamesLogin gamesLogin) { + log.info("GamesAEServiceImpl [loginWithoutRedirect] 请求参数 {}", gamesLogin); + + Map params = this.getKey(gamesLogin); + params.put("userId", gamesLogin.getAccount()); + params.put("externalURL", gamesLogin.getHomeUrl()); + params.put("language", gamesLogin.getLang()); + params.put("betLimit", gamesLogin.getBetLimit()); + AELoginResponse aeLoginResponse = AEClient.loginWithoutRedirect(params); + //判断是否获取成功 + if (this.getIsSuccess(aeLoginResponse.getStatus())) { + return aeLoginResponse.getUrl(); + } else { + throw new BaseException(aeLoginResponse.getDesc()); + } + } + + + /** + * 获取游戏列表 + * + * @param gamesBaseRequestDTO 游戏请求dto + * @return {@link String } + */ + @Transactional + @Override + public String getGameList(GamesBaseRequestDTO gamesBaseRequestDTO) { + Platform platform = gamesBaseRequestDTO.getVendor(); + Game game = gameService.selectGameById(GAME_ID); + //不存在这个游戏 + if (ObjectUtils.isEmpty(game)) { + game = new Game(); + game.setId(GAME_ID); + game.setSortNo(gameService.selectMaxSortNo(PlatformType.VIDEO.getCode(), GamePlatforms.AE.getCode()) + 1); + game.setPlatformCode(platform.getPlatformCode()); + game.setPlatformType(PlatformType.VIDEO.getCode()); + game.setGameCode("1"); + game.setGameSourceType(String.valueOf(1)); + game.setGameName("AE大厅"); + game.setCreateBy(Constants.SYSTEM); + NameInfo nameInfo = new NameInfo(); + nameInfo.setLang("zh-CN"); + nameInfo.setName("AE大厅"); + game.setNameInfo(Collections.singletonList(nameInfo)); + game.setGameId(StringUtils.addSuffix(GamePlatforms.AE.getCode(), 1)); + gameService.insertGame(game); + }else { + NameInfo nameInfo = new NameInfo(); + nameInfo.setLang("zh-CN"); + nameInfo.setName("AE大厅"); + game.setNameInfo(Collections.singletonList(nameInfo)); + gameService.updateGame(game); + } + return CacheConstants.AE_GAMES; + } + + /** + * 获取交易id + * + * @param transactionIdRequestDTO 事务id请求dto + * @return {@link String } + */ + @Override + public String getTransactionId(TransactionIdRequestDTO transactionIdRequestDTO) { + return GamePlatforms.AE.getCode() + IdUtils.simpleUUID(); + } + + /** + * 按代理id进行交换转账 + * + * @param exchangeTransferMoneyRequestDTO 外汇转账moeny dto + * @return {@link Long } + */ + @Override + @Transactional + public Long exchangeTransferByAgentId(ExchangeTransferMoneyRequestDTO exchangeTransferMoneyRequestDTO) { + log.info("GamesAEServiceImpl [exchangeTransferByAgentId] 请求参数 {}", exchangeTransferMoneyRequestDTO); + + + GameExchangeMoney exchangeMoney = gameExchangeMoneyService.selectGameExchangeMoneyById(exchangeTransferMoneyRequestDTO.getGameExchangeId()); + + + + Map params = this.getKey(exchangeTransferMoneyRequestDTO); + AETransactionResponse deposit = null; + try { + if (TransferType.GAMES.getCode().equals(exchangeTransferMoneyRequestDTO.getTransferType())) { + + params.put("userId", exchangeTransferMoneyRequestDTO.getAccount()); + params.put("txCode", exchangeTransferMoneyRequestDTO.getTransactionId()); + params.put("transferAmount", exchangeTransferMoneyRequestDTO.getAmount()); + deposit = AEClient.deposit(params); + + } else { + params.put("userId", exchangeTransferMoneyRequestDTO.getAccount()); + params.put("txCode", exchangeTransferMoneyRequestDTO.getTransactionId()); + params.put("withdrawType", 1); + deposit = AEClient.withdraw(params); + } + }finally { + BigDecimal coinBefore; + if (TransferType.GAMES.getCode().equals(exchangeTransferMoneyRequestDTO.getTransferType())) { + coinBefore = NumberUtil.sub(deposit.getCurrentBalance(), deposit.getAmount()); + } else { + coinBefore = NumberUtil.add(deposit.getCurrentBalance(), deposit.getAmount()); + } + //判断是否转移成功 + if ("0000".equals(deposit.getStatus())) { + exchangeMoney.setStep(GameExchangeStep.PLATFORM_TRANSACTION.getCode()); + exchangeMoney.setStepStatus(GameExchangeStepStatus.SUCCESS.getCode()); + } else { + exchangeMoney.setStep(GameExchangeStep.PLATFORM_TRANSACTION.getCode()); + exchangeMoney.setStepStatus(GameExchangeStepStatus.IN_PROGRESS.getCode()); + } + //更新数据 + exchangeMoney.setBalance(deposit.getAmount()); + exchangeMoney.setCoinBefore(coinBefore); + exchangeMoney.setCoinAfter(deposit.getCurrentBalance()); + exchangeMoney.setCurrencyBefore(exchangeMoney.getCoinBefore()); + exchangeMoney.setCurrencyAfter(exchangeMoney.getCoinAfter()); + gameExchangeMoneyService.updateGameExchangeMoney(exchangeMoney); + + + } + + + return exchangeMoney.getId(); + } + + /** + * 汇兑转移状态 + * + * @param exchangeTransferMoneyRequestDTO 兑换转账请求dto + * @return {@link ExchangeTransferStatusResponseDTO } + */ + @Override + public ExchangeTransferStatusResponseDTO exchangeTransferStatus(ExchangeTransferStatusRequestDTO exchangeTransferMoneyRequestDTO) { + log.info("GamesAEServiceImpl [exchangeTransferStatus] 请求参数 {}", exchangeTransferMoneyRequestDTO); + + Map paramsMap = this.getKey(exchangeTransferMoneyRequestDTO); + paramsMap.put("txCode", exchangeTransferMoneyRequestDTO.getOrderId()); + + AEExchangeTransferStatusResponse exchangeTransferStatusResponse = AEClient.exchangeTransferStatus(paramsMap); + Integer status = StatusType.IN_PROGRESS.getValue(); + if ("0000".equals(exchangeTransferStatusResponse.getStatus()) && "1".equals(exchangeTransferStatusResponse.getTxStatus())) { + status = StatusType.SUCCESS.getValue(); + } else if ("0000".equals(exchangeTransferStatusResponse.getStatus()) && "0".equals(exchangeTransferStatusResponse.getTxStatus())) { + status = StatusType.FAILURE.getValue(); + } else if ("1017".equals(exchangeTransferStatusResponse.getStatus())) { + status = StatusType.FAILURE.getValue(); + } + GameExchangeMoney exchangeMoney = gameExchangeMoneyService.selectGameExchangeMoneyById(exchangeTransferMoneyRequestDTO.getGameExchangeMoneyId()); + //更新 + BigDecimal coinBefore; + if (TransferType.GAMES.getCode().equals(exchangeMoney.getExchangeType())) { + coinBefore = NumberUtil.sub(exchangeTransferStatusResponse.getBalance(), exchangeTransferStatusResponse.getTransferAmount()); + } else { + coinBefore = NumberUtil.add(exchangeTransferStatusResponse.getBalance(), exchangeTransferStatusResponse.getTransferAmount()); + } + + + + return ExchangeTransferStatusResponseDTO.builder() + .statusType(status) + .balance(exchangeTransferStatusResponse.getTransferAmount()) + .coinBefore(coinBefore) + .coinAfter(exchangeTransferStatusResponse.getBalance()) + .build(); + } + + class GetRealtimeRecordTask extends DelayTask { + BetRecordByTimeDTO betRecordByTimeDTO; + + public GetRealtimeRecordTask(BetRecordByTimeDTO betRecordByTimeDTO) { + this.betRecordByTimeDTO = betRecordByTimeDTO; + } + + @Override + public void execute() { + getRealtimeRecord(betRecordByTimeDTO); + } + } + + void getRealtimeRecord(BetRecordByTimeDTO betRecordByTimeDTO) { + //请求参数 + log.info("GamesAEServiceImpl [getBetRecordByTime] 请求参数 {}", betRecordByTimeDTO); + Map params = this.getKey(betRecordByTimeDTO); + + String timeFrom = redisCache.getCacheObject(CacheConstants.AE_TIME_FROM); + if (StringUtils.isEmpty(timeFrom)) { + timeFrom = DateUtils.convertTimestampToFormattedDate(betRecordByTimeDTO.getEndTime(), DateUtils.ISO_8601_FORMAT, "GMT+8") + "+08:00"; + } + + + params.put("timeFrom", timeFrom); + params.put("platform", "SEXYBCRT"); + params.put("delayTime", 10000); + AEBetRecordResponse aeBetRecordResponse = AEClient.getBetRecordByTime(params); + + //判断是否获取成功 + if (this.getIsSuccess(aeBetRecordResponse.getStatus())) { + //数据组装 + this.batchInsert(aeBetRecordResponse, betRecordByTimeDTO); + if (aeBetRecordResponse.getTransactions().size() >= 20000) { + delayService.addTask(new GetRealtimeRecordTask(betRecordByTimeDTO)); + } + //return Boolean.TRUE; + } else { + redisCache.deleteObject(CacheConstants.AE_TIME_FROM); + log.error("GamesAEServiceImpl [getBetRecordByTime] 获取投注记录失败,错误代码{},错误信息{}", aeBetRecordResponse.getStatus(), aeBetRecordResponse.getDesc()); + //throw new BaseException(aeBetRecordResponse.getDesc()); + } + + } + + class GetHistoryRecordTask extends DelayTask { + BetRecordByTimeDTO betRecordByTimeDTO; + + public GetHistoryRecordTask(BetRecordByTimeDTO betRecordByTimeDTO) { + this.betRecordByTimeDTO = betRecordByTimeDTO; + } + + @Override + public void execute() { + getHistoryRecord(betRecordByTimeDTO); + } + } + + void getHistoryRecord(BetRecordByTimeDTO betRecordByTimeDTO) { + log.info("GamesAEServiceImpl [getBetRecordByHistoryTime] 请求参数 {}", betRecordByTimeDTO); + Map params = this.getKey(betRecordByTimeDTO); + String startTime = DateUtils.convertTimestampToFormattedDate(betRecordByTimeDTO.getStartTime(), DateUtils.ISO_8601_FORMAT, "GMT+8") + "+08:00"; + String endTime = DateUtils.convertTimestampToFormattedDate(betRecordByTimeDTO.getEndTime(), DateUtils.ISO_8601_FORMAT, "GMT+8") + "+08:00"; + + + params.put("startTime", startTime); + params.put("endTime", endTime); + params.put("platform", "SEXYBCRT"); + AEBetRecordResponse aeBetRecordResponse = AEClient.getBetHistoryRecordByTime(params); + + //判断是否获取成功 + if (this.getIsSuccess(aeBetRecordResponse.getStatus())) { + //数据组装 + this.batchInsert(aeBetRecordResponse, betRecordByTimeDTO); + if (aeBetRecordResponse.getTransactions().size() >= 20000) { + delayService.addTask(new GetHistoryRecordTask(betRecordByTimeDTO)); + } +// return Boolean.TRUE; + } else { + log.error("GamesAEServiceImpl [getBetRecordByHistoryTime] 获取投注记录失败,错误代码{},错误信息{}", aeBetRecordResponse.getStatus(), aeBetRecordResponse.getDesc()); +// throw new BaseException(aeBetRecordResponse.getDesc()); + } + } + + /** + * 按时间获取投注记录 + * + * @param betRecordByTimeDTO 按时间dto投注记录 + * @return {@link List }<{@link GameBettingDetails }> + */ + @Override + public Boolean getBetRecordByTime(BetRecordByTimeDTO betRecordByTimeDTO) { + delayService.addTask(new GetRealtimeRecordTask(betRecordByTimeDTO)); + return Boolean.TRUE; + } + + /** + * 按历史时间获取投注记录 + * + * @param betRecordByTimeDTO 按时间dto投注记录 + * @return {@link Boolean } + */ + @Override + public Boolean getBetRecordByHistoryTime(BetRecordByTimeDTO betRecordByTimeDTO) { + delayService.addTask(new GetHistoryRecordTask(betRecordByTimeDTO)); + return Boolean.TRUE; + } + + /** + * 赠送免费局数 + * + * @param createFreeSpinRequest 创建自由旋转请求 + * @return {@link Boolean } + */ + @Override + public Boolean createFreeSpin(CreateFreeSpinRequestDTO createFreeSpinRequest) { + throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); + } + + /** + * 获取游戏详细信息 + * + * @param getGameDetailRequestDTO 获取游戏详细信息请求dto + * @return {@link GetGameDetailResponseDTO } + */ + @Override + public GetGameDetailResponseDTO getGameDetail(GetGameDetailRequestDTO getGameDetailRequestDTO) { + throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); + } + + /** + * 强制会员从游戏注销 + * + * @param kickMemberRequestDTO 踢会员请求dto + * @return {@link Boolean } + */ + @Override + public Boolean kickMember(KickMemberRequestDTO kickMemberRequestDTO) { + log.info("GamesAEServiceImpl [kickMember] 请求参数 {}", kickMemberRequestDTO); + Map params = this.getKey(kickMemberRequestDTO); + params.put("userIds", kickMemberRequestDTO.getAccount()); + XKKickMemberDTO xkKickMemberDTO = AEClient.kickMember(params); + //判断是否获取成功 + if (this.getIsSuccess(xkKickMemberDTO.getCode())) { + return Boolean.TRUE; + } else { + throw new BaseException(xkKickMemberDTO.getMsg()); + } + } + + /** + * 踢成员全部 + * + * @param kickMemberAllDTO 踢成员全部dto + * @return {@link Boolean } + */ + @Override + public Boolean kickMemberAll(KickMemberAllDTO kickMemberAllDTO) { + throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); + } + + /** + * 免费游戏玩家使用的纪录 + * + * @param getFreeSpinDashflowRequestDTO 获取自由旋转dashflow请求dto + * @return {@link List }<{@link GameFreeRecord }> + */ + @Override + public List getFreeSpinDashflow(GetFreeSpinDashflowRequestDTO getFreeSpinDashflowRequestDTO) { + throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); + } + + /** + * 取消赠送免费局数 + * + * @param cancelFreeSpinRequestDTO 取消免费旋转请求 + * @return {@link Boolean } + */ + @Override + public Boolean cancelFreeSpin(CancelFreeSpinRequestDTO cancelFreeSpinRequestDTO) { + throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); + } + + /** + * 游戏演示登录 + * + * @param gameDemoLoginRequestDTO 游戏演示登录请求dto + * @return {@link GameDemoLoginResponseDTO } + */ + @Override + public GameDemoLoginResponseDTO gameDemoLogin(GameDemoLoginRequestDTO gameDemoLoginRequestDTO) { + throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); + } + + + /** + * 批量插入 + * + * @param aeBetRecordResponse ae下注记录响应dto + */ + private synchronized void batchInsert(AEBetRecordResponse aeBetRecordResponse, BetRecordByTimeDTO betRecordByTimeDTO) { + List gameBettingDetails = new ArrayList<>(); + List wagersIds = new ArrayList<>(); + //数据组装 + List dataBean = aeBetRecordResponse.getTransactions(); + + String timeFrom = null; + //数据转化 + for (AEBetRecordResponse.Transaction bean : dataBean) { + GameBettingDetails bettingDetails = this.dataBuild(GamesDataBuildDTO.builder() + .platform(betRecordByTimeDTO.getVendor()) + .data(bean).build()); + if (!ObjectUtils.isEmpty(bettingDetails)) { + bettingDetails.setId(IdUtil.getSnowflakeNextId()); + gameBettingDetails.add(bettingDetails); + } + wagersIds.add(bean.getPlatform() + bean.getPlatformTxId()); + timeFrom = bean.getUpdateTime(); + } + if (!CollectionUtils.isEmpty(gameBettingDetails)) { + //查询重复数据id + List removeWagersIds = gameBettingDetailsService.selectGameBettingDetailsByWagersId(wagersIds, GamePlatforms.AE.getInfo()); + //用steam流清除list中与wagersIds集合相同的数据 + gameBettingDetails = gameBettingDetails.stream() + .filter(detail -> !removeWagersIds.contains(detail.getWagersId())) + .collect(Collectors.toList()); + if (!CollectionUtils.isEmpty(gameBettingDetails)) { + gameBettingDetailsService.batchInsert(gameBettingDetails); + } + } + if (StringUtils.isEmpty(timeFrom)) { + timeFrom = DateUtils.convertTimestampToFormattedDate(DateUtils.getNowDate(), DateUtils.ISO_8601_FORMAT, "UTC+8") + "+08:00"; + } + redisCache.setCacheObject(CacheConstants.AE_TIME_FROM, timeFrom); + } + + /** + * 数据构建 + * + * @param gamesDataBuildDTO 数据 + * @return {@link GameBettingDetails } + */ + @Override + public GameBettingDetails dataBuild(GamesDataBuildDTO gamesDataBuildDTO) { + //转化类 + AEBetRecordResponse.Transaction resultBean = (AEBetRecordResponse.Transaction) gamesDataBuildDTO.getData(); + + + Member member = memberService.selectMemberByGameAccount(resultBean.getUserId()); + if (ObjectUtils.isEmpty(member)) { + return null; + } + + + // 判断输赢 + Integer gameStatus = GameStatus.FLAT.getCode(); + BigDecimal payoffAmount = BigDecimal.ZERO; + if (resultBean.getRealWinAmount().compareTo(resultBean.getRealBetAmount()) > 0) { + gameStatus = GameStatus.WIN.getCode(); + payoffAmount = resultBean.getRealWinAmount().subtract(resultBean.getRealBetAmount()); + } else if (resultBean.getRealWinAmount().compareTo(resultBean.getRealBetAmount()) < 0) { + gameStatus = GameStatus.FAIL.getCode(); + payoffAmount = resultBean.getRealWinAmount().subtract(resultBean.getRealBetAmount()).abs(); + } + + //结算状态 + int settlementStatus = SettlementStatusEnum.REVOKED.getCode(); + if (resultBean.getTxStatus() == 1) { + settlementStatus = SettlementStatusEnum.COMPLETED.getCode(); + } + + //数据构造 + GameBettingDetails gameBettingDetails = GameBettingDetails.builder() + .tenantKey(member.getTenantKey()) + //保存我们的币种id + .currencyCode(gamesDataBuildDTO.getPlatform().getOurCurrency(resultBean.getCurrency())) + .memberId(member.getId()) + .gameCode(resultBean.getGameCode()) + .gameType(PlatformType.GAME_HALL.getCode()) + .platformCode(GamePlatforms.AE.getCode()) + .gameId(/*GAME_ID*/ StringUtils.addSuffix(GamePlatforms.AE.getCode(), 1)) + .gameName(resultBean.getGameName()) + .gameStatus(gameStatus) + .gameStatusType(resultBean.getSettleStatus()) + .gameCurrencyCode(resultBean.getCurrency()) + .account(resultBean.getUserId()) + .wagersId(resultBean.getPlatform() + resultBean.getPlatformTxId()) + .wagersTime(resultBean.getBetTime().getTime()) + .betAmount(resultBean.getRealBetAmount()) + .payoffTime(resultBean.getTxTime().getTime()) + .payoffAmount(payoffAmount) + .betContent(resultBean.getGameInfo()) + .settlementTime(resultBean.getTxTime().getTime()) + .turnover(resultBean.getTurnover()) + .orderNo(String.valueOf(resultBean.getRoundId())) + .settlementStatus(settlementStatus) + .build(); + gameBettingDetails.setCreateBy(Constants.SYSTEM); + gameBettingDetails.setCreateTime(DateUtils.getNowDate()); + return gameBettingDetails; + } +} diff --git a/ff-game/src/main/java/com/ff/game/api/db/address/DBSportsAddress.java b/ff-game/src/main/java/com/ff/game/api/db/address/DBSportsAddress.java new file mode 100644 index 0000000..f32e3a0 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/db/address/DBSportsAddress.java @@ -0,0 +1,32 @@ +package com.ff.game.api.db.address; + +import com.dtflys.forest.callback.AddressSource; +import com.dtflys.forest.http.ForestAddress; +import com.dtflys.forest.http.ForestRequest; +import com.ff.base.enums.GamePlatforms; +import com.ff.game.service.IPlatformService; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + + +/** + * DB体育对接文档 + * 账号: api + * 密码: a12345678 + * + * @author cengy + */ +@Component +public class DBSportsAddress implements AddressSource { + + @Resource + private IPlatformService platformService; + + @Override + public ForestAddress getAddress(ForestRequest request) { + String apiBaseUrl = platformService.get(GamePlatforms.DBSports.getCode()) + .getUrlInfo().getUrl(); + return new ForestAddress("https", apiBaseUrl, 443, ""); + } +} \ No newline at end of file diff --git a/ff-game/src/main/java/com/ff/game/api/db/client/DBSportsClient.java b/ff-game/src/main/java/com/ff/game/api/db/client/DBSportsClient.java new file mode 100644 index 0000000..6087b04 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/db/client/DBSportsClient.java @@ -0,0 +1,110 @@ +package com.ff.game.api.db.client; + +import com.dtflys.forest.annotation.*; +import com.ff.game.api.db.address.DBSportsAddress; +import com.ff.game.api.db.dto.*; + +/** + * @author cengy + */ +@Address(source = DBSportsAddress.class) +public interface DBSportsClient { + /** + * 创建投注用户 + * + * @return {@link CreateUserResponse} + */ + @Post(url = "/api/user/create", + headers = { + "Content-type: application/x-www-form-urlencoded" + } + ) + CreateUserResponse createMember(@Body CreateUserRequest request, + @Header("requestId") @Var("requestId") String requestId); + + /** + * 用户登录接口(注册和登录合并为一个接口) + * + * @param request + * @param requestId + * @return + */ + @Post(url = "/api/user/login", + headers = { + "Content-type: application/x-www-form-urlencoded" + } + ) + LoginResponse login(@Body LoginRequest request, + @Header("requestId") String requestId); + + /** + * 用户金额转入到DB体育平台,支持两位小数,最小0.01,必须是正数 + * + * @param request + * @return {@link TransferResponse} + */ + @Post(url = "/api/fund/transfer", + headers = { + "Content-type: application/x-www-form-urlencoded" + } + ) + TransferResponse transferIn(@Body TransferRequest request, + @Header("requestId") @Var("requestId") String requestId + ); + + @Post(url = "/api/fund/transfer", + headers = { + "Content-type: application/x-www-form-urlencoded" + } + ) + TransferResponse transferOut(@Body TransferRequest request, + @Header("requestId") String requestId + ); + + @Post(url = "/api/fund/checkBalance", + headers = { + "Content-type: application/x-www-form-urlencoded" + } + ) + GetMemberInfoResponse getMemberInfo(@Body GetMemberInfoRequest request, + @Header("requestId") String requestId); + + /** + * 根据转账ID查询交易记录接口。 + */ + @Post(url = "/api/fund/getTransferRecord", + headers = { + "Content-type: application/x-www-form-urlencoded" + } + ) + TransferDetailResponse transferDetail(@Body TransferDetailRequest request, + @Header("requestId") String requestId); + + /** + * 剔用户 + * + * @param request + * @param requestId + * @return + */ + @Post(value = "/api/user/kickOutUser", + headers = { + "Content-type: application/x-www-form-urlencoded" + } + ) + KickUserResponse kickUser(@Body KickUserRequest request, + @Header("requestId") String requestId); + + + /** + * 拉取订单Json数据 + */ + @Post(url = "/api/bet/queryBetListV2", + headers = { + "Content-type: application/x-www-form-urlencoded" + } + ) + GetBetListResponse getBetList(@Body GetBetListRequest request, + @Header("requestId") String requestId); + +} diff --git a/ff-game/src/main/java/com/ff/game/api/db/dto/CreateUserRequest.java b/ff-game/src/main/java/com/ff/game/api/db/dto/CreateUserRequest.java new file mode 100644 index 0000000..e80f80a --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/db/dto/CreateUserRequest.java @@ -0,0 +1,28 @@ +package com.ff.game.api.db.dto; + +import com.ff.base.utils.sign.Md5Utils; +import lombok.Data; + +import java.io.Serializable; + +/** + * @author cengy + */ +@Data +public class CreateUserRequest implements Serializable { + + private static final long serialVersionUID = 1L; + + private String userName; // 用户名(可以包含但是不要等同于特殊字符或者空格,长度控制在30个字符以下) + private String merchantCode; // 商户code + private String timestamp = System.currentTimeMillis() + ""; // 13位时间戳 + private String currency; // 币种 + private String nickname; // N 昵称 + private String agentId; // N 信用网(代理id) + private String signature; // 签名 signature =MD5(MD5(userName +”&”+ merchantCode +”&”+ timestamp) + ”&”+ key) + + public void buildSignature(String key) { + String signature = Md5Utils.md5New(Md5Utils.md5New(userName + "&" + merchantCode + "&" + timestamp) + "&" + key); + this.signature = signature; + } +} diff --git a/ff-game/src/main/java/com/ff/game/api/db/dto/CreateUserResponse.java b/ff-game/src/main/java/com/ff/game/api/db/dto/CreateUserResponse.java new file mode 100644 index 0000000..e299ed2 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/db/dto/CreateUserResponse.java @@ -0,0 +1,26 @@ +package com.ff.game.api.db.dto; + +import lombok.Data; + +import java.io.Serializable; + +/** + * @author cengy + */ +@Data +public class CreateUserResponse implements Serializable { + + private static final long serialVersionUID = 1L; + + private Boolean status; + private String msg; + private String code; + private Long serverTime; + private UserDTO data; + + @Data + public static class UserDTO { + private String userId; + } + +} diff --git a/ff-game/src/main/java/com/ff/game/api/db/dto/Enums.java b/ff-game/src/main/java/com/ff/game/api/db/dto/Enums.java new file mode 100644 index 0000000..618297b --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/db/dto/Enums.java @@ -0,0 +1,9 @@ +package com.ff.game.api.db.dto; + +/** + * @author cengy + */ +public class Enums { + + +} diff --git a/ff-game/src/main/java/com/ff/game/api/db/dto/GetBetListRequest.java b/ff-game/src/main/java/com/ff/game/api/db/dto/GetBetListRequest.java new file mode 100644 index 0000000..de41a0f --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/db/dto/GetBetListRequest.java @@ -0,0 +1,93 @@ +package com.ff.game.api.db.dto; + +import com.ff.base.utils.sign.Md5Utils; +import lombok.Data; + +import java.io.Serializable; + +/** + * @author cengy + */ +@Data +public class GetBetListRequest implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 用户名(可选) + */ + private String userName; + + /** + * 开始时间(13位时间戳,必填) + */ + private String startTime; + + /** + * 结束时间(13位时间戳,必填) + */ + private String endTime; + + /** + * 商户编码(必填) + */ + private String merchantCode; + + /** + * 赛种ID(可选) + */ + private Integer sportId; + + /** + * 联赛ID(可选) + */ + private Long tournamentId; + + /** + * 结算状态(可选) + * 0: 未结算 + * 1: 已结算 + * 2: 取消人工 + * 3: 待确认 + * 4: 风控拒单 + * 5: 撤单(赛事取消) + */ + private Integer settleStatus; + + /** + * 页面编号,从1开始(可选) + */ + private Integer pageNum; + + /** + * 每页条数(最大1000,可选) + */ + private Integer pageSize; + + /** + * 请求时间戳(13位,必填) + */ + private String timestamp = String.valueOf(System.currentTimeMillis()); + + /** + * 排序方式(可选) + * 1: 订单创建时间(投注时间) + * 2: 订单更新时间 + */ + private Integer orderBy; + + /** + * 语言(可选,默认中文,传"en"返回英文) + */ + private String language; + + /** + * 签名(必填) + */ + private String signature; + + public void buildSignature(String key) { + String signature = Md5Utils.md5New(Md5Utils.md5New(merchantCode + "&" + startTime + "&" + endTime + "&" + timestamp) + "&" + key); + this.signature = signature; + } +} diff --git a/ff-game/src/main/java/com/ff/game/api/db/dto/GetBetListResponse.java b/ff-game/src/main/java/com/ff/game/api/db/dto/GetBetListResponse.java new file mode 100644 index 0000000..ea1bb84 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/db/dto/GetBetListResponse.java @@ -0,0 +1,199 @@ +package com.ff.game.api.db.dto; + +import lombok.Data; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.List; + +/** + * @author cengy + */ +@Data +public class GetBetListResponse implements Serializable { + + private static final long serialVersionUID = 1L; + + private Boolean status; + private String msg; + private String code; + private Long serverTime; + private DataDTO data; + + @Data + public static class DataDTO { + + + // 当前页码 + private Integer pageNum; + // 每页条数 + private Integer pageSize; + // 总条数 + private Integer totalCount; + // 注单列表 + private List list; + } + + @Data + public static class OrderItemDTO { + // 用户名 + private String userName; + + // 商户编码 + private String merchantCode; + + // 订单ID + private String orderNo; + + // 订单状态,具体见参数字段映射 + private Integer orderStatus; + + // 投注时间(13位时间戳) + private Long createTime; + + // 订单更新时间(13位时间戳) + private Long modifyTime; + + // 实际投注金额 + private String orderAmount; + + // 注单项数量 + private Integer betCount; + + // 结算时间(13位时间戳) + private Long settleTime; + + // 结算金额 + private Double settleAmount; + + // 提前结算投注金额 + private Double preBetAmount; + + // 盈利金额 + private Double profitAmount; + + // 注单结算结果 + // 2:走水,3:输,4:赢,5:赢半,6:输半,7:赛事取消,8:赛事延期 + private Integer outcome; + + // 串关类型 + private Integer seriesType; + + // 串关值 + private String seriesValue; + + // 结算次数 + private Integer settleTimes; + + // 设备类型:1-H5,2-PC,3-Android,4-IOS + private String deviceType; + + // 移动设备标识 + private String deviceImei; + + // 用户IP地址 + private String ip; + + // 币种 + private String currency; + + // 汇率 + private BigDecimal exchangeRate; + + // 最大中奖金额 + private Double maxWinAmount; + + // VIP等级 + private Integer vipLevel; + + // 投注前余额 + private BigDecimal beforeTransfer; + + // 投注后余额 + private BigDecimal afterTransfer; + + // 有效投注金额 + private BigDecimal validOrderAmount; + + // 注单详情列表 + private List detailList; + } + + @Data + public static class DetailItemDTO { + // 投注项编号 + private Long betNo; + + // 投注项ID + private Long playOptionsId; + + // 赛事ID + private Long matchId; + + // 比赛开始时间(13位时间戳) + private Long beginTime; + + // 注单金额 + private Double betAmount; + + // 联赛名称 + private String matchName; + + // 比赛对阵 + private String matchInfo; + + // 投注类型: + // 1:早盘,2:滚球盘,3:冠军盘,4:虚拟赛事,5:电竞赛事 + private Integer matchType; + + // 赛种ID + private Integer sportId; + + // 玩法ID + private Integer playId; + + // 投注项(如主客队) + private String playOptions; + + // 游戏名称 + private String sportName; + + // 联赛ID + private Long tournamentId; + + // 投注项名称 + private String playOptionName; + + // 玩法名称 + private String playName; + + // 盘口类型 + private String marketType; + + // 盘口值 + private String marketValue; + + // 让球值 + private BigDecimal handicap; + + // 结算比分(我方处理后所得,数据商可能未提供) + private String settleScore; + + // 基准分 + private String scoreBenchmark; + + // 当前赔率(欧洲盘表示) + private BigDecimal oddsValue; + + // 注单结算结果: + // 0:无结果,2:走水,3:输,4:赢,5:赢一半,6:输一半, + // 7:赛事取消,8:赛事延期,11:比赛延迟,12:比赛中断, + // 13:未知,15:比赛放弃,16:异常盘口,17:未知状态, + // 18:比赛取消,19:比赛延期 + private String betResult; + + // 最终赔率(按盘口类型) + private BigDecimal oddFinally; + } + +} diff --git a/ff-game/src/main/java/com/ff/game/api/db/dto/GetMemberInfoRequest.java b/ff-game/src/main/java/com/ff/game/api/db/dto/GetMemberInfoRequest.java new file mode 100644 index 0000000..98f5e5b --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/db/dto/GetMemberInfoRequest.java @@ -0,0 +1,36 @@ +package com.ff.game.api.db.dto; + +import com.ff.base.utils.sign.Md5Utils; +import lombok.Data; + +import java.io.Serializable; + +/** + * @author cengy + */ +@Data +public class GetMemberInfoRequest implements Serializable { + private static final long serialVersionUID = 1L; + + /** + * 用户名,不能为空 + */ + private String userName; + + /** + * 商户编码 + */ + private String merchantCode; + /** + * Long型时间戳(13位) + */ + private String timestamp = System.currentTimeMillis() + ""; + + private String signature; + + public void buildSignature(String key) { + + String signature = Md5Utils.md5New(Md5Utils.md5New(merchantCode + "&" + userName + "&" + timestamp) + "&" + key); + this.signature = signature; + } +} diff --git a/ff-game/src/main/java/com/ff/game/api/db/dto/GetMemberInfoResponse.java b/ff-game/src/main/java/com/ff/game/api/db/dto/GetMemberInfoResponse.java new file mode 100644 index 0000000..c10cf48 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/db/dto/GetMemberInfoResponse.java @@ -0,0 +1,27 @@ +package com.ff.game.api.db.dto; + +import lombok.Data; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.List; + +/** + * @author cengy + */ +@Data +public class GetMemberInfoResponse implements Serializable { + private static final long serialVersionUID = 1L; + + private Boolean status; + private String msg; + private String code; + private Long serverTime; + private MemberInfoDTO data; + + @Data + public static class MemberInfoDTO { + private BigDecimal balance; + private String userName; + } +} diff --git a/ff-game/src/main/java/com/ff/game/api/db/dto/KickUserRequest.java b/ff-game/src/main/java/com/ff/game/api/db/dto/KickUserRequest.java new file mode 100644 index 0000000..33bcf0e --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/db/dto/KickUserRequest.java @@ -0,0 +1,24 @@ +package com.ff.game.api.db.dto; + +import com.ff.base.utils.sign.Md5Utils; +import lombok.Data; + +import java.io.Serializable; + +/** + * @author cengy + */ +@Data +public class KickUserRequest implements Serializable { + + private static final long serialVersionUID = 1L; + private String userName; + private String merchantCode; + private String timestamp = System.currentTimeMillis() + ""; + private String signature; + + public void buildSignature(String key) { + String signature = Md5Utils.md5New(Md5Utils.md5New(merchantCode + "&" + userName + "&" + timestamp) + "&" + key); + this.signature = signature; + } +} diff --git a/ff-game/src/main/java/com/ff/game/api/db/dto/KickUserResponse.java b/ff-game/src/main/java/com/ff/game/api/db/dto/KickUserResponse.java new file mode 100644 index 0000000..0f27fd3 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/db/dto/KickUserResponse.java @@ -0,0 +1,20 @@ +package com.ff.game.api.db.dto; + +import lombok.Data; + +import java.io.Serializable; + +/** + * @author cengy + */ +@Data +public class KickUserResponse implements Serializable { + + private static final long serialVersionUID = 1L; + + private Boolean status; + private String msg; + private String code; + private Long serverTime; + +} diff --git a/ff-game/src/main/java/com/ff/game/api/db/dto/LoginRequest.java b/ff-game/src/main/java/com/ff/game/api/db/dto/LoginRequest.java new file mode 100644 index 0000000..d2dc47e --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/db/dto/LoginRequest.java @@ -0,0 +1,57 @@ +package com.ff.game.api.db.dto; + +import com.ff.base.utils.sign.Md5Utils; +import lombok.Data; + +import java.io.Serializable; +import java.math.BigDecimal; + +/** + * @author cengy + */ +@Data +public class LoginRequest implements Serializable { + + private static final long serialVersionUID = 1L; + private String userName; + private String merchantCode; + private String timestamp = System.currentTimeMillis() + ""; + private String signature; + + // 不能传错,用户可能受到设备类型相关风控措施的错误限制,进而影响正常用户货量,并产生客诉 + private String terminal; // 终端类型:【电脑传值:pc】,【移动设备传值:mobile】 注:这个参数传值必须是pc或者mobile, + private BigDecimal balance; // 用户余额,N + private String currency; // 币种(见参数映射:支持币种 )会员首次登录,必须填写币种参数,否则注册失败 + + private String callbackUrl; // 玩家会话失效跳转的商户地址url(非必传) + private String stoken; // 非必传字段(商户方用户会话) + + // 非必传字段(支持体育游戏其他端的跳转) , + // C端⽀持跳转的游戏,如果C端⽀持跳转多个游戏 , + // 则使⽤逗号区分。 具体字段可查看:参数字段映射第6条 参数字段映射 + private String jumpsupport; + private String jumpfrom; // 非必传字段,同上 + + private String agentId; // 信用网(代理id),N + // 用户语种: + //zh:中文 + //en:英文 + //vi:越南语 + //tw:中文繁体 + //th:泰语 + //ms:马来语 + //ad:印尼语 + //ko:韩语 + //mya:缅甸语 + //pt:葡萄牙语 + //es:西班牙语 + //非必传字段 + private String language; + private String ip; // 非必传字段 说明:商户端在该字段上传入用户登陆时端ip + + public void buildSignature(String key) { + String signature = Md5Utils.md5New(Md5Utils.md5New(merchantCode + "&" + userName + "&" + terminal + "&" + timestamp) + "&" + key); + + this.signature = signature; + } +} diff --git a/ff-game/src/main/java/com/ff/game/api/db/dto/LoginResponse.java b/ff-game/src/main/java/com/ff/game/api/db/dto/LoginResponse.java new file mode 100644 index 0000000..10ef3c6 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/db/dto/LoginResponse.java @@ -0,0 +1,34 @@ +package com.ff.game.api.db.dto; + +import lombok.Data; + +import java.io.Serializable; +import java.util.List; + +/** + * @author cengy + */ +@Data +public class LoginResponse implements Serializable { + + private static final long serialVersionUID = 1L; + + private Boolean status; + private String msg; + private String code; + private Long serverTime; + private LoginRespDTO data; + + @Data + public static class LoginRespDTO { + private String domain; // 体育游戏前端URL + private String token; // 带有登录状态的token + private String apiDomain;// 赛事API的域名(若没有对接赛事API,为空) + private String imgDomain; // 静态资源域名 + private String loginUrl; // 登录体育URL,可直接跳转 + private String userId; // 用户id + private String url; // 参加活动的商户使用,客户端域名和参数拼接后提供商户使用 + private List loginUrlArr; // loginUrl数组,多个域名,调试使用 + } + +} diff --git a/ff-game/src/main/java/com/ff/game/api/db/dto/TransferDetailRequest.java b/ff-game/src/main/java/com/ff/game/api/db/dto/TransferDetailRequest.java new file mode 100644 index 0000000..4a6a2a1 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/db/dto/TransferDetailRequest.java @@ -0,0 +1,38 @@ +package com.ff.game.api.db.dto; + +import com.ff.base.utils.sign.Md5Utils; +import lombok.Data; + +import java.io.Serializable; + +/** + * @author cengy + */ +@Data +public class TransferDetailRequest implements Serializable { + + /** + * 用户名,N + */ + private String userName; + /** + * 商户code + */ + private String merchantCode; + /** + * 交易id(19位数字) + */ + private String transferId; + + private String timestamp = System.currentTimeMillis() + ""; + + /** + * 签名 + */ + private String signature; + + public void buildSignature(String key) { + String signature = Md5Utils.md5New(Md5Utils.md5New(merchantCode + "&" + transferId + "&" + timestamp) + "&" + key); + this.signature = signature; + } +} diff --git a/ff-game/src/main/java/com/ff/game/api/db/dto/TransferDetailResponse.java b/ff-game/src/main/java/com/ff/game/api/db/dto/TransferDetailResponse.java new file mode 100644 index 0000000..42866b1 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/db/dto/TransferDetailResponse.java @@ -0,0 +1,39 @@ +package com.ff.game.api.db.dto; + +import lombok.Data; + +import java.io.Serializable; +import java.math.BigDecimal; + +/** + * @author cengy + */ +@Data +public class TransferDetailResponse implements Serializable { + private static final long serialVersionUID = 1L; + + private TransferDetailDTO data; + private Boolean status; + private String msg; + private String code; + private Long serverTime; + + @Data + public static class TransferDetailDTO implements Serializable { + private static final long serialVersionUID = 1L; + + private String transferId; // 交易id + private String merchantCode; // 商户代码 + private Long userId; // 用户id + private Integer transferType; // 交易类型 1:加款,2:扣款 + private BigDecimal amount; // 交易金额 + private BigDecimal beforeTransfer; // 转账前余额 + private Integer afterTransfer; // 转账后余额 + private Integer status; // 转账成功与否(0:失败,1:成功) + private String mag; // 转账模式 1:免转,2:转账 + private Integer transferMode; // 转账涉及订单(transferMode为2时,该字段为空) + private Long createTime; // 交易时间 + + } + +} diff --git a/ff-game/src/main/java/com/ff/game/api/db/dto/TransferRequest.java b/ff-game/src/main/java/com/ff/game/api/db/dto/TransferRequest.java new file mode 100644 index 0000000..03991af --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/db/dto/TransferRequest.java @@ -0,0 +1,28 @@ +package com.ff.game.api.db.dto; + +import com.ff.base.utils.sign.Md5Utils; +import lombok.Data; + +import java.io.Serializable; + +/** + * @author cengy + */ +@Data +public class TransferRequest implements Serializable { + + private String userName; + private String merchantCode; + private int transferType; // 1:加款 2:扣款 + + private String amount; // 金额,小数2位 + private String transferId; // 交易的讯息号,唯一标示,不可重复,19位长度的字符串 + private String timestamp = String.valueOf(System.currentTimeMillis()); + private String signature; + + public void buildSignature(String key) { + String signature = Md5Utils.md5New(Md5Utils.md5New(merchantCode + "&" + userName + "&" + transferType + "&" + amount + "&" + transferId + "&" + timestamp) + "&" + key); + this.signature = signature; + } + +} diff --git a/ff-game/src/main/java/com/ff/game/api/db/dto/TransferResponse.java b/ff-game/src/main/java/com/ff/game/api/db/dto/TransferResponse.java new file mode 100644 index 0000000..5e563f5 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/db/dto/TransferResponse.java @@ -0,0 +1,25 @@ +package com.ff.game.api.db.dto; + +import lombok.Data; + +import java.io.Serializable; + +/** + * @author cengy + */ +@Data +public class TransferResponse implements Serializable { + + private static final long serialVersionUID = 1L; + + private Boolean status; + private String msg; + private String code; + private Long serverTime; + private TransferDTO data; + + @Data + public static class TransferDTO { + private String userName; + } +} diff --git a/ff-game/src/main/java/com/ff/game/api/db/impl/DBSportsServiceImpl.java b/ff-game/src/main/java/com/ff/game/api/db/impl/DBSportsServiceImpl.java new file mode 100644 index 0000000..a2d158b --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/db/impl/DBSportsServiceImpl.java @@ -0,0 +1,609 @@ +package com.ff.game.api.db.impl; + +import cn.hutool.core.util.IdUtil; +import com.ff.base.constant.CacheConstants; +import com.ff.base.constant.Constants; +import com.ff.base.core.redis.RedisCache; +import com.ff.base.enums.*; +import com.ff.base.exception.base.ApiException; +import com.ff.base.exception.base.BaseException; +import com.ff.base.utils.DateUtils; +import com.ff.base.utils.StringUtils; +import com.ff.base.utils.sign.Md5Utils; +import com.ff.base.utils.uuid.IdUtils; +import com.ff.game.api.IGamesService; +import com.ff.game.api.db.dto.*; +import com.ff.game.api.request.*; +import com.ff.game.domain.*; +import com.ff.game.service.IGameBettingDetailsService; +import com.ff.game.service.IGameExchangeMoneyService; +import com.ff.game.service.IGameService; +import com.ff.member.domain.Member; +import com.ff.member.service.IMemberService; +import com.ff.game.api.db.client.DBSportsClient; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ObjectUtils; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + + +/** + * DB体育 + * + * @author cengy + * @date 2024/10/21 + */ +@Service("DBSportsService") +@Slf4j +public class DBSportsServiceImpl implements IGamesService { + + @Resource + private RedisCache redisCache; + + @Resource + private IGameExchangeMoneyService gameExchangeMoneyService; + + @Resource + private IGameService gameService; + + + @Resource + private IMemberService memberService; + + @Resource + private DBSportsClient dbSportsClient; + + @Resource + private IGameBettingDetailsService gameBettingDetailsService; + + /** + * 获得就是成功 + * + * @param errorCode 错误代码 + * @return {@link Boolean } + */ + private Boolean isSuccess(String errorCode) { + return "0000".equals(errorCode); + } + + String getSign(String bodyJsonString, String merchantId, String merchantApiSecret, long requestTimestamp) { + + String stringThatNeedsToBeSigned = bodyJsonString + "." + merchantId + "." + requestTimestamp + "." + merchantApiSecret; + String sign = Md5Utils.md5New(stringThatNeedsToBeSigned); + return sign; + } + + /** + * 创建成员 + * + * @param requestDTO 创建成员请求dto + * @return {@link Boolean } + */ + @Override + public Boolean createMember(CreateMemberRequestDTO requestDTO) { + + CreateUserRequest request = new CreateUserRequest(); + request.setUserName(requestDTO.getAccount()); + request.setMerchantCode(requestDTO.getAgentId()); + request.setCurrency(requestDTO.getCurrency()); + request.buildSignature(requestDTO.getAgentKey()); + + //String lang = requestDTO.getLan + String requestId = IdUtils.fastUUID(); + CreateUserResponse response = dbSportsClient.createMember(request, requestId); + if (isSuccess(response.getCode())) { + return Boolean.TRUE; + } + + log.error("创建会员失败, errorCode:{}, errorMessage:{}", response.getCode(), response.getMsg()); + throw new ApiException(ErrorCode.Create_Member_Failure.getCode()); + } + + + /** + * 按代理id进行交换转账 + * + * @param requestDTO 外汇转账 + * @return {@link Long } + */ + @Override + @Transactional + public Long exchangeTransferByAgentId(ExchangeTransferMoneyRequestDTO requestDTO) { + + GameExchangeMoney exchangeMoney = gameExchangeMoneyService.selectGameExchangeMoneyById(requestDTO.getGameExchangeId()); + // 转入 + if (requestDTO.getTransferType().equals(TransferType.GAMES.getCode())) { + TransferRequest request = new TransferRequest(); + request.setUserName(requestDTO.getAccount()); + request.setTransferType(1); + request.setTransferId(requestDTO.getTransactionId()); + request.setMerchantCode(requestDTO.getAgentId()); + request.setAmount(requestDTO.getAmount().toString()); + request.buildSignature(requestDTO.getAgentKey()); + + TransferResponse response = dbSportsClient.transferIn( + request, IdUtils.fastUUID() + ); + if (isSuccess(response.getCode())) { + GetMemberInfoRequest queryMemberRequest = new GetMemberInfoRequest(); + queryMemberRequest.setUserName(requestDTO.getAccount()); + queryMemberRequest.setMerchantCode(requestDTO.getAgentId()); + queryMemberRequest.buildSignature(requestDTO.getAgentKey()); + String requestId = IdUtils.fastUUID(); + try { + GetMemberInfoResponse queryMemberResponse = dbSportsClient.getMemberInfo(queryMemberRequest, requestId); + if (this.isSuccess(queryMemberResponse.getCode())) { + BigDecimal transAmount = requestDTO.getAmount(); + BigDecimal afterAmount = queryMemberResponse.getData().getBalance(); + BigDecimal beforeAmount = afterAmount.subtract(transAmount); + exchangeMoney.setBalance(transAmount); + exchangeMoney.setCoinBefore(beforeAmount); + exchangeMoney.setCoinAfter(afterAmount); + exchangeMoney.setCurrencyBefore(beforeAmount); + exchangeMoney.setCurrencyAfter(afterAmount); + } + } catch (Exception e) { + log.error("查询会员失败, errorCode:{}, errorMessage:{}", response.getCode(), response.getMsg(), e); + } + exchangeMoney.setStep(GameExchangeStep.PLATFORM_TRANSACTION.getCode()); + exchangeMoney.setStepStatus(GameExchangeStepStatus.SUCCESS.getCode()); + gameExchangeMoneyService.updateGameExchangeMoney(exchangeMoney); + } else { + exchangeMoney.setStep(GameExchangeStep.PLATFORM_TRANSACTION.getCode()); + exchangeMoney.setStepStatus(GameExchangeStepStatus.FAILURE.getCode()); + gameExchangeMoneyService.updateGameExchangeMoney(exchangeMoney); + throw new ApiException(ErrorCode.Transfer_In_Failure.getCode()); + } + } else { + // 获取第三方钱包余额 + MemberInfoRequestDTO memberInfoRequestDTO = MemberInfoRequestDTO.builder() + .accounts(requestDTO.getAccount()) + .agentId(requestDTO.getAgentId()) + .agentKey(requestDTO.getAgentKey()) + .build(); + BigDecimal balance = this.getMemberInfo(memberInfoRequestDTO).getBalance(); + if (balance.compareTo(BigDecimal.ZERO) <= 0) { + throw new ApiException(ErrorCode.INSUFFICIENT_PLAYER_BALANCE.getCode()); + } + + TransferRequest request = new TransferRequest(); + request.setUserName(requestDTO.getAccount()); + request.setTransferType(2); // 转出 + request.setTransferId(requestDTO.getTransactionId()); + request.setMerchantCode(requestDTO.getAgentId()); + request.setAmount(/*requestDTO.getAmount().toString()*/ balance.toString()); + request.buildSignature(requestDTO.getAgentKey()); + + TransferResponse response = dbSportsClient + .transferOut( + request, IdUtils.fastUUID() + ); + + //判断是否转移成功 + if (this.isSuccess(response.getCode())) { + BigDecimal transAmount = balance; + BigDecimal beforeAmount = balance; + BigDecimal afterAmount = BigDecimal.ZERO; + + //更新数据 + exchangeMoney.setBalance(transAmount); + exchangeMoney.setCoinBefore(beforeAmount); + exchangeMoney.setCoinAfter(afterAmount); + exchangeMoney.setCurrencyBefore(beforeAmount); + exchangeMoney.setCurrencyAfter(afterAmount); + exchangeMoney.setStep(GameExchangeStep.PLATFORM_TRANSACTION.getCode()); + exchangeMoney.setStepStatus(GameExchangeStepStatus.SUCCESS.getCode()); + gameExchangeMoneyService.updateGameExchangeMoney(exchangeMoney); + } else { + exchangeMoney.setStep(GameExchangeStep.PLATFORM_TRANSACTION.getCode()); + exchangeMoney.setStepStatus(GameExchangeStepStatus.FAILURE.getCode()); + gameExchangeMoneyService.updateGameExchangeMoney(exchangeMoney); + throw new ApiException(ErrorCode.Transfer_Out_Failure.getCode()); + } + } + return exchangeMoney.getId(); + } + + /** + * 获取交易id + * + * @param transactionIdRequestDTO 事务id请求dto + * @return {@link String } + */ + @Override + public String getTransactionId(TransactionIdRequestDTO transactionIdRequestDTO) { + return gameExchangeMoneyService.getTransactionId(GamePlatforms.DBSports.getInfo(), 11); + } + + /** + * 获取会员信息 + * + * @param requestDTO 会员信息请求dto + * @return {@link MemberInfoResponseDTO } + */ + @Override + public MemberInfoResponseDTO getMemberInfo(MemberInfoRequestDTO requestDTO) { + GetMemberInfoRequest request = new GetMemberInfoRequest(); + request.setUserName(requestDTO.getAccounts()); + request.setMerchantCode(requestDTO.getAgentId()); + request.buildSignature(requestDTO.getAgentKey()); + String requestId = IdUtils.fastUUID(); + GetMemberInfoResponse response = dbSportsClient.getMemberInfo(request, requestId); + //判断是否获取成功 + if (this.isSuccess(response.getCode())) { + return MemberInfoResponseDTO.builder() + .status(GameMemberStatus.UNKNOWN.getCode()) + .balance(response.getData().getBalance()) + .account(requestDTO.getAccounts()) + .build(); + } + throw new ApiException(ErrorCode.Get_Member_Info_Failure.getCode()); + } + + /** + * 无重定向登录 + * + * @param requestDTO 游戏登录 + * @return {@link String } + */ + @Override + public String loginWithoutRedirect(GamesLogin requestDTO) { + LoginRequest request = new LoginRequest(); + request.setUserName(requestDTO.getAccount()); + request.setMerchantCode(requestDTO.getAgentId()); + if (requestDTO.getPlatform().equalsIgnoreCase("web")) { + request.setTerminal("pc"); + } else { + request.setTerminal("mobile"); + } + request.setLanguage(requestDTO.getLang()); + request.setCurrency(requestDTO.getCurrency()); + + request.buildSignature(requestDTO.getAgentKey()); + + LoginResponse response = dbSportsClient.login( + request, IdUtils.fastUUID() + ); + + if (this.isSuccess(response.getCode())) { + LoginResponse.LoginRespDTO respDTO = response.getData(); + + String loginURL = respDTO.getLoginUrl(); + if (StringUtils.isEmpty(loginURL)) { + throw new ApiException(ErrorCode.Get_Url_Failure.getCode()); + } + + return loginURL; + } + throw new ApiException(ErrorCode.Get_Url_Failure.getCode()); + } + + /** + * 获取游戏列表 + * + * @param gamesBaseRequestDTO 游戏请求dto + * @return {@link String } + */ + @Transactional + @Override + public String getGameList(GamesBaseRequestDTO gamesBaseRequestDTO) { + + Platform platform = gamesBaseRequestDTO.getVendor(); + Game condition = new Game(); + condition.setPlatformCode(platform.getPlatformCode()); + condition.setPlatformType(PlatformType.SPORTS.getCode()); + List gameList = gameService.selectGameList(condition); + //不存在这个游戏 + if (ObjectUtils.isEmpty(gameList)) { + Game game = new Game(); + game.setId(IdUtil.getSnowflakeNextId()); + game.setSortNo(1); + game.setPlatformCode(platform.getPlatformCode()); + game.setPlatformType(PlatformType.SPORTS.getCode()); + game.setGameCode("1"); + game.setGameSourceType(String.valueOf(1)); + game.setGameName(GamePlatforms.DBSports.getInfo()); + game.setCreateBy(Constants.SYSTEM); + NameInfo nameInfo = new NameInfo(); + nameInfo.setLang("zh-CN"); + nameInfo.setName("DB体育"); + game.setNameInfo(Collections.singletonList(nameInfo)); + gameService.insertGame(game); + } + /*GameName gameName = gameNameService.selectGameNameById(GAME_NAME_ID); + if (ObjectUtils.isEmpty(gameName)) { + gameNameService.insertGameName(GameName.builder() + .id(GAME_NAME_ID) + .gameId(game.getId()) + .gameName(game.getGameName()) + .langCode("zh-CN") + .createBy(Constants.SYSTEM) + .build()); + }*/ + + return CacheConstants.DB_Sports; + } + + /** + * 汇兑转移状态 + * + * @param requestDTO 兑换转账请求dto + * @return {@link Boolean } + */ + @Override + public ExchangeTransferStatusResponseDTO exchangeTransferStatus(ExchangeTransferStatusRequestDTO requestDTO) { + + GameExchangeMoney gameExchangeMoney = gameExchangeMoneyService.selectGameExchangeMoneyById(requestDTO.getGameExchangeMoneyId()); + if (null == gameExchangeMoney) { + throw new ApiException(ErrorCode.Transfer_Not_Exist.getCode()); + } + Integer status = StatusType.IN_PROGRESS.getValue(); + + if (!Objects.equals(gameExchangeMoney.getStatus(), StatusType.SUCCESS.getValue())) { + TransferDetailRequest request = new TransferDetailRequest(); + request.setMerchantCode(requestDTO.getAgentId()); + request.setTransferId(gameExchangeMoney.getOrderId()); + request.buildSignature(requestDTO.getAgentKey()); + TransferDetailResponse response = dbSportsClient.transferDetail( + request, IdUtils.fastUUID() + ); + if (this.isSuccess(response.getCode()) && response.getData().getStatus() == 1) { + status = StatusType.SUCCESS.getValue(); + } else { + status = StatusType.FAILURE.getValue(); + } + } + + return ExchangeTransferStatusResponseDTO.builder() + .statusType(status) + .balance(gameExchangeMoney.getBalance()) + .coinBefore(gameExchangeMoney.getCoinBefore()) + .coinAfter(gameExchangeMoney.getCoinAfter()) + .build(); + } + + + /** + * 按时间获取投注记录 + * + * @param requestDTO 按时间dto投注记录 + * @return {@link Boolean } + */ + @Override + public Boolean getBetRecordByTime(BetRecordByTimeDTO requestDTO) { + + this.getRealtimeRecord(requestDTO, 1); + + return Boolean.TRUE; + } + + void getRealtimeRecord(BetRecordByTimeDTO requestDTO, int pageNum) { + + GetBetListRequest request = new GetBetListRequest(); + request.setStartTime(String.valueOf(requestDTO.getStartTime())); + request.setEndTime(String.valueOf(requestDTO.getEndTime())); + request.setMerchantCode(requestDTO.getAgentId()); + request.setPageNum(pageNum); + request.setPageSize(1000); + request.buildSignature(requestDTO.getAgentKey()); + + GetBetListResponse response = dbSportsClient.getBetList( + request, IdUtils.fastUUID() + ); + + if (this.isSuccess(response.getCode())) { + List list = response.getData().getList(); + if (CollectionUtils.isEmpty(list)) { + return; + } + this.batchInsert(list, requestDTO); + getRealtimeRecord(requestDTO, ++pageNum); + } + } + + /** + * 按历史时间获取投注记录 + * + * @param requestDTO 按时间dto投注记录 + * @return {@link Boolean } + */ + @Override + public Boolean getBetRecordByHistoryTime(BetRecordByTimeDTO requestDTO) { + + return Boolean.TRUE; + } + + + /** + * 赠送免费局数 + * + * @param createFreeSpinRequest 创建自由旋转请求 + * @return {@link Boolean } + */ + @Override + public Boolean createFreeSpin(CreateFreeSpinRequestDTO createFreeSpinRequest) { + throw new BaseException("暂不支持免费局数"); + } + + /** + * 获取游戏详细信息 + * + * @param getGameDetailRequestDTO 获取游戏详细信息请求dto + * @return {@link GetGameDetailResponseDTO } + */ + @Override + public GetGameDetailResponseDTO getGameDetail(GetGameDetailRequestDTO getGameDetailRequestDTO) { + throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); + } + + /** + * 强制会员从游戏注销 + * + * @param kickMemberRequestDTO 踢会员请求dto + * @return {@link Boolean } + */ + @Override + public Boolean kickMember(KickMemberRequestDTO kickMemberRequestDTO) { + + KickUserRequest request = new KickUserRequest(); + request.setUserName(kickMemberRequestDTO.getAccount()); + request.setMerchantCode(kickMemberRequestDTO.getAgentId()); + request.buildSignature(kickMemberRequestDTO.getAgentKey()); + KickUserResponse kickUserResponse = dbSportsClient.kickUser(request, IdUtils.fastUUID()); + if (this.isSuccess(kickUserResponse.getCode())) { + return Boolean.TRUE; + } + return Boolean.FALSE; + } + + /** + * 踢成员全部 + * + * @param kickMemberAllDTO 踢成员全部dto + * @return {@link Boolean } + */ + @Override + public Boolean kickMemberAll(KickMemberAllDTO kickMemberAllDTO) { + throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); + } + + /** + * 免费游戏玩家使用的纪录 + * + * @param getFreeSpinDashflowRequestDTO 获取自由旋转dashflow请求dto + * @return {@link List }<{@link GameFreeRecord }> + */ + @Override + public List getFreeSpinDashflow(GetFreeSpinDashflowRequestDTO getFreeSpinDashflowRequestDTO) { + throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); + } + + /** + * 取消赠送免费局数 + * + * @param cancelFreeSpinRequestDTO 取消免费旋转请求 + * @return {@link Boolean } + */ + @Override + public Boolean cancelFreeSpin(CancelFreeSpinRequestDTO cancelFreeSpinRequestDTO) { + throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); + } + + /** + * 游戏演示登录 + * + * @param gameDemoLoginRequestDTO 游戏演示登录请求dto + * @return {@link GameDemoLoginResponseDTO } + */ + @Override + public GameDemoLoginResponseDTO gameDemoLogin(GameDemoLoginRequestDTO gameDemoLoginRequestDTO) { + throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); + } + + /** + * 批量插入 + * + * @param settledOrderList 投注记录 + */ + private void batchInsert(List settledOrderList, BetRecordByTimeDTO betRecordByTimeDTO) { + List gameBettingDetails = new ArrayList<>(); + List wagersIds = new ArrayList<>(); + //数据组装 + List dataList = settledOrderList; + if (CollectionUtils.isEmpty(dataList)) { + return; + } + + //数据转化 + for (GetBetListResponse.OrderItemDTO dataBean : dataList) { + if (dataBean.getOrderStatus() != 1) { // 只关心结算的 + continue; + } + GameBettingDetails bettingDetails = this.dataBuild(GamesDataBuildDTO.builder() + .platform(betRecordByTimeDTO.getVendor()) + .data(dataBean).build()); + if (!ObjectUtils.isEmpty(bettingDetails)) { + bettingDetails.setId(IdUtil.getSnowflakeNextId()); + gameBettingDetails.add(bettingDetails); + } + wagersIds.add(dataBean.getOrderNo()); + } + if (CollectionUtils.isEmpty(gameBettingDetails)) { + return; + } + //查询重复数据id + List removeWagersIds = gameBettingDetailsService + .selectGameBettingDetailsByWagersId(wagersIds, GamePlatforms.DBSports.getCode()); + //用steam流清除list中与wagersIds集合相同的数据 + gameBettingDetails = gameBettingDetails.stream() + .filter(detail -> !removeWagersIds.contains(detail.getWagersId())) + .collect(Collectors.toList()); + if (!CollectionUtils.isEmpty(gameBettingDetails)) { + gameBettingDetailsService.batchInsert(gameBettingDetails); + } + } + + /** + * 数据构建 + * + * @param gamesDataBuildDTO 数据 + * @return {@link GameBettingDetails } + */ + @Override + public GameBettingDetails dataBuild(GamesDataBuildDTO gamesDataBuildDTO) { + + //转化类 + GetBetListResponse.OrderItemDTO dataBean = (GetBetListResponse.OrderItemDTO) gamesDataBuildDTO.getData(); + Member member = memberService.selectMemberByGameAccount(dataBean.getUserName()); + if (ObjectUtils.isEmpty(member)) { + return null; + } + //List gameList = redisCache.getCacheList(CacheConstants.DB_Sports); + //Game game = gameList.get(0); + BigDecimal originPayoffAmount = BigDecimal.valueOf(dataBean.getSettleAmount()); + BigDecimal betAmount = new BigDecimal(dataBean.getOrderAmount()); + + int compareResult = originPayoffAmount.compareTo(betAmount); + long payoffTime = dataBean.getSettleTime(); + long createTime = dataBean.getCreateTime(); + Platform platform = gamesDataBuildDTO.getPlatform(); + String systemCurrency = platform.getOurCurrency(dataBean.getCurrency()); + //数据构造 + GameBettingDetails gameBettingDetails = GameBettingDetails.builder() + .tenantKey(member.getTenantKey()) + //保存我们的币种id + .currencyCode(systemCurrency) + .memberId(member.getId()) + .gameCode("1") + .gameType(PlatformType.SPORTS.getCode()) // 体育 + .platformCode(GamePlatforms.DBSports.getCode()) + .gameId(GamePlatforms.DBSports.getCode() + "_1") + .gameName(GamePlatforms.DBSports.getInfo()) + .gameStatus(compareResult > 0 ? GameStatus.WIN.getCode() : compareResult < 0 ? GameStatus.FAIL.getCode() : GameStatus.FLAT.getCode()) + .gameStatusType(1) // 一般下注 + .gameCurrencyCode(dataBean.getCurrency()) + .account(dataBean.getUserName()) + .wagersId(dataBean.getOrderNo()) + .wagersTime(createTime) + .betAmount(betAmount) + .payoffTime(payoffTime) + .payoffAmount(originPayoffAmount.abs()) + .settlementTime(payoffTime) + .turnover(betAmount) + .orderNo(dataBean.getOrderNo()) + .settlementStatus(SettlementStatusEnum.COMPLETED.getCode()) + .build(); + gameBettingDetails.setCreateBy(Constants.SYSTEM); + gameBettingDetails.setCreateTime(DateUtils.getNowDate()); + return gameBettingDetails; + } +} diff --git a/ff-game/src/main/java/com/ff/game/api/dg/address/MyDGAddressSource.java b/ff-game/src/main/java/com/ff/game/api/dg/address/MyDGAddressSource.java index 9bf5985..b98459f 100644 --- a/ff-game/src/main/java/com/ff/game/api/dg/address/MyDGAddressSource.java +++ b/ff-game/src/main/java/com/ff/game/api/dg/address/MyDGAddressSource.java @@ -3,8 +3,8 @@ package com.ff.game.api.dg.address; import com.dtflys.forest.callback.AddressSource; import com.dtflys.forest.http.ForestAddress; import com.dtflys.forest.http.ForestRequest; -import com.ff.base.constant.Constants; -import com.ff.base.system.service.ISysConfigService; +import com.ff.base.enums.GamePlatforms; +import com.ff.game.service.IPlatformService; import org.springframework.stereotype.Component; import javax.annotation.Resource; @@ -20,12 +20,12 @@ import javax.annotation.Resource; public class MyDGAddressSource implements AddressSource { @Resource - private ISysConfigService configService; - + private IPlatformService platformService; @Override public ForestAddress getAddress(ForestRequest request) { - String apiBaseUrl = configService.selectConfigByKey(Constants.DG_API_BASE_URL); - return new ForestAddress("http",apiBaseUrl, 80,""); + String apiBaseUrl = platformService.get(GamePlatforms.DG.getCode()) + .getUrlInfo().getUrl(); + return new ForestAddress("http", apiBaseUrl, 80, ""); } } \ No newline at end of file diff --git a/ff-game/src/main/java/com/ff/game/api/dg/client/DGClient.java b/ff-game/src/main/java/com/ff/game/api/dg/client/DGClient.java index bc58304..15679c4 100644 --- a/ff-game/src/main/java/com/ff/game/api/dg/client/DGClient.java +++ b/ff-game/src/main/java/com/ff/game/api/dg/client/DGClient.java @@ -55,6 +55,16 @@ public interface DGClient { @Post(url = "/v2/api/transfer") DGTransactionResponseDTO exchangeTransferByAgentId(@JSONBody Map params, @Header Map header); + + /** + * 汇兑转移状态 + * + * @param params 参数 + * @param header 头球 + * @return {@link DGTransactionResponseDTO } + */ + @Post(url = "/v2/api/checkTransfer") + DGTransactionResponseDTO exchangeTransferStatus(@JSONBody Map params, @Header Map header); /** * 按时间获取投注记录 * diff --git a/ff-game/src/main/java/com/ff/game/api/dg/service/impl/GamesDGServiceImpl.java b/ff-game/src/main/java/com/ff/game/api/dg/service/impl/GamesDGServiceImpl.java index 8c90a26..e1e9a1d 100644 --- a/ff-game/src/main/java/com/ff/game/api/dg/service/impl/GamesDGServiceImpl.java +++ b/ff-game/src/main/java/com/ff/game/api/dg/service/impl/GamesDGServiceImpl.java @@ -4,30 +4,24 @@ import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.NumberUtil; import com.ff.base.constant.CacheConstants; import com.ff.base.constant.Constants; -import com.ff.base.core.redis.RedisCache; import com.ff.base.enums.*; import com.ff.base.exception.base.ApiException; import com.ff.base.exception.base.BaseException; -import com.ff.base.system.service.ISysConfigService; import com.ff.base.utils.DateUtils; -import com.ff.base.utils.JsonUtil; import com.ff.base.utils.SleepUtil; import com.ff.base.utils.StringUtils; import com.ff.base.utils.sign.Md5Utils; import com.ff.base.utils.uuid.IdUtils; import com.ff.config.KeyConfig; import com.ff.game.api.IGamesService; +import com.ff.game.api.ae.dto.AEExchangeTransferStatusResponse; import com.ff.game.api.dg.client.DGClient; import com.ff.game.api.dg.dto.*; -import com.ff.game.api.ng.dto.ApiLoginResponseDTO; -import com.ff.game.api.ng.dto.ApiMemberInfoResponseDTO; -import com.ff.game.api.ng.dto.ApiNGResponseDTO; import com.ff.game.api.request.*; -import com.ff.game.api.xk.client.XKClient; -import com.ff.game.api.xk.dto.*; import com.ff.game.domain.*; -import com.ff.game.dto.GameSecretKeyCurrencyDTO; -import com.ff.game.service.*; +import com.ff.game.service.IGameBettingDetailsService; +import com.ff.game.service.IGameExchangeMoneyService; +import com.ff.game.service.IGameService; import com.ff.member.domain.Member; import com.ff.member.service.IMemberService; import lombok.extern.slf4j.Slf4j; @@ -40,7 +34,6 @@ import org.springframework.util.ObjectUtils; import javax.annotation.Resource; import java.math.BigDecimal; import java.util.*; -import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @@ -54,21 +47,9 @@ import java.util.stream.Collectors; @Slf4j public class GamesDGServiceImpl implements IGamesService { - - @Resource - private ISysConfigService configService; - - @Resource - private RedisCache redisCache; - @Resource private IGameExchangeMoneyService gameExchangeMoneyService; - - @Resource - private IGamePlatformService gamePlatformService; - - @Resource private IGameService gameService; @@ -76,42 +57,20 @@ public class GamesDGServiceImpl implements IGamesService { @Resource private IMemberService memberService; - @Resource - private IGameFreeRecordService gameFreeRecordService; - @Resource - private IGameSecretKeyService gameSecretKeyService; - - @Resource - private IGameSecretKeyCurrencyService gameSecretKeyCurrencyService; - @Resource private DGClient DGClient; - @Resource private KeyConfig keyConfig; @Resource private IGameBettingDetailsService gameBettingDetailsService; - @Resource - private IGameNameService gameNameService; - - /** * 游戏id */ private static final Long GAME_ID = 1904452832756003817L; - /** - * 平台ID - */ - private static final Long PLATFORM_ID = 1904411420157108325L; - - /** - * 游戏名称id - */ - private static final Long GAME_NAME_ID = 1904452832756002317L; /** * 获得就是成功 @@ -229,44 +188,44 @@ public class GamesDGServiceImpl implements IGamesService { @Transactional @Override public String getGameList(GamesBaseRequestDTO gamesBaseRequestDTO) { - GamePlatform gamePlatform = gamePlatformService.selectGamePlatformById(PLATFORM_ID); - //没有此平台就新增一个平台 - if (ObjectUtils.isEmpty(gamePlatform)) { - gamePlatform = new GamePlatform(); - gamePlatform.setId(PLATFORM_ID); - gamePlatform.setPlatformCode(GamePlatforms.DG.getInfo()); - gamePlatform.setPlatformType(PlatformType.CARD_GAME.getCode()); - gamePlatform.setPlatformName(GamePlatforms.DG.getInfo() + PlatformType.CARD_GAME.getName()); - gamePlatform.setSortNo(gamePlatformService.selectMaxSortNo() + 1); - gamePlatform.setCreateBy(Constants.SYSTEM); - gamePlatformService.insertGamePlatform(gamePlatform); - } + Game game = gameService.selectGameById(GAME_ID); //不存在这个游戏 if (ObjectUtils.isEmpty(game)) { game = new Game(); game.setId(GAME_ID); - game.setSortNo(gameService.selectMaxSortNoByPlatformId(gamePlatform.getId()) + 1); - game.setPlatformId(gamePlatform.getId()); + game.setSortNo(1); + game.setPlatformCode(GamePlatforms.DG.getCode()); + game.setPlatformType(PlatformType.VIDEO.getCode()); game.setGameCode("1"); game.setGameSourceType(String.valueOf(1)); game.setGameName("真人棋牌"); game.setCreateBy(Constants.SYSTEM); + game.setNameInfo(Collections.singletonList(new NameInfo("真人棋牌", "zh-CN"))); + game.setGameId(StringUtils.addSuffix(GamePlatforms.DG.getCode(), 1)); gameService.insertGame(game); - } - GameName gameName = gameNameService.selectGameNameById(GAME_NAME_ID); - if (ObjectUtils.isEmpty(gameName)) { - gameNameService.insertGameName(GameName.builder() - .id(GAME_NAME_ID) - .gameId(game.getId()) - .gameName(game.getGameName()) - .langCode("zh-CN") - .createBy(Constants.SYSTEM) - .build()); + }else { + game.setNameInfo(Collections.singletonList(new NameInfo("真人棋牌", "zh-CN"))); + gameService.updateGame(game); } return CacheConstants.DG_GAMES; } + + + /** + * 获取交易id + * + * @param transactionIdRequestDTO 事务id请求dto + * @return {@link String } + */ + @Override + public String getTransactionId(TransactionIdRequestDTO transactionIdRequestDTO) { + return GamePlatforms.DG.getInfo() + IdUtils.simpleUUID(); + } + + + /** * 按代理id进行交换转账 * @@ -277,41 +236,16 @@ public class GamesDGServiceImpl implements IGamesService { @Transactional public Long exchangeTransferByAgentId(ExchangeTransferMoneyRequestDTO exchangeTransferMoneyRequestDTO) { log.info("GamesDGServiceImpl [exchangeTransferByAgentId] 请求参数 {}", exchangeTransferMoneyRequestDTO); - GameSecretKeyCurrency currencyDTO = gameSecretKeyCurrencyService.findByGameSecretKeyCurrencyDTO(GameSecretKeyCurrencyDTO.builder() - .platformCode(GamePlatforms.DG.getInfo()) - .code(exchangeTransferMoneyRequestDTO.getAgentId()) - .build()); - Member member = memberService.selectMemberByGameAccount(exchangeTransferMoneyRequestDTO.getAccount()); - String transactionId = GamePlatforms.DG.getInfo() + IdUtils.simpleUUID(); - List gameExchangeMonies = gameExchangeMoneyService.selectGameExchangeMoneyList( - GameExchangeMoney.builder() - .tenantKey(exchangeTransferMoneyRequestDTO.getTenantKey()) - .orderId(exchangeTransferMoneyRequestDTO.getOrderId()) - .build() - ); - Assert.isTrue(CollectionUtils.isEmpty(gameExchangeMonies), "订单号重复"); - //获取下一个自增id - GameExchangeMoney exchangeMoney = GameExchangeMoney - .builder() - .tenantKey(exchangeTransferMoneyRequestDTO.getTenantKey()) - .orderId(exchangeTransferMoneyRequestDTO.getOrderId()) - .quota(exchangeTransferMoneyRequestDTO.getQuota()) - .balance(exchangeTransferMoneyRequestDTO.getAmount()) - .exchangeType(exchangeTransferMoneyRequestDTO.getTransferType()) - .currencyCode(currencyDTO.getSystemCurrency()) - .memberId(member.getId()) - .transactionId(transactionId) - .platformCode(GamePlatforms.DG.getInfo()) - .build(); - exchangeMoney.setCreateBy(Constants.SYSTEM); + GameExchangeMoney exchangeMoney = gameExchangeMoneyService.selectGameExchangeMoneyById(exchangeTransferMoneyRequestDTO.getGameExchangeId()); + BigDecimal amount = exchangeTransferMoneyRequestDTO.getAmount(); if (TransferType.ALL.getCode().equals(exchangeTransferMoneyRequestDTO.getTransferType())) { // 获取第三方钱包余额 MemberInfoRequestDTO gamesBaseRequestDTO = MemberInfoRequestDTO.builder() - .accounts(member.getGameAccount()) + .accounts(exchangeTransferMoneyRequestDTO.getAccount()) .agentId(exchangeTransferMoneyRequestDTO.getAgentId()) .currency(exchangeTransferMoneyRequestDTO.getCurrency()) .agentKey(exchangeTransferMoneyRequestDTO.getAgentKey()) @@ -324,7 +258,7 @@ public class GamesDGServiceImpl implements IGamesService { Map params = new LinkedHashMap<>(); params.put("username", exchangeTransferMoneyRequestDTO.getAccount()); params.put("amount", amount); - params.put("serial", transactionId); + params.put("serial", exchangeTransferMoneyRequestDTO.getTransactionId()); Map headerMap = this.getKey(exchangeTransferMoneyRequestDTO); DGTransactionResponseDTO dgTransactionResponseDTO = DGClient.exchangeTransferByAgentId(params, headerMap); @@ -337,10 +271,14 @@ public class GamesDGServiceImpl implements IGamesService { exchangeMoney.setCoinAfter(dgTransactionResponseDTO.getBalance()); exchangeMoney.setCurrencyBefore(exchangeMoney.getCoinBefore()); exchangeMoney.setCurrencyAfter(exchangeMoney.getCoinAfter()); - exchangeMoney.setStatus(StatusType.SUCCESS.getValue()); - gameExchangeMoneyService.insertGameExchangeMoney(exchangeMoney); + exchangeMoney.setStep(GameExchangeStep.PLATFORM_TRANSACTION.getCode()); + exchangeMoney.setStepStatus(GameExchangeStepStatus.SUCCESS.getCode()); + gameExchangeMoneyService.updateGameExchangeMoney(exchangeMoney); } else { - log.error("GamesXKServiceImpl [exchangeTransferByAgentId] 金额转移失败,错误代码{},错误信息{}", dgTransactionResponseDTO.getCodeId(), dgTransactionResponseDTO.getMsg()); + exchangeMoney.setStep(GameExchangeStep.PLATFORM_TRANSACTION.getCode()); + exchangeMoney.setStepStatus(GameExchangeStepStatus.FAILURE.getCode()); + gameExchangeMoneyService.updateGameExchangeMoney(exchangeMoney); + log.error("GamesDGServiceImpl [exchangeTransferByAgentId] 金额转移失败,错误代码{},错误信息{}", dgTransactionResponseDTO.getCodeId(), dgTransactionResponseDTO.getMsg()); throw new ApiException(ErrorCode.BALANCE_TRANSFER_FAILED.getCode()); } @@ -351,11 +289,31 @@ public class GamesDGServiceImpl implements IGamesService { * 汇兑转移状态 * * @param exchangeTransferMoneyRequestDTO 兑换转账请求dto - * @return {@link Boolean } + * @return {@link ExchangeTransferStatusResponseDTO } */ @Override - public Boolean exchangeTransferStatus(ExchangeTransferStatusRequestDTO exchangeTransferMoneyRequestDTO) { - return Boolean.TRUE; + public ExchangeTransferStatusResponseDTO exchangeTransferStatus(ExchangeTransferStatusRequestDTO exchangeTransferMoneyRequestDTO) { + log.info("GamesDGServiceImpl [exchangeTransferStatus] 请求参数 {}", exchangeTransferMoneyRequestDTO); + + Map params = new LinkedHashMap<>(); + params.put("serial", exchangeTransferMoneyRequestDTO.getOrderId()); + + Map headerMap = this.getKey(exchangeTransferMoneyRequestDTO); + + DGTransactionResponseDTO dgTransactionResponseDTO = DGClient.exchangeTransferStatus(params, headerMap); + Integer status = StatusType.IN_PROGRESS.getValue(); + if (this.getIsSuccess(dgTransactionResponseDTO.getCodeId())) { + status = StatusType.SUCCESS.getValue(); + } else { + status = StatusType.FAILURE.getValue(); + } + + return ExchangeTransferStatusResponseDTO.builder() + .statusType(status) + .balance(dgTransactionResponseDTO.getAmount().abs()) + .coinBefore(NumberUtil.sub(dgTransactionResponseDTO.getBalance(), dgTransactionResponseDTO.getAmount().abs()).abs()) + .coinAfter(dgTransactionResponseDTO.getBalance()) + .build(); } @@ -367,18 +325,17 @@ public class GamesDGServiceImpl implements IGamesService { */ @Override public Boolean getBetRecordByTime(BetRecordByTimeDTO betRecordByTimeDTO) { + SleepUtil.sleep(50000); //请求参数 log.info("GamesDGServiceImpl [getBetRecordByTime] 请求参数 {}", betRecordByTimeDTO); Map key = this.getKey(betRecordByTimeDTO); DGBetRecordResponseDTO betRecordByTime = DGClient.getBetRecordByTime(key); if (this.getIsSuccess(betRecordByTime.getCodeId())) { - this.batchInsert(betRecordByTime,betRecordByTimeDTO); - - + this.batchInsert(betRecordByTime, betRecordByTimeDTO); return Boolean.TRUE; } else { - log.error("GamesXKServiceImpl [getBetRecordByTime] 获取投注记录失败,错误代码{},错误信息{}", betRecordByTime.getCodeId(), betRecordByTime.getMsg()); + log.error("GamesDGServiceImpl [getBetRecordByTime] 获取投注记录失败,错误代码{},错误信息{}", betRecordByTime.getCodeId(), betRecordByTime.getMsg()); throw new BaseException(betRecordByTime.getMsg()); } @@ -393,7 +350,7 @@ public class GamesDGServiceImpl implements IGamesService { */ @Override public Boolean getBetRecordByHistoryTime(BetRecordByTimeDTO betRecordByTimeDTO) { - return null; + return Boolean.FALSE; } /** @@ -432,14 +389,14 @@ public class GamesDGServiceImpl implements IGamesService { if (!this.getIsSuccess(userListResponseDTO.getCodeId())) { throw new ApiException(ErrorCode.KICK_OUT_AILED.getCode()); } - if (CollectionUtils.isEmpty(userListResponseDTO.getList())){ + if (CollectionUtils.isEmpty(userListResponseDTO.getList())) { return Boolean.TRUE; } DGUserListResponseDTO.UserDTO userDTO = userListResponseDTO.getList().stream() .filter(user -> user.getUsername().equals(kickMemberRequestDTO.getAccount())) .findFirst() .orElse(null); - if (Objects.isNull(userDTO)){ + if (Objects.isNull(userDTO)) { return Boolean.TRUE; } @@ -447,7 +404,7 @@ public class GamesDGServiceImpl implements IGamesService { List memberIds = new ArrayList<>(); memberIds.add(userDTO.getMemberId()); Map params = new LinkedHashMap<>(); - params.put("list",memberIds); + params.put("list", memberIds); DGResponse dgResponse = DGClient.kickMember(params, key); //判断是否获取成功 if (this.getIsSuccess(dgResponse.getCodeId())) { @@ -472,7 +429,7 @@ public class GamesDGServiceImpl implements IGamesService { throw new ApiException(ErrorCode.KICK_OUT_AILED.getCode()); } - if (CollectionUtils.isEmpty(userListResponseDTO.getList())){ + if (CollectionUtils.isEmpty(userListResponseDTO.getList())) { return Boolean.TRUE; } @@ -480,7 +437,7 @@ public class GamesDGServiceImpl implements IGamesService { Map params = new LinkedHashMap<>(); - params.put("list",memberIds); + params.put("list", memberIds); DGResponse dgResponse = DGClient.kickMember(params, key); //判断是否获取成功 if (this.getIsSuccess(dgResponse.getCodeId())) { @@ -501,6 +458,18 @@ public class GamesDGServiceImpl implements IGamesService { throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); } + /** + * 游戏演示登录 + * + * @param gameDemoLoginRequestDTO 游戏演示登录请求dto + * @return {@link GameDemoLoginResponseDTO } + */ + @Override + public GameDemoLoginResponseDTO gameDemoLogin(GameDemoLoginRequestDTO gameDemoLoginRequestDTO) { + throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); + } + + /** * 取消赠送免费局数 * @@ -518,14 +487,16 @@ public class GamesDGServiceImpl implements IGamesService { * * @param dgBetRecordResponseDTO dg投注记录响应dto */ - private void batchInsert(DGBetRecordResponseDTO dgBetRecordResponseDTO,GamesBaseRequestDTO gamesBaseRequestDTO) { + private void batchInsert(DGBetRecordResponseDTO dgBetRecordResponseDTO, GamesBaseRequestDTO gamesBaseRequestDTO) { List gameBettingDetails = new ArrayList<>(); List wagersIds = new ArrayList<>(); //数据组装 List report = dgBetRecordResponseDTO.getList(); //数据转化 for (DGBetRecordResponseDTO.ReportDTO bean : report) { - GameBettingDetails bettingDetails = this.dataBuild(GamesDataBuildDTO.builder().data(bean).build()); + GameBettingDetails bettingDetails = this.dataBuild(GamesDataBuildDTO.builder() + .platform(gamesBaseRequestDTO.getVendor()) + .data(bean).build()); if (!ObjectUtils.isEmpty(bettingDetails)) { bettingDetails.setId(IdUtil.getSnowflakeNextId()); gameBettingDetails.add(bettingDetails); @@ -534,7 +505,7 @@ public class GamesDGServiceImpl implements IGamesService { } if (!CollectionUtils.isEmpty(gameBettingDetails)) { //查询重复数据id - List removeWagersIds = gameBettingDetailsService.selectGameBettingDetailsByWagersId(wagersIds); + List removeWagersIds = gameBettingDetailsService.selectGameBettingDetailsByWagersId(wagersIds, GamePlatforms.DG.getInfo()); //用steam流清除list中与wagersIds集合相同的数据 gameBettingDetails = gameBettingDetails.stream() .filter(detail -> !removeWagersIds.contains(detail.getWagersId())) @@ -544,7 +515,7 @@ public class GamesDGServiceImpl implements IGamesService { Map key = this.getKey(gamesBaseRequestDTO); Map params = new HashMap<>(); params.put("list", wagersIds); - DGClient.markReport(params,key); + DGClient.markReport(params, key); } } @@ -562,10 +533,10 @@ public class GamesDGServiceImpl implements IGamesService { DGBetRecordResponseDTO.ReportDTO resultBean = (DGBetRecordResponseDTO.ReportDTO) gamesDataBuildDTO.getData(); - GameSecretKeyCurrency currencyDTO = gameSecretKeyCurrencyService.findByGameSecretKeyCurrencyDTO(GameSecretKeyCurrencyDTO.builder() - .platformCode(GamePlatforms.DG.getInfo()) - .currencyId(String.valueOf(resultBean.getCurrencyId())) - .build()); +// GameSecretKeyCurrency currencyDTO = gameSecretKeyCurrencyService.findByGameSecretKeyCurrencyDTO(GameSecretKeyCurrencyDTO.builder() +// .platformCode(GamePlatforms.DG.getInfo()) +// .currencyId(String.valueOf(resultBean.getCurrencyId())) +// .build()); Member member = memberService.selectMemberByGameAccount(resultBean.getUserName()); @@ -595,16 +566,17 @@ public class GamesDGServiceImpl implements IGamesService { GameBettingDetails gameBettingDetails = GameBettingDetails.builder() .tenantKey(member.getTenantKey()) //保存我们的币种id - .currencyCode(currencyDTO.getSystemCurrency()) + .currencyCode(gamesDataBuildDTO.getPlatform().getExtInfo().getOurCurrency(String.valueOf(resultBean.getCurrencyId()))) .memberId(member.getId()) .gameCode(String.valueOf(resultBean.getGameId())) .gameType(PlatformType.CARD_GAME.getCode()) - .platformCode(GamePlatforms.DG.getInfo()) - .gameId(GAME_ID) + .platformCode(GamePlatforms.DG.getCode()) + //.gameId(GAME_ID) + .gameId(game.getGameId()) .gameName(game.getGameName()) .gameStatus(gameStatus) .gameStatusType(resultBean.getGameType()) - .gameCurrencyCode(currencyDTO.getCurrency()) + .gameCurrencyCode(/*gamesDataBuildDTO.getCurrencyCode()*/String.valueOf(resultBean.getCurrencyId())) .account(String.valueOf(resultBean.getUserName())) .wagersId(String.valueOf(resultBean.getId())) .wagersTime(resultBean.getBetTime().getTime()) diff --git a/ff-game/src/main/java/com/ff/game/api/exchange/AbstractStepProcessor.java b/ff-game/src/main/java/com/ff/game/api/exchange/AbstractStepProcessor.java new file mode 100644 index 0000000..6e0713f --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/exchange/AbstractStepProcessor.java @@ -0,0 +1,118 @@ +package com.ff.game.api.exchange; + +import com.ff.base.enums.GameExchangeStep; +import com.ff.base.enums.GameExchangeStepStatus; +import com.ff.base.exception.base.BaseException; +import com.ff.game.api.exchange.dto.GameExchangeDTO; +import com.ff.game.domain.GameExchangeMoney; +import com.ff.game.service.IGameExchangeMoneyService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.transaction.TransactionDefinition; +import org.springframework.transaction.support.TransactionTemplate; + +import javax.annotation.Resource; + +/** + * 抽象步进处理机 + * + * @author shi + * @date 2025/04/09 + */ +@Slf4j +public abstract class AbstractStepProcessor implements StepProcessorService { + + + @Resource + private StepProcessorFactory stepProcessorFactory; + + + @Resource + private IGameExchangeMoneyService gameExchangeMoneyService; + + /** + * 过程 + * + * @param gameExchangeMoney 游戏兑换货币 + */ + @Override + public void process(GameExchangeDTO gameExchangeMoney) { + boolean processResult = false; + try { + processResult = doProcess(gameExchangeMoney); + } catch (Exception e) { + log.error("游戏余额转移{}-步骤任务{}-执行异常", gameExchangeMoney.getId(), stepKey().getDescription(), e); + throw new BaseException("游戏余额转移"+gameExchangeMoney.getId()+"-步骤任务"+stepKey().getDescription()+"-执行异常" ); + } + //更新状态 + if (processResult) { + log.info("游戏余额转移{}-步骤任务{}-执行成功", gameExchangeMoney.getId(), stepKey().getDescription()); + triggerNextStep(gameExchangeMoney); + } + } + + + + /** + * 降低 + * + * @param gameExchangeMoney 游戏兑换货币 + */ + @Override + public void rollBack(GameExchangeDTO gameExchangeMoney){ + boolean processResult = false; + try { + processResult = doRollBack(gameExchangeMoney); + } catch (Exception e) { + log.error("游戏余额转移{}-步骤任务{}-回滚异常", gameExchangeMoney.getId(), stepKey().getDescription(), e); + } + if (processResult) { + log.info("游戏余额转移{}-步骤任务{}-回滚成功", gameExchangeMoney.getId(), stepKey().getDescription()); + triggerBackStep(gameExchangeMoney); + } + } + + + /** + * 触发后退 + * + * @param exchangeMoney 兑换货币 + */ + private void triggerBackStep(GameExchangeDTO exchangeMoney) { + GameExchangeStep nextStep = backStepProcessor(); + if (nextStep != null) { + stepProcessorFactory.getStepProcessor(nextStep).rollBack(exchangeMoney); + } + } + + + + /** + * 触发下一步 + * + * @param exchangeMoney 兑换货币 + */ + private void triggerNextStep(GameExchangeDTO exchangeMoney) { + GameExchangeStep nextStep = nextStepProcessor(); + if (nextStep != null) { + stepProcessorFactory.getStepProcessor(nextStep).process(exchangeMoney); + } + } + + /** + * 一定要回滚 + * + * @param gameExchangeMoney 游戏兑换货币 + * @return boolean + * @throws Exception 例外 + */ + abstract public boolean doRollBack(GameExchangeDTO gameExchangeMoney) throws Exception; + + /** + * do过程 + * + * @param gameExchangeMoney 游戏兑换货币 + * @return boolean + * @throws Exception 例外 + */ + abstract public boolean doProcess(GameExchangeDTO gameExchangeMoney) throws Exception; +} diff --git a/ff-game/src/main/java/com/ff/game/api/exchange/StepProcessorFactory.java b/ff-game/src/main/java/com/ff/game/api/exchange/StepProcessorFactory.java new file mode 100644 index 0000000..7db1768 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/exchange/StepProcessorFactory.java @@ -0,0 +1,47 @@ +package com.ff.game.api.exchange; + +import com.ff.base.enums.GameExchangeStep; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * 步进处理机厂 + * + * @author shi + * @date 2025/04/09 + */ +@Component +public class StepProcessorFactory { + + @Autowired + List stepProcessors; + + private Map processorMap; + + @PostConstruct + public void init() { + Map map = new HashMap<>(); + for (StepProcessorService stepProcessor : stepProcessors) { + map.put(stepProcessor.stepKey(), stepProcessor); + } + + processorMap = Collections.unmodifiableMap(map); + } + + /** + * 获取步进处理器 + * + * @param stepKey 步进键 + * @return {@link StepProcessorService } + */ + public StepProcessorService getStepProcessor(GameExchangeStep stepKey) { + return processorMap.get(stepKey); + } + +} diff --git a/ff-game/src/main/java/com/ff/game/api/exchange/StepProcessorService.java b/ff-game/src/main/java/com/ff/game/api/exchange/StepProcessorService.java new file mode 100644 index 0000000..be5efb8 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/exchange/StepProcessorService.java @@ -0,0 +1,56 @@ +package com.ff.game.api.exchange; + +import com.ff.base.enums.GameExchangeStep; +import com.ff.game.api.exchange.dto.GameExchangeDTO; + +/** + * 步进处理机 + * + * @author shi + * @date 2025/04/09 + */ +public interface StepProcessorService { + + /** + * 返回处理器类型 + * + * @return {@link GameExchangeStep } + */ + GameExchangeStep stepKey(); + + + /** + * 过程 + * + * @param gameExchangeMoney 游戏兑换货币 + */ + void process(GameExchangeDTO gameExchangeMoney); + + + /** + * 回退 + * + * @param gameExchangeMoney 游戏兑换货币 + */ + void rollBack(GameExchangeDTO gameExchangeMoney); + + + /** + * 步骤之间有依赖 + * 找出下一个步骤处理器进行处理 + * + * @return + */ + GameExchangeStep nextStepProcessor(); + + + /** + * 步骤之间有依赖 + * 找出上一个步骤处理器进行处理 + * + * @return {@link GameExchangeStep } + */ + GameExchangeStep backStepProcessor(); + + +} diff --git a/ff-game/src/main/java/com/ff/game/api/exchange/dto/GameExchangeDTO.java b/ff-game/src/main/java/com/ff/game/api/exchange/dto/GameExchangeDTO.java new file mode 100644 index 0000000..584e9f6 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/exchange/dto/GameExchangeDTO.java @@ -0,0 +1,32 @@ +package com.ff.game.api.exchange.dto; + +import com.ff.base.annotation.Excel; +import com.ff.game.domain.GameExchangeMoney; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * 游戏兑换货币dto + * + * @author shi + * @date 2025/04/09 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@SuperBuilder +public class GameExchangeDTO extends GameExchangeMoney { + /** + * 触发类型 1 用户调用手动触发 2 定时器触发 + */ + private Integer triggerType; + + /** 会员账号 */ + private String memberAccount; + + /** 游戏账号 */ + private String gameAccount; + +} diff --git a/ff-game/src/main/java/com/ff/game/api/exchange/impl/AddBalanceServiceImpl.java b/ff-game/src/main/java/com/ff/game/api/exchange/impl/AddBalanceServiceImpl.java new file mode 100644 index 0000000..b45e7d3 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/exchange/impl/AddBalanceServiceImpl.java @@ -0,0 +1,170 @@ +package com.ff.game.api.exchange.impl; + +import com.ff.base.constant.Constants; +import com.ff.base.enums.*; +import com.ff.base.exception.base.ApiException; +import com.ff.base.utils.StringUtils; +import com.ff.common.domain.TenantGameQuotaFlow; +import com.ff.common.dto.BalanceChangesDTO; +import com.ff.common.dto.GameBalanceExchange; +import com.ff.common.service.ITenantGameQuotaFlowService; +import com.ff.common.service.ITenantGameQuotaService; +import com.ff.game.api.IGamesService; +import com.ff.game.api.exchange.AbstractStepProcessor; +import com.ff.game.api.exchange.dto.GameExchangeDTO; +import com.ff.game.api.request.ExchangeTransferMoneyRequestDTO; +import com.ff.game.api.request.ExchangeTransferStatusRequestDTO; +import com.ff.game.api.request.ExchangeTransferStatusResponseDTO; +import com.ff.game.domain.KeyInfo; +import com.ff.game.domain.Platform; +import com.ff.game.service.IGameExchangeMoneyService; +import com.ff.game.service.IPlatformService; +import com.ff.member.domain.Member; +import com.ff.member.service.IMemberService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Service; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.TransactionDefinition; +import org.springframework.transaction.support.TransactionTemplate; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.util.List; +import java.util.Map; + + +/** + * 增加余额 + * + * @author shi + * @date 2025/04/09 + */ +@Service +@Order(4) +public class AddBalanceServiceImpl extends AbstractStepProcessor { + + + @Resource + private IMemberService memberService; + + @Resource + private ITenantGameQuotaService tenantGameQuotaService; + @Resource + private IGameExchangeMoneyService gameExchangeMoneyService; + @Resource + private PlatformTransactionManager transactionManager; + @Resource + private IPlatformService platformService; + /** + * 步进键 + * + * @return {@link GameExchangeStep } + */ + @Override + public GameExchangeStep stepKey() { + return GameExchangeStep.TENANT_QUOTA_DEDUCTED; + } + + + /** + * do过程 + * + * @param gameExchangeMoney 游戏兑换货币 + * @return boolean + */ + @Override + public boolean doProcess(GameExchangeDTO gameExchangeMoney) { + //如果不是之前的步骤代码执行过了 或者是转入操作 + if (!gameExchangeMoney.getStep().equals(GameExchangeStep.PLATFORM_TRANSACTION.getCode()) ) { + return Boolean.TRUE; + } + if (!gameExchangeMoney.getStepStatus().equals(StatusType.SUCCESS.getValue())){ + return Boolean.TRUE; + } + + TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager); + transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); + Boolean result = transactionTemplate.execute(transactionStatus -> { + //不是转入操作 + if (!TransferType.ALL.getCode().equals(gameExchangeMoney.getExchangeType())) { + gameExchangeMoney.setStep(GameExchangeStep.DEDUCT_BALANCE.getCode()); + gameExchangeMoney.setStepStatus(GameExchangeStepStatus.SUCCESS.getCode()); + gameExchangeMoney.setStatus(StatusType.SUCCESS.getValue()); + return gameExchangeMoneyService.updateGameExchangeMoney(gameExchangeMoney) > 0; + } + + Platform platform = platformService.get(gameExchangeMoney.getPlatformCode()); + KeyInfo keyInfo = null; + for (KeyInfo keyData : platform.getKeyInfo()) { + if (StringUtils.isNotEmpty(gameExchangeMoney.getCurrencyCode())) { + if (keyData.getCurrency().equalsIgnoreCase(gameExchangeMoney.getCurrencyCode())) { + keyInfo = keyData; + break; + } + } + } + + + BigDecimal decimal = tenantGameQuotaService.gameBalanceExchange(GameBalanceExchange.builder() + .platformCode(gameExchangeMoney.getPlatformCode()) + .sourceId(String.valueOf(gameExchangeMoney.getId())) + .currencyCode(gameExchangeMoney.getCurrencyCode()) + .currency(gameExchangeMoney.getCurrencyCode()) + .transferType(gameExchangeMoney.getExchangeType()) + .amount(gameExchangeMoney.getBalance()) + .isAll(Boolean.FALSE) + .account(memberService.selectMemberById(gameExchangeMoney.getMemberId()).getMemberAccount()) + .tenantKey(gameExchangeMoney.getTenantKey()) + .systemCurrency(gameExchangeMoney.getCurrencyCode()) + .agentId(keyInfo.getCode()) + .agentKey(keyInfo.getKey()) + .build()); + + gameExchangeMoney.setQuota(decimal); + gameExchangeMoney.setStep(GameExchangeStep.TENANT_QUOTA_DEDUCTED.getCode()); + gameExchangeMoney.setStepStatus(GameExchangeStepStatus.SUCCESS.getCode()); + gameExchangeMoney.setStatus(StatusType.SUCCESS.getValue()); + return gameExchangeMoneyService.updateGameExchangeMoney(gameExchangeMoney) > 0; + + }); + return Boolean.TRUE.equals(result); + + + } + + + /** + * 一定要回滚 最后一步成功了就结束了 + * + * @param gameExchangeMoney 游戏兑换货币 + * @return boolean + */ + @Override + public boolean doRollBack(GameExchangeDTO gameExchangeMoney) { + return Boolean.TRUE; + } + + /** + * 下一步处理器 + * + * @return {@link GameExchangeStep } + */ + @Override + public GameExchangeStep nextStepProcessor() { + return null; + } + + /** + * 后级处理器 最后一步无法回滚 + * + * @return {@link GameExchangeStep } + */ + @Override + public GameExchangeStep backStepProcessor() { + { + return null; + } + } + +} diff --git a/ff-game/src/main/java/com/ff/game/api/exchange/impl/CreateOrderServiceImpl.java b/ff-game/src/main/java/com/ff/game/api/exchange/impl/CreateOrderServiceImpl.java new file mode 100644 index 0000000..9909e68 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/exchange/impl/CreateOrderServiceImpl.java @@ -0,0 +1,112 @@ +package com.ff.game.api.exchange.impl; + +import com.ff.base.constant.Constants; +import com.ff.base.enums.*; +import com.ff.base.exception.base.ApiException; +import com.ff.base.manager.AsyncManager; +import com.ff.base.utils.DateUtils; +import com.ff.base.utils.uuid.IdUtils; +import com.ff.game.api.IGamesService; +import com.ff.game.api.exchange.AbstractStepProcessor; +import com.ff.game.api.exchange.StepProcessorFactory; +import com.ff.game.api.exchange.StepProcessorService; +import com.ff.game.api.exchange.dto.GameExchangeDTO; +import com.ff.game.api.request.ExchangeTransferStatusRequestDTO; +import com.ff.game.api.request.TransactionIdRequestDTO; +import com.ff.game.domain.GameExchangeMoney; +import com.ff.game.service.IGameExchangeMoneyService; +import com.ff.member.domain.Member; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import javax.crypto.spec.SecretKeySpec; +import java.util.Base64; +import java.util.Map; + +/** + * 创建订单impl + * + * @author shi + * @date 2025/04/09 + */ +@Service +@Order(1) +public class CreateOrderServiceImpl extends AbstractStepProcessor { + + @Resource + private IGameExchangeMoneyService gameExchangeMoneyService; + @Resource + private StepProcessorFactory stepProcessorFactory; + + @Autowired + private Map gamesService; + + /** + * 步进键 + * + * @return {@link GameExchangeStep } + */ + @Override + public GameExchangeStep stepKey() { + return GameExchangeStep.CREATE_ORDER; + } + + + /** + * do过程 + * + * @param gameExchangeMoney 游戏兑换货币 + * @return boolean + */ + @Override + public boolean doProcess(GameExchangeDTO gameExchangeMoney) { + + String transactionId = gamesService.get(gameExchangeMoney.getPlatformCode()+Constants.SERVICE).getTransactionId(TransactionIdRequestDTO.builder().exchangeType(gameExchangeMoney.getExchangeType()).gameAccount(gameExchangeMoney.getGameAccount()).build()); + gameExchangeMoney.setTransactionId(transactionId); + gameExchangeMoney.setCreateBy(Constants.SYSTEM); + gameExchangeMoney.setStatus(StatusType.IN_PROGRESS.getValue()); + gameExchangeMoney.setStep(GameExchangeStep.CREATE_ORDER.getCode()); + gameExchangeMoney.setStepStatus(GameExchangeStepStatus.SUCCESS.getCode()); + return gameExchangeMoneyService.insertGameExchangeMoney(gameExchangeMoney) > 0; + } + + + + /** + * 一定要回滚 + * + * @param gameExchangeMoney 游戏兑换货币 + * @return boolean + */ + @Override + public boolean doRollBack(GameExchangeDTO gameExchangeMoney) { + gameExchangeMoney.setStep(GameExchangeStep.CREATE_ORDER.getCode()); + gameExchangeMoney.setStepStatus(GameExchangeStepStatus.FAILURE.getCode()); + gameExchangeMoney.setStatus(StatusType.FAILURE.getValue()); + gameExchangeMoney.setUpdateBy(Constants.SYSTEM); + gameExchangeMoney.setUpdateTime(DateUtils.getNowDate()); + return gameExchangeMoneyService.updateGameExchangeMoney(gameExchangeMoney) > 0; + } + + /** + * 下一步处理器 + * + * @return {@link GameExchangeStep } + */ + @Override + public GameExchangeStep nextStepProcessor() { + return GameExchangeStep.DEDUCT_BALANCE; + } + + /** + * 后级处理器 + * + * @return {@link GameExchangeStep } + */ + @Override + public GameExchangeStep backStepProcessor() { + return null; + } +} diff --git a/ff-game/src/main/java/com/ff/game/api/exchange/impl/DeductBalanceServiceImpl.java b/ff-game/src/main/java/com/ff/game/api/exchange/impl/DeductBalanceServiceImpl.java new file mode 100644 index 0000000..a400b1c --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/exchange/impl/DeductBalanceServiceImpl.java @@ -0,0 +1,207 @@ +package com.ff.game.api.exchange.impl; + +import com.ff.base.constant.Constants; +import com.ff.base.enums.*; +import com.ff.base.exception.base.ApiException; +import com.ff.base.utils.DateUtils; +import com.ff.base.utils.QuotaUtils; +import com.ff.base.utils.StringUtils; +import com.ff.base.utils.uuid.IdUtils; +import com.ff.common.domain.TenantGameQuota; +import com.ff.common.domain.TenantGameQuotaFlow; +import com.ff.common.dto.BalanceChangesDTO; +import com.ff.common.dto.GameBalanceExchange; +import com.ff.common.service.ITenantGameQuotaFlowService; +import com.ff.common.service.ITenantGameQuotaService; +import com.ff.game.api.exchange.AbstractStepProcessor; +import com.ff.game.api.exchange.StepProcessorFactory; +import com.ff.game.api.exchange.dto.GameExchangeDTO; +import com.ff.game.domain.GameExchangeMoney; +import com.ff.game.domain.KeyInfo; +import com.ff.game.domain.Platform; +import com.ff.game.service.IGameExchangeMoneyService; +import com.ff.game.service.IPlatformService; +import com.ff.member.service.IMemberService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Service; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.TransactionDefinition; +import org.springframework.transaction.support.TransactionTemplate; +import org.springframework.util.CollectionUtils; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.util.List; + + +/** + * 转入提前扣租户余额impl + * + * @author shi + * @date 2025/04/09 + */ +@Service +@Order(2) +public class DeductBalanceServiceImpl extends AbstractStepProcessor { + + @Resource + private IGameExchangeMoneyService gameExchangeMoneyService; + + @Resource + private ITenantGameQuotaService tenantGameQuotaService; + + @Resource + private IMemberService memberService; + + @Resource + private IPlatformService platformService; + @Resource + private ITenantGameQuotaFlowService tenantGameQuotaFlowService; + @Autowired + private PlatformTransactionManager transactionManager; + + /** + * 步进键 + * + * @return {@link GameExchangeStep } + */ + @Override + public GameExchangeStep stepKey() { + return GameExchangeStep.DEDUCT_BALANCE; + } + + + /** + * do过程 + * + * @param gameExchangeMoney 游戏兑换货币 + * @return boolean + */ + @Override + public boolean doProcess(GameExchangeDTO gameExchangeMoney) { + TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager); + transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); + Boolean result = transactionTemplate.execute(transactionStatus -> { + + //如果不是之前的步骤代码执行过了 + if (!gameExchangeMoney.getStep().equals(this.backStepProcessor().getCode())) { + return Boolean.TRUE; + } + //不是转入操作 + if (!TransferType.GAMES.getCode().equals(gameExchangeMoney.getExchangeType())) { + gameExchangeMoney.setStep(GameExchangeStep.DEDUCT_BALANCE.getCode()); + gameExchangeMoney.setStepStatus(GameExchangeStepStatus.SUCCESS.getCode()); + return gameExchangeMoneyService.updateGameExchangeMoney(gameExchangeMoney) > 0; + } + + Platform platform = platformService.get(gameExchangeMoney.getPlatformCode()); + KeyInfo keyInfo = null; + for (KeyInfo keyData : platform.getKeyInfo()) { + if (StringUtils.isNotEmpty(gameExchangeMoney.getCurrencyCode())) { + if (keyData.getCurrency().equalsIgnoreCase(gameExchangeMoney.getCurrencyCode())) { + keyInfo = keyData; + break; + } + } + } + BigDecimal decimal = tenantGameQuotaService.gameBalanceExchange(GameBalanceExchange.builder() + .platformCode(gameExchangeMoney.getPlatformCode()) + .sourceId(String.valueOf(gameExchangeMoney.getId())) + .currencyCode(gameExchangeMoney.getCurrencyCode()) + .currency(gameExchangeMoney.getCurrencyCode()) + .transferType(gameExchangeMoney.getExchangeType()) + .amount(gameExchangeMoney.getBalance()) + .account(memberService.selectMemberById(gameExchangeMoney.getMemberId()).getMemberAccount()) + .tenantKey(gameExchangeMoney.getTenantKey()) + .systemCurrency(gameExchangeMoney.getCurrencyCode()) + .agentId(keyInfo.getCode()) + .isAll(Boolean.TRUE) + .agentKey(keyInfo.getKey()) + .build()); + + gameExchangeMoney.setQuota(decimal); + + + gameExchangeMoney.setStep(GameExchangeStep.DEDUCT_BALANCE.getCode()); + gameExchangeMoney.setStepStatus(GameExchangeStepStatus.SUCCESS.getCode()); + return gameExchangeMoneyService.updateGameExchangeMoney(gameExchangeMoney) > 0; + }); + return Boolean.TRUE.equals(result); + } + + + /** + * 一定要回滚 + * + * @param gameExchangeMoney 游戏兑换货币 + * @return boolean + */ + @Override + public boolean doRollBack(GameExchangeDTO gameExchangeMoney) { + //如果不是之前的步骤代码执行过了 或者是转入操作 + if (!gameExchangeMoney.getStep().equals(this.stepKey().getCode())) { + return Boolean.TRUE; + } + TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager); + transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW); + + //如果该订单已经回滚过增加余额 + List tenantGameQuotaFlows = tenantGameQuotaFlowService.selectTenantGameQuotaFlowList( + TenantGameQuotaFlow.builder() + .sourceId(String.valueOf(gameExchangeMoney.getId())) + .isOut(Boolean.TRUE) + .build()); + if (!CollectionUtils.isEmpty(tenantGameQuotaFlows)){ + return Boolean.TRUE; + } + + + + + tenantGameQuotaFlows = tenantGameQuotaFlowService.selectTenantGameQuotaFlowList( + TenantGameQuotaFlow.builder() + .sourceId(String.valueOf(gameExchangeMoney.getId())) + .isOut(Boolean.FALSE) + .build()); + if (CollectionUtils.isEmpty(tenantGameQuotaFlows)) { + return Boolean.TRUE; + } + //取出第一个 + TenantGameQuotaFlow tenantGameQuotaFlow = tenantGameQuotaFlows.get(0); + return tenantGameQuotaService.balanceChanges(BalanceChangesDTO.builder() + .isOut(Boolean.TRUE) + .platformCode(tenantGameQuotaFlow.getPlatformCode()) + .currencyCode(tenantGameQuotaFlow.getCurrencyCode()) + .tenantKey(tenantGameQuotaFlow.getTenantKey()) + .balance(tenantGameQuotaFlow.getBalance()) + .sourceId(tenantGameQuotaFlow.getSourceId()) + .memberId(gameExchangeMoney.getMemberId()) + .operationType(OperationType.API_BALANCE.getCode()) + .remark(OperationType.API_BALANCE.getDescription()) + .quotaType(tenantGameQuotaFlow.getQuotaType()).build()); + } + + /** + * 下一步处理器 + * + * @return {@link GameExchangeStep } + */ + @Override + public GameExchangeStep nextStepProcessor() { + return GameExchangeStep.PLATFORM_TRANSACTION; + } + + /** + * 后级处理器 + * + * @return {@link GameExchangeStep } + */ + @Override + public GameExchangeStep backStepProcessor() { + { + return GameExchangeStep.CREATE_ORDER; + } + } + +} diff --git a/ff-game/src/main/java/com/ff/game/api/exchange/impl/PlatformTransactionServiceImpl.java b/ff-game/src/main/java/com/ff/game/api/exchange/impl/PlatformTransactionServiceImpl.java new file mode 100644 index 0000000..f0c5798 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/exchange/impl/PlatformTransactionServiceImpl.java @@ -0,0 +1,214 @@ +package com.ff.game.api.exchange.impl; + +import com.ff.base.constant.Constants; +import com.ff.base.enums.*; +import com.ff.base.exception.base.ApiException; +import com.ff.base.utils.StringUtils; +import com.ff.common.domain.TenantGameQuotaFlow; +import com.ff.common.dto.BalanceChangesDTO; +import com.ff.common.dto.GameBalanceExchange; +import com.ff.common.service.ITenantGameQuotaFlowService; +import com.ff.common.service.ITenantGameQuotaService; +import com.ff.game.api.IGamesService; +import com.ff.game.api.exchange.AbstractStepProcessor; +import com.ff.game.api.exchange.dto.GameExchangeDTO; +import com.ff.game.api.request.ExchangeTransferMoneyRequestDTO; +import com.ff.game.api.request.ExchangeTransferStatusRequestDTO; +import com.ff.game.api.request.ExchangeTransferStatusResponseDTO; +import com.ff.game.domain.GameExchangeMoney; +import com.ff.game.domain.KeyInfo; +import com.ff.game.domain.Platform; +import com.ff.game.service.IGameExchangeMoneyService; +import com.ff.game.service.IPlatformService; +import com.ff.member.domain.Member; +import com.ff.member.service.IMemberService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.util.List; +import java.util.Map; + + +/** + * 操作第三方扣减 + * + * @author shi + * @date 2025/04/09 + */ +@Service +@Order(3) +public class PlatformTransactionServiceImpl extends AbstractStepProcessor { + + + @Resource + private IGameExchangeMoneyService gameExchangeMoneyService; + + @Resource + private IMemberService memberService; + + @Resource + private IPlatformService platformService; + + @Autowired + private Map gamesService; + + /** + * 步进键 + * + * @return {@link GameExchangeStep } + */ + @Override + public GameExchangeStep stepKey() { + return GameExchangeStep.PLATFORM_TRANSACTION; + } + + + /** + * do过程 + * + * @param gameExchangeMoney 游戏兑换货币 + * @return boolean + */ + @Override + public boolean doProcess(GameExchangeDTO gameExchangeMoney) { + //如果不是之前的步骤代码执行过了 或者当前步骤成功的 + if (!gameExchangeMoney.getStep().equals(this.backStepProcessor().getCode())&& + (GameExchangeStep.PLATFORM_TRANSACTION.getCode().equals(gameExchangeMoney.getStep())&& + gameExchangeMoney.getStepStatus().equals(GameExchangeStepStatus.SUCCESS.getCode())) + ) { + return Boolean.TRUE; + } + + + Platform platform = platformService.get(gameExchangeMoney.getPlatformCode()); + + String targetCurrency = platform.getCurrencyInfo().get(gameExchangeMoney.getCurrencyCode()); + ApiException.notNull(targetCurrency, ErrorCode.CURRENCY_NOT_EXIST.getCode()); + + KeyInfo keyInfo = null; + for (KeyInfo keyData : platform.getKeyInfo()) { + if (StringUtils.isNotEmpty(gameExchangeMoney.getCurrencyCode())) { + if (keyData.getCurrency().equalsIgnoreCase(gameExchangeMoney.getCurrencyCode())) { + keyInfo = keyData; + break; + } + } + } + Member member = memberService.selectMemberById(gameExchangeMoney.getMemberId()); + IGamesService iGamesService = gamesService.get(gameExchangeMoney.getPlatformCode() + Constants.SERVICE); + + //查询订单详情 + if (TriggerType.TIMER.getCode() == gameExchangeMoney.getTriggerType()) { + //做二次确认调订单详情接口 + this.doRollBack(gameExchangeMoney); + if (GameExchangeStepStatus.FAILURE.getCode() == gameExchangeMoney.getStepStatus()){ + throw new ApiException(ErrorCode.BALANCE_TRANSFER_FAILED.getCode()); + } + } + + try { + //操作第三方额度接口 + ExchangeTransferMoneyRequestDTO exchangeTransferMoneyRequestDTO = ExchangeTransferMoneyRequestDTO.builder() + .agentId(keyInfo.getCode()) + .agentKey(keyInfo.getKey()) + .account(member.getGameAccount()) + .currency(targetCurrency) + .amount(gameExchangeMoney.getBalance()) + .transferType(gameExchangeMoney.getExchangeType()) + .transactionId(gameExchangeMoney.getTransactionId()) + .gameExchangeId(gameExchangeMoney.getId()) + .vendor(platform) + .keyInfo(keyInfo) + .build(); + Long id = iGamesService.exchangeTransferByAgentId(exchangeTransferMoneyRequestDTO); + }catch (Exception e){ + //做二次确认调订单详情接口 + this.doRollBack(gameExchangeMoney); + if (GameExchangeStepStatus.FAILURE.getCode() == gameExchangeMoney.getStepStatus()){ + throw new ApiException(ErrorCode.BALANCE_TRANSFER_FAILED.getCode()); + } + } + + + GameExchangeMoney exchangeMoney = gameExchangeMoneyService.selectGameExchangeMoneyById(gameExchangeMoney.getId()); + gameExchangeMoney.setBalance(exchangeMoney.getBalance()); + gameExchangeMoney.setStep(exchangeMoney.getStep()); + gameExchangeMoney.setStepStatus(exchangeMoney.getStepStatus()); + return gameExchangeMoneyService.updateGameExchangeMoney(gameExchangeMoney) > 0; + } + + + /** + * 一定要回滚 + * + * @param gameExchangeMoney 游戏兑换货币 + * @return boolean + */ + @Override + public boolean doRollBack(GameExchangeDTO gameExchangeMoney) { + + Platform platform = platformService.get(gameExchangeMoney.getPlatformCode()); + + String targetCurrency = platform.getCurrencyInfo().get(gameExchangeMoney.getCurrencyCode()); + ApiException.notNull(targetCurrency, ErrorCode.CURRENCY_NOT_EXIST.getCode()); + + KeyInfo keyInfo = null; + for (KeyInfo keyData : platform.getKeyInfo()) { + if (StringUtils.isNotEmpty(gameExchangeMoney.getCurrencyCode())) { + if (keyData.getCurrency().equalsIgnoreCase(gameExchangeMoney.getCurrencyCode())) { + keyInfo = keyData; + break; + } + } + } + Member member = memberService.selectMemberById(gameExchangeMoney.getMemberId()); + IGamesService iGamesService = gamesService.get(gameExchangeMoney.getPlatformCode() + Constants.SERVICE); + + ExchangeTransferStatusRequestDTO exchangeTransferStatusRequestDTO = new ExchangeTransferStatusRequestDTO(); + exchangeTransferStatusRequestDTO.setAccount(member.getGameAccount()); + exchangeTransferStatusRequestDTO.setCurrency(targetCurrency); + exchangeTransferStatusRequestDTO.setOrderId(gameExchangeMoney.getTransactionId()); + exchangeTransferStatusRequestDTO.setAgentId(keyInfo.getCode()); + exchangeTransferStatusRequestDTO.setAgentKey(keyInfo.getKey()); + exchangeTransferStatusRequestDTO.setGameExchangeMoneyId(gameExchangeMoney.getId()); + exchangeTransferStatusRequestDTO.setVendor(platform); + exchangeTransferStatusRequestDTO.setKeyInfo(keyInfo); + exchangeTransferStatusRequestDTO.setSystemCurrency(gameExchangeMoney.getCurrencyCode()); + ExchangeTransferStatusResponseDTO statusResponseDTO = iGamesService.exchangeTransferStatus(exchangeTransferStatusRequestDTO); + //订单已成功 + if (StatusType.SUCCESS.getValue().equals(statusResponseDTO.getStatusType())) { + gameExchangeMoney.setStep(GameExchangeStep.PLATFORM_TRANSACTION.getCode()); + gameExchangeMoney.setStepStatus(GameExchangeStepStatus.SUCCESS.getCode()); + return gameExchangeMoneyService.updateGameExchangeMoney(gameExchangeMoney) > 0; + } + gameExchangeMoney.setStep(GameExchangeStep.PLATFORM_TRANSACTION.getCode()); + gameExchangeMoney.setStepStatus(GameExchangeStepStatus.FAILURE.getCode()); + return gameExchangeMoneyService.updateGameExchangeMoney(gameExchangeMoney) > 0; + } + + /** + * 下一步处理器 + * + * @return {@link GameExchangeStep } + */ + @Override + public GameExchangeStep nextStepProcessor() { + return GameExchangeStep.TENANT_QUOTA_DEDUCTED; + } + + /** + * 后级处理器 + * + * @return {@link GameExchangeStep } + */ + @Override + public GameExchangeStep backStepProcessor() { + { + return GameExchangeStep.DEDUCT_BALANCE; + } + } + +} diff --git a/ff-game/src/main/java/com/ff/game/api/fb/address/FBSportsAddress.java b/ff-game/src/main/java/com/ff/game/api/fb/address/FBSportsAddress.java new file mode 100644 index 0000000..86974ec --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/fb/address/FBSportsAddress.java @@ -0,0 +1,30 @@ +package com.ff.game.api.fb.address; + +import com.dtflys.forest.callback.AddressSource; +import com.dtflys.forest.http.ForestAddress; +import com.dtflys.forest.http.ForestRequest; +import com.ff.base.enums.GamePlatforms; +import com.ff.game.service.IPlatformService; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + + +/** + * 对接文档地址 + * + * @author cengy + */ +@Component +public class FBSportsAddress implements AddressSource { + + @Resource + private IPlatformService platformService; + + @Override + public ForestAddress getAddress(ForestRequest request) { + String apiBaseUrl = platformService.get(GamePlatforms.FBSports.getCode()) + .getUrlInfo().getUrl(); + return new ForestAddress("https", apiBaseUrl, 443, "fb/data"); + } +} \ No newline at end of file diff --git a/ff-game/src/main/java/com/ff/game/api/fb/client/FBSportsClient.java b/ff-game/src/main/java/com/ff/game/api/fb/client/FBSportsClient.java new file mode 100644 index 0000000..78dbf29 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/fb/client/FBSportsClient.java @@ -0,0 +1,102 @@ +package com.ff.game.api.fb.client; + +import com.dtflys.forest.annotation.*; +import com.ff.game.api.fb.address.FBSportsAddress; +import com.ff.game.api.fb.dto.*; + +/** + * 数据接口文档
+ * 网页接入文档 + * + * @author cengy + */ +@Address(source = FBSportsAddress.class) +public interface FBSportsClient { + /** + * 创建投注用户 + * + * @return {@link CreateUserResponse} + */ + @Post(url = "/api/v2/new/user/create") + CreateUserResponse createMember(@JSONBody CreateUserRequest request, + @Header("sign") @Var("sign") String sign, + @Header("timestamp") @Var("timestamp") long timestamp, + @Header("merchantId") @Var("merchantId") String merchantId); + + /** + * 用户金额转入到FB体育平台,支持两位小数,最小0.01,必须是正数 + * + * @param request + * @param sign + * @param timestamp + * @param merchantId + * @return {@link TransferInResponse} + */ + @Post(url = "/api/v2/new/transfer/in") + TransferInResponse transferIn(@JSONBody TransferInRequest request, + @Header("sign") @Var("sign") String sign, + @Header("timestamp") @Var("timestamp") long timestamp, + @Header("merchantId") @Var("merchantId") String merchantId); + + @Post(url = "/api/v2/new/transfer/out") + TransferOutResponse transferOut(@JSONBody TransferOutRequest request, + @Header("sign") @Var("sign") String sign, + @Header("timestamp") @Var("timestamp") long timestamp, + @Header("merchantId") @Var("merchantId") String merchantId); + + @Post(url = "/api/v2/new/user/detail") + GetMemberInfoResponse getMemberInfo(@JSONBody GetMemberInfoRequest request, + @Header("sign") @Var("sign") String sign, + @Header("timestamp") @Var("timestamp") long timestamp, + @Header("merchantId") @Var("merchantId") String merchantId); + + /** + * 查询转账详情,当转入/转出接口遇到异常,可查询某次转账是否成功 + */ + @Post(url = "/api/v2/transfer/detail") + TransferDetailResponse transferDetail(@JSONBody TransferDetailRequest request, + @Header("sign") @Var("sign") String sign, + @Header("timestamp") @Var("timestamp") long timestamp, + @Header("merchantId") @Var("merchantId") String merchantId); + + @Post(url = "/api/v2/service/domain/list") + GetUrlResponse getUrl(@JSONBody GetUrlRequest request, + @Header("sign") @Var("sign") String sign, + @Header("timestamp") @Var("timestamp") long timestamp, + @Header("merchantId") @Var("merchantId") String merchantId); + + /** + * FB体育用拉取订单文件的方式同步订单数据,FB体育每5分钟生成一次订单文件, + * 通过此接口获取某一段时间内的文件ID列表,再通过文件ID获取具体订单数据 + */ + @Post(url = "/api/v2/order/file/ids") + OrderFilesResponse orderFiles(@JSONBody OrderFilesRequest request, + @Header("sign") @Var("sign") String sign, + @Header("timestamp") @Var("timestamp") long timestamp, + @Header("merchantId") @Var("merchantId") String merchantId); + + /** + * 拉取订单Json数据 + */ + @Post(url = "/api/v2/order/list") + OrderInfoResponse getOrderJsonData(@JSONBody OrderInfoRequest request, + @Header("sign") @Var("sign") String sign, + @Header("timestamp") @Var("timestamp") long timestamp, + @Header("merchantId") @Var("merchantId") String merchantId); + + + /** + * 获取用户app端鉴权token和相关服务url,获取到的token用于app调用接口鉴权 + * + * @param request + * @param sign + * @param timestamp + * @param merchantId + * @return + */ + @Post(url = "/api/v2/token/get") + GetTokenResponse getToken(@JSONBody GetTokenRequest request, + @Header("sign") @Var("sign") String sign, + @Header("timestamp") @Var("timestamp") long timestamp, + @Header("merchantId") @Var("merchantId") String merchantId); +} diff --git a/ff-game/src/main/java/com/ff/game/api/fb/dto/CreateUserRequest.java b/ff-game/src/main/java/com/ff/game/api/fb/dto/CreateUserRequest.java new file mode 100644 index 0000000..58ba958 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/fb/dto/CreateUserRequest.java @@ -0,0 +1,30 @@ +package com.ff.game.api.fb.dto; + +import com.alibaba.fastjson2.JSON; +import lombok.Data; + +import java.io.Serializable; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** + * @author cengy + */ +@Data +public class CreateUserRequest implements Serializable { + + private static final long serialVersionUID = 1L; + + private String merchantUserId;// 渠道用户id,支持40位字符串,必须唯一 + private List currencyIds = null; // 币种id集合 , see enum: currency + private Integer oddsLevel = null; // 赔率级别,不传则为默认, see enum: user_odds_level_enum + + public String toJSON() { + Map map = new LinkedHashMap<>(); + map.put("currencyIds", currencyIds); + map.put("merchantUserId", merchantUserId); + map.put("oddsLevel", oddsLevel); + return JSON.toJSONString(map); + } +} diff --git a/ff-game/src/main/java/com/ff/game/api/fb/dto/CreateUserResponse.java b/ff-game/src/main/java/com/ff/game/api/fb/dto/CreateUserResponse.java new file mode 100644 index 0000000..0599c91 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/fb/dto/CreateUserResponse.java @@ -0,0 +1,19 @@ +package com.ff.game.api.fb.dto; + +import lombok.Data; + +import java.io.Serializable; + +/** + * @author cengy + */ +@Data +public class CreateUserResponse implements Serializable { + + private static final long serialVersionUID = 1L; + + private Boolean success; + private Integer data; + private Integer code; + private String message; +} diff --git a/ff-game/src/main/java/com/ff/game/api/fb/dto/Enums.java b/ff-game/src/main/java/com/ff/game/api/fb/dto/Enums.java new file mode 100644 index 0000000..378f03c --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/fb/dto/Enums.java @@ -0,0 +1,9 @@ +package com.ff.game.api.fb.dto; + +/** + * @author cengy + */ +public class Enums { + + +} diff --git a/ff-game/src/main/java/com/ff/game/api/fb/dto/GetMemberInfoRequest.java b/ff-game/src/main/java/com/ff/game/api/fb/dto/GetMemberInfoRequest.java new file mode 100644 index 0000000..42d187a --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/fb/dto/GetMemberInfoRequest.java @@ -0,0 +1,27 @@ +package com.ff.game.api.fb.dto; + +import com.alibaba.fastjson2.JSON; +import lombok.Data; + +import java.io.Serializable; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * @author cengy + */ +@Data +public class GetMemberInfoRequest implements Serializable { + private static final long serialVersionUID = 1L; + + /** + * 渠道用户id,不能为空 + */ + private String merchantUserId; + + public String toJSON() { + Map map = new LinkedHashMap<>(); + map.put("merchantUserId", merchantUserId); + return JSON.toJSONString(map); + } +} diff --git a/ff-game/src/main/java/com/ff/game/api/fb/dto/GetMemberInfoResponse.java b/ff-game/src/main/java/com/ff/game/api/fb/dto/GetMemberInfoResponse.java new file mode 100644 index 0000000..632dfd2 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/fb/dto/GetMemberInfoResponse.java @@ -0,0 +1,38 @@ +package com.ff.game.api.fb.dto; + +import lombok.Data; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.List; + +/** + * @author cengy + */ +@Data +public class GetMemberInfoResponse implements Serializable { + private static final long serialVersionUID = 1L; + + private Boolean success; + private String message; + private MemberInfo data; + private Integer code; + + @Data + public static class MemberInfo implements Serializable{ + private static final long serialVersionUID = 1L; + private String merchantUserId; + private Integer userId; // FB体育用户id + private Integer walletType; // 用户钱包类型 , see enum: wallet_type + private Integer currencyType; // 用户币种类型 , see enum: currency_type + private List wallets; // 钱包集合 + private Integer oddsLevel;// 赔率级别 , see enum: user_odds_level_enum + } + @Data + public static class Wallet implements Serializable{ + private static final long serialVersionUID = 1L; + private Integer currencyType; // 币种类型 , see enum: currency_type + private BigDecimal balance; // 余额 + private Integer currencyId; // 币种id , see enum: currency + } +} diff --git a/ff-game/src/main/java/com/ff/game/api/fb/dto/GetTokenRequest.java b/ff-game/src/main/java/com/ff/game/api/fb/dto/GetTokenRequest.java new file mode 100644 index 0000000..eefab72 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/fb/dto/GetTokenRequest.java @@ -0,0 +1,30 @@ +package com.ff.game.api.fb.dto; + +import com.alibaba.fastjson2.JSON; +import lombok.Data; + +import java.io.Serializable; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * @author cengy + */ +@Data +public class GetTokenRequest implements Serializable { + + private static final long serialVersionUID = 1L; + + private String merchantUserId; + // 平台类型,pc,h5, mobile , see enum: plat_form_enum + private String platForm; + // 客户端用户ip地址,尽可能提供,我们用于风控 + private String ip; // 可选 + + public String toJSON() { + Map map = new LinkedHashMap<>(); + map.put("merchantUserId", merchantUserId); + map.put("platForm", platForm); + return JSON.toJSONString(map); + } +} diff --git a/ff-game/src/main/java/com/ff/game/api/fb/dto/GetTokenResponse.java b/ff-game/src/main/java/com/ff/game/api/fb/dto/GetTokenResponse.java new file mode 100644 index 0000000..1780037 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/fb/dto/GetTokenResponse.java @@ -0,0 +1,49 @@ +package com.ff.game.api.fb.dto; + +import lombok.Data; + +import java.io.Serializable; +import java.util.List; + +/** + * @author cengy + */ +@Data +public class GetTokenResponse implements Serializable { + private static final long serialVersionUID = 1L; + + private Boolean success; + private String message; + private Integer code; + private TokenDTO data; + + @Data + public static class TokenDTO implements Serializable { + private String token; // 用户鉴权token,用于客户端鉴权 + private ServerInfo serverInfo; // 服务器地址信息 + private List domains; // 全部服务器地址信息 + private String themeBgColor; // 主题背景色 + private String themeFgColor; // 主题前景色 + private Integer userId; // FB用户ID + } + + @Data + public static class ServerInfo implements Serializable { + private static final long serialVersionUID = 1L; + private String apiServerAddress; // app接口服务地址 + private String apiEmbeddedServerAddress; // app内嵌网页地址 + private String pushServerAddress; // 推送服务地址 + private String pcAddress; // PC投注网站地址 + private String h5Address; // h5投注网站地址 + private String virtualAddress; // 虚拟体育投注网站地址 + private String virtualMatchVideoAddress; // 虚拟赛事视频地址 + private String ouH5Address; // 欧版h5地址 + private String ouPcAddress; // 欧版pc地址 + } + + @Data + public static class Domain { + private Integer type; // 域名类型 + private List domains; // 域名集合 + } +} diff --git a/ff-game/src/main/java/com/ff/game/api/fb/dto/GetUrlRequest.java b/ff-game/src/main/java/com/ff/game/api/fb/dto/GetUrlRequest.java new file mode 100644 index 0000000..8228a41 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/fb/dto/GetUrlRequest.java @@ -0,0 +1,17 @@ +package com.ff.game.api.fb.dto; + +import lombok.Data; + +import java.io.Serializable; + +/** + * @author cengy + */ +@Data +public class GetUrlRequest implements Serializable { + private static final long serialVersionUID = 1L; + + public String toJSON() { + return "{}"; + } +} diff --git a/ff-game/src/main/java/com/ff/game/api/fb/dto/GetUrlResponse.java b/ff-game/src/main/java/com/ff/game/api/fb/dto/GetUrlResponse.java new file mode 100644 index 0000000..1471461 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/fb/dto/GetUrlResponse.java @@ -0,0 +1,33 @@ +package com.ff.game.api.fb.dto; + +import lombok.Data; + +import java.io.Serializable; +import java.util.List; + +/** + * @author cengy + */ +@Data +public class GetUrlResponse implements Serializable { + private static final long serialVersionUID = 1L; + + private Boolean success; + private String message; + private List data; + private Integer code; + + @Data + public static class UrlDTO implements Serializable { + private static final long serialVersionUID = 1L; + private int type; //域名类型,1:API,2:PUSH,3:H5,4:PC,5:IMAGE , see enum: domain_type_enum + private List domainList; // 域名集合 + } + + @Data + public static class DomainDTO implements Serializable { + private static final long serialVersionUID = 1L; + private String domain; // 域名 + private int weight; // 权限值 + } +} diff --git a/ff-game/src/main/java/com/ff/game/api/fb/dto/OrderFilesRequest.java b/ff-game/src/main/java/com/ff/game/api/fb/dto/OrderFilesRequest.java new file mode 100644 index 0000000..7ac25bc --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/fb/dto/OrderFilesRequest.java @@ -0,0 +1,41 @@ +package com.ff.game.api.fb.dto; + +import com.alibaba.fastjson2.JSON; +import lombok.Data; + +import java.io.Serializable; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * @author cengy + */ +@Data +public class OrderFilesRequest implements Serializable { + private static final long serialVersionUID = 1L; + + /** + * 开始时间戳,13位数字,不能为null + */ + private Long startTime; + + /** + * 结束时间戳,13位数字,不能为null + */ + private Long endTime; + + public String toJSON() { + Map map = new LinkedHashMap<>(); + map.put("endTime", endTime); + map.put("startTime", startTime); + return JSON.toJSONString(map); +// String endTimeStr = endTime ; // 转换为字符串 +// String startTimeStr = startTime; // 转换为字符串 +// +// String json = "{" + +// "\"endTime\": \"" + endTimeStr + "\", " + +// "\"startTime\": \"" + startTimeStr + "\"" + +// "}"; +// return json; + } +} diff --git a/ff-game/src/main/java/com/ff/game/api/fb/dto/OrderFilesResponse.java b/ff-game/src/main/java/com/ff/game/api/fb/dto/OrderFilesResponse.java new file mode 100644 index 0000000..f600fdd --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/fb/dto/OrderFilesResponse.java @@ -0,0 +1,27 @@ +package com.ff.game.api.fb.dto; + +import lombok.Data; + +import java.io.Serializable; +import java.util.List; + +/** + * @author cengy + */ +@Data +public class OrderFilesResponse implements Serializable { + private static final long serialVersionUID = 1L; + + private Boolean success; + private String message; + private Integer code; + + private List data; + + @Data + public static class FileId implements Serializable { + private static final long serialVersionUID = 1L; + private Long fileId; + } + +} diff --git a/ff-game/src/main/java/com/ff/game/api/fb/dto/OrderInfoRequest.java b/ff-game/src/main/java/com/ff/game/api/fb/dto/OrderInfoRequest.java new file mode 100644 index 0000000..2197629 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/fb/dto/OrderInfoRequest.java @@ -0,0 +1,26 @@ +package com.ff.game.api.fb.dto; + +import com.alibaba.fastjson2.JSON; +import lombok.Data; + +import java.io.Serializable; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * @author cengy + */ +@Data +public class OrderInfoRequest implements Serializable { + private static final long serialVersionUID = 1L; + /** + * 文件Id,需要从/order/file/ids接口获取到 + */ + private Long fileId; + + public String toJSON() { + Map map = new LinkedHashMap<>(); + map.put("fileId", fileId); + return JSON.toJSONString(map); + } +} diff --git a/ff-game/src/main/java/com/ff/game/api/fb/dto/OrderInfoResponse.java b/ff-game/src/main/java/com/ff/game/api/fb/dto/OrderInfoResponse.java new file mode 100644 index 0000000..106ffb5 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/fb/dto/OrderInfoResponse.java @@ -0,0 +1,115 @@ +package com.ff.game.api.fb.dto; + +import lombok.Data; + +import java.io.Serializable; +import java.util.List; + +/** + * @author cengy + */ +@Data +public class OrderInfoResponse implements Serializable { + private static final long serialVersionUID = 1L; + + private Boolean success; + private String message; + private Integer code; + + private List data; + + @Data + public static class OrderDTO implements Serializable { + private static final long serialVersionUID = 1L; + private String id; // 订单号 + private Integer rejectReason; // 拒单原因码 see enum: order_reject_type + private String rejectReasonStr; // 拒单原因 + private String userId; // FB平台用户ID + private String merchantId; // 渠道ID + private String merchantUserId; // 渠道用户ID + private Integer currency; // 币种 see enum: currency + private String exchangeRate; // 汇率快照 + private Integer seriesType; // 关次类型 ,0 单关、1 串关, see enum: series_type + private String betType; // 投注类型 + private Integer allUp; // 总关数 + private Integer allUpAlive; // 存活关数 + private String stakeAmount; // 投注额(本金) + private String liabilityStake; // 名义投注额(名义本金) + private String settleAmount; // 结算派奖金额 + private Integer orderStatus; // 订单状态 see enum: order_status + private Integer payStatus; // 付款状态 + private Integer oddsChange; // 是否接受赔率变更 0不接受,1 接受更好赔率,2接受任意赔率 , see enum: odds_change_enum + private String device; // 设备类型 (pc、h5、mobile) , see enum: plat_form_enum + private String ip; // 投注IP地址 + private String settleTime; // 订单结算时间 + private String createTime; // 订单创建时间 + private String modifyTime; // 订单确认时间 + private String cancelTime; // 订单取消时间 + private String thirdRemark; // 第三方备注 + private String relatedId; // 三方关联ID + private String maxWinAmount; // 最大可赢金额 + private String loseAmount; // 最大赔付金额 + private Integer rollBackCount; // 回滚次数 + private Integer itemCount; // 选项数 + private Integer seriesValue; // 串几关 + private Integer betNum; // 子单数 + private String cashOutTotalStake; // 提前结算总本金 + private String liabilityCashoutStake; // 提前结算名义总本金 + private String cashOutPayoutStake; // 提前结算总派奖额 + private String reserveId; // 预约订单单号 + private Integer cashOutCount; // 提前结算次数 + private String unitStake; // 每单金额 + private Integer reserveVersion; // 预约订单版本号 + private List betList; // 注单集合 + } + + @Data + public static class BetDTO implements Serializable { + private static final long serialVersionUID = 1L; + + private String id; // ID + private String orderId; // 订单ID + private Integer sportId; // 运动ID + private String matchId; // 比赛ID + private String matchName; // 比赛名称 + private Integer period; // 阶段ID + private String marketId; // 玩法ID + private Integer marketType; // 玩法类型 + private Integer optionType; // 投注项类型 + private String optionName; // 选项名称 + private String marketName; // 玩法名称 + private String tournamentId; // 联赛ID + private String tournamentName; // 联赛名称 + private String odds; // 欧式赔率 + private Integer oddsFormat; // 投注时赔率类型 + private String betOdds; // 投注时赔率 + private Integer settleStatus; // 结算状态 + private Integer settleResult; // 结算结果 + private Boolean isInplay; // 是否滚球 + private String remark; // 备注 + private Double p1; // 变量1 (例如:让几个球) + private Double p2; // 变量2 + private Double p3; // 变量3 + private String extendedParameter; // 亚洲让球线 + private String extraInfo; // 当前比分 + private String pendingTime; // 延迟等待时间 + private String betScore; // 下注当时比分 + private Integer cancelReason; // 取消原因 + private String cancelReasonName; // 取消原因文本 + private Integer matchType; // 赛事类型 + private String matchTime; // 开赛时间 + private Integer virtualMatchDay; // 轮次 + private Integer virtualChampId; // 赛季 + private Integer virtualLegOrder; // 淘汰赛回合 + private Integer virtualWeekDay; // 小组赛比赛日 + private Integer virtualBlockId; // 期 + private Integer leaguePhase; // 联赛阶段 + private String maxStake; // 最大投注额 + private String validSettleStakeAmount; // 有效已结算投注额 + private String validSettleAmount; // 有效返还额 + private String cashOutCancelStake; // 提前结算取消总额 + private Integer walletType; // 钱包类型 + private Integer version; // 数据变更标记 + } + +} diff --git a/ff-game/src/main/java/com/ff/game/api/fb/dto/TransferDetailRequest.java b/ff-game/src/main/java/com/ff/game/api/fb/dto/TransferDetailRequest.java new file mode 100644 index 0000000..0c4edfd --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/fb/dto/TransferDetailRequest.java @@ -0,0 +1,39 @@ +package com.ff.game.api.fb.dto; + +import com.alibaba.fastjson2.JSON; +import lombok.Data; + +import java.io.Serializable; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * @author cengy + */ +@Data +public class TransferDetailRequest implements Serializable { + + + /** + * 业务id,不能为null + */ + private String businessId; + + /** + * 渠道用户ID,不能为null + */ + private String merchantUserId; + + /** + * 转账类型 , see enum: transfer_type_enum 不能为空 + */ + private String transferType; + + public String toJSON() { + Map map = new LinkedHashMap<>(); + map.put("businessId", businessId); + map.put("merchantUserId", merchantUserId); + map.put("transferType", transferType); + return JSON.toJSONString(map); + } +} diff --git a/ff-game/src/main/java/com/ff/game/api/fb/dto/TransferDetailResponse.java b/ff-game/src/main/java/com/ff/game/api/fb/dto/TransferDetailResponse.java new file mode 100644 index 0000000..af870bc --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/fb/dto/TransferDetailResponse.java @@ -0,0 +1,39 @@ +package com.ff.game.api.fb.dto; + +import lombok.Data; + +import java.io.Serializable; +import java.math.BigDecimal; + +/** + * @author cengy + */ +@Data +public class TransferDetailResponse implements Serializable { + private static final long serialVersionUID = 1L; + + private Boolean success; + private String message; + private TransferDetail data; + private Integer code; + + @Data + public static class TransferDetail implements Serializable { + private static final long serialVersionUID = 1L; + + private Integer id; + private Integer userId; + private String merchantUserId; + private String businessId; + // IN 转入 + // OUT 转出 + private String transferType; + private BigDecimal beforeTransferAmount; + private BigDecimal afterTransferAmount; + private Integer status; // 状态 , see enum: transfer_status_enum, 1 Successful 0 Failure + private Long createTime; // 记录创建时间 + private Integer currencyId;// 币种id , see enum: currency + + } + +} diff --git a/ff-game/src/main/java/com/ff/game/api/fb/dto/TransferInRequest.java b/ff-game/src/main/java/com/ff/game/api/fb/dto/TransferInRequest.java new file mode 100644 index 0000000..bc35430 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/fb/dto/TransferInRequest.java @@ -0,0 +1,46 @@ +package com.ff.game.api.fb.dto; + +import com.alibaba.fastjson2.JSON; +import lombok.Data; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * @author cengy + */ +@Data +public class TransferInRequest implements Serializable { + + /** + * 转账金额,不能为null + * 必须大於或等於0 + */ + private BigDecimal amount; + + /** + * 业务id,不能为null + */ + private String businessId; + + /** + * 渠道用户ID,不能为null + */ + private String merchantUserId; + + /** + * 币种id,可不传入 + */ + private Integer currencyId; + + public String toJSON() { + Map map = new LinkedHashMap<>(); + map.put("amount", amount); + map.put("businessId", businessId); + map.put("currencyId", currencyId); + map.put("merchantUserId", merchantUserId); + return JSON.toJSONString(map); + } +} diff --git a/ff-game/src/main/java/com/ff/game/api/fb/dto/TransferInResponse.java b/ff-game/src/main/java/com/ff/game/api/fb/dto/TransferInResponse.java new file mode 100644 index 0000000..562aca6 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/fb/dto/TransferInResponse.java @@ -0,0 +1,20 @@ +package com.ff.game.api.fb.dto; + +import lombok.Data; + +import java.io.Serializable; +import java.math.BigDecimal; + +/** + * @author cengy + */ +@Data +public class TransferInResponse implements Serializable { + + private static final long serialVersionUID = 1L; + + private Boolean success; + private BigDecimal data; + private Integer code; + private String message; +} diff --git a/ff-game/src/main/java/com/ff/game/api/fb/dto/TransferOutRequest.java b/ff-game/src/main/java/com/ff/game/api/fb/dto/TransferOutRequest.java new file mode 100644 index 0000000..795f00b --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/fb/dto/TransferOutRequest.java @@ -0,0 +1,46 @@ +package com.ff.game.api.fb.dto; + +import com.alibaba.fastjson2.JSON; +import lombok.Data; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * @author cengy + */ +@Data +public class TransferOutRequest implements Serializable { + + /** + * 转账金额,不能为null + * 必须大於或等於0 + */ + private BigDecimal amount; + + /** + * 业务id,不能为null + */ + private String businessId; + + /** + * 渠道用户ID,不能为null + */ + private String merchantUserId; + + /** + * 币种id,可不传入 + */ + private Integer currencyId; + + public String toJSON() { + Map map = new LinkedHashMap<>(); + map.put("amount", amount); + map.put("businessId", businessId); + map.put("currencyId", currencyId); + map.put("merchantUserId", merchantUserId); + return JSON.toJSONString(map); + } +} diff --git a/ff-game/src/main/java/com/ff/game/api/fb/dto/TransferOutResponse.java b/ff-game/src/main/java/com/ff/game/api/fb/dto/TransferOutResponse.java new file mode 100644 index 0000000..c784222 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/fb/dto/TransferOutResponse.java @@ -0,0 +1,20 @@ +package com.ff.game.api.fb.dto; + +import lombok.Data; + +import java.io.Serializable; +import java.math.BigDecimal; + +/** + * @author cengy + */ +@Data +public class TransferOutResponse implements Serializable { + + private static final long serialVersionUID = 1L; + + private Boolean success; + private BigDecimal data; + private Integer code; + private String message; +} diff --git a/ff-game/src/main/java/com/ff/game/api/fb/impl/FBSportsServiceImpl.java b/ff-game/src/main/java/com/ff/game/api/fb/impl/FBSportsServiceImpl.java new file mode 100644 index 0000000..bc3f65b --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/fb/impl/FBSportsServiceImpl.java @@ -0,0 +1,753 @@ +package com.ff.game.api.fb.impl; + +import cn.hutool.core.util.IdUtil; +import com.ff.base.constant.CacheConstants; +import com.ff.base.constant.Constants; +import com.ff.base.core.redis.RedisCache; +import com.ff.base.enums.*; +import com.ff.base.exception.base.ApiException; +import com.ff.base.exception.base.BaseException; +import com.ff.base.utils.DateUtils; +import com.ff.base.utils.StringUtils; +import com.ff.base.utils.sign.Md5Utils; +import com.ff.base.utils.uuid.IdUtils; +import com.ff.game.api.IGamesService; +import com.ff.game.api.fb.dto.*; +import com.ff.game.api.request.*; +import com.ff.game.domain.*; +import com.ff.game.service.IGameBettingDetailsService; +import com.ff.game.service.IGameExchangeMoneyService; +import com.ff.game.service.IGameService; +import com.ff.member.domain.Member; +import com.ff.member.service.IMemberService; +import com.ff.game.api.fb.client.FBSportsClient; +import com.ff.utils.TimestampFromString; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ObjectUtils; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + + +/** + * FB体育 + * + * @author shi + * @date 2024/10/21 + */ +@Service("FBSportsService") +@Slf4j +public class FBSportsServiceImpl implements IGamesService { + + @Resource + private RedisCache redisCache; + + @Resource + private IGameExchangeMoneyService gameExchangeMoneyService; + + @Resource + private IGameService gameService; + + + @Resource + private IMemberService memberService; + + @Resource + private FBSportsClient fbSportsClient; + + @Resource + private IGameBettingDetailsService gameBettingDetailsService; + + /** + * 获得就是成功 + * + * @param errorCode 错误代码 + * @return {@link Boolean } + */ + private Boolean isSuccess(Integer errorCode) { + return 0 == errorCode; + } + + String getSign(String bodyJsonString, String merchantId, String merchantApiSecret, long requestTimestamp) { + + String stringThatNeedsToBeSigned = bodyJsonString + "." + merchantId + "." + requestTimestamp + "." + merchantApiSecret; + String sign = Md5Utils.md5New(stringThatNeedsToBeSigned); + return sign; + } + + /** + * 创建成员 + * + * @param createMemberRequestDTO 创建成员请求dto + * @return {@link Boolean } + */ + @Override + public Boolean createMember(CreateMemberRequestDTO createMemberRequestDTO) { + + long timestamp = System.currentTimeMillis(); + CreateUserRequest request = new CreateUserRequest(); + request.setMerchantUserId(createMemberRequestDTO.getAccount()); + ArrayList currencyIds = new ArrayList<>(); + currencyIds.add(Integer.parseInt(createMemberRequestDTO.getCurrency())); + request.setCurrencyIds(currencyIds); + String jsonBody = /*SortByAttributeNameASC.get(request)*/ request.toJSON(); + String sign = getSign(jsonBody, + createMemberRequestDTO.getAgentId(), + createMemberRequestDTO.getAgentKey(), + timestamp + ); + + CreateUserResponse response = fbSportsClient.createMember( + request, + sign, + timestamp, createMemberRequestDTO.getAgentId()); + if (isSuccess(response.getCode())) { + log.info("创建会员成功, account:{}->{}", createMemberRequestDTO.getAccount(), response.getData()); + return Boolean.TRUE; + } + + log.error("创建会员失败, errorCode:{}, errorMessage:{}", response.getCode(), response.getMessage()); + throw new ApiException(ErrorCode.Create_Member_Failure.getCode()); + } + + + /** + * 按代理id进行交换转账 + * + * @param requestDTO 外汇转账moeny dto + * @return {@link Long } + */ + @Override + @Transactional + public Long exchangeTransferByAgentId(ExchangeTransferMoneyRequestDTO requestDTO) { + + + GameExchangeMoney exchangeMoney = gameExchangeMoneyService.selectGameExchangeMoneyById(requestDTO.getGameExchangeId()); + + // 转入 + if (requestDTO.getTransferType().equals(TransferType.GAMES.getCode())) { + TransferInRequest request = new TransferInRequest(); + request.setMerchantUserId(requestDTO.getAccount()); + request.setAmount(requestDTO.getAmount()); + request.setBusinessId(requestDTO.getTransactionId()); + request.setCurrencyId(Integer.parseInt(requestDTO.getCurrency())); + long timestamp = System.currentTimeMillis(); + String jsonBody = request.toJSON(); + String sign = getSign(jsonBody, + requestDTO.getAgentId(), + requestDTO.getAgentKey(), + timestamp + ); + + TransferInResponse response = fbSportsClient.transferIn( + request, + sign, + timestamp, + requestDTO.getAgentId()); + if (isSuccess(response.getCode())) { + BigDecimal transAmount = requestDTO.getAmount(); + + exchangeMoney.setBalance(transAmount); + exchangeMoney.setCoinBefore(response.getData().subtract(transAmount)); + exchangeMoney.setCoinAfter(response.getData()); + exchangeMoney.setCurrencyBefore(response.getData().subtract(transAmount)); + exchangeMoney.setCurrencyAfter(response.getData()); + exchangeMoney.setStep(GameExchangeStep.PLATFORM_TRANSACTION.getCode()); + exchangeMoney.setStepStatus(GameExchangeStepStatus.SUCCESS.getCode()); + gameExchangeMoneyService.updateGameExchangeMoney(exchangeMoney); + } else { + exchangeMoney.setStep(GameExchangeStep.PLATFORM_TRANSACTION.getCode()); + exchangeMoney.setStepStatus(GameExchangeStepStatus.FAILURE.getCode()); + gameExchangeMoneyService.updateGameExchangeMoney(exchangeMoney); + throw new ApiException(ErrorCode.Transfer_In_Failure.getCode()); + } + } else { + // 获取第三方钱包余额 + MemberInfoRequestDTO memberInfoRequestDTO = MemberInfoRequestDTO.builder() + .accounts(requestDTO.getAccount()) + .agentId(requestDTO.getAgentId()) + .agentKey(requestDTO.getAgentKey()) + .build(); + BigDecimal balance = this.getMemberInfo(memberInfoRequestDTO).getBalance(); + + TransferOutRequest request = new TransferOutRequest(); + request.setMerchantUserId(requestDTO.getAccount()); + request.setAmount(/*requestDTO.getAmount()*/ balance); + request.setBusinessId(requestDTO.getTransactionId()); + request.setCurrencyId(Integer.parseInt(requestDTO.getCurrency())); + + long timestamp = System.currentTimeMillis(); + String jsonBody = request.toJSON(); + String sign = getSign(jsonBody, + requestDTO.getAgentId(), + requestDTO.getAgentKey(), + timestamp + ); + + TransferOutResponse response = fbSportsClient + .transferOut( + request, + sign, + timestamp, + requestDTO.getAgentId() + ); + + + //判断是否转移成功 + if (this.isSuccess(response.getCode())) { + BigDecimal transAmount = balance; + //更新数据 + exchangeMoney.setBalance(transAmount); + exchangeMoney.setCoinBefore(response.getData().add(transAmount)); + exchangeMoney.setCoinAfter(response.getData()); + exchangeMoney.setCurrencyBefore(response.getData().add(transAmount)); + exchangeMoney.setCurrencyAfter(response.getData()); + exchangeMoney.setStep(GameExchangeStep.PLATFORM_TRANSACTION.getCode()); + exchangeMoney.setStepStatus(GameExchangeStepStatus.SUCCESS.getCode()); + gameExchangeMoneyService.updateGameExchangeMoney(exchangeMoney); + } else { + exchangeMoney.setStep(GameExchangeStep.PLATFORM_TRANSACTION.getCode()); + exchangeMoney.setStepStatus(GameExchangeStepStatus.FAILURE.getCode()); + gameExchangeMoneyService.updateGameExchangeMoney(exchangeMoney); + throw new ApiException(ErrorCode.Transfer_Out_Failure.getCode()); + } + } + return exchangeMoney.getId(); + } + + /** + * 获取会员信息 + * + * @param requestDTO 会员信息请求dto + * @return {@link MemberInfoResponseDTO } + */ + @Override + public MemberInfoResponseDTO getMemberInfo(MemberInfoRequestDTO requestDTO) { + GetMemberInfoRequest request = new GetMemberInfoRequest(); + request.setMerchantUserId(requestDTO.getAccounts()); + long timestamp = System.currentTimeMillis(); + String jsonBody = request.toJSON(); + String sign = getSign(jsonBody, + requestDTO.getAgentId(), + requestDTO.getAgentKey(), + timestamp + ); + GetMemberInfoResponse response = fbSportsClient.getMemberInfo( + request, + sign, + timestamp, + requestDTO.getAgentId() + ); + //判断是否获取成功 + if (this.isSuccess(response.getCode())) { + BigDecimal balance = new BigDecimal("0.00"); + + for (GetMemberInfoResponse.Wallet wallet : response.getData().getWallets()) { + balance = balance.add(wallet.getBalance()); + } + return MemberInfoResponseDTO.builder() + .status(GameMemberStatus.UNKNOWN.getCode()) + .balance(balance) + .account(requestDTO.getAccounts()) + .build(); + } else { + throw new ApiException(ErrorCode.Get_Member_Info_Failure.getCode()); + } + } + + + /** + * 获取交易id + * + * @param transactionIdRequestDTO 事务id请求dto + * @return {@link String } + */ + @Override + public String getTransactionId(TransactionIdRequestDTO transactionIdRequestDTO) { + return GamePlatforms.FBSports.getCode() + IdUtils.simpleUUID(); + } + + + /** + * 无重定向登录 + * + * @param requestDTO 游戏登录 + * @return {@link String } + */ + @Override + public String loginWithoutRedirect(GamesLogin requestDTO) { + GetTokenRequest request = new GetTokenRequest(); + request.setMerchantUserId(requestDTO.getAccount()); + request.setPlatForm(/*requestDTO.getPlatform()*/ "mobile"); // pc,h5, mobile , see enum: plat_form_enum + long timestamp = System.currentTimeMillis(); + String jsonBody = request.toJSON(); + String sign = getSign(jsonBody, + requestDTO.getAgentId(), + requestDTO.getAgentKey(), + timestamp + ); + + GetTokenResponse response = fbSportsClient.getToken( + request, + sign, + timestamp, + requestDTO.getAgentId() + ); + + if (this.isSuccess(response.getCode())) { + String token = response.getData().getToken(); + Integer userId = response.getData().getUserId(); + GetTokenResponse.ServerInfo serverInfo = response.getData().getServerInfo(); + String h5Address = serverInfo.getH5Address(); + if (StringUtils.isEmpty(h5Address)) { + throw new ApiException(ErrorCode.Get_Url_Failure.getCode()); + } + + return h5Address + + "/index.html#/" + + "?token=" + + token + + "&nickname=" + + userId + + "&apiSrc=" + + serverInfo.getApiServerAddress() + + "&pushSrc=" + + serverInfo.getPushServerAddress() + + "&virtualSrc=" + + serverInfo.getVirtualAddress() + + "&platformName=XK体育"; + } + + + /*GetUrlRequest request = new GetUrlRequest(); + long timestamp = System.currentTimeMillis(); + String jsonBody = request.toJSON(); + String sign = getSign(jsonBody, + requestDTO.getAgentId(), + requestDTO.getAgentKey(), + timestamp + ); + GetUrlResponse response = fbSportsClient.getUrl( + request, + sign, + timestamp, + requestDTO.getAgentId() + ); + //判断是否获取成功 + if (this.isSuccess(response.getCode())) { + List urlDTOS = new ArrayList<>(); + for (GetUrlResponse.UrlDTO urlDTO : response.getData()) { + if (urlDTO.getType() == 3) { // 3:h5 + urlDTOS.add(urlDTO); + } + } + if (urlDTOS.isEmpty()){ + throw new ApiException(ErrorCode.Get_Url_Failure.getCode()); + } + int randomIndex = new Random().nextInt(urlDTOS.size()); + GetUrlResponse.UrlDTO urlDTO = urlDTOS.get(randomIndex); + Collections.shuffle(urlDTO.getDomainList()); + return urlDTO.getDomainList().get(0).getDomain(); + }*/ + throw new ApiException(ErrorCode.Get_Url_Failure.getCode()); + } + + private static final Long GAME_ID = 11111L; + + /** + * 获取游戏列表 + * + * @param gamesBaseRequestDTO 游戏请求dto + * @return {@link String } + */ + @Transactional + @Override + public String getGameList(GamesBaseRequestDTO gamesBaseRequestDTO) { + + Platform platform = gamesBaseRequestDTO.getVendor(); + Game game = gameService.selectGameById(GAME_ID); + //不存在这个游戏 + if (ObjectUtils.isEmpty(game)) { + game = new Game(); + game.setId(/*IdUtil.getSnowflakeNextId()*/GAME_ID); + game.setSortNo(1); + //game.setPlatformId(gamePlatform.getId()); + game.setPlatformCode(platform.getPlatformCode()); + game.setPlatformType(PlatformType.SPORTS.getCode()); + game.setGameCode("1"); + game.setGameSourceType(String.valueOf(1)); + game.setGameName("FB体育"); + game.setCreateBy(Constants.SYSTEM); + NameInfo nameInfo = new NameInfo(); + nameInfo.setLang("zh-CN"); + nameInfo.setName("FB体育"); + game.setNameInfo(Collections.singletonList(nameInfo)); + gameService.insertGame(game); + } + /*GameName gameName = gameNameService.selectGameNameById(GAME_NAME_ID); + if (ObjectUtils.isEmpty(gameName)) { + gameNameService.insertGameName(GameName.builder() + .id(GAME_NAME_ID) + .gameId(game.getId()) + .gameName(game.getGameName()) + .langCode("zh-CN") + .createBy(Constants.SYSTEM) + .build()); + }*/ + + return CacheConstants.FB_Sports; + } + + /** + * 汇兑转移状态 + * + * @param requestDTO 兑换转账请求dto + * @return {@link Boolean } + */ + @Override + public ExchangeTransferStatusResponseDTO exchangeTransferStatus(ExchangeTransferStatusRequestDTO requestDTO) { + + GameExchangeMoney gameExchangeMoney = gameExchangeMoneyService.selectGameExchangeMoneyById(requestDTO.getGameExchangeMoneyId()); + if (null == gameExchangeMoney) { + throw new ApiException(ErrorCode.Transfer_Not_Exist.getCode()); + } + Integer status = StatusType.IN_PROGRESS.getValue(); + + if (!Objects.equals(gameExchangeMoney.getStatus(), StatusType.SUCCESS.getValue())) { + TransferDetailRequest request = new TransferDetailRequest(); + request.setMerchantUserId(requestDTO.getAccount()); + request.setTransferType(Objects.equals(gameExchangeMoney.getExchangeType(), TransferType.GAMES.getCode()) + ? "IN" : "OUT"); + long timestamp = System.currentTimeMillis(); + String jsonBody = request.toJSON(); + String sign = getSign(jsonBody, + requestDTO.getAgentId(), + requestDTO.getAgentKey(), + timestamp + ); + TransferDetailResponse response = fbSportsClient.transferDetail( + request, + sign, + timestamp, + requestDTO.getAgentId() + ); + if (this.isSuccess(response.getCode())) { + status = StatusType.SUCCESS.getValue(); + } else { + status = StatusType.FAILURE.getValue(); + } + } + + return ExchangeTransferStatusResponseDTO.builder() + .statusType(status) + .balance(gameExchangeMoney.getBalance()) + .coinBefore(gameExchangeMoney.getCoinBefore()) + .coinAfter(gameExchangeMoney.getCoinAfter()) + .build(); + } + + + /** + * 按时间获取投注记录 + * + * @param requestDTO 按时间dto投注记录 + * @return {@link Boolean } + */ + @Override + public Boolean getBetRecordByTime(BetRecordByTimeDTO requestDTO) { + Long lend = requestDTO.getEndTime(); + Long lstart = requestDTO.getStartTime(); + //betRecordByTimeDTO.setStartTime(lstart); + //betRecordByTimeDTO.setEndTime(lend); + + OrderFilesRequest request = new OrderFilesRequest(); + request.setStartTime(lstart); + request.setEndTime(lend); + long timestamp = System.currentTimeMillis(); + String jsonBody = request.toJSON(); + String sign = getSign(jsonBody, + requestDTO.getAgentId(), + requestDTO.getAgentKey(), + timestamp + ); + OrderFilesResponse orderFilesResponse = fbSportsClient.orderFiles( + request, + sign, + timestamp, + requestDTO.getAgentId() + ); + if (this.isSuccess(orderFilesResponse.getCode())) { + for (OrderFilesResponse.FileId fileId : orderFilesResponse.getData()) { + try { + getOrderData(fileId.getFileId(), requestDTO); + } catch (Exception e) { + log.error("获取订单数据失败,fileId:{},agentId:{}", fileId, requestDTO.getAgentId()); + } + } + return true; + } + log.error("获取订单文件失败,agentId:{}", requestDTO.getAgentId()); + return false; + } + + void getOrderData(Long fileId, BetRecordByTimeDTO requestDTO) { + OrderInfoRequest request = new OrderInfoRequest(); + request.setFileId(fileId); + long timestamp = System.currentTimeMillis(); + String jsonBody = request.toJSON(); + String sign = getSign(jsonBody, + requestDTO.getAgentId(), + requestDTO.getAgentKey(), + timestamp + ); + + OrderInfoResponse orderInfoResponse = fbSportsClient.getOrderJsonData( + request, + sign, + timestamp, + requestDTO.getAgentId() + ); + if (!this.isSuccess(orderInfoResponse.getCode())) { + return; + } + List settledOrderList = new ArrayList<>(); + for (OrderInfoResponse.OrderDTO orderDTO : orderInfoResponse.getData()) { +// 0 Created 未确认 +// 1 Confirming 确认中 +// 2 Rejected 已拒单 +// 3 Canceled 已取消 +// 4 Confirmed 已接单 +// 5 Settled 已结算 + if (!orderDTO.getOrderStatus().equals(5)) { // 已结算 + continue; + } + settledOrderList.add(orderDTO); + } + this.batchInsert(settledOrderList, requestDTO); + } + + /** + * 按历史时间获取投注记录 + * + * @param requestDTO 按时间dto投注记录 + * @return {@link Boolean } + */ + @Override + public Boolean getBetRecordByHistoryTime(BetRecordByTimeDTO requestDTO) { + Long lend = requestDTO.getEndTime(); + Long lstart = requestDTO.getStartTime(); + //betRecordByTimeDTO.setStartTime(lstart); + //betRecordByTimeDTO.setEndTime(lend); + + OrderFilesRequest request = new OrderFilesRequest(); + request.setStartTime(lstart); + request.setEndTime(lend); + long timestamp = System.currentTimeMillis(); + String jsonBody = request.toJSON(); + String sign = getSign(jsonBody, + requestDTO.getAgentId(), + requestDTO.getAgentKey(), + timestamp + ); + OrderFilesResponse orderFilesResponse = fbSportsClient.orderFiles( + request, + sign, + timestamp, + requestDTO.getAgentId() + ); + if (this.isSuccess(orderFilesResponse.getCode())) { + for (OrderFilesResponse.FileId fileId : orderFilesResponse.getData()) { + try { + getOrderData(fileId.getFileId(), requestDTO); + } catch (Exception e) { + log.error("获取订单数据失败,fileId:{},agentId:{}", fileId, requestDTO.getAgentId()); + } + } + return true; + } + log.error("获取订单文件失败,agentId:{}", requestDTO.getAgentId()); + return false; + } + + + /** + * 赠送免费局数 + * + * @param createFreeSpinRequest 创建自由旋转请求 + * @return {@link Boolean } + */ + @Override + public Boolean createFreeSpin(CreateFreeSpinRequestDTO createFreeSpinRequest) { + throw new BaseException("暂不支持免费局数"); + } + + /** + * 获取游戏详细信息 + * + * @param getGameDetailRequestDTO 获取游戏详细信息请求dto + * @return {@link GetGameDetailResponseDTO } + */ + @Override + public GetGameDetailResponseDTO getGameDetail(GetGameDetailRequestDTO getGameDetailRequestDTO) { + throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); + } + + /** + * 强制会员从游戏注销 + * + * @param kickMemberRequestDTO 踢会员请求dto + * @return {@link Boolean } + */ + @Override + public Boolean kickMember(KickMemberRequestDTO kickMemberRequestDTO) { + + return Boolean.FALSE; + } + + /** + * 踢成员全部 + * + * @param kickMemberAllDTO 踢成员全部dto + * @return {@link Boolean } + */ + @Override + public Boolean kickMemberAll(KickMemberAllDTO kickMemberAllDTO) { + throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); + } + + /** + * 免费游戏玩家使用的纪录 + * + * @param getFreeSpinDashflowRequestDTO 获取自由旋转dashflow请求dto + * @return {@link List }<{@link GameFreeRecord }> + */ + @Override + public List getFreeSpinDashflow(GetFreeSpinDashflowRequestDTO getFreeSpinDashflowRequestDTO) { + throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); + } + + /** + * 取消赠送免费局数 + * + * @param cancelFreeSpinRequestDTO 取消免费旋转请求 + * @return {@link Boolean } + */ + @Override + public Boolean cancelFreeSpin(CancelFreeSpinRequestDTO cancelFreeSpinRequestDTO) { + throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); + } + + /** + * 游戏演示登录 + * + * @param gameDemoLoginRequestDTO 游戏演示登录请求dto + * @return {@link GameDemoLoginResponseDTO } + */ + @Override + public GameDemoLoginResponseDTO gameDemoLogin(GameDemoLoginRequestDTO gameDemoLoginRequestDTO) { + throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); + } + + /** + * 批量插入 + * + * @param settledOrderList 投注记录 + */ + private void batchInsert(List settledOrderList, BetRecordByTimeDTO betRecordByTimeDTO) { + List gameBettingDetails = new ArrayList<>(); + List wagersIds = new ArrayList<>(); + //数据组装 + List dataList = settledOrderList; + if (CollectionUtils.isEmpty(dataList)) { + return; + } + + //数据转化 + for (OrderInfoResponse.OrderDTO dataBean : dataList) { + GameBettingDetails bettingDetails = this.dataBuild(GamesDataBuildDTO.builder() + .platform(betRecordByTimeDTO.getVendor()) + .data(dataBean).build()); + if (!ObjectUtils.isEmpty(bettingDetails)) { + bettingDetails.setId(IdUtil.getSnowflakeNextId()); + gameBettingDetails.add(bettingDetails); + } + wagersIds.add(dataBean.getId()); + } + if (CollectionUtils.isEmpty(gameBettingDetails)) { + return; + } + //查询重复数据id + List removeWagersIds = gameBettingDetailsService + .selectGameBettingDetailsByWagersId(wagersIds, GamePlatforms.FBSports.getCode()); + //用steam流清除list中与wagersIds集合相同的数据 + gameBettingDetails = gameBettingDetails.stream() + .filter(detail -> !removeWagersIds.contains(detail.getWagersId())) + .collect(Collectors.toList()); + if (!CollectionUtils.isEmpty(gameBettingDetails)) { + gameBettingDetailsService.batchInsert(gameBettingDetails); + } + } + + /** + * 数据构建 + * + * @param gamesDataBuildDTO 数据 + * @return {@link GameBettingDetails } + */ + @Override + public GameBettingDetails dataBuild(GamesDataBuildDTO gamesDataBuildDTO) { + + //转化类 + OrderInfoResponse.OrderDTO dataBean = (OrderInfoResponse.OrderDTO) gamesDataBuildDTO.getData(); + Member member = memberService.selectMemberByGameAccount(dataBean.getMerchantUserId()); + if (ObjectUtils.isEmpty(member)) { + return null; + } + List gameList = redisCache.getCacheList(CacheConstants.FB_Sports); + Game game = gameList.get(0); + BigDecimal originPayoffAmount = new BigDecimal(dataBean.getSettleAmount()); + BigDecimal betAmount = new BigDecimal(dataBean.getStakeAmount()); + + int compareResult = originPayoffAmount.compareTo(betAmount); + long payoffTime = TimestampFromString.to(dataBean.getSettleTime()); + long createTime = TimestampFromString.to(dataBean.getCreateTime()); + Platform platform = gamesDataBuildDTO.getPlatform(); + String systemCurrency = platform.getOurCurrency(dataBean.getCurrency().toString()); + //数据构造 + GameBettingDetails gameBettingDetails = GameBettingDetails.builder() + .tenantKey(member.getTenantKey()) + //保存我们的币种id + .currencyCode(systemCurrency) + .memberId(member.getId()) + .gameCode(game.getGameCode()) + .gameType(8) // 体育 + .platformCode(GamePlatforms.FBSports.getCode()) + .gameId(game.getGameId()) + .gameName(game.getGameName()) + .gameStatus(compareResult > 0 ? GameStatus.WIN.getCode() : compareResult < 0 ? GameStatus.FAIL.getCode() : GameStatus.FLAT.getCode()) + .gameStatusType(1) // 一般下注 + .gameCurrencyCode(dataBean.getCurrency().toString()) + .account(dataBean.getMerchantUserId()) + .wagersId(dataBean.getId()) + .wagersTime(createTime) + .betAmount(betAmount) + .payoffTime(payoffTime) + .payoffAmount(originPayoffAmount.abs()) + .settlementTime(payoffTime) + .turnover(betAmount) + .orderNo(dataBean.getId()) + .settlementStatus(SettlementStatusEnum.COMPLETED.getCode()) + .build(); + gameBettingDetails.setCreateBy(Constants.SYSTEM); + gameBettingDetails.setCreateTime(DateUtils.getNowDate()); + return gameBettingDetails; + } +} diff --git a/ff-game/src/main/java/com/ff/game/api/fc/address/MyFCAddressSource.java b/ff-game/src/main/java/com/ff/game/api/fc/address/MyFCAddressSource.java index e67a7f0..529c7c9 100644 --- a/ff-game/src/main/java/com/ff/game/api/fc/address/MyFCAddressSource.java +++ b/ff-game/src/main/java/com/ff/game/api/fc/address/MyFCAddressSource.java @@ -3,8 +3,8 @@ package com.ff.game.api.fc.address; import com.dtflys.forest.callback.AddressSource; import com.dtflys.forest.http.ForestAddress; import com.dtflys.forest.http.ForestRequest; -import com.ff.base.constant.Constants; -import com.ff.base.system.service.ISysConfigService; +import com.ff.base.enums.GamePlatforms; +import com.ff.game.service.IPlatformService; import org.springframework.stereotype.Component; import javax.annotation.Resource; @@ -13,12 +13,17 @@ import javax.annotation.Resource; public class MyFCAddressSource implements AddressSource { @Resource - private ISysConfigService configService; + private IPlatformService platformService; @Override public ForestAddress getAddress(ForestRequest request) { - String apiBaseUrl = configService.selectConfigByKey(Constants.FC_API_BASE_URL); - return new ForestAddress("https",apiBaseUrl, 443,""); + String apiBaseUrl = platformService.get(GamePlatforms.FC.getCode()) + .getUrlInfo().getUrl(); + String https = platformService.get(GamePlatforms.FC.getCode()) + .getUrlInfo().getHttps(); + String host = platformService.get(GamePlatforms.FC.getCode()) + .getUrlInfo().getHost(); + return new ForestAddress(https, apiBaseUrl, Integer.valueOf(host), ""); } } diff --git a/ff-game/src/main/java/com/ff/game/api/fc/client/FCClient.java b/ff-game/src/main/java/com/ff/game/api/fc/client/FCClient.java index cdb3e12..5c31ed9 100644 --- a/ff-game/src/main/java/com/ff/game/api/fc/client/FCClient.java +++ b/ff-game/src/main/java/com/ff/game/api/fc/client/FCClient.java @@ -89,6 +89,11 @@ public interface FCClient { ApiCFBalanceTransferResponseDTO exchangeTransferByAgentId(@JSONBody Map parameters); + @Post(url = "/GetSingleBill") + ApiCFBalanceTransferStatusResponseDTO exchangeTransferStatus(@JSONBody Map parameters); + + + /** * 按时间获取投注记录 * diff --git a/ff-game/src/main/java/com/ff/game/api/fc/dto/ApiCFBalanceTransferStatusResponseDTO.java b/ff-game/src/main/java/com/ff/game/api/fc/dto/ApiCFBalanceTransferStatusResponseDTO.java new file mode 100644 index 0000000..ecae0ae --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/fc/dto/ApiCFBalanceTransferStatusResponseDTO.java @@ -0,0 +1,96 @@ +package com.ff.game.api.fc.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.math.BigDecimal; + +/** + * api cfbalance传输状态响应dto + * + * @author shi + * @date 2025/04/08 + */ +@Data +public class ApiCFBalanceTransferStatusResponseDTO { + + /** + * 请求结果代码 + * 0 表示成功 + */ + @JsonProperty("Result") + private int result; + + /** + * 银行 ID + */ + @JsonProperty("bankID") + private int bankId; + + /** + * 交易 ID + */ + @JsonProperty("trsID") + private String trsId; + + /** + * 操作类型(如存款、取款等) + */ + @JsonProperty("action") + private String action; + + /** + * 交易的点数 + */ + @JsonProperty("points") + private BigDecimal points; + + /** + * 用户账号 + */ + @JsonProperty("account") + private String account; + + /** + * 交易状态 + * 1: 成功,其他值表示失败 + */ + @JsonProperty("status") + private int status; + + /** + * 交易前点数 + */ + @JsonProperty("beforepoints") + private BigDecimal beforePoints; + + /** + * 交易后点数 + */ + @JsonProperty("afterpoints") + private BigDecimal afterPoints; + + /** + * 创建日期 + */ + @JsonProperty("cdate") + private String createDate; + + /** + * 变更日期 + */ + @JsonProperty("bdate") + private String updateDate; + + /** + * 事件 ID + */ + @JsonProperty("eventID") + private String eventId; + + /** + * 货币类型 + */ + @JsonProperty("currency") + private String currency; +} diff --git a/ff-game/src/main/java/com/ff/game/api/fc/dto/ApiFCGameListResponseDTO.java b/ff-game/src/main/java/com/ff/game/api/fc/dto/ApiFCGameListResponseDTO.java index 784fd18..879d51b 100644 --- a/ff-game/src/main/java/com/ff/game/api/fc/dto/ApiFCGameListResponseDTO.java +++ b/ff-game/src/main/java/com/ff/game/api/fc/dto/ApiFCGameListResponseDTO.java @@ -37,7 +37,7 @@ public class ApiFCGameListResponseDTO { /** * 系统游戏id */ - private Long systemGameId; + private String systemGameId; /** * 游戏id */ diff --git a/ff-game/src/main/java/com/ff/game/api/fc/impl/GamesFCServiceImpl.java b/ff-game/src/main/java/com/ff/game/api/fc/impl/GamesFCServiceImpl.java index 41b96ba..3e39e79 100644 --- a/ff-game/src/main/java/com/ff/game/api/fc/impl/GamesFCServiceImpl.java +++ b/ff-game/src/main/java/com/ff/game/api/fc/impl/GamesFCServiceImpl.java @@ -9,19 +9,20 @@ import com.ff.base.core.redis.RedisCache; import com.ff.base.enums.*; import com.ff.base.exception.base.ApiException; import com.ff.base.exception.base.BaseException; -import com.ff.base.system.service.ISysConfigService; import com.ff.base.utils.DateUtils; +import com.ff.base.utils.StringUtils; import com.ff.base.utils.sign.Md5Utils; import com.ff.config.KeyConfig; import com.ff.game.api.IGamesService; -import com.ff.game.api.fc.dto.*; +import com.ff.game.api.dg.dto.DGTransactionResponseDTO; import com.ff.game.api.fc.client.FCClient; -import com.ff.game.api.ng.client.NGClient; +import com.ff.game.api.fc.dto.*; import com.ff.game.api.request.*; import com.ff.game.domain.*; -import com.ff.game.dto.GameBettingDetailsDTO; -import com.ff.game.dto.GameSecretKeyCurrencyDTO; -import com.ff.game.service.*; +import com.ff.game.service.IGameBettingDetailsService; +import com.ff.game.service.IGameExchangeMoneyService; +import com.ff.game.service.IGameService; +import com.ff.game.service.IPlatformService; import com.ff.member.domain.Member; import com.ff.member.service.IMemberService; import lombok.extern.slf4j.Slf4j; @@ -54,21 +55,12 @@ import java.util.stream.Collectors; @Slf4j public class GamesFCServiceImpl implements IGamesService { - - @Resource - private ISysConfigService configService; - @Resource private RedisCache redisCache; @Resource private IGameExchangeMoneyService gameExchangeMoneyService; - - @Resource - private IGamePlatformService gamePlatformService; - - @Resource private IGameService gameService; @@ -76,37 +68,22 @@ public class GamesFCServiceImpl implements IGamesService { @Resource private IMemberService memberService; - @Resource - private IGameFreeRecordService gameFreeRecordService; - - @Resource - private IGameSecretKeyService gameSecretKeyService; - @Resource private FCClient FCClient; - @Resource private KeyConfig keyConfig; @Resource private IGameBettingDetailsService gameBettingDetailsService; - @Resource - private IGameSecretKeyCurrencyService gameSecretKeyCurrencyService; - - @Resource - private IGameNameService gameNameService; - - - @Resource - private IGameSecretKeyLangService gameSecretKeyLangService; - - @Autowired @Qualifier("threadPoolTaskExecutor") private ThreadPoolTaskExecutor threadPoolTaskExecutor; + @Autowired + private IPlatformService platformService; + /** * 获得就是成功 * @@ -276,63 +253,44 @@ public class GamesFCServiceImpl implements IGamesService { for (String gameTypeKey : gameList.getGetGameIconList().keySet()) { Map integerGameDetailsMap = gameList.getGetGameIconList().get(gameTypeKey); - GamePlatform gamePlatform = GamePlatform.builder() - .platformType(FCGameType.findSystemByCode(gameTypeKey)) - .platformCode(GamePlatforms.FC.getCode()) - .build(); - List gamePlatforms = gamePlatformService.selectGamePlatformList(gamePlatform); - //没有此平台就新增一个平台 - if (CollectionUtils.isEmpty(gamePlatforms)) { - gamePlatform.setPlatformName(GamePlatforms.FC.getInfo() + FCGameType.findInfoByCode(gameTypeKey)); - gamePlatform.setSortNo(gamePlatformService.selectMaxSortNo() + 1); - gamePlatform.setCreateBy(Constants.SYSTEM); - gamePlatformService.insertGamePlatform(gamePlatform); - } else { - gamePlatform = gamePlatforms.get(0); - } //新增游戏 for (String gameIdKey : integerGameDetailsMap.keySet()) { ApiFCGameListResponseDTO.GameDetails gameDetails = integerGameDetailsMap.get(gameIdKey); Game game = Game.builder() - .platformId(gamePlatform.getId()) + .platformCode(GamePlatforms.FC.getCode()) .gameCode(gameIdKey) .build(); List games = gameService.selectGameList(game); + int platformType = FCGameType.findSystemByCode(gameTypeKey); //不存在这个游戏 if (CollectionUtils.isEmpty(games)) { game.setGameSourceType(String.valueOf(PlatformType.ELECTRONIC.getCode())); game.setFreespin(Boolean.FALSE); game.setDemoStatus(Boolean.TRUE); - game.setSortNo(gameService.selectMaxSortNoByPlatformId(gamePlatform.getId()) + 1); + + game.setSortNo(gameService.selectMaxSortNo(platformType, GamePlatforms.FC.getCode()) + 1); game.setGameName(gameDetails.getGameNameOfChinese()); game.setCreateBy(Constants.SYSTEM); + game.setPlatformCode(GamePlatforms.FC.getCode()); + game.setPlatformType(platformType); + List nameInfos = new ArrayList<>(); + nameInfos.add(NameInfo.builder().lang("zh-CN").name(gameDetails.getGameNameOfChinese()).build()); + nameInfos.add(NameInfo.builder().lang("en-US").name(gameDetails.getGameNameOfEnglish()).build()); + game.setNameInfo(nameInfos); + game.setGameId(StringUtils.addSuffix(GamePlatforms.FC.getCode(), gameIdKey)); gameService.insertGame(game); } else { game = games.get(0); - } - gameDetails.setSystemGameId(game.getId()); + List nameInfos = new ArrayList<>(); + nameInfos.add(NameInfo.builder().lang("zh-CN").name(gameDetails.getGameNameOfChinese()).build()); + nameInfos.add(NameInfo.builder().lang("en-US").name(gameDetails.getGameNameOfEnglish()).build()); + game.setNameInfo(nameInfos); + gameService.updateGame(game); - List gameNames = gameNameService.selectGameNameList(GameName.builder().gameId(game.getId()).gameName(gameDetails.getGameNameOfChinese()).build()); - if (CollectionUtils.isEmpty(gameNames)) { - gameNameService.insertGameName(GameName.builder() - .gameId(game.getId()) - .gameName(gameDetails.getGameNameOfChinese()) - .langCode("zh-CN") - .createBy(Constants.SYSTEM) - .build()); } - gameNames = gameNameService.selectGameNameList(GameName.builder().gameId(game.getId()).gameName(gameDetails.getGameNameOfEnglish()).build()); - if (CollectionUtils.isEmpty(gameNames)) { - gameNameService.insertGameName(GameName.builder() - .gameId(game.getId()) - .gameName(gameDetails.getGameNameOfEnglish()) - .langCode("en-US") - .createBy(Constants.SYSTEM) - .build()); - } - + gameDetails.setSystemGameId(game.getGameId()); gameDetails.setGameId(gameIdKey); gameDetailsList.add(gameDetails); } @@ -359,36 +317,9 @@ public class GamesFCServiceImpl implements IGamesService { public Long exchangeTransferByAgentId(ExchangeTransferMoneyRequestDTO exchangeTransferMoneyRequestDTO) { log.info("GamesFCServiceImpl [exchangeTransferByAgentId] 请求参数 {}", exchangeTransferMoneyRequestDTO); - GameSecretKeyCurrency currencyDTO = gameSecretKeyCurrencyService.findByGameSecretKeyCurrencyDTO(GameSecretKeyCurrencyDTO.builder() - .platformCode(GamePlatforms.FC.getCode()) - .code(exchangeTransferMoneyRequestDTO.getAgentId()) - .currency(exchangeTransferMoneyRequestDTO.getCurrency()) - .build()); - Member member = memberService.selectMemberByGameAccount(exchangeTransferMoneyRequestDTO.getAccount()); - String transactionId = gameExchangeMoneyService.getTransactionId(GamePlatforms.FC.getCode(), 30); - List gameExchangeMonies = gameExchangeMoneyService.selectGameExchangeMoneyList( - GameExchangeMoney.builder() - .tenantKey(exchangeTransferMoneyRequestDTO.getTenantKey()) - .orderId(exchangeTransferMoneyRequestDTO.getOrderId()) - .build() - ); - Assert.isTrue(CollectionUtils.isEmpty(gameExchangeMonies), "订单号重复"); + GameExchangeMoney exchangeMoney = gameExchangeMoneyService.selectGameExchangeMoneyById(exchangeTransferMoneyRequestDTO.getGameExchangeId()); - //获取下一个自增id - GameExchangeMoney exchangeMoney = GameExchangeMoney - .builder() - .tenantKey(exchangeTransferMoneyRequestDTO.getTenantKey()) - .orderId(exchangeTransferMoneyRequestDTO.getOrderId()) - .quota(exchangeTransferMoneyRequestDTO.getQuota()) - .balance(exchangeTransferMoneyRequestDTO.getAmount()) - .exchangeType(exchangeTransferMoneyRequestDTO.getTransferType()) - .currencyCode(currencyDTO.getSystemCurrency()) - .memberId(member.getId()) - .transactionId(transactionId) - .platformCode(GamePlatforms.FC.getCode()) - .build(); - exchangeMoney.setCreateBy(Constants.SYSTEM); //获取余额 String type = TransferType.ALL.getCode().equals(exchangeTransferMoneyRequestDTO.getTransferType()) ? FCTransferType.TRANSFER_OUT_ALL.getValue() : FCTransferType.TRANSFER_OUT.getValue(); @@ -399,10 +330,10 @@ public class GamesFCServiceImpl implements IGamesService { //获取当前游戏币 MemberInfoRequestDTO gamesBaseRequestDTO = MemberInfoRequestDTO.builder() - .accounts(member.getGameAccount()) + .accounts(exchangeTransferMoneyRequestDTO.getAccount()) .agentId(exchangeTransferMoneyRequestDTO.getAgentId()) .agentKey(exchangeTransferMoneyRequestDTO.getAgentKey()) - .currency(currencyDTO.getCurrency()) + .currency(exchangeTransferMoneyRequestDTO.getCurrency()) .build(); MemberInfoResponseDTO memberInfo = this.getMemberInfo(gamesBaseRequestDTO); //判断是不是转出 @@ -413,7 +344,7 @@ public class GamesFCServiceImpl implements IGamesService { Map paramsMap = new HashMap<>(); paramsMap.put("MemberAccount", exchangeTransferMoneyRequestDTO.getAccount()); - paramsMap.put("TrsID", transactionId); + paramsMap.put("TrsID", exchangeTransferMoneyRequestDTO.getTransactionId()); paramsMap.put("AllOut", type); paramsMap.put("Points", amount); paramsMap.putAll(getKeyMap(paramsMap, gamesBaseRequestDTO.getAgentKey(), gamesBaseRequestDTO.getCurrency(), gamesBaseRequestDTO.getAgentId())); @@ -427,25 +358,60 @@ public class GamesFCServiceImpl implements IGamesService { exchangeMoney.setCoinAfter(transferResponseDTO.getAfterPoint()); exchangeMoney.setCurrencyBefore(exchangeMoney.getCoinBefore()); exchangeMoney.setCurrencyAfter(exchangeMoney.getCoinAfter()); - exchangeMoney.setStatus(StatusType.SUCCESS.getValue()); - - gameExchangeMoneyService.insertGameExchangeMoney(exchangeMoney); + exchangeMoney.setStep(GameExchangeStep.PLATFORM_TRANSACTION.getCode()); + exchangeMoney.setStepStatus(GameExchangeStepStatus.SUCCESS.getCode()); + gameExchangeMoneyService.updateGameExchangeMoney(exchangeMoney); } else { + exchangeMoney.setStep(GameExchangeStep.PLATFORM_TRANSACTION.getCode()); + exchangeMoney.setStepStatus(GameExchangeStepStatus.FAILURE.getCode()); + gameExchangeMoneyService.updateGameExchangeMoney(exchangeMoney); log.error("GamesFCServiceImpl [exchangeTransferByAgentId] 金额转移失败,错误代码{}", transferResponseDTO.getResult()); throw new ApiException(ErrorCode.BALANCE_TRANSFER_FAILED.getCode()); } return exchangeMoney.getId(); } + + /** + * 获取交易id + * + * @param transactionIdRequestDTO 事务id请求dto + * @return {@link String } + */ + @Override + public String getTransactionId(TransactionIdRequestDTO transactionIdRequestDTO) { + return gameExchangeMoneyService.getTransactionId(GamePlatforms.FC.getInfo(), 30); + } + + /** * 汇兑转移状态 * * @param exchangeTransferMoneyRequestDTO 兑换转账请求dto - * @return {@link Boolean } + * @return {@link ExchangeTransferStatusResponseDTO } */ @Override - public Boolean exchangeTransferStatus(ExchangeTransferStatusRequestDTO exchangeTransferMoneyRequestDTO) { - throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); + public ExchangeTransferStatusResponseDTO exchangeTransferStatus(ExchangeTransferStatusRequestDTO exchangeTransferMoneyRequestDTO) { + log.info("GamesDGServiceImpl [exchangeTransferStatus] 请求参数 {}", exchangeTransferMoneyRequestDTO); + + Map paramsMap = new LinkedHashMap<>(); + paramsMap.put("TrsID", exchangeTransferMoneyRequestDTO.getOrderId()); + paramsMap.putAll(getKeyMap(paramsMap, exchangeTransferMoneyRequestDTO.getAgentKey(), exchangeTransferMoneyRequestDTO.getCurrency(), exchangeTransferMoneyRequestDTO.getAgentId())); + + ApiCFBalanceTransferStatusResponseDTO apiCFBalanceTransferStatusResponseDTO = FCClient.exchangeTransferStatus(paramsMap); + Integer status = StatusType.IN_PROGRESS.getValue(); + if (this.getIsSuccess(apiCFBalanceTransferStatusResponseDTO.getResult())) { + status = StatusType.SUCCESS.getValue(); + } else { + status = StatusType.FAILURE.getValue(); + } + + return ExchangeTransferStatusResponseDTO.builder() + .statusType(status) + .balance(apiCFBalanceTransferStatusResponseDTO.getPoints()) + .coinBefore(apiCFBalanceTransferStatusResponseDTO.getBeforePoints()) + .coinAfter(apiCFBalanceTransferStatusResponseDTO.getAfterPoints()) + .build(); } @@ -460,27 +426,27 @@ public class GamesFCServiceImpl implements IGamesService { public Boolean getBetRecordByTime(BetRecordByTimeDTO betRecordByTimeDTO) { - List gameSecretKeyCurrencies = gameSecretKeyCurrencyService.findByGameSecretKeyCurrencyDTOList(GameSecretKeyCurrencyDTO.builder() - .platformCode(GamePlatforms.FC.getCode()) - .build()); + Platform platform = betRecordByTimeDTO.getVendor(); + String startTime = DateUtils.convertTimeZone(betRecordByTimeDTO.getStartTime(), "America/New_York", DateUtils.YYYY_MM_DD_HH_MM_SS); + String endTime = DateUtils.convertTimeZone(betRecordByTimeDTO.getEndTime(), "America/New_York", DateUtils.YYYY_MM_DD_HH_MM_SS); + Map paramsMap = new HashMap<>(); + paramsMap.put("StartDate", startTime); + paramsMap.put("EndDate", endTime); + KeyInfo keyInfo = betRecordByTimeDTO.getKeyInfo(); + String currency = keyInfo.getCurrency(); + String targetCurrency = platform.getCurrencyInfo().get(currency); + if (StringUtils.isEmpty(targetCurrency)) { + log.error("获取不到币种,platformCode:{},{}->{}", platform.getPlatformCode(), currency, targetCurrency); + return Boolean.FALSE; + } - for (GameSecretKeyCurrency gameSecretKeyCurrency : gameSecretKeyCurrencies) { - String startTime = DateUtils.convertTimeZone(betRecordByTimeDTO.getStartTime(), "America/New_York", DateUtils.YYYY_MM_DD_HH_MM_SS); - String endTime = DateUtils.convertTimeZone(betRecordByTimeDTO.getEndTime(), "America/New_York", DateUtils.YYYY_MM_DD_HH_MM_SS); - Map paramsMap = new HashMap<>(); - paramsMap.put("StartDate", startTime); - paramsMap.put("EndDate", endTime); - paramsMap.putAll(getKeyMap(paramsMap, betRecordByTimeDTO.getAgentKey(), gameSecretKeyCurrency.getCurrency(), betRecordByTimeDTO.getAgentId())); - - ApiFCBetRecordResponseDTO betRecordByTime = FCClient.getBetRecordByTime(paramsMap); - - if (this.getIsSuccess(betRecordByTime.getResult())) { - //数据组装 - this.batchInsert(betRecordByTime, gameSecretKeyCurrency.getSystemCurrency(), gameSecretKeyCurrency.getCurrency()); - - } + paramsMap.putAll(getKeyMap(paramsMap, betRecordByTimeDTO.getAgentKey(), keyInfo.getCurrency(), betRecordByTimeDTO.getAgentId())); + ApiFCBetRecordResponseDTO betRecordByTime = FCClient.getBetRecordByTime(paramsMap); + if (this.getIsSuccess(betRecordByTime.getResult())) { + //数据组装 + this.batchInsert(betRecordByTime, currency, targetCurrency); } return Boolean.TRUE; } @@ -493,15 +459,20 @@ public class GamesFCServiceImpl implements IGamesService { */ @Override public Boolean getBetRecordByHistoryTime(BetRecordByTimeDTO betRecordByTimeDTO) { - List gameSecretKeyCurrencies = gameSecretKeyCurrencyService.findByGameSecretKeyCurrencyDTOList(GameSecretKeyCurrencyDTO.builder() - .platformCode(GamePlatforms.FC.getCode()) - .build()); - for (GameSecretKeyCurrency gameSecretKeyCurrency : gameSecretKeyCurrencies) { + Platform platform = betRecordByTimeDTO.getVendor(); + for (KeyInfo keyInfo : platform.getKeyInfo()) { + + //必须两个小时之前的数据 long startTimeLong = DateUtils.addOrSubtractMinutes(betRecordByTimeDTO.getStartTime(), -120); long endTimeLong = DateUtils.addOrSubtractMinutes(betRecordByTimeDTO.getEndTime(), -120); - + String currency = keyInfo.getCurrency(); + String targetCurrency = platform.getCurrencyInfo().get(currency); + if (StringUtils.isEmpty(targetCurrency)) { + log.error("获取不到币种,platformCode:{},{}->{}", platform.getPlatformCode(), currency, targetCurrency); + continue; + } //查询一个小时内的数据一次最多15分钟 int timeWheel = 60; while (timeWheel > 0) { @@ -510,18 +481,16 @@ public class GamesFCServiceImpl implements IGamesService { Map paramsMap = new HashMap<>(); paramsMap.put("StartDate", startTime); paramsMap.put("EndDate", endTime); - paramsMap.putAll(getKeyMap(paramsMap, betRecordByTimeDTO.getAgentKey(), gameSecretKeyCurrency.getCurrency(), betRecordByTimeDTO.getAgentId())); + paramsMap.putAll(getKeyMap(paramsMap, betRecordByTimeDTO.getAgentKey(), targetCurrency, betRecordByTimeDTO.getAgentId())); ApiFCBetRecordResponseDTO betRecordByTime = FCClient.getBetRecordByHistoryTime(paramsMap); if (this.getIsSuccess(betRecordByTime.getResult())) { //数据组装 - this.batchInsert(betRecordByTime, gameSecretKeyCurrency.getSystemCurrency(), gameSecretKeyCurrency.getCurrency()); + this.batchInsert(betRecordByTime, currency, targetCurrency); } timeWheel -= 15; } - - } return Boolean.TRUE; } @@ -610,6 +579,17 @@ public class GamesFCServiceImpl implements IGamesService { throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); } + /** + * 游戏演示登录 + * + * @param gameDemoLoginRequestDTO 游戏演示登录请求dto + * @return {@link GameDemoLoginResponseDTO } + */ + @Override + public GameDemoLoginResponseDTO gameDemoLogin(GameDemoLoginRequestDTO gameDemoLoginRequestDTO) { + throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); + } + /** * 数据构建 @@ -683,7 +663,9 @@ public class GamesFCServiceImpl implements IGamesService { List wagersIds = new ArrayList<>(); //数据转化 for (ApiFCBetRecordResponseDTO.BetRecord bean : data.getRecords()) { - GameBettingDetails bettingDetails = this.dataBuild(GamesDataBuildDTO.builder().data(bean).currencyCode(currencyCode).systemCurrencyCode(systemCurrencyCode).build()); + GameBettingDetails bettingDetails = this.dataBuild(GamesDataBuildDTO.builder().data(bean) + .currencyCode(currencyCode) + .systemCurrencyCode(systemCurrencyCode).build()); if (!ObjectUtils.isEmpty(bettingDetails)) { bettingDetails.setId(IdUtil.getSnowflakeNextId()); gameBettingDetails.add(bettingDetails); @@ -692,7 +674,7 @@ public class GamesFCServiceImpl implements IGamesService { } if (!CollectionUtils.isEmpty(gameBettingDetails)) { //查询重复数据id - List removeWagersIds = gameBettingDetailsService.selectGameBettingDetailsByWagersId(wagersIds); + List removeWagersIds = gameBettingDetailsService.selectGameBettingDetailsByWagersId(wagersIds, GamePlatforms.FC.getInfo()); //用steam流清除list中与wagersIds集合相同的数据 gameBettingDetails = gameBettingDetails.stream() .filter(detail -> !removeWagersIds.contains(detail.getWagersId())) diff --git a/ff-game/src/main/java/com/ff/game/api/jili/address/MyJILIAddressSource.java b/ff-game/src/main/java/com/ff/game/api/jili/address/MyJILIAddressSource.java index d27b734..592bae2 100644 --- a/ff-game/src/main/java/com/ff/game/api/jili/address/MyJILIAddressSource.java +++ b/ff-game/src/main/java/com/ff/game/api/jili/address/MyJILIAddressSource.java @@ -3,13 +3,11 @@ package com.ff.game.api.jili.address; import com.dtflys.forest.callback.AddressSource; import com.dtflys.forest.http.ForestAddress; import com.dtflys.forest.http.ForestRequest; -import com.ff.base.constant.Constants; -import com.ff.base.system.service.ISysConfigService; -import org.springframework.beans.factory.annotation.Autowired; +import com.ff.base.enums.GamePlatforms; +import com.ff.game.service.IPlatformService; import org.springframework.stereotype.Component; import javax.annotation.Resource; -import java.util.Random; /** @@ -19,15 +17,15 @@ import java.util.Random; * @date 2025/02/10 */ @Component -public class MyJILIAddressSource implements AddressSource { +public class MyJILIAddressSource implements AddressSource { @Resource - private ISysConfigService configService; - + private IPlatformService platformService; @Override public ForestAddress getAddress(ForestRequest request) { - String apiBaseUrl = configService.selectConfigByKey(Constants.JILI_API_BASE_URL); - return new ForestAddress("https",apiBaseUrl, 443,"api1"); + String apiBaseUrl = platformService.get(GamePlatforms.JILI.getCode()) + .getUrlInfo().getUrl(); + return new ForestAddress("https", apiBaseUrl, 443, "api1"); } } \ No newline at end of file diff --git a/ff-game/src/main/java/com/ff/game/api/jili/client/JILIClient.java b/ff-game/src/main/java/com/ff/game/api/jili/client/JILIClient.java index bcc4bae..7f38bac 100644 --- a/ff-game/src/main/java/com/ff/game/api/jili/client/JILIClient.java +++ b/ff-game/src/main/java/com/ff/game/api/jili/client/JILIClient.java @@ -63,6 +63,22 @@ public interface JILIClient { ) JILIExchangeMoneyResponseDTO exchangeTransferByAgentId(@Var("parameters") String parameters,@Body("AgentId") String agentId); + /** + * 按交易id检查转账 + * + * @param parameters 范围 + * @param agentId 代理id + * @return {@link JILITransferStatusResponseDTO } + */ + @Post( + url = "/CheckTransferByTransactionId?${parameters}", + headers = { + "Content-type: application/x-www-form-urlencoded" + } + ) + JILITransferStatusResponseDTO checkTransferByTransactionId(@Var("parameters") String parameters,@Body("AgentId") String agentId); + + /** * 按时间获取投注记录 * diff --git a/ff-game/src/main/java/com/ff/game/api/jili/dto/JILIGamesDataDTO.java b/ff-game/src/main/java/com/ff/game/api/jili/dto/JILIGamesDataDTO.java index 55a35da..f653ae0 100644 --- a/ff-game/src/main/java/com/ff/game/api/jili/dto/JILIGamesDataDTO.java +++ b/ff-game/src/main/java/com/ff/game/api/jili/dto/JILIGamesDataDTO.java @@ -22,7 +22,7 @@ public class JILIGamesDataDTO { /** *自己系统游戏id */ - private Long systemGameId; + private String systemGameId; /** * 名称 diff --git a/ff-game/src/main/java/com/ff/game/api/jili/dto/JILITransferStatusResponseDTO.java b/ff-game/src/main/java/com/ff/game/api/jili/dto/JILITransferStatusResponseDTO.java new file mode 100644 index 0000000..ea53732 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/jili/dto/JILITransferStatusResponseDTO.java @@ -0,0 +1,78 @@ +package com.ff.game.api.jili.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.math.BigDecimal; + +/** + * jilitransfer状态响应数据 + * + * @author shi + * @date 2025/04/08 + */ +@Data +public class JILITransferStatusResponseDTO { + + + /** + * 错误代码,0 表示成功 + */ + @JsonProperty("ErrorCode") + private int errorCode; + + /** + * 错误或状态信息 + */ + @JsonProperty("Message") + private String message; + + /** + * 转账相关数据 + */ + @JsonProperty("Data") + private TransferData data; + + /** + * 转账详细数据结构 + */ + @Data + public static class TransferData { + + /** + * 用户账户名 + */ + @JsonProperty("Account") + private String account; + + /** + * 转账交易 ID + */ + @JsonProperty("TransactionId") + private String transactionId; + + /** + * 转账时间,格式为 ISO 8601,如:2023-03-13T01:13:59-04:00 + */ + @JsonProperty("TransferTime") + private String transferTime; + + /** + * 转账金额 + */ + @JsonProperty("Amount") + private BigDecimal amount; + + /** + * 转账状态,1 表示成功,其他值可表示失败等状态 + */ + @JsonProperty("Status") + private int status; + + /** + * 转账类型,例如 1 表示入账,2 表示出账(视接口定义而定) + */ + @JsonProperty("TransferType") + private int transferType; + } +} diff --git a/ff-game/src/main/java/com/ff/game/api/jili/service/impl/GamesJILIServiceImpl.java b/ff-game/src/main/java/com/ff/game/api/jili/service/impl/GamesJILIServiceImpl.java index 0b6924e..ed3cb96 100644 --- a/ff-game/src/main/java/com/ff/game/api/jili/service/impl/GamesJILIServiceImpl.java +++ b/ff-game/src/main/java/com/ff/game/api/jili/service/impl/GamesJILIServiceImpl.java @@ -15,12 +15,15 @@ import com.ff.base.utils.sign.Md5Utils; import com.ff.base.utils.uuid.IdUtils; import com.ff.config.KeyConfig; import com.ff.game.api.IGamesService; +import com.ff.game.api.fc.dto.ApiCFBalanceTransferStatusResponseDTO; import com.ff.game.api.jili.client.JILIClient; import com.ff.game.api.jili.dto.*; import com.ff.game.api.request.*; import com.ff.game.domain.*; -import com.ff.game.dto.GameSecretKeyCurrencyDTO; -import com.ff.game.service.*; +import com.ff.game.service.IGameBettingDetailsService; +import com.ff.game.service.IGameExchangeMoneyService; +import com.ff.game.service.IGameFreeRecordService; +import com.ff.game.service.IGameService; import com.ff.member.domain.Member; import com.ff.member.service.IMemberService; import lombok.extern.slf4j.Slf4j; @@ -58,10 +61,6 @@ public class GamesJILIServiceImpl implements IGamesService { private IGameExchangeMoneyService gameExchangeMoneyService; - @Resource - private IGamePlatformService gamePlatformService; - - @Resource private IGameService gameService; @@ -72,8 +71,6 @@ public class GamesJILIServiceImpl implements IGamesService { @Resource private IGameFreeRecordService gameFreeRecordService; - @Resource - private IGameSecretKeyService gameSecretKeyService; @Resource private JILIClient jiliClient; @@ -85,11 +82,6 @@ public class GamesJILIServiceImpl implements IGamesService { @Resource private IGameBettingDetailsService gameBettingDetailsService; - @Resource - private IGameSecretKeyCurrencyService gameSecretKeyCurrencyService; - - @Resource - private IGameNameService gameNameService; /** * 获得就是成功 * @@ -138,10 +130,10 @@ public class GamesJILIServiceImpl implements IGamesService { String key = this.getKey(createMemberRequestDTO); JILICreateMemberResponseDTO createMemberResponseDTO = jiliClient.createMember(query + "&Key=" + key); int errorCode = createMemberResponseDTO.getErrorCode(); - if (0 == errorCode){ + if (0 == errorCode) { return Boolean.TRUE; } - if (101 == errorCode){ + if (101 == errorCode) { throw new ApiException(ErrorCode.GAME_ACCOUNT_CREATION_FAILED.getCode()); } //判断是否获取成功 @@ -235,22 +227,10 @@ public class GamesJILIServiceImpl implements IGamesService { if (this.getIsSuccess(jiliGames.getErrorCode())) { for (JILIGamesDataDTO gamesDataDTO : jiliGames.getData()) { - GamePlatform gamePlatform = GamePlatform.builder() - .platformType(JILIGameType.findSystemByCode(gamesDataDTO.getGameCategoryId())) - .platformCode(GamePlatforms.JILI.getCode()) - .build(); - List gamePlatforms = gamePlatformService.selectGamePlatformList(gamePlatform); - //没有此平台就新增一个平台 - if (CollectionUtils.isEmpty(gamePlatforms)) { - gamePlatform.setPlatformName(GamePlatforms.JILI.getInfo() + JILIGameType.findInfoByCode(gamesDataDTO.getGameCategoryId())); - gamePlatform.setSortNo(gamePlatformService.selectMaxSortNo() + 1); - gamePlatform.setCreateBy(Constants.SYSTEM); - gamePlatformService.insertGamePlatform(gamePlatform); - } else { - gamePlatform = gamePlatforms.get(0); - } + Integer platformType = JILIGameType.findSystemByCode(gamesDataDTO.getGameCategoryId()); Game game = Game.builder() - .platformId(gamePlatform.getId()) + .platformCode(GamePlatforms.JILI.getCode()) + .platformType(platformType) .gameCode(String.valueOf(gamesDataDTO.getGameId())) .build(); List games = gameService.selectGameList(game); @@ -258,32 +238,27 @@ public class GamesJILIServiceImpl implements IGamesService { if (CollectionUtils.isEmpty(games)) { game.setGameSourceType(String.valueOf(gamesDataDTO.getGameCategoryId())); game.setFreespin(gamesDataDTO.isFreespin()); - game.setSortNo(gameService.selectMaxSortNoByPlatformId(gamePlatform.getId()) + 1); + game.setSortNo(gameService.selectMaxSortNo(platformType, GamePlatforms.JILI.getCode()) + 1); game.setGameName(gamesDataDTO.getName().getZhCN()); game.setCreateBy(Constants.SYSTEM); + game.setPlatformType(platformType); + game.setPlatformCode(GamePlatforms.JILI.getCode()); + game.setGameId(StringUtils.addSuffix(GamePlatforms.JILI.getCode(), gamesDataDTO.getGameId())); + List nameInfos = new ArrayList<>(); + nameInfos.add(new NameInfo(gamesDataDTO.getName().getZhCN(), "zh-CN")); + nameInfos.add(new NameInfo(gamesDataDTO.getName().getEnUS(), "en-US")); + game.setNameInfo(nameInfos); + gameService.insertGame(game); } else { game = games.get(0); + List nameInfos = new ArrayList<>(); + nameInfos.add(new NameInfo(gamesDataDTO.getName().getZhCN(), "zh-CN")); + nameInfos.add(new NameInfo(gamesDataDTO.getName().getEnUS(), "en-US")); + game.setNameInfo(nameInfos); + gameService.updateGame(game); } - gamesDataDTO.setSystemGameId(game.getId()); - - List gameNames = gameNameService.selectGameNameList(GameName.builder().gameId(game.getId()).gameName(game.getGameName()).build()); - if (CollectionUtils.isEmpty(gameNames)){ - gameNameService.insertGameName(GameName.builder() - .gameId(game.getId()) - .gameName(game.getGameName()) - .langCode("zh-CN") - .createBy(Constants.SYSTEM) - .build()); - - gameNameService.insertGameName(GameName.builder() - .gameId(game.getId()) - .gameName(gamesDataDTO.getName().getEnUS()) - .langCode("en-US") - .createBy(Constants.SYSTEM) - .build()); - } - + gamesDataDTO.setSystemGameId(game.getGameId()); } @@ -299,6 +274,17 @@ public class GamesJILIServiceImpl implements IGamesService { return CacheConstants.JILI_GAMES; } + /** + * 获取交易id + * + * @param transactionIdRequestDTO 事务id请求dto + * @return {@link String } + */ + @Override + public String getTransactionId(TransactionIdRequestDTO transactionIdRequestDTO) { + return GamePlatforms.JILI.getInfo() + IdUtils.simpleUUID(); + } + /** * 按代理id进行交换转账 * @@ -308,38 +294,14 @@ public class GamesJILIServiceImpl implements IGamesService { @Override @Transactional public Long exchangeTransferByAgentId(ExchangeTransferMoneyRequestDTO exchangeTransferMoneyRequestDTO) { - GameSecretKeyCurrencyDTO gameSecretKey = gameSecretKeyCurrencyService.findByGameSecretKeyCurrencyDTO(GameSecretKeyCurrencyDTO.builder() - .code(exchangeTransferMoneyRequestDTO.getAgentId()) - .currency(exchangeTransferMoneyRequestDTO.getCurrency()).build()); Member member = memberService.selectMemberByGameAccount(exchangeTransferMoneyRequestDTO.getAccount()); - String transactionId = GamePlatforms.JILI.getCode() + IdUtils.simpleUUID(); - - List gameExchangeMonies = gameExchangeMoneyService.selectGameExchangeMoneyList( - GameExchangeMoney.builder() - .tenantKey(exchangeTransferMoneyRequestDTO.getTenantKey()) - .orderId(exchangeTransferMoneyRequestDTO.getOrderId()) - .build() - ); - Assert.isTrue(CollectionUtils.isEmpty(gameExchangeMonies), "订单号重复"); + GameExchangeMoney exchangeMoney = gameExchangeMoneyService.selectGameExchangeMoneyById(exchangeTransferMoneyRequestDTO.getGameExchangeId()); + + + - //获取下一个自增id - GameExchangeMoney exchangeMoney = GameExchangeMoney - .builder() - .orderId(exchangeTransferMoneyRequestDTO.getOrderId()) - .tenantKey(exchangeTransferMoneyRequestDTO.getTenantKey()) - .quota(exchangeTransferMoneyRequestDTO.getQuota()) - .balance(exchangeTransferMoneyRequestDTO.getAmount()) - .exchangeType(exchangeTransferMoneyRequestDTO.getTransferType()) - .currencyCode(gameSecretKey.getSystemCurrency()) - .memberId(member.getId()) - .transactionId(transactionId) - .platformCode(GamePlatforms.JILI.getCode()) - .build(); - exchangeMoney.setCreateBy(Constants.SYSTEM); - //接口限制限制50字符 - exchangeMoney.setTransactionId(transactionId); String query = "Account=" + exchangeTransferMoneyRequestDTO.getAccount() + "&TransactionId=" + exchangeMoney.getTransactionId() + "&Amount=" + exchangeTransferMoneyRequestDTO.getAmount() @@ -366,10 +328,14 @@ public class GamesJILIServiceImpl implements IGamesService { exchangeMoney.setCoinAfter(exchangeMoneyResponseData.getCoinAfter()); exchangeMoney.setCurrencyBefore(exchangeMoneyResponseData.getCurrencyBefore()); exchangeMoney.setCurrencyAfter(exchangeMoneyResponseData.getCurrencyAfter()); - exchangeMoney.setStatus(exchangeMoneyResponseData.getStatus()); - gameExchangeMoneyService.insertGameExchangeMoney(exchangeMoney); + exchangeMoney.setStep(GameExchangeStep.PLATFORM_TRANSACTION.getCode()); + exchangeMoney.setStepStatus(GameExchangeStepStatus.SUCCESS.getCode()); + gameExchangeMoneyService.updateGameExchangeMoney(exchangeMoney); } else { + exchangeMoney.setStep(GameExchangeStep.PLATFORM_TRANSACTION.getCode()); + exchangeMoney.setStepStatus(GameExchangeStepStatus.FAILURE.getCode()); + gameExchangeMoneyService.updateGameExchangeMoney(exchangeMoney); throw new BaseException(exchangeMoneyResponse.getMessage()); } @@ -384,8 +350,32 @@ public class GamesJILIServiceImpl implements IGamesService { * @return {@link Boolean } */ @Override - public Boolean exchangeTransferStatus(ExchangeTransferStatusRequestDTO exchangeTransferMoneyRequestDTO) { - return Boolean.TRUE; + public ExchangeTransferStatusResponseDTO exchangeTransferStatus(ExchangeTransferStatusRequestDTO exchangeTransferMoneyRequestDTO) { + log.info("GamesDGServiceImpl [exchangeTransferStatus] 请求参数 {}", exchangeTransferMoneyRequestDTO); + + String query = "TransactionId=" + exchangeTransferMoneyRequestDTO.getOrderId() + + "&AgentId=" + exchangeTransferMoneyRequestDTO.getAgentId(); + exchangeTransferMoneyRequestDTO.setQuery(query); + + String key = this.getKey(exchangeTransferMoneyRequestDTO); + + JILITransferStatusResponseDTO jiliTransferStatusResponseDTO = jiliClient.checkTransferByTransactionId(query + "&Key=" + key, exchangeTransferMoneyRequestDTO.getAgentId()); + Integer status = StatusType.IN_PROGRESS.getValue(); + if (this.getIsSuccess(jiliTransferStatusResponseDTO.getErrorCode())) { + status = StatusType.SUCCESS.getValue(); + } else { + status = StatusType.FAILURE.getValue(); + } + JILITransferStatusResponseDTO.TransferData data = jiliTransferStatusResponseDTO.getData(); + ExchangeTransferStatusResponseDTO statusResponseDTO = ExchangeTransferStatusResponseDTO.builder() + .statusType(status) + .build(); + if (!ObjectUtils.isEmpty(data)) { + + statusResponseDTO.setBalance(data.getAmount()); + } + + return statusResponseDTO; } @@ -410,8 +400,9 @@ public class GamesJILIServiceImpl implements IGamesService { //判断是否获取成功 if (this.getIsSuccess(betRecordJILIResponse.getErrorCode())) { + //数据插入 - this.batchInsert(betRecordJILIResponse); + this.batchInsert(betRecordJILIResponse, betRecordByTimeDTO); JILIBetRecordResponseDTO.DataBean dataBean = betRecordJILIResponse.getData(); //获取下一页数据 while (dataBean.getPagination().getCurrentPage() != dataBean.getPagination().getTotalPages() && dataBean.getPagination().getTotalPages() > 0) { @@ -422,9 +413,10 @@ public class GamesJILIServiceImpl implements IGamesService { betRecordByTimeDTO.setQuery(query); key = this.getKey(betRecordByTimeDTO); betRecordJILIResponse = jiliClient.getBetRecordByTime(query + "&Key=" + key, betRecordByTimeDTO.getAgentId()); + dataBean = betRecordJILIResponse.getData(); if (this.getIsSuccess(betRecordJILIResponse.getErrorCode())) { //数据插入 - this.batchInsert(betRecordJILIResponse); + this.batchInsert(betRecordJILIResponse, betRecordByTimeDTO); } else { log.error("GameBettingDataJILIServiceImpl [getBetRecordByTime] 获取投注记录失败,错误代码{},错误信息{}", betRecordJILIResponse.getErrorCode(), betRecordJILIResponse.getMessage()); } @@ -445,7 +437,45 @@ public class GamesJILIServiceImpl implements IGamesService { */ @Override public Boolean getBetRecordByHistoryTime(BetRecordByTimeDTO betRecordByTimeDTO) { - return null; + String startTime = DateUtils.formatDateToGMT4(new Date(betRecordByTimeDTO.getStartTime())); + String endTime = DateUtils.formatDateToGMT4(new Date(betRecordByTimeDTO.getEndTime())); + + //请求参数 + String query = "StartTime=" + startTime + "&EndTime=" + endTime + "&Page=" + betRecordByTimeDTO.getPage() + "&PageLimit=" + betRecordByTimeDTO.getPageLimit() + "&AgentId=" + betRecordByTimeDTO.getAgentId(); + log.info("GamesJILIServiceImpl [getBetRecordByHistoryTime] 请求参数 {}", query); + betRecordByTimeDTO.setQuery(query); + //获取key + String key = this.getKey(betRecordByTimeDTO); + JILIBetRecordResponseDTO betRecordJILIResponse = jiliClient.getBetRecordByTime(query + "&Key=" + key, betRecordByTimeDTO.getAgentId()); + + //判断是否获取成功 + if (this.getIsSuccess(betRecordJILIResponse.getErrorCode())) { + + //数据插入 + this.batchInsert(betRecordJILIResponse, betRecordByTimeDTO); + JILIBetRecordResponseDTO.DataBean dataBean = betRecordJILIResponse.getData(); + //获取下一页数据 + while (dataBean.getPagination().getCurrentPage() != dataBean.getPagination().getTotalPages() && dataBean.getPagination().getTotalPages() > 0) { + betRecordByTimeDTO.setPage(dataBean.getPagination().getCurrentPage() + 1); + //请求参数 + query = "StartTime=" + startTime + "&EndTime=" + endTime + "&Page=" + betRecordByTimeDTO.getPage() + "&PageLimit=" + betRecordByTimeDTO.getPageLimit() + "&AgentId=" + betRecordByTimeDTO.getAgentId(); + log.info("GamesJILIServiceImpl [getBetRecordByHistoryTime] 请求参数 {}", query); + betRecordByTimeDTO.setQuery(query); + key = this.getKey(betRecordByTimeDTO); + betRecordJILIResponse = jiliClient.getBetRecordByTime(query + "&Key=" + key, betRecordByTimeDTO.getAgentId()); + dataBean = betRecordJILIResponse.getData(); + if (this.getIsSuccess(betRecordJILIResponse.getErrorCode())) { + //数据插入 + this.batchInsert(betRecordJILIResponse, betRecordByTimeDTO); + } else { + log.error("GameBettingDataJILIServiceImpl [getBetRecordByHistoryTime] 获取投注记录失败,错误代码{},错误信息{}", betRecordJILIResponse.getErrorCode(), betRecordJILIResponse.getMessage()); + } + } + } else { + log.error("GameBettingDataJILIServiceImpl [getBetRecordByHistoryTime] 获取投注记录失败,错误代码{},错误信息{}", betRecordJILIResponse.getErrorCode(), betRecordJILIResponse.getMessage()); + return Boolean.FALSE; + } + return Boolean.TRUE; } @@ -460,9 +490,6 @@ public class GamesJILIServiceImpl implements IGamesService { String freeSpinValidity = DateUtils.formatDateToGMT4(new Date(createFreeSpinRequest.getFreeSpinValidity())); - GameSecretKeyCurrencyDTO gameSecretKey = gameSecretKeyCurrencyService.findByGameSecretKeyCurrencyDTO(GameSecretKeyCurrencyDTO.builder() - .code(createFreeSpinRequest.getAgentId()) - .currency(createFreeSpinRequest.getCurrency()).build()); List gameIds = createFreeSpinRequest.getGameIds(); GameUniqueDTO gameUniqueDTO = new GameUniqueDTO(); @@ -513,7 +540,7 @@ public class GamesJILIServiceImpl implements IGamesService { GameFreeRecord gameFreeRecord = GameFreeRecord.builder() - .currencyCode(gameSecretKey.getSystemCurrency()) + .currencyCode(createFreeSpinRequest.getSystemCurrency()) .referenceId(referenceId) .platformCode(GamePlatforms.JILI.getInfo()) .memberId(member.getId()) @@ -671,12 +698,11 @@ public class GamesJILIServiceImpl implements IGamesService { //请求参数 String query = "ReferenceId=" + cancelFreeSpinRequestDTO.getReferenceId() + "&AgentId=" + cancelFreeSpinRequestDTO.getAgentId(); - ; log.info("GamesJILIServiceImpl [cancelFreeSpin] 请求参数 {}", query); cancelFreeSpinRequestDTO.setQuery(query); //获取key String key = this.getKey(cancelFreeSpinRequestDTO); - JILICancelFreeSpinResponseDTO cancelFreeSpinResponseDTO = jiliClient.cancelFreeSpin(query + "&Key=" + key); + JILICancelFreeSpinResponseDTO cancelFreeSpinResponseDTO = jiliClient.cancelFreeSpin(query + "&Key=" + key); //判断是否获取成功 if (this.getIsSuccess(cancelFreeSpinResponseDTO.getErrorCode())) { List gameFreeRecords = gameFreeRecordService.selectGameFreeRecordList(GameFreeRecord.builder() @@ -692,6 +718,17 @@ public class GamesJILIServiceImpl implements IGamesService { } } + /** + * 游戏演示登录 + * + * @param gameDemoLoginRequestDTO 游戏演示登录请求dto + * @return {@link GameDemoLoginResponseDTO } + */ + @Override + public GameDemoLoginResponseDTO gameDemoLogin(GameDemoLoginRequestDTO gameDemoLoginRequestDTO) { + throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); + } + /** * 批量插入 @@ -699,14 +736,19 @@ public class GamesJILIServiceImpl implements IGamesService { * @param betRecordJILIResponse 投注记录jiliresponse * @return {@link Integer } */ - private void batchInsert(JILIBetRecordResponseDTO betRecordJILIResponse) { + private synchronized void batchInsert(JILIBetRecordResponseDTO betRecordJILIResponse, BetRecordByTimeDTO betRecordByTimeDTO) { List gameBettingDetails = new ArrayList<>(); List wagersIds = new ArrayList<>(); //数据组装 JILIBetRecordResponseDTO.DataBean dataBean = betRecordJILIResponse.getData(); //数据转化 for (JILIBetRecordDataResponseDTO jiliBetRecordDataResponseDTO : dataBean.getResult()) { - GameBettingDetails bettingDetails = this.dataBuild(GamesDataBuildDTO.builder().data(jiliBetRecordDataResponseDTO).build()); + GameBettingDetails bettingDetails = this.dataBuild(GamesDataBuildDTO.builder() + .systemCurrencyCode(betRecordByTimeDTO.getSystemCurrency()) + .platform(betRecordByTimeDTO.getVendor()) + .currencyCode(betRecordByTimeDTO.getCurrency()) + .platform(betRecordByTimeDTO.getVendor()) + .data(jiliBetRecordDataResponseDTO).build()); if (!ObjectUtils.isEmpty(bettingDetails)) { bettingDetails.setId(IdUtil.getSnowflakeNextId()); gameBettingDetails.add(bettingDetails); @@ -715,7 +757,7 @@ public class GamesJILIServiceImpl implements IGamesService { } if (!CollectionUtils.isEmpty(gameBettingDetails)) { //查询重复数据id - List removeWagersIds = gameBettingDetailsService.selectGameBettingDetailsByWagersId(wagersIds); + List removeWagersIds = gameBettingDetailsService.selectGameBettingDetailsByWagersId(wagersIds, GamePlatforms.JILI.getInfo()); //用steam流清除list中与wagersIds集合相同的数据 gameBettingDetails = gameBettingDetails.stream() .filter(detail -> !removeWagersIds.contains(detail.getWagersId())) @@ -738,10 +780,6 @@ public class GamesJILIServiceImpl implements IGamesService { //转化类 JILIBetRecordDataResponseDTO jiliBetRecordDataResponseDTO = (JILIBetRecordDataResponseDTO) gamesDataBuildDTO.getData(); - GameSecretKeyCurrencyDTO gameSecretKey = gameSecretKeyCurrencyService.findByGameSecretKeyCurrencyDTO(GameSecretKeyCurrencyDTO.builder() - .code(jiliBetRecordDataResponseDTO.getAgentId()) - .platformCode(GamePlatforms.JILI.getInfo()).build()); - Member member = memberService.selectMemberByGameAccount(jiliBetRecordDataResponseDTO.getAccount()); if (ObjectUtils.isEmpty(member)) { @@ -761,12 +799,12 @@ public class GamesJILIServiceImpl implements IGamesService { GameBettingDetails gameBettingDetails = GameBettingDetails.builder() .tenantKey(member.getTenantKey()) //保存我们的币种id - .currencyCode(gameSecretKey.getSystemCurrency()) + .currencyCode(/*gameSecretKey.getSystemCurrency()*/gamesDataBuildDTO.getSystemCurrencyCode()) .memberId(member.getId()) .gameCode(jiliBetRecordDataResponseDTO.getGameId()) .gameType(JILIGameType.findSystemByCode(jiliBetRecordDataResponseDTO.getGameCategoryId())) - .platformCode(GamePlatforms.JILI.getCode()) - .gameId(gamesDataDTO.getSystemGameId()) + .platformCode(GamePlatforms.JILI.getInfo()) + .gameId(/*gamesDataDTO.getSystemGameId()*/gamesDataDTO.getSystemGameId()) .gameName(gamesDataDTO.getName().getZhCN()) .gameStatus(jiliBetRecordDataResponseDTO.getStatus()) .gameStatusType(jiliBetRecordDataResponseDTO.getType()) diff --git a/ff-game/src/main/java/com/ff/game/api/km/address/MyKMAddressSource.java b/ff-game/src/main/java/com/ff/game/api/km/address/MyKMAddressSource.java new file mode 100644 index 0000000..c93baab --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/km/address/MyKMAddressSource.java @@ -0,0 +1,31 @@ +package com.ff.game.api.km.address; + +import com.dtflys.forest.callback.AddressSource; +import com.dtflys.forest.http.ForestAddress; +import com.dtflys.forest.http.ForestRequest; +import com.ff.base.enums.GamePlatforms; +import com.ff.game.service.IPlatformService; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + + +/** + * 我jili address来源 + * + * @author shi + * @date 2025/02/10 + */ +@Component +public class MyKMAddressSource implements AddressSource { + + @Resource + private IPlatformService platformService; + + @Override + public ForestAddress getAddress(ForestRequest request) { + String apiBaseUrl = platformService.get(GamePlatforms.KM.getCode()) + .getUrlInfo().getUrl(); + return new ForestAddress("https", apiBaseUrl, 443, "api"); + } +} \ No newline at end of file diff --git a/ff-game/src/main/java/com/ff/game/api/km/client/KMClient.java b/ff-game/src/main/java/com/ff/game/api/km/client/KMClient.java new file mode 100644 index 0000000..77009c2 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/km/client/KMClient.java @@ -0,0 +1,103 @@ +package com.ff.game.api.km.client; + + +import com.dtflys.forest.annotation.*; +import com.ff.game.api.dg.dto.DGResponse; +import com.ff.game.api.fc.dto.ApiCFBalanceTransferStatusResponseDTO; +import com.ff.game.api.km.address.MyKMAddressSource; +import com.ff.game.api.km.dto.*; +import com.ff.game.api.success.MySuccessCondition; + +import java.util.Map; + +/** + * dg 请求 + * + * @author shi + * @date 2025/02/10 + */ +@Address(source = MyKMAddressSource.class) +@Success(condition = MySuccessCondition.class) +public interface KMClient { + /** + * 创建成员 + * + * @param params 参数 + * @param header 头球 + * @return {@link DGResponse } + */ + @Post("/player/authorize") + KMAuthTokenResponse createMember(@JSONBody Map params, @Header Map header); + + /** + * 获取会员信息 + * + * @param params 参数 + */ + @Get("/player/balance?{params}") + KMBalanceResponse getMemberInfo(@Var("params") String params, @Header Map header); + + + /** + * 游戏 + * + * @param params 参数 + * @param header 头球 + * @return {@link KMGameResponse } + */ + @Get("/games?{params}") + KMGameResponse getGameList(@Var("params") String params, @Header Map header); + + + /** + * 加钱 + * + * @param params 参数 + * @param header 头球 + * @return {@link KMTransactionResponse } + */ + @Post(url = "/wallet/credit") + KMTransactionResponse credit(@JSONBody Map params, @Header Map header); + + + /** + * 扣钱 + * + * @param params 参数 + * @param header 头球 + * @return {@link KMTransactionResponse } + */ + @Post(url = "/wallet/debit") + KMTransactionResponse debit(@JSONBody Map params, @Header Map header); + + /** + * 按时间获取投注记录 + * + * @param params 参数 + * @return {@link KMBetRecordResponse } + */ + @Get(url ="/v2/history/bets?{params}") + KMBetRecordResponse getBetRecordByTime(@Var("params")String params, @Header Map header); + + /** + * 汇兑转移状态 + * + * @param params 参数 + * @param parameters 范围 + * @return {@link KMBalanceTransferStatusResponseDTO } + */ + @Post(url = "/history/transfers/{params}") + KMBalanceTransferStatusResponseDTO exchangeTransferStatus(@Var("params")String params,@JSONBody Map parameters); + + + /** + * 踢腿队员 + * + * @param params 参数 + * @param header 头球 + * @return {@link KMKickMemberResponse } + */ + @Post(url = "/player/deauthorize") + KMKickMemberResponse kickMember(@JSONBody Map params, @Header Map header); + +} diff --git a/ff-game/src/main/java/com/ff/game/api/km/dto/KMAuthTokenResponse.java b/ff-game/src/main/java/com/ff/game/api/km/dto/KMAuthTokenResponse.java new file mode 100644 index 0000000..46c55b5 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/km/dto/KMAuthTokenResponse.java @@ -0,0 +1,37 @@ +package com.ff.game.api.km.dto; + + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +/** + * kmaust令牌响应 + * + * @author shi + * @date 2025/04/02 + */ +@Data +public class KMAuthTokenResponse { + /** + * 错误代码 + */ + @JsonProperty("err") + private Integer errorCode; + + /** + * 错误描述 + */ + @JsonProperty("errdesc") + private String errorDescription; + /** + * 身份验证令牌 + */ + @JsonProperty("authtoken") + private String authToken; + + /** + * 是否为新用户 + */ + @JsonProperty("isnew") + private Boolean isNew; +} diff --git a/ff-game/src/main/java/com/ff/game/api/km/dto/KMBalanceResponse.java b/ff-game/src/main/java/com/ff/game/api/km/dto/KMBalanceResponse.java new file mode 100644 index 0000000..4a32921 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/km/dto/KMBalanceResponse.java @@ -0,0 +1,38 @@ +package com.ff.game.api.km.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.math.BigDecimal; + +/** + * km平衡响应 + * + * @author shi + * @date 2025/04/02 + */ +@Data +public class KMBalanceResponse { + /** + * 错误代码 + */ + @JsonProperty("err") + private Integer errorCode; + + /** + * 错误描述 + */ + @JsonProperty("errdesc") + private String errorDescription; + /** + * 余额 + */ + @JsonProperty("bal") + private BigDecimal balance; + + /** + * 货币代码 + */ + @JsonProperty("cur") + private String currency; +} diff --git a/ff-game/src/main/java/com/ff/game/api/km/dto/KMBalanceTransferStatusResponseDTO.java b/ff-game/src/main/java/com/ff/game/api/km/dto/KMBalanceTransferStatusResponseDTO.java new file mode 100644 index 0000000..9a30d2d --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/km/dto/KMBalanceTransferStatusResponseDTO.java @@ -0,0 +1,77 @@ +package com.ff.game.api.km.dto; + + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.math.BigDecimal; + +/** + * km平衡传输状态响应数据 + * + * @author shi + * @date 2025/04/08 + */ +@Data +public class KMBalanceTransferStatusResponseDTO { + + /** + * 错误代码 + */ + @JsonProperty("err") + private Integer errorCode; + + /** + * 错误描述 + */ + @JsonProperty("errdesc") + private String errorDescription; + + /** + * 转账交易 ID + */ + @JsonProperty("txid") + private String txid; + + /** + * 转账时间戳,格式为 ISO 8601,如:2017-12-12T12:11:16+08:00 + */ + @JsonProperty("timestamp") + private String timestamp; + + /** + * 用户 ID + */ + @JsonProperty("userid") + private String userid; + + /** + * 用户名 + */ + @JsonProperty("username") + private String username; + + /** + * 玩家类型,1 代表普通玩家(具体含义根据接口文档定义) + */ + @JsonProperty("playertype") + private int playertype; + + /** + * 转账金额 + */ + @JsonProperty("amt") + private BigDecimal amt; + + /** + * 转账后的余额 + */ + @JsonProperty("postbal") + private BigDecimal postbal; + + /** + * 货币类型,符合 ISO 4217 标准(如 THB) + */ + @JsonProperty("cur") + private String cur; +} diff --git a/ff-game/src/main/java/com/ff/game/api/km/dto/KMBetRecordResponse.java b/ff-game/src/main/java/com/ff/game/api/km/dto/KMBetRecordResponse.java new file mode 100644 index 0000000..9f36e9b --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/km/dto/KMBetRecordResponse.java @@ -0,0 +1,145 @@ +package com.ff.game.api.km.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.math.BigDecimal; +import java.util.Date; +import java.util.List; + +/** + * kmbet记录响应 + * + * @author shi + * @date 2025/04/02 + */ +@Data +public class KMBetRecordResponse { + /** + * 错误代码 + */ + @JsonProperty("err") + private Integer errorCode; + + /** + * 错误描述 + */ + @JsonProperty("errdesc") + private String errorDescription; + + /** + * bets 包含下列字段的对象数组容器。 + */ + @JsonProperty("bets") + private List bets; + + @Data + public static class Bet { + + /** + * KM内部投注辨识码。此字段是唯一的标识符。 + */ + @JsonProperty("id") + private String id; + + /** + * 记录在KM服务器的投注时间,采用ISO 8601格式。 + */ + @JsonProperty("beton") + private Date beton; // 使用 Date 类型来表示 ISO 8601 格式的时间 + + /** + * 投注关闭的时间,采用ISO 8601格式。如果回合尚未结束,则为null。 + */ + @JsonProperty("closedon") + private Date closedon; // 使用 Date 类型来表示 ISO 8601 格式的时间 + + /** + * 交易回合的唯一辨识代码。 + */ + @JsonProperty("roundid") + private String roundId; + + /** + * 游戏交易执行回合时的游戏供应商辨识码。 + */ + @JsonProperty("externalroundid") + private String externalRoundId; + + /** + * 游戏供应商代码,例如 "KMQM"。 + */ + @JsonProperty("gpcode") + private String gpCode; + + /** + * 游戏代码。 + */ + @JsonProperty("gcode") + private String gCode; + + /** + * 游戏平台的类型。 + */ + @JsonProperty("platformtype") + private Integer platformType; + + /** + * 玩家专属辨识代码。 + */ + @JsonProperty("userid") + private String userId; + + /** + * 玩家在KM系统使用的货币。 + */ + @JsonProperty("cur") + private String currency; + + /** + * 投注的总金额,为负数表示从账户扣款。 + */ + @JsonProperty("riskamt") + private BigDecimal riskAmount; + + /** + * 投注赢的金额,若玩家赢得金额则为正数,若没有输赢则为0。 + */ + @JsonProperty("winamt") + private BigDecimal winAmount; + + /** + * 回合中所有投注的有效投注总金额。 + */ + @JsonProperty("validbet") + private BigDecimal validBet; + + /** + * 下注玩家的佣金金额。 + */ + @JsonProperty("commission") + private BigDecimal commission; + + /** + * 累积奖金对象,包含贡献金额和中奖金额。若没有配置累积奖金,则为null。 + */ + @JsonProperty("jackpot") + private Jackpot jackpot; + + @Data + public static class Jackpot { + + /** + * 贡献到累积奖金的金额。 + */ + @JsonProperty("contrib") + private BigDecimal contrib; + + /** + * 本注的累积奖金赢取金额。 + */ + @JsonProperty("winamt") + private BigDecimal winAmount; + } + } +} diff --git a/ff-game/src/main/java/com/ff/game/api/km/dto/KMGameResponse.java b/ff-game/src/main/java/com/ff/game/api/km/dto/KMGameResponse.java new file mode 100644 index 0000000..57eb949 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/km/dto/KMGameResponse.java @@ -0,0 +1,130 @@ +package com.ff.game.api.km.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.math.BigDecimal; +import java.util.List; + +/** + * kmgame响应 + * + * @author shi + * @date 2025/04/02 + */ +@Data +public class KMGameResponse { + /** + * 错误代码 + */ + @JsonProperty("err") + private Integer errorCode; + + /** + * 错误描述 + */ + @JsonProperty("errdesc") + private String errorDescription; + /** + * 游戏图标解析度 + */ + @JsonProperty("iconres") + private List iconResolutions; + + /** + * 游戏数组,包含具体的游戏信息 + */ + @JsonProperty("games") + private List games; + + @Data + public static class Game { + + /** + * 游戏供应商游戏专属辨识代码 + */ + @JsonProperty("externalid") + private String externalId; + + /** + * 游戏代码 + */ + @JsonProperty("code") + private String code; + + /** + * 游戏名称 + */ + @JsonProperty("name") + private String name; + + /** + * 游戏说明 + */ + @JsonProperty("description") + private String description; + + /** + * 游戏供应商代码 + */ + @JsonProperty("providercode") + private String providerCode; + + /** + * 游戏的状态 + */ + @JsonProperty("isactive") + private Boolean isActive; + + /** + * 游戏种类代码 + */ + @JsonProperty("type") + private Integer type; + + /** + * 游戏图标 URL(此字段不可用) + */ + @JsonProperty("iconurl") + private String iconUrl; + + /** + * 系统游戏id + */ + private String systemGameId; + + /** + * 游戏是否提供试玩 + */ + @JsonProperty("supportdemourl") + private Boolean supportDemoUrl; + + /** + * 投注限额数组(如果有的话) + */ + @JsonProperty("betlimits") + private List betLimits; + + @Data + public static class BetLimit { + + /** + * 游戏供应商的投注限制辨识码 + */ + @JsonProperty("id") + private String id; + + /** + * 最小投注金额 + */ + @JsonProperty("min") + private BigDecimal min; + + /** + * 最大投注金额 + */ + @JsonProperty("max") + private BigDecimal max; + } + } +} diff --git a/ff-game/src/main/java/com/ff/game/api/km/dto/KMKickMemberResponse.java b/ff-game/src/main/java/com/ff/game/api/km/dto/KMKickMemberResponse.java new file mode 100644 index 0000000..cf782dd --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/km/dto/KMKickMemberResponse.java @@ -0,0 +1,37 @@ +package com.ff.game.api.km.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +/** + * kmkick成员响应 + * + * @author shi + * @date 2025/04/03 + */ +@Data +public class KMKickMemberResponse { + /** + * 错误代码 + */ + @JsonProperty("err") + private Integer errorCode; + + /** + * 错误描述 + */ + @JsonProperty("errdesc") + private String errorDescription; + + /** + * 成功标志,true 表示操作成功,false 表示操作失败 + */ + @JsonProperty("success") + private boolean success; + + /** + * 描述信息 + */ + @JsonProperty("desc") + private String description; +} diff --git a/ff-game/src/main/java/com/ff/game/api/km/dto/KMTransactionResponse.java b/ff-game/src/main/java/com/ff/game/api/km/dto/KMTransactionResponse.java new file mode 100644 index 0000000..66112ef --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/km/dto/KMTransactionResponse.java @@ -0,0 +1,59 @@ +package com.ff.game.api.km.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.math.BigDecimal; + +/** + * km事务响应 + * + * @author shi + * @date 2025/04/02 + */ +@Data +public class KMTransactionResponse { + + /** + * 错误代码 + */ + @JsonProperty("err") + private Integer errorCode; + + /** + * 错误描述 + */ + @JsonProperty("errdesc") + private String errorDescription; + + /** + * 余额 + */ + @JsonProperty("bal") + private BigDecimal balance; + + /** + * 货币类型 + */ + @JsonProperty("cur") + private String currency; + + /** + * 交易 ID + */ + @JsonProperty("txid") + private String txId; + + /** + * 平台交易 ID + */ + @JsonProperty("ptxid") + private String ptxId; + + /** + * 是否为重复交易 + */ + @JsonProperty("dup") + private Boolean isDuplicate; + +} diff --git a/ff-game/src/main/java/com/ff/game/api/km/impl/GamesKMServiceImpl.java b/ff-game/src/main/java/com/ff/game/api/km/impl/GamesKMServiceImpl.java new file mode 100644 index 0000000..f510799 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/km/impl/GamesKMServiceImpl.java @@ -0,0 +1,706 @@ +package com.ff.game.api.km.impl; + +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.NumberUtil; +import com.ff.base.constant.CacheConstants; +import com.ff.base.constant.Constants; +import com.ff.base.core.redis.RedisCache; +import com.ff.base.enums.*; +import com.ff.base.exception.base.ApiException; +import com.ff.base.exception.base.BaseException; +import com.ff.base.utils.DateUtils; +import com.ff.base.utils.JsonUtil; +import com.ff.base.utils.StringUtils; +import com.ff.base.utils.ip.IpUtils; +import com.ff.base.utils.uuid.IdUtils; +import com.ff.config.KeyConfig; +import com.ff.game.api.IGamesService; +import com.ff.game.api.fc.dto.ApiCFBalanceTransferStatusResponseDTO; +import com.ff.game.api.jili.dto.JILITransferStatusResponseDTO; +import com.ff.game.api.km.client.KMClient; +import com.ff.game.api.km.dto.*; +import com.ff.game.api.request.*; +import com.ff.game.api.xk.dto.XKGamesDTO; +import com.ff.game.domain.*; +import com.ff.game.service.IGameBettingDetailsService; +import com.ff.game.service.IGameExchangeMoneyService; +import com.ff.game.service.IGameService; +import com.ff.game.service.IPlatformService; +import com.ff.member.domain.Member; +import com.ff.member.service.IMemberService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.Assert; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ObjectUtils; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.net.URLEncoder; +import java.util.*; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + + +/** + * DG 游戏 impl + * + * @author shi + * @date 2024/11/12 + */ +@Service("KMService") +@Slf4j +public class GamesKMServiceImpl implements IGamesService { + + @Resource + private IPlatformService platformService; + + @Resource + private RedisCache redisCache; + + @Resource + private IGameExchangeMoneyService gameExchangeMoneyService; + + @Resource + private IGameService gameService; + + + @Resource + private IMemberService memberService; + + @Resource + private KMClient KMClient; + + + @Resource + private KeyConfig keyConfig; + + @Resource + private IGameBettingDetailsService gameBettingDetailsService; + + + /** + * 获得就是成功 + * + * @param errorCode 错误代码 + * @return {@link Boolean } + */ + private Boolean getIsSuccess(Integer errorCode) { + return 200 == errorCode; + } + + + /** + * 获取密钥 + * + * @param gamesBaseRequestDTO 游戏请求dto + * @return {@link String } + */ + private Map getKey(GamesBaseRequestDTO gamesBaseRequestDTO) { + + //取出对应的key跟密钥跟请求参数 + String agentKey = gamesBaseRequestDTO.getAgentKey(); + String agentId = gamesBaseRequestDTO.getAgentId(); + + Map keyMap = new HashMap<>(); + keyMap.put("X-QM-ClientId", agentId); + keyMap.put("X-QM-ClientSecret", agentKey); + return keyMap; + } + + /** + * 创建成员 + * + * @param createMemberRequestDTO 创建成员请求dto + * @return {@link Boolean } + */ + @Override + public Boolean createMember(CreateMemberRequestDTO createMemberRequestDTO) { + log.info("GamesKMServiceImpl [createMember] 请求参数 {}", createMemberRequestDTO); + + Map params = new LinkedHashMap<>(); + params.put("ipaddress", IpUtils.getHostIp()); + params.put("username", createMemberRequestDTO.getAccount()); + params.put("userid", createMemberRequestDTO.getAccount()); + params.put("lang", "en-US"); + params.put("cur", createMemberRequestDTO.getCurrency()); + /* 1 青铜-基本额度 + 2 白银-升级额度 + 3 黄金-高级额度 + 4 白金-贵宾额度*/ + params.put("betlimitid", 4); + //TODO 后面去掉 + params.put("istestplayer", Boolean.TRUE); + params.put("platformtype", ObjectUtils.isEmpty(createMemberRequestDTO.getPlatformType()) ? 1 : createMemberRequestDTO.getPlatformType()); + + Map headerMap = this.getKey(createMemberRequestDTO); + KMAuthTokenResponse member = KMClient.createMember(params, headerMap); + if (ObjectUtils.isEmpty(member.getErrorCode()) || this.getIsSuccess(member.getErrorCode())) { + redisCache.setCacheObject(CacheConstants.KM_USER_TOKEN + createMemberRequestDTO.getAccount(), member.getAuthToken()); + return Boolean.TRUE; + } + //判断是否获取成功 + return Boolean.FALSE; + } + + + /** + * 获取会员信息 + * + * @param memberInfoRequestDTO 会员信息请求dto + * @return {@link MemberInfoResponseDTO } + */ + @Override + public MemberInfoResponseDTO getMemberInfo(MemberInfoRequestDTO memberInfoRequestDTO) { + log.info("GamesDGServiceImpl [getMemberInfo] 请求参数 {}", memberInfoRequestDTO); + Map paramsMap = new HashMap<>(); + + + paramsMap.put("userid", memberInfoRequestDTO.getAccounts()); + paramsMap.put("cur", memberInfoRequestDTO.getCurrency()); + Map headerMap = this.getKey(memberInfoRequestDTO); + KMBalanceResponse memberInfo = KMClient.getMemberInfo(JsonUtil.mapToQueryString(paramsMap), headerMap); + if (ObjectUtils.isEmpty(memberInfo.getErrorCode()) || this.getIsSuccess(memberInfo.getErrorCode())) { + return MemberInfoResponseDTO.builder().account(memberInfoRequestDTO.getAccounts()).balance(memberInfo.getBalance()).status(GameMemberStatus.UNKNOWN.getCode()).build(); + } else { + throw new ApiException(ErrorCode.ACCOUNT_NOT_EXIST.getCode()); + } + } + + /** + * 无重定向登录 + * + * @param gamesLogin 游戏登录 + * @return {@link String } + */ + @Override + public String loginWithoutRedirect(GamesLogin gamesLogin) { + log.info("GamesKMServiceImpl [loginWithoutRedirect] 请求参数 {}", gamesLogin); + String kmUserToken = redisCache.getCacheObject(CacheConstants.KM_USER_TOKEN + gamesLogin.getAccount()); + if (StringUtils.isEmpty(kmUserToken)) { + + + CreateMemberRequestDTO gamesBaseRequestDTO = CreateMemberRequestDTO.builder() + .account(gamesLogin.getAccount()) + .agentId(gamesLogin.getAgentId()) + .agentKey(gamesLogin.getAgentKey()) + .currency(gamesLogin.getCurrency()) + .build(); + this.createMember(gamesBaseRequestDTO); + kmUserToken = redisCache.getCacheObject(CacheConstants.KM_USER_TOKEN + gamesLogin.getAccount()); + } + + String loginUrl = platformService.get(GamePlatforms.KM.getCode()).getUrlInfo().getLoginUrl(); + + return loginUrl + "/gamelauncher?gpcode=" + gamesLogin.getGameType() + + "&gcode=" + gamesLogin.getGameId() + + "&token=" + kmUserToken + + "&lang=" + gamesLogin.getLang(); + } + + + /** + * 获取游戏列表 + * + * @param gamesBaseRequestDTO 游戏请求dto + * @return {@link String } + */ + @Transactional + @Override + public String getGameList(GamesBaseRequestDTO gamesBaseRequestDTO) { + + List gamesDatas = redisCache.getCacheList(CacheConstants.KM_GAMES); + if (!CollectionUtils.isEmpty(gamesDatas)) { + return CacheConstants.KM_GAMES; + } + + + Map params = new LinkedHashMap<>(); + params.put("lang", "zh-CN"); + params.put("platformtype", 1); + Map headerMap = this.getKey(gamesBaseRequestDTO); + KMGameResponse gameMobiles = KMClient.getGameList(JsonUtil.mapToQueryString(params), headerMap); + //判断是否获取成功 + List gameListData = new ArrayList<>(); + if (ObjectUtils.isEmpty(gameMobiles.getErrorCode()) || this.getIsSuccess(gameMobiles.getErrorCode())) { + gameListData.addAll(this.gameList(gameMobiles, IngressType.MOBILE_WEB.getValue())); + + } else { + throw new BaseException(gameMobiles.getErrorDescription()); + + } + params = new LinkedHashMap<>(); + params.put("lang", "zh-CN"); + params.put("platformtype", 0); + KMGameResponse gamePCs = KMClient.getGameList(JsonUtil.mapToQueryString(params), headerMap); + //判断是否获取成功 + if (ObjectUtils.isEmpty(gamePCs.getErrorCode()) || this.getIsSuccess(gamePCs.getErrorCode())) { + gameListData.addAll(this.gameList(gamePCs, IngressType.PC_WEB.getValue())); + + } else { + throw new BaseException(gamePCs.getErrorDescription()); + } + // 使用集合操作来找出相同 code 的对象 + List games = gameMobiles.getGames().stream() + .filter(mobile -> gamePCs.getGames().stream() + .anyMatch(pc -> pc.getCode().equals(mobile.getCode()))) + .collect(Collectors.toList()); + for (KMGameResponse.Game game : games) { + + Integer platformType = KMGameType.findSystemByCode(game.getProviderCode()); + Game gameOne = Game.builder() + .platformCode(GamePlatforms.KM.getCode()) + .platformType(platformType) + .gameCode(game.getCode()) + .build(); + List gameOnes = gameService.selectGameList(gameOne); + for (Game one : gameOnes) { + one.setIngress(IngressType.PC_AND_MOBILE_WEB.getValue()); + gameService.updateGame(one); + } + } + + redisCache.deleteObject(CacheConstants.KM_GAMES); + redisCache.setCacheList(CacheConstants.KM_GAMES, gameListData); + redisCache.expire(CacheConstants.KM_GAMES, 5L, TimeUnit.HOURS); + return CacheConstants.KM_GAMES; + } + + /** + * 游戏列表 + * + * @param gameList 游戏列表 + * @param ingress 进入 + * @return {@link List }<{@link KMGameResponse.Game }> + */ + private List gameList(KMGameResponse gameList, Integer ingress) { + for (KMGameResponse.Game gamesDataDTO : gameList.getGames()) { + Integer platformType = KMGameType.findSystemByCode(gamesDataDTO.getProviderCode()); + Game game = Game.builder() + .platformCode(GamePlatforms.KM.getCode()) + .platformType(platformType) + .gameCode(gamesDataDTO.getCode()) + .build(); + List games = gameService.selectGameList(game); + //不存在这个游戏 + if (CollectionUtils.isEmpty(games)) { + game.setGameSourceType(gamesDataDTO.getProviderCode()); + game.setFreespin(Boolean.FALSE); + game.setDemoStatus(gamesDataDTO.getSupportDemoUrl()); + game.setSortNo(gameService.selectMaxSortNo(platformType, GamePlatforms.KM.getCode()) + 1); + game.setGameName(gamesDataDTO.getName()); + game.setCreateBy(Constants.SYSTEM); + game.setIngress(ingress); + game.setPlatformCode(GamePlatforms.KM.getCode()); + game.setPlatformType(platformType); + game.setGameId(StringUtils.addSuffix(GamePlatforms.KM.getCode(), gamesDataDTO.getCode())); + List nameInfos = new ArrayList<>(); + nameInfos.add(new NameInfo(gamesDataDTO.getName(), "zh-CN")); + game.setNameInfo(nameInfos); + gameService.insertGame(game); + } else { + game = games.get(0); + List nameInfos = new ArrayList<>(); + nameInfos.add(new NameInfo(gamesDataDTO.getName(), "zh-CN")); + game.setNameInfo(nameInfos); + gameService.updateGame(game); + } + gamesDataDTO.setSystemGameId(game.getGameId()); + } + return gameList.getGames(); + } + + + /** + * 获取交易id + * + * @param transactionIdRequestDTO 事务id请求dto + * @return {@link String } + */ + @Override + public String getTransactionId(TransactionIdRequestDTO transactionIdRequestDTO) { + return GamePlatforms.KM.getInfo() + IdUtils.simpleUUID(); + } + + + + /** + * 按代理id进行交换转账 + * + * @param exchangeTransferMoneyRequestDTO 外汇转账moeny dto + * @return {@link Long } + */ + @Override + @Transactional + public Long exchangeTransferByAgentId(ExchangeTransferMoneyRequestDTO exchangeTransferMoneyRequestDTO) { + log.info("GamesKMServiceImpl [exchangeTransferByAgentId] 请求参数 {}", exchangeTransferMoneyRequestDTO); + + + GameExchangeMoney exchangeMoney = gameExchangeMoneyService.selectGameExchangeMoneyById(exchangeTransferMoneyRequestDTO.getGameExchangeId()); + + + + + + BigDecimal amount = exchangeTransferMoneyRequestDTO.getAmount(); + if (TransferType.ALL.getCode().equals(exchangeTransferMoneyRequestDTO.getTransferType())) { + // 获取第三方钱包余额 + MemberInfoRequestDTO gamesBaseRequestDTO = MemberInfoRequestDTO.builder() + .accounts(exchangeTransferMoneyRequestDTO.getAccount()) + .agentId(exchangeTransferMoneyRequestDTO.getAgentId()) + .currency(exchangeTransferMoneyRequestDTO.getCurrency()) + .agentKey(exchangeTransferMoneyRequestDTO.getAgentKey()) + .build(); + + amount = this.getMemberInfo(gamesBaseRequestDTO).getBalance(); + } + + Map params = new LinkedHashMap<>(); + params.put("userid", exchangeTransferMoneyRequestDTO.getAccount()); + params.put("amt", amount); + params.put("cur", exchangeTransferMoneyRequestDTO.getCurrency()); + params.put("txid", exchangeTransferMoneyRequestDTO.getTransactionId()); + + Map headerMap = this.getKey(exchangeTransferMoneyRequestDTO); + KMTransactionResponse kmTransactionResponse; + if (TransferType.ALL.getCode().equals(exchangeTransferMoneyRequestDTO.getTransferType())) { + kmTransactionResponse = KMClient.debit(params, headerMap); + } else { + kmTransactionResponse = KMClient.credit(params, headerMap); + } + + //判断是否转移成功 + if (ObjectUtils.isEmpty(kmTransactionResponse.getErrorCode()) || this.getIsSuccess(kmTransactionResponse.getErrorCode())) { + + //更新数据 + exchangeMoney.setBalance(amount); + exchangeMoney.setCoinBefore(NumberUtil.sub(amount, kmTransactionResponse.getBalance()).abs()); + exchangeMoney.setCoinAfter(kmTransactionResponse.getBalance()); + exchangeMoney.setCurrencyBefore(exchangeMoney.getCoinBefore()); + exchangeMoney.setCurrencyAfter(exchangeMoney.getCoinAfter()); + exchangeMoney.setStep(GameExchangeStep.PLATFORM_TRANSACTION.getCode()); + exchangeMoney.setStepStatus(GameExchangeStepStatus.SUCCESS.getCode()); + gameExchangeMoneyService.updateGameExchangeMoney(exchangeMoney); + } else { + exchangeMoney.setStep(GameExchangeStep.PLATFORM_TRANSACTION.getCode()); + exchangeMoney.setStepStatus(GameExchangeStepStatus.FAILURE.getCode()); + gameExchangeMoneyService.updateGameExchangeMoney(exchangeMoney); + log.error("GamesDGServiceImpl [exchangeTransferByAgentId] 金额转移失败,错误代码{},错误信息{}", kmTransactionResponse.getErrorCode(), kmTransactionResponse.getErrorDescription()); + throw new ApiException(ErrorCode.BALANCE_TRANSFER_FAILED.getCode()); + } + + return exchangeMoney.getId(); + } + + /** + * 汇兑转移状态 + * + * @param exchangeTransferMoneyRequestDTO 兑换转账请求dto + * @return {@link Boolean } + */ + @Override + public ExchangeTransferStatusResponseDTO exchangeTransferStatus(ExchangeTransferStatusRequestDTO exchangeTransferMoneyRequestDTO) { + log.info("GamesKMServiceImpl [exchangeTransferStatus] 请求参数 {}", exchangeTransferMoneyRequestDTO); + + + Map headerMap = this.getKey(exchangeTransferMoneyRequestDTO); + + KMBalanceTransferStatusResponseDTO kmBalanceTransferStatusResponseDTO = KMClient.exchangeTransferStatus(exchangeTransferMoneyRequestDTO.getOrderId(), headerMap); + Integer status = StatusType.IN_PROGRESS.getValue(); + if (ObjectUtils.isEmpty(kmBalanceTransferStatusResponseDTO.getErrorCode()) || this.getIsSuccess(kmBalanceTransferStatusResponseDTO.getErrorCode())) { + status = StatusType.SUCCESS.getValue(); + } else { + status = StatusType.FAILURE.getValue(); + } + return ExchangeTransferStatusResponseDTO.builder() + .statusType(status) + .balance(kmBalanceTransferStatusResponseDTO.getAmt()) + .coinBefore(NumberUtil.sub(kmBalanceTransferStatusResponseDTO.getAmt(), kmBalanceTransferStatusResponseDTO.getPostbal()).abs()) + .coinAfter(kmBalanceTransferStatusResponseDTO.getPostbal()) + .build(); + } + + + /** + * 按时间获取投注记录 + * + * @param betRecordByTimeDTO 按时间dto投注记录 + * @return {@link List }<{@link GameBettingDetails }> + */ + @Override + public Boolean getBetRecordByTime(BetRecordByTimeDTO betRecordByTimeDTO) { + //请求参数 + + log.info("GamesKMServiceImpl [getBetRecordByTime] 请求参数 {}", betRecordByTimeDTO); + Map key = this.getKey(betRecordByTimeDTO); + String startTime = null; + String endTime = null; + try { + + + startTime = URLEncoder.encode(DateUtils.convertTimestampToFormattedDate(betRecordByTimeDTO.getStartTime(), DateUtils.ISO_8601_FORMAT, "GMT+8") + "+08:00", "UTF-8"); + endTime = URLEncoder.encode(DateUtils.convertTimestampToFormattedDate(betRecordByTimeDTO.getEndTime(), DateUtils.ISO_8601_FORMAT, "GMT+8") + "+08:00", "UTF-8"); + } catch (Exception e) { + throw new BaseException(e.getMessage()); + } + Map params = new LinkedHashMap<>(); + params.put("startdate", startTime); + params.put("enddate", endTime); + params.put("includetestplayers", Boolean.TRUE); + params.put("issettled", Boolean.TRUE); + + KMBetRecordResponse betRecordByTime = KMClient.getBetRecordByTime(JsonUtil.mapToQueryString(params), key); + + if (ObjectUtils.isEmpty(betRecordByTime.getErrorCode()) || this.getIsSuccess(betRecordByTime.getErrorCode())) { + this.batchInsert(betRecordByTime, betRecordByTimeDTO); + return Boolean.TRUE; + } else { + log.error("GamesKMServiceImpl [getBetRecordByTime] 获取投注记录失败,错误代码{},错误信息{}", betRecordByTime.getErrorCode(), betRecordByTime.getErrorDescription()); + throw new BaseException(betRecordByTime.getErrorDescription()); + } + + + } + + /** + * 按历史时间获取投注记录 + * + * @param betRecordByTimeDTO 按时间dto投注记录 + * @return {@link Boolean } + */ + @Override + public Boolean getBetRecordByHistoryTime(BetRecordByTimeDTO betRecordByTimeDTO) { + + log.info("GamesKMServiceImpl [getBetRecordByHistoryTime] 请求参数 {}", betRecordByTimeDTO); + Map key = this.getKey(betRecordByTimeDTO); + String startTime = null; + String endTime = null; + try { + + + startTime = URLEncoder.encode(DateUtils.convertTimestampToFormattedDate(betRecordByTimeDTO.getStartTime(), DateUtils.ISO_8601_FORMAT, "GMT+8") + "+08:00", "UTF-8"); + endTime = URLEncoder.encode(DateUtils.convertTimestampToFormattedDate(betRecordByTimeDTO.getEndTime(), DateUtils.ISO_8601_FORMAT, "GMT+8") + "+08:00", "UTF-8"); + } catch (Exception e) { + throw new BaseException(e.getMessage()); + } + Map params = new LinkedHashMap<>(); + params.put("startdate", startTime); + params.put("enddate", endTime); + params.put("includetestplayers", Boolean.TRUE); + params.put("issettled", Boolean.TRUE); + + KMBetRecordResponse betRecordByTime = KMClient.getBetRecordByTime(JsonUtil.mapToQueryString(params), key); + + if (ObjectUtils.isEmpty(betRecordByTime.getErrorCode()) || this.getIsSuccess(betRecordByTime.getErrorCode())) { + this.batchInsert(betRecordByTime, betRecordByTimeDTO); + return Boolean.TRUE; + } else { + log.error("GamesKMServiceImpl [getBetRecordByHistoryTime] 获取投注记录失败,错误代码{},错误信息{}", betRecordByTime.getErrorCode(), betRecordByTime.getErrorDescription()); + throw new BaseException(betRecordByTime.getErrorDescription()); + } + + } + + /** + * 赠送免费局数 + * + * @param createFreeSpinRequest 创建自由旋转请求 + * @return {@link Boolean } + */ + @Override + public Boolean createFreeSpin(CreateFreeSpinRequestDTO createFreeSpinRequest) { + throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); + } + + /** + * 获取游戏详细信息 + * + * @param getGameDetailRequestDTO 获取游戏详细信息请求dto + * @return {@link GetGameDetailResponseDTO } + */ + @Override + public GetGameDetailResponseDTO getGameDetail(GetGameDetailRequestDTO getGameDetailRequestDTO) { + throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); + } + + /** + * 强制会员从游戏注销 + * + * @param kickMemberRequestDTO 踢会员请求dto + * @return {@link Boolean } + */ + @Override + public Boolean kickMember(KickMemberRequestDTO kickMemberRequestDTO) { + log.info("GamesKMServiceImpl [kickMember] 请求参数 {}", kickMemberRequestDTO); + Map key = this.getKey(kickMemberRequestDTO); + Map params = new LinkedHashMap<>(); + params.put("userid", kickMemberRequestDTO.getAccount()); + KMKickMemberResponse kickMember = KMClient.kickMember(params, key); + if (ObjectUtils.isEmpty(kickMember.getErrorCode()) || this.getIsSuccess(kickMember.getErrorCode())) { + redisCache.deleteObject(CacheConstants.KM_USER_TOKEN + kickMemberRequestDTO.getAccount()); + return kickMember.isSuccess(); + } else { + throw new BaseException(kickMember.getDescription()); + } + } + + /** + * 踢成员全部 + * + * @param kickMemberAllDTO 踢成员全部dto + * @return {@link Boolean } + */ + @Override + public Boolean kickMemberAll(KickMemberAllDTO kickMemberAllDTO) { + throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); + } + + /** + * 免费游戏玩家使用的纪录 + * + * @param getFreeSpinDashflowRequestDTO 获取自由旋转dashflow请求dto + * @return {@link List }<{@link GameFreeRecord }> + */ + @Override + public List getFreeSpinDashflow(GetFreeSpinDashflowRequestDTO getFreeSpinDashflowRequestDTO) { + throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); + } + + /** + * 取消赠送免费局数 + * + * @param cancelFreeSpinRequestDTO 取消免费旋转请求 + * @return {@link Boolean } + */ + @Override + public Boolean cancelFreeSpin(CancelFreeSpinRequestDTO cancelFreeSpinRequestDTO) { + throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); + } + + /** + * 游戏演示登录 + * + * @param gameDemoLoginRequestDTO 游戏演示登录请求dto + * @return {@link GameDemoLoginResponseDTO } + */ + @Override + public GameDemoLoginResponseDTO gameDemoLogin(GameDemoLoginRequestDTO gameDemoLoginRequestDTO) { + log.info("GamesKMServiceImpl [gameDemoLogin] 请求参数 {}", gameDemoLoginRequestDTO); + Map params = new LinkedHashMap<>(); + params.put("lang", gameDemoLoginRequestDTO.getLang()); + String loginUrl = platformService.get(GamePlatforms.KM.getCode()).getUrlInfo().getLoginUrl(); + //String selectConfigByKey = configService.selectConfigByKey(Constants.KM_API_BASE_LOGIN_URL); + return GameDemoLoginResponseDTO.builder() + .url(loginUrl + "/demolauncher?gpcode=" + gameDemoLoginRequestDTO.getGameType() + + "&gcode=" + gameDemoLoginRequestDTO.getGameId() + + "&lang=" + gameDemoLoginRequestDTO.getLang()) + .build(); + } + + + /** + * 批量插入 + * + * @param betRecordByTime dg投注记录响应dto + */ + private void batchInsert(KMBetRecordResponse betRecordByTime, BetRecordByTimeDTO betRecordByTimeDTO) { + List gameBettingDetails = new ArrayList<>(); + List wagersIds = new ArrayList<>(); + //数据组装 + List report = betRecordByTime.getBets(); + //数据转化 + for (KMBetRecordResponse.Bet bean : report) { + GameBettingDetails bettingDetails = this.dataBuild(GamesDataBuildDTO.builder() + //.systemCurrencyCode(systemCurrency) + //.currencyCode(targetCurrency) + .platform(betRecordByTimeDTO.getVendor()) + .data(bean).build()); + if (!ObjectUtils.isEmpty(bettingDetails)) { + bettingDetails.setId(IdUtil.getSnowflakeNextId()); + gameBettingDetails.add(bettingDetails); + } + wagersIds.add(String.valueOf(bean.getId())); + } + if (!CollectionUtils.isEmpty(gameBettingDetails)) { + //查询重复数据id + List removeWagersIds = gameBettingDetailsService.selectGameBettingDetailsByWagersId(wagersIds, GamePlatforms.KM.getInfo()); + //用steam流清除list中与wagersIds集合相同的数据 + gameBettingDetails = gameBettingDetails.stream() + .filter(detail -> !removeWagersIds.contains(detail.getWagersId())) + .collect(Collectors.toList()); + if (!CollectionUtils.isEmpty(gameBettingDetails)) { + gameBettingDetailsService.batchInsert(gameBettingDetails); + } + } + + } + + /** + * 数据构建 + * + * @param gamesDataBuildDTO 数据 + * @return {@link GameBettingDetails } + */ + @Override + public GameBettingDetails dataBuild(GamesDataBuildDTO gamesDataBuildDTO) { + //转化类 + KMBetRecordResponse.Bet resultBean = (KMBetRecordResponse.Bet) gamesDataBuildDTO.getData(); + + + + Member member = memberService.selectMemberByGameAccount(resultBean.getUserId()); + if (ObjectUtils.isEmpty(member)) { + return null; + } + List gamesDatas = redisCache.getCacheList(CacheConstants.KM_GAMES); + Map dataDTOMap = gamesDatas.stream().collect(Collectors.toMap( + KMGameResponse.Game::getCode, + e -> e, + (existing, replacement) -> existing + )); + KMGameResponse.Game gamesDataDTO = dataDTOMap.get(resultBean.getGCode()); + + //输赢状态 + Integer gameStatus = GameStatus.FLAT.getCode(); + BigDecimal payoffAmount = NumberUtil.sub(resultBean.getWinAmount(), resultBean.getRiskAmount().abs()); + if (payoffAmount.compareTo(BigDecimal.ZERO) > 0) { + gameStatus = GameStatus.WIN.getCode(); + } else if (payoffAmount.compareTo(BigDecimal.ZERO) < 0) { + gameStatus = GameStatus.FAIL.getCode(); + } + + + Platform platform = gamesDataBuildDTO.getPlatform(); + String systemCurrency = platform.getOurCurrency(resultBean.getCurrency()); + //数据构造 + GameBettingDetails gameBettingDetails = GameBettingDetails.builder() + .tenantKey(member.getTenantKey()) + //保存我们的币种id + .currencyCode(systemCurrency) + .memberId(member.getId()) + .gameCode(gamesDataDTO.getCode()) + .gameType(PlatformType.CARD_GAME.getCode()) + .platformCode(GamePlatforms.KM.getCode()) + .gameId(gamesDataDTO.getSystemGameId()) + .gameName(gamesDataDTO.getName()) + .gameStatus(gameStatus) + .gameStatusType(1) + .gameCurrencyCode(resultBean.getCurrency()) + .account(resultBean.getUserId()) + .wagersId(resultBean.getId()) + .wagersTime(resultBean.getBeton().getTime()) + .betAmount(resultBean.getRiskAmount().abs()) + .payoffTime(resultBean.getClosedon().getTime()) + .payoffAmount(payoffAmount.abs()) + .settlementTime(resultBean.getClosedon().getTime()) + .turnover(resultBean.getValidBet()) + .settlementStatus(SettlementStatusEnum.COMPLETED.getCode()) + .orderNo(resultBean.getExternalRoundId()) + .round(resultBean.getRoundId()) + .build(); + gameBettingDetails.setCreateBy(Constants.SYSTEM); + gameBettingDetails.setCreateTime(DateUtils.getNowDate()); + return gameBettingDetails; + } +} diff --git a/ff-game/src/main/java/com/ff/game/api/meitian/address/MeiTianAddressSource.java b/ff-game/src/main/java/com/ff/game/api/meitian/address/MeiTianAddressSource.java new file mode 100644 index 0000000..299414b --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/meitian/address/MeiTianAddressSource.java @@ -0,0 +1,29 @@ +package com.ff.game.api.meitian.address; + +import com.dtflys.forest.callback.AddressSource; +import com.dtflys.forest.http.ForestAddress; +import com.dtflys.forest.http.ForestRequest; +import com.ff.base.enums.GamePlatforms; +import com.ff.game.service.IPlatformService; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + + +/** + * @author shi + * @date 2025/02/10 + */ +@Component +public class MeiTianAddressSource implements AddressSource { + + @Resource + private IPlatformService platformService; + + @Override + public ForestAddress getAddress(ForestRequest request) { + String apiBaseUrl = platformService.get(GamePlatforms.MT.getCode()) + .getUrlInfo().getUrl(); + return new ForestAddress("https", apiBaseUrl, 443, "services"); + } +} \ No newline at end of file diff --git a/ff-game/src/main/java/com/ff/game/api/meitian/client/MeiTianClient.java b/ff-game/src/main/java/com/ff/game/api/meitian/client/MeiTianClient.java new file mode 100644 index 0000000..8f1fb3e --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/meitian/client/MeiTianClient.java @@ -0,0 +1,174 @@ +package com.ff.game.api.meitian.client; + +import com.dtflys.forest.annotation.Address; +import com.dtflys.forest.annotation.Post; +import com.dtflys.forest.annotation.Var; +import com.ff.game.api.km.dto.KMBalanceTransferStatusResponseDTO; +import com.ff.game.api.meitian.address.MeiTianAddressSource; +import com.ff.game.api.meitian.dto.*; + +/** + * jili 请求 + * + * @author shi + * @date 2025/02/10 + */ +@Address(source = MeiTianAddressSource.class) +public interface MeiTianClient { + + /** + * 创建会员 + * + * @param playerName + * @param merchantId + * @param pwd + * @return {@link MeiTianCreateMemberResponseDTO} + */ + @Post("/dg/player/playerCreate2/{playerName}/{merchantId}/{pwd}/{code}/{data}") + MeiTianCreateMemberResponseDTO createMember( + @Var("playerName") String playerName, + @Var("merchantId") String merchantId, + @Var("pwd") String pwd, + @Var("code") String code, + @Var("data") String data); + + /** + * 查询余额 + * + * @param playerName 用户名 + * @param merchantId 商户号 + * @return {@link MeiTianMemberInfoDTO} + */ + @Post("/dg/player/getPlayerBalance/{playerName}/{merchantId}") + MeiTianMemberInfoDTO getMemberInfo( + @Var("playerName") String playerName, + @Var("merchantId") String merchantId); + + /** + * 登录 + * + * @param merchantId 商户id + * @param playerName 玩家名 + * @return {@link MeiTianLoginResultDTO } + */ + @Post("/dg/player/playerPlatformUrl/{merchantId}/{playerName}/{pwd}/{code}/{data}") + MeiTianLoginResultDTO loginWithoutRedirect( + @Var("merchantId") String merchantId, + @Var("playerName") String playerName, + @Var("pwd") String pwd, + @Var("code") String code, + @Var("data") String data + ); + + + /** + * 转入 + * + * @param merchantId + * @param playerName + * @param coins + * @param extTransId + * @param code + * @param data + * @return {@link MeiTianExchangeMoneyResponseDTO} + */ + @Post("/dg/player/deposit2/{merchantId}/{playerName}/{coins}/{extTransId}/{code}/{data}") + MeiTianExchangeMoneyResponseDTO transferIn( + @Var("merchantId") String merchantId, + @Var("playerName") String playerName, + @Var("coins") String coins, + @Var("extTransId") String extTransId, + @Var("code") String code, + @Var("data") String data + ); + + + /** + * 转出 + * + * @param merchantId + * @param playerName + * @param coins + * @param extTransId + * @param code + * @param data + * @return {@link MeiTianExchangeMoneyResponseDTO} + */ + @Post("/dg/player/withdraw2/{merchantId}/{playerName}/{coins}/{extTransId}/{code}/{data}") + MeiTianExchangeMoneyResponseDTO transferOut( + @Var("merchantId") String merchantId, + @Var("playerName") String playerName, + @Var("coins") String coins, + @Var("extTransId") String extTransId, + @Var("code") String code, + @Var("data") String data + ); + + + /** + * 汇兑转移状态 + * + * @param merchantId 商户ID + * @param playerName 玩家姓名 + * @param coins 硬币 + * @return {@link MeiTianBalanceTransferStatusResponseDTO } + */ + @Post("dg/player/queryTransbyId/{playerName}/{merchantId}/{extTransId}") + MeiTianBalanceTransferStatusResponseDTO exchangeTransferStatus( + @Var("playerName") String merchantId, + @Var("merchantId") String playerName, + @Var("extTransId") String coins + ); + + /** + * 按recordId获取投注记录 + * + * @param merchantId 代理id + * @param data + * @return {@link MeiTianBetRecordResponseDTO } + */ + @Post(url = "/dg/player/queryMerchantGameRecord2/{merchantId}/{data}") + MeiTianBetRecordResponseDTO syncRecordByRecordID( + @Var("merchantId") String merchantId, + @Var("data") String data); + + /** + * 按照日期获取投注记录 + * + * @param merchantId + * @param data + * @return + */ + @Post(url = "/dg/player/queryMerchantGameRecord3/{merchantId}/{data}") + MeiTianBetRecordResponseDTO syncRecordByDate( + @Var("merchantId") String merchantId, + @Var("data") String data); + + /** + * 踢出 + * + * @param merchantId + * @param playerName + * @return {@link MeiTianLogoutDTO } + */ + @Post("/dg/player/logOutGame/{merchantId}/{playerName}") + MeiTianLogoutDTO kickMember( + @Var("merchantId") String merchantId, + @Var("playerName") String playerName + ); + + /** + * 获取游戏详情 + * + * @param merchantId + * @param code + * @param data + * @return {@link MeiTianGameRecordDetailDTO} + */ + @Post("/dg/player/playCheckUrl/{merchantId}/{code}/{data}") + MeiTianGameRecordDetailDTO getGameDetail( + @Var("merchantId") String merchantId, + @Var("code") String code, + @Var("data") String data + ); +} diff --git a/ff-game/src/main/java/com/ff/game/api/meitian/dto/MeiTianBalanceTransferStatusResponseDTO.java b/ff-game/src/main/java/com/ff/game/api/meitian/dto/MeiTianBalanceTransferStatusResponseDTO.java new file mode 100644 index 0000000..4c95d1c --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/meitian/dto/MeiTianBalanceTransferStatusResponseDTO.java @@ -0,0 +1,69 @@ +package com.ff.game.api.meitian.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.math.BigDecimal; + +/** + * 梅田余额转移状态响应dto + * + * @author shi + * @date 2025/04/08 + */ +@Data +public class MeiTianBalanceTransferStatusResponseDTO { + /** + * 响应结果代码 + */ + @JsonProperty("resultCode") + private Integer resultCode; + + /** + * 交易 ID + */ + @JsonProperty("transId") + private String transId; + + /** + * 交易时间,格式为 yyyy-MM-dd HH:mm:ss + */ + @JsonProperty("transTime") + private String transTime; + + /** + * 交易类型代码 + */ + @JsonProperty("transType") + private String transType; + + /** + * 交易金额 + */ + @JsonProperty("transCoins") + private BigDecimal transCoins; + + /** + * 当前余额 + */ + @JsonProperty("curBalance") + private BigDecimal curBalance; + + /** + * 时区信息,如:GMT+8 + */ + @JsonProperty("timeZone") + private String timeZone; + + /** + * 交易状态,1 表示成功 + */ + @JsonProperty("status") + private String status; + + /** + * 货币类型,如:CNY + */ + @JsonProperty("currency") + private String currency; +} diff --git a/ff-game/src/main/java/com/ff/game/api/meitian/dto/MeiTianBetRecordResponseDTO.java b/ff-game/src/main/java/com/ff/game/api/meitian/dto/MeiTianBetRecordResponseDTO.java new file mode 100644 index 0000000..bc50e57 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/meitian/dto/MeiTianBetRecordResponseDTO.java @@ -0,0 +1,77 @@ +package com.ff.game.api.meitian.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * 游戏纪录查询返回值 + * + * @author shi + * @date 2024/10/21 + */ +@NoArgsConstructor +@Data +public class MeiTianBetRecordResponseDTO { + + @JsonProperty("resultCode") + private int errorCode; + + @JsonProperty("transList") + private List dataList; + + @NoArgsConstructor + @Data + public static class DataBean { + @JsonProperty("rowID") + private String rowID; // 美天棋牌交易流水号 + @JsonProperty("playerName") + private String playerName; + @JsonProperty("gameDate") + private String gameDate; + @JsonProperty("gameCode") + private String gameCode; + @JsonProperty("period") + private String period; // 游戏局ID + @JsonProperty("betAmount") + private String betAmount; // 下注金额 + @JsonProperty("commissionable") + private String commissionable; // 有效投注量 + private String roomFee;// 房费 + private String income; // 赢得金额-下注金额-房费 + @JsonProperty("recordID") + private String recordID; // 游戏记录ID + private String gameType; // 游戏类型 1表示百人场,2表示对战,3表示捕鱼,4表示街机 + private String timeZone; // 时区 + private String currency; // 币种 + } + + @Getter + @AllArgsConstructor + public enum ResultMessage { + QueryException(0, "查询异常"), + QuerySuccess(1, "查询成功"), + MerchantNotExist(2, "商户不存在"), + MerchantInvalid(3, "商户无效"), + IPLimited(15, "IP被限制"), + OptionalParameterError(32, "可选参数错误"), + MaintenanceMode(40, "维护模式"), + Unknown(-1, "未知错误"), + ; + private final int code; + private final String message; + } + + public static ResultMessage get(int code) { + for (ResultMessage message : ResultMessage.values()) { + if (message.code == code) { + return message; + } + } + return ResultMessage.Unknown; + } +} diff --git a/ff-game/src/main/java/com/ff/game/api/meitian/dto/MeiTianCreateMemberResponseDTO.java b/ff-game/src/main/java/com/ff/game/api/meitian/dto/MeiTianCreateMemberResponseDTO.java new file mode 100644 index 0000000..61a81df --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/meitian/dto/MeiTianCreateMemberResponseDTO.java @@ -0,0 +1,46 @@ +package com.ff.game.api.meitian.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.Getter; + + +/** + * 创建成员响应dto + * + * @author shi + * @date 2024/10/22 + */ +@Data +public class MeiTianCreateMemberResponseDTO { + + /** + * 错误代码 + */ + @JsonProperty("resultCode") + private int resultCode; + + + @Getter + @AllArgsConstructor + public enum CreateMemberResultCode { + /** + * 成功 + */ + CreateException(0, "创建异常"), + CreateSuccess(1, "创建成功"), + MerchantNotExist(2, "商户不存在"), + MerchantInvalid(3, "商户无效"), + AlreadyRegistered(5, "商户用户已注册"), + IpLimit(15, "IP被限制"), + DecryptError(21, "解密错误"), + OptionalParameterError(32, "可选参数错误"), + Maintenance(40, "维护模式"), + ; + + private int code; + private String message; + + } +} diff --git a/ff-game/src/main/java/com/ff/game/api/meitian/dto/MeiTianExchangeMoneyResponseDTO.java b/ff-game/src/main/java/com/ff/game/api/meitian/dto/MeiTianExchangeMoneyResponseDTO.java new file mode 100644 index 0000000..c3a47b3 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/meitian/dto/MeiTianExchangeMoneyResponseDTO.java @@ -0,0 +1,118 @@ +package com.ff.game.api.meitian.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.Getter; + +import java.math.BigDecimal; + +/** + * jiliexchange货币回应 + * + * @author shi + * @date 2024/10/22 + */ +@Data +public class MeiTianExchangeMoneyResponseDTO { + + + /** + * 错误代码 + */ + @JsonProperty("resultCode") + private int errorCode; + /** + * 交易序号,额度转移纪录唯一值, 长度上限 50 + */ + @JsonProperty("transId") + private String transactionId; + + /** + * 币种 + */ + @JsonProperty("currency") + private String currency; + + /** + * 余额 + */ + @JsonProperty("curBalance") + private BigDecimal balance; + + /** + * 时区(商户时区) GMT+8 + */ + @JsonProperty("timezone") + private String timezone; + + /** + * 交易时间 2018-08-08 12:23:44 + */ + @JsonProperty("date") + private String date; + + @Getter + @AllArgsConstructor + public enum TransferIn { + // 提现异常 + WITHDRAW_ERROR(0, "充值异常"), + // 提现成功 + WITHDRAW_SUCCESS(1, "充值成功"), + MERCHANT_NOT_EXIST(2, "商户不存在"), + MERCHANT_INVALID(3, "商户无效"), + MERCHANT_USER_NOT_EXIST(4, "商户用户不存在"), + MERCHANT_USER_SYSTEM_DISABLED(6, "商户用户系统禁用"), + MERCHANT_USER_GOLD_BALANCE_INSUFFICIENT(9, "商户用户金币余额不足"), + GAME_NOT_SETTLED(12, "游戏未结算"), + IP_LIMIT(15, "IP被限制"), + DECRYPT_ERROR(21, "解密错误"), + OPTIONAL_PARAMETER_ERROR(32, "可选参数错误"), + EXIST_UNPROCESSED_ORDER(36, "存在未处理订单"), + MAINTENANCE(40, "维护模式"), + Unknown(-1, "未知");; + private int code; + private String message; + + + public static TransferIn get(int code) { + for (TransferIn resultMessage : TransferIn.values()) { + if (resultMessage.code == code) { + return resultMessage; + } + } + return Unknown; + } + } + + @Getter + @AllArgsConstructor + public enum TransferOut { + WITHDRAW_ERROR(0, "提现异常"), + WITHDRAW_SUCCESS(1, "提现成功"), + MERCHANT_NOT_EXIST(2, "商户不存在"), + MERCHANT_INVALID(3, "商户无效"), + MERCHANT_USER_NOT_EXIST(4, "商户用户不存在"), + MERCHANT_USER_SYSTEM_DISABLED(6, "商户用户系统禁用"), + MERCHANT_USER_GOLD_BALANCE_INSUFFICIENT(9, "商户用户金币余额不足"), + GAME_NOT_SETTLED(12, "游戏未结算"), + IP_LIMIT(15, "IP被限制"), + DECRYPT_ERROR(21, "解密错误"), + OPTIONAL_PARAMETER_ERROR(32, "可选参数错误"), + EXIST_UNPROCESSED_ORDER(36, "存在未处理订单"), + MAINTENANCE(40, "维护模式"), + Unknown(-1, "未知");; + private int code; + private String message; + + + public static TransferOut get(int code) { + for (TransferOut resultMessage : TransferOut.values()) { + if (resultMessage.code == code) { + return resultMessage; + } + } + return Unknown; + } + } +} diff --git a/ff-game/src/main/java/com/ff/game/api/meitian/dto/MeiTianGameDataDTO.java b/ff-game/src/main/java/com/ff/game/api/meitian/dto/MeiTianGameDataDTO.java new file mode 100644 index 0000000..45cccf1 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/meitian/dto/MeiTianGameDataDTO.java @@ -0,0 +1,31 @@ +package com.ff.game.api.meitian.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * jiligames数据dto + * + * @author shi + * @date 2024/10/22 + */ +@NoArgsConstructor +@Data +@Builder +@AllArgsConstructor +public class MeiTianGameDataDTO { + + + /** + *自己系统游戏id + */ + private String systemGameId; + private String gameId; + private String cnName; + private String enName; + private Integer gameCategoryId; + +} \ No newline at end of file diff --git a/ff-game/src/main/java/com/ff/game/api/meitian/dto/MeiTianGameRecordDetailDTO.java b/ff-game/src/main/java/com/ff/game/api/meitian/dto/MeiTianGameRecordDetailDTO.java new file mode 100644 index 0000000..c7d2bbd --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/meitian/dto/MeiTianGameRecordDetailDTO.java @@ -0,0 +1,51 @@ +package com.ff.game.api.meitian.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.Getter; +import lombok.NoArgsConstructor; + +/** + * 获取游戏详细信息请求dto + * + * @author shi + * @date 2024/11/12 + */ +@NoArgsConstructor +@Data +public class MeiTianGameRecordDetailDTO { + + @JsonProperty("resultCode") + private int errorCode; + + private String url; + private String currency; + + @Getter + @AllArgsConstructor + public enum ResultMessage { + QueryException(0, "查询异常"), + QuerySuccess(1, "查询成功"), + MerchantNotExist(2, "商户不存在"), + MerchantInvalid(3, "商户无效"), + IPLimited(15, "IP被限制"), + DecryptError(21, "解密错误"), + OptionalParameterError(32, "可选参数错误"), + MaintenanceMode(40, "维护模式"), + Unknown(-1, "未知错误"), + ; + private int code; + private String message; + } + + public static ResultMessage get(int code) { + for (ResultMessage resultMessage : ResultMessage.values()) { + if (resultMessage.getCode() == code) { + return resultMessage; + } + } + return ResultMessage.Unknown; + } + +} diff --git a/ff-game/src/main/java/com/ff/game/api/meitian/dto/MeiTianGamesDTO.java b/ff-game/src/main/java/com/ff/game/api/meitian/dto/MeiTianGamesDTO.java new file mode 100644 index 0000000..606febf --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/meitian/dto/MeiTianGamesDTO.java @@ -0,0 +1,171 @@ +package com.ff.game.api.meitian.dto; + +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * 游戏 + * + * @author shi + * @date 2024/10/22 + */ + +@NoArgsConstructor +@Data +public class MeiTianGamesDTO { + + // 捕鱼:3棋牌:2街机:4百人:1全部:0或不传 + private List data; + + { + data = new java.util.ArrayList<>(); + // 捕鱼游戏数据列表 + String[][] buyu = { + {"PTG0056", "3D捕鱼", "3D Fishing", "3"}, + {"PTG0011", "李逵劈鱼", "Fishing Kui Lee", "3"}, + {"PTG0045", "金蟾捕鱼", "Golden Toad", "3"}, + {"PTG0100", "海王2", "Ocean King 2", "3"}, + {"PTG0094", "疯狂捕鱼", "Crazy Fishing", "3"}, + {"PTG0004", "捕鱼来了", "Fishing Joy", "3"}, + {"PTG0104", "疯狂魔鬼城", "Trick or Treat", "3"}, + {"PTG0125", "水果炸翻天", "Fruits Carnival", "3"}, + }; + + addGames(buyu, data); + + // 棋牌游戏数据列表 + String[][] qipai = { + {"PTG0042", "五人牛牛", "Beat Bullfight", "2"}, + {"PTG0022", "通比牛牛", "Mutual Bullfight", "2"}, + {"PTG0013", "二人牛牛", "Versus Niu-Niu", "2"}, + {"PTG0039", "十三水", "Winning Thirteen", "2"}, + {"PTG0062", "炸金花", "Fraud Jinhua", "2"}, + {"PTG0037", "德州扑克", "Texas Hold'em", "2"}, + {"PTG0006", "欢乐斗地主", "Fight the Landlord", "2"}, + {"PTG0023", "黑杰克", "Black Jack", "2"}, + {"PTG0017", "二人梭哈", "Show Hand", "2"}, + {"PTG0080", "抢庄牌九", "Pai Gow", "2"}, + {"PTG0082", "三公", "3-card poker", "2"}, + {"PTG0061", "明牌牛牛", "Spread Bullfight", "2"}, + {"PTG0084", "土豪百家乐", "Rich Baccarat", "2"}, + {"PTG0085", "推筒子", "versus 2-8 bar", "2"}, + {"PTG0086", "二人雀神", "Versus Mahjong", "2"}, + {"PTG0093", "血流成河", "Rivers of Blood", "2"}, + {"PTG0110", "看牌牛牛", "Royal Bull-fight", "2"}, + {"PTG0121", "越式13张", "TIEN LEN", "2"}, + {"PTG0127", "UNO", "UNO", "2"}, + {"PTG0122", "Dummy", "Dummy", "2"}, + {"PTG0123", "九鸡", "Jiu-Ji", "2"}, // 未分类 + {"PTG0124", "博丁", "Bo-Ding", "2"}, // 未分类 + {"PTG0126", "牌肯", "Card Ken", "2"}, + {"PTG0133", "泰式十三支", "Thai 13 Cards", "2"}, + {"PTG0134", "泰九牌", "Gao Gae Thai", "2"}, + {"PTG0136", "Dummy Speto", "Dummy Speto", "2"}, + {"PTG0137", "Gao Gae Sam Bai Thod", "Gao Gae Sam Bai Thod", "2"}, + {"PTG0138", "Slave Card", "Slave Card", "2"} + }; + addGames(qipai, data); + + // 百人场游戏数据列表 + String[][] bairenchang = { + {"PTG0058", "红黑大战", "King's Queen", "1"}, + {"PTG0044", "百人牛牛", "Hundred Niu-Niu", "1"}, + {"PTG0059", "百家乐", "Baccarat", "1"}, + {"PTG0008", "豪车漂移", "Drift Car Racing", "-1"}, // 未分类 + {"PTG0041", "龙虎斗", "The Chinese Boxer", "1"}, + {"PTG0007", "飞禽走兽", "Fowls and Beasts", "-1"}, // 未分类 + {"PTG0036", "五星宏辉", "Five Star Stud", "1"}, + {"PTG0064", "金鲨银鲨", "Golden Shark", "1"}, + {"PTG0020", "西游争霸", "Journey to the West", "1"}, + {"PTG0018", "港式赛马", "Horse Racing", "-1"}, // 未分类 + {"PTG0070", "二八杠", "2-8 Bar", "-1"}, // 未分类 + {"PTG0081", "骰宝", "Sic bo", "1"}, + {"PTG0067", "森林舞会", "Forest Party", "-1"}, // 未分类 + {"PTG0091", "鱼虾蟹", "Crab and Shrimp", "1"}, + {"PTG0092", "红包扫雷", "Minesweeping", "-1"}, // 未分类 + {"PTG0089", "动物跑跑跑", "Animal Running", "-1"}, // 未分类 + {"PTG0116", "越式鱼虾蟹", "Vietnamese Fish-Prawn-Crab", "-1"}, // 未分类 + {"PTG0102", "正版抢车位", "GA Car Parking", "-1"}, // 未分类 + {"PTG0120", "番摊", "FAN TAN", "1"}, + {"PTG2008", "西游争霸战无不胜", "Monkey King2 PLUS", "-1"}, // 未分类 + {"PTG0135", "泰式鱼虾蟹", "Thai Fish Prawn Crab", "-1"} // 未分类 + }; + addGames(bairenchang, data); + + // 街机游戏数据列表 + String[][] dianzi = { + {"PTG0060", "超级大亨", "Super Tycoon", "4"}, + {"PTG0069", "ATT金皇冠", "ATT Gold Crown", "4"}, + {"PTG0001", "水果机", "Super Frootz", "4"}, + {"PTG0010", "水浒传", "The Water Margin", "4"}, + {"PTG0066", "大满贯水果机", "Grand Slam Frootz", "4"}, + {"PTG0068", "泰山闯天关2", "Tarzan Adventure 2", "4"}, + {"PTG0083", "财神到", "Mammon", "4"}, + {"PTG0079", "不倒翁", "Happy tumbler", "4"}, + {"PTG0087", "醉西游", "Monkey King", "4"}, + {"PTG0090", "延禧攻略", "Story of Yanxi Palace", "4"}, + {"PTG0095", "连环夺宝", "Linking Jewels", "4"}, + {"PTG0098", "三只小猪", "Three Little Pigs", "4"}, + {"PTG0097", "招财猫", "Fortune Cat", "4"}, + {"PTG0099", "欲望魅影", "Sexy Succubus", "4"}, + {"PTG0096", "绝地求生", "Playerunknown's Battlegrounds", "4"}, + {"PTG0101", "埃及艳后", "Cleopatra's treasures", "4"}, + {"PTG0103", "年年有鱼", "Lucky boy", "4"}, + {"PTG0105", "天空之神", "God of Sky", "4"}, + {"PTG0107", "阿拉丁神灯", "PLUS ALADDIN'S GOLD", "4"}, + {"PTG0109", "武媚娘传奇", "Empress Wu Zetian", "4"}, + {"PTG0106", "亿万富翁", "Billionaire", "4"}, + {"PTG0115", "萝卜跳一跳", "Jump Hot", "4"}, + {"PTG0117", "宫心计", "Beyond The Realm Of Conscience", "4"}, + {"PTG2001", "恭喜发财", "Good Fortune", "4"}, + {"PTG2002", "新潘金莲", "Pan Jinlian", "4"}, + {"PTG2003", "宫本武藏", "Miyamoto Musashi", "4"}, + {"PTG2004", "武则天", "Empress of the Great Tang", "4"}, + {"PTG2005", "发发发", "Fa Fa Fa", "4"}, + {"PTG2007", "赏金船长", "Captain's Bounty", "4"}, + {"PTG2009", "爱尔兰精灵", "Leprechaun Riches", "4"}, + {"PTG2010", "水浒传豪华版", "Water Margin DELUXE", "4"}, + {"PTG2011", "金钱豹水果机", "Golden Jaguar", "4"}, + {"PTG0118", "疯狂猴子", "Crazy Monkey", "4"}, + {"PTG2015", "金刚", "King Kong", "4"}, + {"PTG2016", "福星献舞", "Dancing FU", "4"}, + {"PTG2017", "野蛮世界", "HUGA", "4"}, + {"PTG2018", "上海甜心", "Shanghai Honey", "4"}, + {"PTG2019", "美洲野牛", "Buffalo Gold", "4"}, + {"PTG2020", "白蛇传", "The Legend of White Snake", "4"}, + {"PTG2021", "笑弥勒", "Happys Prosperous", "4"}, + {"PTG2013", "招财推币机", "Fortune Coindozer", "4"}, + {"PTG2025", "东海之王", "Dragon Of The Eastern Ocean", "4"}, + {"PTG2028", "中国龙", "Dragon World", "4"}, + {"PTG2023", "秦皇传说", "Legend of Emperor Qin", "4"}, + {"PTG2026", "辣椒多多", "More Chilli", "4"}, + {"PTG2029", "财神驾到", "CHOY SUN DOA", "4"}, + {"PTG2030", "招财猫2", "Fortune Cat 2", "4"}, + {"PTG2031", "黄金城魅影", "Gold City Treasure Hunt", "4"}, + {"PTG2032", "亡灵宝藏", "WILD BANDITO", "4"}, + {"PTG2033", "麒麟献宝", "WAYS OF THE QILIN", "4"}, + {"PTG2034", "天将神兵", "Heavenly Warriors", "4"} + }; + + addGames(dianzi, data); + + } + + public void addGames(String[][] gameData, List dataList) { + // 添加数据到 List + for (String[] game : gameData) { + String gameId = game[0]; + String cnName = game[1]; + String enName = game[2]; + Integer categoryId = Integer.valueOf(game[3]); + dataList.add(MeiTianGameDataDTO.builder().gameId(gameId) + .cnName(cnName) + .enName(enName) + .gameCategoryId(categoryId) + .build()); + } + + } +} diff --git a/ff-game/src/main/java/com/ff/game/api/meitian/dto/MeiTianLoginResultDTO.java b/ff-game/src/main/java/com/ff/game/api/meitian/dto/MeiTianLoginResultDTO.java new file mode 100644 index 0000000..cea3089 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/meitian/dto/MeiTianLoginResultDTO.java @@ -0,0 +1,52 @@ +package com.ff.game.api.meitian.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.Getter; +import lombok.NoArgsConstructor; + +/** + * 登录时不重定向响应dto + * + * @author shi + * @date 2024/10/22 + */ +@NoArgsConstructor +@Data +public class MeiTianLoginResultDTO { + + @JsonProperty("resultCode") + private int errorCode; + @JsonProperty("url") + private String url; + + @Getter + @AllArgsConstructor + public enum ResultMessage { + LoginException(0, "登录异常"), + LoginSuccess(1, "登录成功"), + MerchantNotExist(2, "商户不存在"), + MerchantInvalid(3, "商户无效"), + MerchantUserNotExist(4, "商户用户不存在"), + MerchantUserSystemDisabled(6, "商户用户系统禁用"), + PasswordError(7, "密码错误"), + IPLimited(15, "IP被限制"), + DecryptError(21, "解密错误"), + MerchantUserLoginDisabled(22, "商户用户登录禁用"), + OptionalParameterError(32, "可选参数错误"), + MaintenanceMode(40, "维护模式"), + Unknown(-1, "未知错误"); + private int code; + private String message; + } + + public static ResultMessage get(int errorCode) { + for (ResultMessage resultMessage : ResultMessage.values()) { + if (resultMessage.getCode() == errorCode) { + return resultMessage; + } + } + return ResultMessage.Unknown; + } +} diff --git a/ff-game/src/main/java/com/ff/game/api/meitian/dto/MeiTianLogoutDTO.java b/ff-game/src/main/java/com/ff/game/api/meitian/dto/MeiTianLogoutDTO.java new file mode 100644 index 0000000..103321c --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/meitian/dto/MeiTianLogoutDTO.java @@ -0,0 +1,43 @@ +package com.ff.game.api.meitian.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@NoArgsConstructor +@Data +public class MeiTianLogoutDTO { + + @JsonProperty("resultCode") + private int errorCode; + + + @Getter + @AllArgsConstructor + public enum ResultMessage { + QueryException(0, "查询异常"), + QuerySuccess(1, "查询成功"), + MerchantNotExist(2, "商户不存在"), + MerchantInvalid(3, "商户无效"), + MerchantUserNotExist(4, "商户用户不存在"), + MerchantUserSystemDisabled(6, "商户用户系统禁用"), + MerchantUserGameOnline(12, "商户用户游戏在线"), + IPLimited(15, "IP被限制"), + MaintenanceMode(40, "维护模式"), + Unknown(-1, "未知错误") + ,; + private int code; + private String message; + } + + public static ResultMessage get(int errorCode) { + for (ResultMessage resultMessage : ResultMessage.values()) { + if (resultMessage.code == errorCode) { + return resultMessage; + } + } + return ResultMessage.Unknown; + } +} diff --git a/ff-game/src/main/java/com/ff/game/api/meitian/dto/MeiTianMemberInfoDTO.java b/ff-game/src/main/java/com/ff/game/api/meitian/dto/MeiTianMemberInfoDTO.java new file mode 100644 index 0000000..c28eea2 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/meitian/dto/MeiTianMemberInfoDTO.java @@ -0,0 +1,69 @@ +package com.ff.game.api.meitian.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.Getter; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; + +/** + * 会员信息dto + * + * @author shi + * @date 2024/10/30 + */ +@NoArgsConstructor +@Data +public class MeiTianMemberInfoDTO { + + /** + * 错误代码 + */ + @JsonProperty("resultCode") + private int errorCode; + /** + * 余额 + */ + @JsonProperty("coinBalance") + private BigDecimal balance; + + @JsonProperty("status") + private Integer status; + + @JsonProperty("currency") + private String currency; + + + @Getter + @AllArgsConstructor + public enum ResultMessage { + Excep(0,"查询异常"), + Success(1,"查询成功"), + // 商户不存在 + MerchantNotExist(2,"商户不存在"), + // 商户无效 + MerchantInvalid(3,"商户无效"), + // 商户用户不存在 + AccountNotExist(4,"商户用户不存在"), + // IP被限制 + IpLimit(15,"IP被限制"), + // 维护模式 + Maintenance(40,"维护模式"), + + Unknown(-1, "未知") + ,; + private int code; + private String message; + + public static ResultMessage getResultMessage(int code) { + for (ResultMessage resultMessage : ResultMessage.values()) { + if (resultMessage.code == code) { + return resultMessage; + } + } + return Unknown; + } + } +} diff --git a/ff-game/src/main/java/com/ff/game/api/meitian/impl/MeiTianGameServiceImpl.java b/ff-game/src/main/java/com/ff/game/api/meitian/impl/MeiTianGameServiceImpl.java new file mode 100644 index 0000000..22cb71f --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/meitian/impl/MeiTianGameServiceImpl.java @@ -0,0 +1,831 @@ +package com.ff.game.api.meitian.impl; + +import cn.hutool.core.codec.Base64; +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.NumberUtil; +import com.alibaba.fastjson2.JSON; +import com.ff.base.constant.CacheConstants; +import com.ff.base.constant.Constants; +import com.ff.base.core.redis.RedisCache; +import com.ff.base.enums.*; +import com.ff.base.exception.base.ApiException; +import com.ff.base.exception.base.BaseException; +import com.ff.base.system.service.impl.SysConfigServiceImpl; +import com.ff.base.utils.DateUtils; +import com.ff.base.utils.StringUtils; +import com.ff.base.utils.sign.Md5Utils; +import com.ff.base.utils.uuid.IdUtils; +import com.ff.delay.DelayService; +import com.ff.delay.DelayTask; +import com.ff.game.api.IGamesService; +import com.ff.game.api.meitian.client.MeiTianClient; +import com.ff.game.api.meitian.dto.*; +import com.ff.game.api.request.*; +import com.ff.game.domain.*; +import com.ff.game.service.IGameBettingDetailsService; +import com.ff.game.service.IGameExchangeMoneyService; +import com.ff.game.service.IGameService; +import com.ff.member.domain.Member; +import com.ff.member.service.IMemberService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.Assert; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ObjectUtils; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.nio.charset.StandardCharsets; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.*; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + + +/** + * 游戏数据解析服务 + * + * @author shi + * @date 2024/10/21 + */ +@Service("MTService") +@Slf4j +public class MeiTianGameServiceImpl implements IGamesService { + + @Resource + private RedisCache redisCache; + + @Resource + private IGameExchangeMoneyService gameExchangeMoneyService; + + @Resource + private IGameService gameService; + + + @Resource + private IMemberService memberService; + + @Resource + private MeiTianClient meiTianClient; + + @Resource + private IGameBettingDetailsService gameBettingDetailsService; + + @Autowired + private SysConfigServiceImpl sysConfigServiceImpl; + + @Autowired + private DelayService delayService; + + /** + * 获得就是成功 + * + * @param errorCode 错误代码 + * @return {@link Boolean } + */ + private Boolean isSuccess(Integer errorCode) { + return 1 == errorCode; + } + + /** + * 创建成员 + * + * @param createMemberRequestDTO 创建成员请求dto + * @return {@link Boolean } + */ + @Override + public Boolean createMember(CreateMemberRequestDTO createMemberRequestDTO) { + + String playerName = createMemberRequestDTO.getAccount(); + String merchantId = createMemberRequestDTO.getAgentId(); + String md5Password = Md5Utils.md5New(createMemberRequestDTO.getKeyInfo().getPassword()); + Map rawMap = new LinkedHashMap<>(); + rawMap.put("nickname", createMemberRequestDTO.getAccount()); + rawMap.put("playerLevel", "0"); + String rawData = JSON.toJSONString(rawMap); + String data = null; + try { + data = Base64.encode(rawData.getBytes(StandardCharsets.UTF_8)); + } catch (Exception e) { + log.error("[MeiTian] encode rawData failure", e); + throw new ApiException(ErrorCode.ERROR.getCode()); + } + String md5Code = Md5Utils.md5New(createMemberRequestDTO.getKeyInfo().getKey() + rawData);//MD5(key+rawData); + MeiTianCreateMemberResponseDTO createMemberResponseDTO = + meiTianClient.createMember( + playerName, + merchantId, + md5Password, + md5Code, + data); + int errorCode = createMemberResponseDTO.getResultCode(); + log.info("[MeiTian]创建会员失败返回结果:{}", errorCode); + if (1 == errorCode) { + return Boolean.TRUE; + } + if (5 == errorCode) { + throw new ApiException(ErrorCode.GAME_ACCOUNT_CREATION_FAILED.getCode()); + } + //判断是否获取成功 + return Boolean.FALSE; + } + + + /** + * 获取会员信息 + * + * @param memberInfoRequestDTO 会员信息请求dto + * @return {@link MemberInfoResponseDTO } + */ + @Override + public MemberInfoResponseDTO getMemberInfo(MemberInfoRequestDTO memberInfoRequestDTO) { + + String playerName = memberInfoRequestDTO.getAccounts(); + String merchantId = memberInfoRequestDTO.getAgentId(); + MeiTianMemberInfoDTO memberInfoDTO = meiTianClient.getMemberInfo(playerName, merchantId); + //判断是否获取成功 + if (this.isSuccess(memberInfoDTO.getErrorCode())) { + return MemberInfoResponseDTO.builder() + .status(GameMemberStatus.UNKNOWN.getCode()) + .balance(memberInfoDTO.getBalance()) + .account(playerName) + .build(); + } else { + throw new BaseException(MeiTianMemberInfoDTO.ResultMessage.getResultMessage(memberInfoDTO.getErrorCode()).getMessage()); + } + } + + /** + * 无重定向登录 + * + * @param gamesLogin 游戏登录 + * @return {@link String } + */ + @Override + public String loginWithoutRedirect(GamesLogin gamesLogin) { + + String merchantId = gamesLogin.getAgentId(); + String playerName = gamesLogin.getAccount(); + String md5Password = Md5Utils.md5New(gamesLogin.getKeyInfo().getPassword()); + Map rawMap = new LinkedHashMap<>(); + /*rawMap.put("gameHall ", gamesLogin.getGameType());*/ + rawMap.put("gameCode", gamesLogin.getGameId()); + rawMap.put("lang", gamesLogin.getLang()); + rawMap.put("roomID", "0"); + + String rawData = JSON.toJSONString(rawMap); + String data = null; + try { + data = Base64.encode(rawData.getBytes(StandardCharsets.UTF_8)); + } catch (Exception e) { + log.error("[MeiTian] encode rawData failure", e); + throw new ApiException(ErrorCode.ERROR.getCode()); + } + String code = Md5Utils.md5New(gamesLogin.getKeyInfo().getKey() + rawData); + MeiTianLoginResultDTO loginWithoutRedirectResponseDTO = + meiTianClient.loginWithoutRedirect( + merchantId, + playerName, + md5Password, + code, + data + ); + //判断是否获取成功 + if (this.isSuccess(loginWithoutRedirectResponseDTO.getErrorCode())) { + return loginWithoutRedirectResponseDTO.getUrl(); + } else { + throw new BaseException(MeiTianLoginResultDTO.get(loginWithoutRedirectResponseDTO.getErrorCode()).getMessage()); + } + + } + + /** + * 获取游戏列表 + * + * @param gamesBaseRequestDTO 游戏请求dto + * @return {@link String } + */ + @Transactional + @Override + public String getGameList(GamesBaseRequestDTO gamesBaseRequestDTO) { + + List gamesDatas = redisCache.getCacheList(CacheConstants.MeiTian_GAMES); + if (!CollectionUtils.isEmpty(gamesDatas)) { + return CacheConstants.MeiTian_GAMES; + } + + MeiTianGamesDTO gameList = new MeiTianGamesDTO(); + + for (MeiTianGameDataDTO gamesDataDTO : gameList.getData()) { + Integer platformType = MeiTianGameType.findSystemByCode(gamesDataDTO.getGameCategoryId()); + Game game = Game.builder() + .platformCode(GamePlatforms.MT.getCode()) + .platformType(platformType) + .gameCode(String.valueOf(gamesDataDTO.getGameId())) + .build(); + List games = gameService.selectGameList(game); + //不存在这个游戏 + if (CollectionUtils.isEmpty(games)) { + game.setGameSourceType(String.valueOf(gamesDataDTO.getGameCategoryId())); + game.setFreespin(false); + game.setSortNo(gameService.selectMaxSortNo(platformType, GamePlatforms.MT.getCode()) + 1); + game.setGameName(gamesDataDTO.getCnName()); + game.setCreateBy(Constants.SYSTEM); + game.setPlatformType(platformType); + game.setPlatformCode(GamePlatforms.MT.getCode()); + game.setGameId(StringUtils.addSuffix(GamePlatforms.MT.getCode(), gamesDataDTO.getGameId())); + List nameInfos = new ArrayList<>(); + nameInfos.add(new NameInfo(gamesDataDTO.getCnName(), "zh-CN")); + nameInfos.add(new NameInfo(gamesDataDTO.getEnName(), "en-US")); + game.setNameInfo(nameInfos); + gameService.insertGame(game); + } else { + game = games.get(0); + List nameInfos = new ArrayList<>(); + nameInfos.add(new NameInfo(gamesDataDTO.getCnName(), "zh-CN")); + nameInfos.add(new NameInfo(gamesDataDTO.getEnName(), "en-US")); + game.setNameInfo(nameInfos); + gameService.updateGame(game); + } + gamesDataDTO.setSystemGameId(game.getGameId()); + } + + redisCache.deleteObject(CacheConstants.MeiTian_GAMES); + redisCache.setCacheList(CacheConstants.MeiTian_GAMES, gameList.getData()); + redisCache.expire(CacheConstants.MeiTian_GAMES, 5L, TimeUnit.HOURS); + + return CacheConstants.MeiTian_GAMES; + } + + + /** + * 获取交易id + * + * @param transactionIdRequestDTO 事务id请求dto + * @return {@link String } + */ + @Override + public String getTransactionId(TransactionIdRequestDTO transactionIdRequestDTO) { + return GamePlatforms.MT.getCode() + IdUtils.simpleUUID(); + } + /** + * 按代理id进行交换转账 + * + * @param exchangeTransferMoneyRequestDTO 外汇转账moeny dto + * @return {@link Long } + */ + @Override + @Transactional + public Long exchangeTransferByAgentId(ExchangeTransferMoneyRequestDTO exchangeTransferMoneyRequestDTO) { + + Member member = memberService.selectMemberByGameAccount(exchangeTransferMoneyRequestDTO.getAccount()); + GameExchangeMoney exchangeMoney = gameExchangeMoneyService.selectGameExchangeMoneyById(exchangeTransferMoneyRequestDTO.getGameExchangeId()); + + + + + String key = exchangeTransferMoneyRequestDTO.getAgentKey(); + String merchantId = exchangeTransferMoneyRequestDTO.getAgentId(); + String playerName = exchangeTransferMoneyRequestDTO.getAccount(); + String coins = exchangeTransferMoneyRequestDTO.getAmount().setScale(4, RoundingMode.DOWN).toString(); + if (exchangeTransferMoneyRequestDTO.getTransferType().equals(TransferType.ALL.getCode())) { + MemberInfoRequestDTO gamesBaseRequestDTO = MemberInfoRequestDTO.builder() + .accounts(member.getGameAccount()) + .agentId(exchangeTransferMoneyRequestDTO.getAgentId()) + .currency(exchangeTransferMoneyRequestDTO.getCurrency()) + .agentKey(exchangeTransferMoneyRequestDTO.getAgentKey()) + .build(); + coins = this.getMemberInfo(gamesBaseRequestDTO).getBalance().setScale(4, RoundingMode.DOWN).toString(); + } + + Map rawMap = new LinkedHashMap<>(); + rawMap.put("merchantId", merchantId); + rawMap.put("playerName", playerName); + rawMap.put("extTransId", exchangeTransferMoneyRequestDTO.getTransactionId()); + rawMap.put("coins", coins); + String rawData = JSON.toJSONString(rawMap); + String data = null; + try { + data = Base64.encode(rawData.getBytes(StandardCharsets.UTF_8)); + } catch (Exception e) { + log.error("[MeiTian] base64 rawData failure", e); + throw new ApiException(ErrorCode.BALANCE_TRANSFER_FAILED.getCode()); + } + String md5Code = Md5Utils.md5New(key + rawData); + // 转入到游戏商 type == 2 + if (exchangeTransferMoneyRequestDTO.getTransferType().equals(TransferType.GAMES.getCode())) { + + MeiTianExchangeMoneyResponseDTO exchangeMoneyResponse = meiTianClient + .transferIn( + merchantId, + playerName, + coins, + exchangeTransferMoneyRequestDTO.getTransactionId(), + md5Code, + data + ); + + //判断是否转移成功 + if (this.isSuccess(exchangeMoneyResponse.getErrorCode())) { + //更新数据 + BigDecimal transAmount = new BigDecimal(coins); + exchangeMoney.setBalance(transAmount); + + exchangeMoney.setCoinBefore(exchangeMoneyResponse.getBalance().subtract(transAmount)); + exchangeMoney.setCoinAfter(exchangeMoneyResponse.getBalance()); + exchangeMoney.setCurrencyBefore(exchangeMoneyResponse.getBalance().subtract(transAmount)); + exchangeMoney.setCurrencyAfter(exchangeMoneyResponse.getBalance()); + exchangeMoney.setStep(GameExchangeStep.PLATFORM_TRANSACTION.getCode()); + exchangeMoney.setStepStatus(GameExchangeStepStatus.SUCCESS.getCode()); + gameExchangeMoneyService.updateGameExchangeMoney(exchangeMoney); + + } else { + exchangeMoney.setStep(GameExchangeStep.PLATFORM_TRANSACTION.getCode()); + exchangeMoney.setStepStatus(GameExchangeStepStatus.FAILURE.getCode()); + gameExchangeMoneyService.updateGameExchangeMoney(exchangeMoney); + throw new BaseException(MeiTianExchangeMoneyResponseDTO.TransferIn.get(exchangeMoneyResponse.getErrorCode()).getMessage()); + } + + } else { + + MeiTianExchangeMoneyResponseDTO exchangeMoneyResponse = meiTianClient + .transferOut( + merchantId, + playerName, + coins, + exchangeTransferMoneyRequestDTO.getTransactionId(), + md5Code, + data + ); + + //判断是否转移成功 + if (this.isSuccess(exchangeMoneyResponse.getErrorCode())) { + //更新数据 + BigDecimal transAmount = new BigDecimal(coins); + exchangeMoney.setBalance(transAmount); + + exchangeMoney.setCoinBefore(exchangeMoneyResponse.getBalance().add(transAmount)); + exchangeMoney.setCoinAfter(exchangeMoneyResponse.getBalance()); + exchangeMoney.setCurrencyBefore(exchangeMoneyResponse.getBalance().add(transAmount)); + exchangeMoney.setCurrencyAfter(exchangeMoneyResponse.getBalance()); + exchangeMoney.setStep(GameExchangeStep.PLATFORM_TRANSACTION.getCode()); + exchangeMoney.setStepStatus(GameExchangeStepStatus.SUCCESS.getCode()); + gameExchangeMoneyService.updateGameExchangeMoney(exchangeMoney); + } else { + exchangeMoney.setStep(GameExchangeStep.PLATFORM_TRANSACTION.getCode()); + exchangeMoney.setStepStatus(GameExchangeStepStatus.FAILURE.getCode()); + gameExchangeMoneyService.updateGameExchangeMoney(exchangeMoney); + throw new BaseException(MeiTianExchangeMoneyResponseDTO.TransferOut.get(exchangeMoneyResponse.getErrorCode()).getMessage()); + } + } + return exchangeMoney.getId(); + } + + /** + * 汇兑转移状态 + * + * @param exchangeTransferMoneyRequestDTO 兑换转账请求dto + * @return {@link Boolean } + */ + @Override + public ExchangeTransferStatusResponseDTO exchangeTransferStatus(ExchangeTransferStatusRequestDTO exchangeTransferMoneyRequestDTO) { + log.info("MeiTianGameServiceImpl [exchangeTransferStatus] 请求参数 {}", exchangeTransferMoneyRequestDTO); + + + String merchantId = exchangeTransferMoneyRequestDTO.getAgentId(); + String playerName = exchangeTransferMoneyRequestDTO.getAccount(); + + MeiTianBalanceTransferStatusResponseDTO meiTianBalanceTransferStatusResponseDTO = meiTianClient.exchangeTransferStatus( + playerName, + merchantId, + exchangeTransferMoneyRequestDTO.getOrderId() + ); + Integer status = StatusType.IN_PROGRESS.getValue(); + if (this.isSuccess(meiTianBalanceTransferStatusResponseDTO.getResultCode()) && "1".equals(meiTianBalanceTransferStatusResponseDTO.getStatus())) { + status = StatusType.SUCCESS.getValue(); + } else { + status = StatusType.FAILURE.getValue(); + } + return ExchangeTransferStatusResponseDTO.builder() + .statusType(status) + .balance(meiTianBalanceTransferStatusResponseDTO.getTransCoins()) + .coinBefore(NumberUtil.sub(meiTianBalanceTransferStatusResponseDTO.getTransCoins(), meiTianBalanceTransferStatusResponseDTO.getCurBalance()).abs()) + .coinAfter(meiTianBalanceTransferStatusResponseDTO.getCurBalance()) + .build(); + } + + + class GetRecordByTimeTask extends DelayTask { + + BetRecordByTimeDTO betRecordByTimeDTO; + + public GetRecordByTimeTask(BetRecordByTimeDTO betRecordByTimeDTO) { + this.betRecordByTimeDTO = betRecordByTimeDTO; + } + + @Override + public void execute() { + doSyncRecordByRecordID(betRecordByTimeDTO); + } + } + + class GetRecordByHistoryTimeTask extends DelayTask { + + BetRecordByTimeDTO betRecordByTimeDTO; + + public GetRecordByHistoryTimeTask(BetRecordByTimeDTO betRecordByTimeDTO) { + this.betRecordByTimeDTO = betRecordByTimeDTO; + } + + @Override + public void execute() { + doSyncRecordByDate(betRecordByTimeDTO, 1); + } + } + + /** + * 按时间获取投注记录 + * + * @param betRecordByTimeDTO 按时间dto投注记录 + * @return {@link Boolean } + */ + @Override + public Boolean getBetRecordByTime(BetRecordByTimeDTO betRecordByTimeDTO) { + delayService.addTask(new GetRecordByTimeTask(betRecordByTimeDTO)); + return Boolean.TRUE; + //return doSyncRecordByRecordID(betRecordByTimeDTO); + } + + boolean doSyncRecordByRecordID(BetRecordByTimeDTO betRecordByTimeDTO) { + String configKey = GamePlatforms.MT.getCode() + ":lastSyncRecordID"; + Long recordID = redisCache.getCacheObject(configKey); + + //String lastRecordID = sysConfigServiceImpl.selectConfigByKey(configKey); + /*if (lastRecordID == null || lastRecordID.isEmpty()) { + + } else { + recordID = Long.parseLong(lastRecordID); + }*/ + String merchantId = betRecordByTimeDTO.getAgentId(); + Map rawMap = new LinkedHashMap<>(); + rawMap.put("recordID", recordID); + String rawData = JSON.toJSONString(rawMap); + String data = null; + try { + data = Base64.encode(rawData.getBytes(StandardCharsets.UTF_8)); + } catch (Exception e) { + log.error("[MeiTian] base64 rawData failure", e); + throw new ApiException(ErrorCode.ERROR.getCode()); + } + + //获取key + MeiTianBetRecordResponseDTO recordResponse = + meiTianClient.syncRecordByRecordID(merchantId, data); + + //判断是否获取成功 + if (this.isSuccess(recordResponse.getErrorCode())) { + List dataList = recordResponse.getDataList(); + if (CollectionUtils.isEmpty(dataList)) { + return Boolean.TRUE; + } + //数据插入 + this.batchInsert(recordResponse, betRecordByTimeDTO); + MeiTianBetRecordResponseDTO.DataBean dataBean = dataList.get(dataList.size() - 1); + redisCache.setCacheObject(configKey, Long.parseLong(dataBean.getRowID())); + + /*SysConfig config = sysConfigServiceImpl.getByConfigKey(configKey); + if (config == null) { + config = new SysConfig(); + config.setConfigKey(configKey); + config.setConfigValue(dataBean.getRecordID()); + sysConfigServiceImpl.insertConfig(config); + } else { + config.setConfigValue(dataBean.getRecordID()); + sysConfigServiceImpl.updateConfig(config); + }*/ + // 它每次返回25000条,所以需要判断,如果大于25000条,则继续拉取 + if (dataList.size() >= 25000) { + doSyncRecordByRecordID(betRecordByTimeDTO); + } + } else { + log.error("[MeiTian] syncRecordByRecordID failure, errorCode:{}", recordResponse.getErrorCode()); + return Boolean.FALSE; + } + return Boolean.TRUE; + } + + boolean doSyncRecordByDate(BetRecordByTimeDTO betRecordByTimeDTO, int daysToSubtract) { + + String date = getDateStr(daysToSubtract); + String configKey = GamePlatforms.MT.getCode() + ":lastSyncDate"; + long recordID = redisCache.getCacheObject(configKey); + String merchantId = betRecordByTimeDTO.getAgentId(); + Map rawMap = new LinkedHashMap<>(); + rawMap.put("rowID", recordID); + rawMap.put("startTime", date); + rawMap.put("endTime", date); + String rawData = JSON.toJSONString(rawMap); + String data = null; + try { + data = Base64.encode(rawData.getBytes(StandardCharsets.UTF_8)); + } catch (Exception e) { + log.error("[MeiTian] base64 rawData failure", e); + throw new ApiException(ErrorCode.ERROR.getCode()); + } + + //获取key + MeiTianBetRecordResponseDTO recordResponse = + meiTianClient.syncRecordByDate(merchantId, data); + + //判断是否获取成功 + if (this.isSuccess(recordResponse.getErrorCode())) { + List dataList = recordResponse.getDataList(); + if (CollectionUtils.isEmpty(dataList)) { + return Boolean.TRUE; + } + //数据插入 + this.batchInsert(recordResponse, betRecordByTimeDTO); + MeiTianBetRecordResponseDTO.DataBean dataBean = dataList.get(dataList.size() - 1); + //syncDateMap.put(date, Long.parseLong(dataBean.getRowID())); + redisCache.setCacheObject(configKey, Long.parseLong(dataBean.getRowID())); + /*SysConfig config = sysConfigServiceImpl.getByConfigKey(configKey); + if (null == config) { + config = new SysConfig(); + config.setConfigKey(configKey); + config.setConfigValue(JSON.toJSONString(syncDateMap)); + sysConfigServiceImpl.insertConfig(config); + } else { + config.setConfigValue(JSON.toJSONString(syncDateMap)); + sysConfigServiceImpl.updateConfig(config); + }*/ + + // 它每次返回25000条,所以需要判断,如果大于25000条,则继续拉取 + if (dataList.size() >= 25000) { + doSyncRecordByDate(betRecordByTimeDTO, daysToSubtract); + } + } else { + log.error("[MeiTian] syncRecordByDate error, errorCode:{}", recordResponse.getErrorCode()); + return Boolean.FALSE; + } + return Boolean.TRUE; + } + + /** + * 按历史时间获取投注记录 + * + * @param betRecordByTimeDTO 按时间dto投注记录 + * @return {@link Boolean } + */ + @Override + public Boolean getBetRecordByHistoryTime(BetRecordByTimeDTO betRecordByTimeDTO) { + //doSyncRecordByDate(betRecordByTimeDTO, 0); + //doSyncRecordByDate(betRecordByTimeDTO, 1); // yesterday + + delayService.addTask(new GetRecordByHistoryTimeTask(betRecordByTimeDTO)); + return true; + } + + + /** + * 赠送免费局数 + * + * @param createFreeSpinRequest 创建自由旋转请求 + * @return {@link Boolean } + */ + @Override + public Boolean createFreeSpin(CreateFreeSpinRequestDTO createFreeSpinRequest) { + throw new BaseException("暂不支持免费局数"); + } + + /** + * 获取游戏详细信息 + * + * @param getGameDetailRequestDTO 获取游戏详细信息请求dto + * @return {@link GetGameDetailResponseDTO } + */ + @Override + public GetGameDetailResponseDTO getGameDetail(GetGameDetailRequestDTO getGameDetailRequestDTO) { + + String key = getGameDetailRequestDTO.getKeyInfo().getKey(); + String merchantId = getGameDetailRequestDTO.getAgentId(); + Map rawMap = new LinkedHashMap<>(); + rawMap.put("rowID", getGameDetailRequestDTO.getWagersId()); + rawMap.put("lang", getGameDetailRequestDTO.getLang()); + + String rawData = JSON.toJSONString(rawMap); + String data = null; + try { + data = Base64.encode(rawData.getBytes(StandardCharsets.UTF_8)); + } catch (Exception e) { + log.error("[MeiTian] encode rawData failure", e); + throw new ApiException(ErrorCode.ERROR.getCode()); + } + String code = Md5Utils.md5New(key + rawData); + MeiTianGameRecordDetailDTO responseDTO = meiTianClient.getGameDetail(merchantId, code, data); + + //判断是否获取成功 + if (this.isSuccess(responseDTO.getErrorCode())) { + GetGameDetailResponseDTO getGameDetailResponseDTO = new GetGameDetailResponseDTO(); + getGameDetailResponseDTO.setUrl(responseDTO.getUrl()); + return getGameDetailResponseDTO; + } else { + throw new BaseException(MeiTianGameRecordDetailDTO.get(responseDTO.getErrorCode()).getMessage()); + } + } + + /** + * 强制会员从游戏注销 + * + * @param kickMemberRequestDTO 踢会员请求dto + * @return {@link Boolean } + */ + @Override + public Boolean kickMember(KickMemberRequestDTO kickMemberRequestDTO) { + + String merchantId = kickMemberRequestDTO.getAgentId(); + String playerName = kickMemberRequestDTO.getAccount(); + + MeiTianLogoutDTO jiliKickMemberDTO = meiTianClient.kickMember( + merchantId, + playerName); + //判断是否获取成功 + if (this.isSuccess(jiliKickMemberDTO.getErrorCode())) { + return Boolean.TRUE; + } else { + throw new BaseException(MeiTianLogoutDTO.get(jiliKickMemberDTO.getErrorCode()).getMessage()); + + } + } + + /** + * 踢成员全部 + * + * @param kickMemberAllDTO 踢成员全部dto + * @return {@link Boolean } + */ + @Override + public Boolean kickMemberAll(KickMemberAllDTO kickMemberAllDTO) { + throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); + } + + /** + * 免费游戏玩家使用的纪录 + * + * @param getFreeSpinDashflowRequestDTO 获取自由旋转dashflow请求dto + * @return {@link List }<{@link GameFreeRecord }> + */ + @Override + public List getFreeSpinDashflow(GetFreeSpinDashflowRequestDTO getFreeSpinDashflowRequestDTO) { + throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); + } + + /** + * 取消赠送免费局数 + * + * @param cancelFreeSpinRequestDTO 取消免费旋转请求 + * @return {@link Boolean } + */ + @Override + public Boolean cancelFreeSpin(CancelFreeSpinRequestDTO cancelFreeSpinRequestDTO) { + throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); + } + + /** + * 游戏演示登录 + * + * @param gameDemoLoginRequestDTO 游戏演示登录请求dto + * @return {@link GameDemoLoginResponseDTO } + */ + @Override + public GameDemoLoginResponseDTO gameDemoLogin(GameDemoLoginRequestDTO gameDemoLoginRequestDTO) { + throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); + } + + + /** + * 批量插入 + * + * @param recordResponse 投注记录 + */ + private void batchInsert(MeiTianBetRecordResponseDTO recordResponse, BetRecordByTimeDTO betRecordByTimeDTO) { + List gameBettingDetails = new ArrayList<>(); + List wagersIds = new ArrayList<>(); + //数据组装 + List dataList = recordResponse.getDataList(); + if (CollectionUtils.isEmpty(dataList)) { + return; + } + + //数据转化 + for (MeiTianBetRecordResponseDTO.DataBean dataBean : dataList) { + GameBettingDetails bettingDetails = this.dataBuild(GamesDataBuildDTO.builder() + .platform(betRecordByTimeDTO.getVendor()) + .data(dataBean).build()); + if (!ObjectUtils.isEmpty(bettingDetails)) { + bettingDetails.setId(IdUtil.getSnowflakeNextId()); + gameBettingDetails.add(bettingDetails); + } + wagersIds.add(dataBean.getRowID()); + } + if (!CollectionUtils.isEmpty(gameBettingDetails)) { + //查询重复数据id + List removeWagersIds = gameBettingDetailsService.selectGameBettingDetailsByWagersId(wagersIds, GamePlatforms.MT.getCode()); + //用steam流清除list中与wagersIds集合相同的数据 + gameBettingDetails = gameBettingDetails.stream() + .filter(detail -> !removeWagersIds.contains(detail.getWagersId())) + .collect(Collectors.toList()); + if (!CollectionUtils.isEmpty(gameBettingDetails)) { + gameBettingDetailsService.batchInsert(gameBettingDetails); + } + } + + } + + /** + * 数据构建 + * + * @param gamesDataBuildDTO 数据 + * @return {@link GameBettingDetails } + */ + @Override + public GameBettingDetails dataBuild(GamesDataBuildDTO gamesDataBuildDTO) { + + //转化类 + MeiTianBetRecordResponseDTO.DataBean dataBean = (MeiTianBetRecordResponseDTO.DataBean) gamesDataBuildDTO.getData(); +// GameSecretKeyCurrencyDTO gameSecretKey = +// gameSecretKeyCurrencyService.findByGameSecretKeyCurrencyDTO(GameSecretKeyCurrencyDTO.builder() +// .currency(dataBean.getCurrency()) +// .platformCode(GamePlatforms.MT.getCode()).build()); + + + Member member = memberService.selectMemberByGameAccount(dataBean.getPlayerName()); + if (ObjectUtils.isEmpty(member)) { + return null; + } + List gameDatas = redisCache.getCacheList(CacheConstants.MeiTian_GAMES); + Map dataDTOMap = gameDatas.stream().collect(Collectors.toMap(MeiTianGameDataDTO::getGameId, e -> e)); + MeiTianGameDataDTO gamesDataDTO = dataDTOMap.get(dataBean.getGameCode()); + BigDecimal originPayoffAmount = new BigDecimal(dataBean.getIncome()); // 这个值是到手的 + + int compareResult = originPayoffAmount.compareTo(BigDecimal.ZERO); + long gameTime = getTime(dataBean.getGameDate()); + Platform platform = gamesDataBuildDTO.getPlatform(); + String systemCurrency = platform.getOurCurrency(dataBean.getCurrency()); + //数据构造 + GameBettingDetails gameBettingDetails = GameBettingDetails.builder() + .tenantKey(member.getTenantKey()) + //保存我们的币种id + .currencyCode(systemCurrency) + .memberId(member.getId()) + .gameCode(dataBean.getGameCode()) + .gameType(MeiTianGameType.findSystemByCode(Integer.parseInt(dataBean.getGameType()))) + .platformCode(GamePlatforms.MT.getCode()) + .gameId(gamesDataDTO.getSystemGameId()) + .gameName(gamesDataDTO.getCnName()) + .gameStatus(compareResult > 0 ? GameStatus.WIN.getCode() : compareResult < 0 ? GameStatus.FAIL.getCode() : GameStatus.FLAT.getCode()) + .gameStatusType(1) // 一般下注 + .gameCurrencyCode(dataBean.getCurrency()) + .account(dataBean.getPlayerName()) + .wagersId(dataBean.getRowID()) + .wagersTime(gameTime) + .betAmount(new BigDecimal(dataBean.getBetAmount())) + .payoffTime(gameTime) + .payoffAmount(originPayoffAmount.abs()) + .settlementTime(gameTime) + .turnover(new BigDecimal(dataBean.getCommissionable())) + .orderNo(dataBean.getRowID()) + .settlementStatus(SettlementStatusEnum.COMPLETED.getCode()) + .build(); + gameBettingDetails.setCreateBy(Constants.SYSTEM); + gameBettingDetails.setCreateTime(DateUtils.getNowDate()); + return gameBettingDetails; + } + + public long getTime(String date) { + SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + try { + Date parse = simpleDateFormat.parse(date); + return parse.getTime(); + } catch (ParseException e) { + return System.currentTimeMillis(); + } + } + + public String getDateStr(int daysToSubtract) { + // 获取当前日期减去指定天数 + LocalDate date = LocalDate.now().minusDays(daysToSubtract); + + // 定义日期格式 + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + + // 返回格式化日期字符串 + return date.format(formatter); + } + +} diff --git a/ff-game/src/main/java/com/ff/game/api/ng/address/MyNGAddressSource.java b/ff-game/src/main/java/com/ff/game/api/ng/address/MyNGAddressSource.java index 7f1a0d0..3a6b35a 100644 --- a/ff-game/src/main/java/com/ff/game/api/ng/address/MyNGAddressSource.java +++ b/ff-game/src/main/java/com/ff/game/api/ng/address/MyNGAddressSource.java @@ -3,22 +3,23 @@ package com.ff.game.api.ng.address; import com.dtflys.forest.callback.AddressSource; import com.dtflys.forest.http.ForestAddress; import com.dtflys.forest.http.ForestRequest; -import com.ff.base.constant.Constants; -import com.ff.base.system.service.ISysConfigService; +import com.ff.base.enums.GamePlatforms; +import com.ff.game.service.IPlatformService; import org.springframework.stereotype.Component; import javax.annotation.Resource; @Component -public class MyNGAddressSource implements AddressSource { +public class MyNGAddressSource implements AddressSource { @Resource - private ISysConfigService configService; + private IPlatformService platformService; @Override public ForestAddress getAddress(ForestRequest request) { - String apiBaseUrl = configService.selectConfigByKey(Constants.NG_API_BASE_URL); - return new ForestAddress("https",apiBaseUrl, 443,"api"); + String apiBaseUrl = platformService.get(GamePlatforms.PG.getCode()) + .getUrlInfo().getUrl(); + return new ForestAddress("https", apiBaseUrl, 443, "api"); } } diff --git a/ff-game/src/main/java/com/ff/game/api/ng/dto/ApiGameInfoResponseDTO.java b/ff-game/src/main/java/com/ff/game/api/ng/dto/ApiGameInfoResponseDTO.java index b4e75db..1e31c30 100644 --- a/ff-game/src/main/java/com/ff/game/api/ng/dto/ApiGameInfoResponseDTO.java +++ b/ff-game/src/main/java/com/ff/game/api/ng/dto/ApiGameInfoResponseDTO.java @@ -37,5 +37,5 @@ public class ApiGameInfoResponseDTO { /** * 系统游戏id */ - private Long systemGameId; + private String systemGameId; } diff --git a/ff-game/src/main/java/com/ff/game/api/ng/service/impl/GamesPGServiceImpl.java b/ff-game/src/main/java/com/ff/game/api/ng/service/impl/GamesPGServiceImpl.java index 8b71e88..8109635 100644 --- a/ff-game/src/main/java/com/ff/game/api/ng/service/impl/GamesPGServiceImpl.java +++ b/ff-game/src/main/java/com/ff/game/api/ng/service/impl/GamesPGServiceImpl.java @@ -2,7 +2,6 @@ package com.ff.game.api.ng.service.impl; import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.NumberUtil; -import com.ff.base.config.RedisConfig; import com.ff.base.constant.CacheConstants; import com.ff.base.constant.Constants; import com.ff.base.core.redis.RedisCache; @@ -11,22 +10,21 @@ import com.ff.base.exception.base.ApiException; import com.ff.base.exception.base.BaseException; import com.ff.base.system.service.ISysConfigService; import com.ff.base.utils.DateUtils; -import com.ff.base.utils.JsonUtil; import com.ff.base.utils.SleepUtil; import com.ff.base.utils.StringUtils; import com.ff.base.utils.sign.Md5Utils; import com.ff.base.utils.uuid.IdUtils; import com.ff.config.KeyConfig; import com.ff.game.api.IGamesService; -import com.ff.game.api.jili.dto.*; import com.ff.game.api.ng.client.NGClient; import com.ff.game.api.ng.dto.*; import com.ff.game.api.request.*; -import com.ff.game.api.xk.dto.XKBetRecordResponseDTO; -import com.ff.game.api.xk.dto.XKGamesDTO; import com.ff.game.domain.*; -import com.ff.game.dto.*; -import com.ff.game.service.*; +import com.ff.game.dto.GameBettingDetailsDTO; +import com.ff.game.dto.GameDTO; +import com.ff.game.service.IGameBettingDetailsService; +import com.ff.game.service.IGameExchangeMoneyService; +import com.ff.game.service.IGameService; import com.ff.member.domain.Member; import com.ff.member.service.IMemberService; import lombok.extern.slf4j.Slf4j; @@ -42,15 +40,12 @@ import org.springframework.util.ObjectUtils; import javax.annotation.Resource; import java.math.BigDecimal; import java.security.SecureRandom; -import java.text.SimpleDateFormat; import java.time.Instant; import java.time.ZoneId; -import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; import java.util.*; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.Function; import java.util.stream.Collectors; @@ -74,11 +69,6 @@ public class GamesPGServiceImpl implements IGamesService { @Resource private IGameExchangeMoneyService gameExchangeMoneyService; - - @Resource - private IGamePlatformService gamePlatformService; - - @Resource private IGameService gameService; @@ -86,33 +76,15 @@ public class GamesPGServiceImpl implements IGamesService { @Resource private IMemberService memberService; - @Resource - private IGameFreeRecordService gameFreeRecordService; - - @Resource - private IGameSecretKeyService gameSecretKeyService; - @Resource private NGClient ngClient; - @Resource private KeyConfig keyConfig; @Resource private IGameBettingDetailsService gameBettingDetailsService; - @Resource - private IGameSecretKeyCurrencyService gameSecretKeyCurrencyService; - - @Resource - private IGameNameService gameNameService; - - - @Resource - private IGameSecretKeyLangService gameSecretKeyLangService; - - @Autowired @Qualifier("threadPoolTaskExecutor") private ThreadPoolTaskExecutor threadPoolTaskExecutor; @@ -228,7 +200,7 @@ public class GamesPGServiceImpl implements IGamesService { paramsMap.put("lang", gamesLogin.getLang()); paramsMap.put("gameCode", gamesLogin.getGameId()); paramsMap.put("returnUrl", gamesLogin.getHomeUrl()); - paramsMap.put("ingress", PlatformHomeType.WEB.getValue().equals(gamesLogin.getPlatform()) ? IngressType.PC_WEB.getValue() : IngressType.MOBILE_WEB.getValue()); + paramsMap.put("ingress", PlatformHomeType.WEB.getValue().equals(gamesLogin.getVendor()) ? IngressType.PC_WEB.getValue() : IngressType.MOBILE_WEB.getValue()); Map headerMap = this.getKey(gamesLogin); ApiNGResponseDTO apiLoginResponseDTOApiNGResponseDTO = ngClient.loginWithoutRedirect(paramsMap, headerMap); if (this.getIsSuccess(apiLoginResponseDTOApiNGResponseDTO.getCode())) { @@ -261,22 +233,10 @@ public class GamesPGServiceImpl implements IGamesService { ApiNGResponseDTO> gameList = ngClient.getGameList(paramsMap, headerMap); if (this.getIsSuccess(gameList.getCode())) { for (ApiGameInfoResponseDTO apiGameInfoResponseDTO : gameList.getData()) { - GamePlatform gamePlatform = GamePlatform.builder() - .platformType(NGGameType.findSystemByCode(apiGameInfoResponseDTO.getGameType())) - .platformCode(GamePlatforms.PG.getCode()) - .build(); - List gamePlatforms = gamePlatformService.selectGamePlatformList(gamePlatform); - //没有此平台就新增一个平台 - if (CollectionUtils.isEmpty(gamePlatforms)) { - gamePlatform.setPlatformName(GamePlatforms.PG.getInfo() + NGGameType.findInfoByCode(apiGameInfoResponseDTO.getGameType())); - gamePlatform.setSortNo(gamePlatformService.selectMaxSortNo() + 1); - gamePlatform.setCreateBy(Constants.SYSTEM); - gamePlatformService.insertGamePlatform(gamePlatform); - } else { - gamePlatform = gamePlatforms.get(0); - } + Integer platformType = NGGameType.findSystemByCode(apiGameInfoResponseDTO.getGameType()); Game game = Game.builder() - .platformId(gamePlatform.getId()) + .platformCode(GamePlatforms.PG.getCode()) + .platformType(platformType) .gameCode(apiGameInfoResponseDTO.getGameCode()) .build(); List games = gameService.selectGameList(game); @@ -285,40 +245,28 @@ public class GamesPGServiceImpl implements IGamesService { game.setGameSourceType(String.valueOf(apiGameInfoResponseDTO.getGameType())); game.setFreespin(Boolean.FALSE); game.setDemoStatus(Boolean.TRUE); - game.setSortNo(gameService.selectMaxSortNoByPlatformId(gamePlatform.getId()) + 1); + game.setSortNo(gameService.selectMaxSortNo(platformType, GamePlatforms.PG.getCode()) + 1); game.setGameName(apiGameInfoResponseDTO.getGameName().get("zh-hans")); game.setCreateBy(Constants.SYSTEM); + game.setPlatformCode(GamePlatforms.PG.getCode()); + game.setPlatformType(platformType); + game.setGameId(StringUtils.addSuffix(GamePlatforms.PG.getCode(), apiGameInfoResponseDTO.getGameCode())); + List nameInfos = new ArrayList<>(); + nameInfos.add(new NameInfo(apiGameInfoResponseDTO.getGameName().get("zh-hans"), "zh-CN")); + nameInfos.add(new NameInfo(apiGameInfoResponseDTO.getGameName().get("zh-hant"), "zh-TW")); + nameInfos.add(new NameInfo(apiGameInfoResponseDTO.getGameName().get("en"), "en-US")); + game.setNameInfo(nameInfos); gameService.insertGame(game); } else { game = games.get(0); + List nameInfos = new ArrayList<>(); + nameInfos.add(new NameInfo(apiGameInfoResponseDTO.getGameName().get("zh-hans"), "zh-CN")); + nameInfos.add(new NameInfo(apiGameInfoResponseDTO.getGameName().get("zh-hant"), "zh-TW")); + nameInfos.add(new NameInfo(apiGameInfoResponseDTO.getGameName().get("en"), "en-US")); + game.setNameInfo(nameInfos); + gameService.updateGame(game); } - apiGameInfoResponseDTO.setSystemGameId(game.getId()); - Map gameName = apiGameInfoResponseDTO.getGameName(); - for (String key : gameName.keySet()) { - String name = gameName.get(key); - List gameNames = gameNameService.selectGameNameList(GameName.builder().gameId(game.getId()).gameName(name).build()); - if (CollectionUtils.isEmpty(gameNames)) { - if ("zh-hans".equals(key)) { - gameNameService.insertGameName(GameName.builder() - .gameId(game.getId()) - .gameName(name) - .langCode("zh-CN") - .createBy(Constants.SYSTEM) - .build()); - } else if (!"zh-hant".equals(key)) { - GameSecretKeyLangDTO gameSecretKeyLangDTO = gameSecretKeyLangService.findGameSecretKeyLangDTO(GameSecretKeyLangDTO.builder() - .platformCode(GamePlatforms.PG.getCode()) - .lang(key) - .build()); - gameNameService.insertGameName(GameName.builder() - .gameId(game.getId()) - .gameName(name) - .langCode(gameSecretKeyLangDTO.getSystemLangCode()) - .createBy(Constants.SYSTEM) - .build()); - } - } - } + apiGameInfoResponseDTO.setSystemGameId(game.getGameId()); } @@ -332,6 +280,19 @@ public class GamesPGServiceImpl implements IGamesService { return CacheConstants.PG_GAMES; } + /** + * 获取交易id + * + * @param transactionIdRequestDTO 事务id请求dto + * @return {@link String } + */ + @Override + public String getTransactionId(TransactionIdRequestDTO transactionIdRequestDTO) { + return gameExchangeMoneyService.getTransactionId(GamePlatforms.PG.getCode(), 32); + } + + + /** * 按代理id进行交换转账 * @@ -343,60 +304,38 @@ public class GamesPGServiceImpl implements IGamesService { public Long exchangeTransferByAgentId(ExchangeTransferMoneyRequestDTO exchangeTransferMoneyRequestDTO) { log.info("GamesNGServiceImpl [exchangeTransferByAgentId] 请求参数 {}", exchangeTransferMoneyRequestDTO); - GameSecretKeyCurrency currencyDTO = gameSecretKeyCurrencyService.findByGameSecretKeyCurrencyDTO(GameSecretKeyCurrencyDTO.builder() - .platformCode(GamePlatforms.PG.getCode()) - .code(exchangeTransferMoneyRequestDTO.getAgentId()) - .currency(exchangeTransferMoneyRequestDTO.getCurrency()) - .build()); - Member member = memberService.selectMemberByGameAccount(exchangeTransferMoneyRequestDTO.getAccount()); - String transactionId = gameExchangeMoneyService.getTransactionId(GamePlatforms.PG.getCode(), 32); - List gameExchangeMonies = gameExchangeMoneyService.selectGameExchangeMoneyList( - GameExchangeMoney.builder() - .tenantKey(exchangeTransferMoneyRequestDTO.getTenantKey()) - .orderId(exchangeTransferMoneyRequestDTO.getOrderId()) - .build() - ); - Assert.isTrue(CollectionUtils.isEmpty(gameExchangeMonies), "订单号重复"); + GameExchangeMoney exchangeMoney = gameExchangeMoneyService.selectGameExchangeMoneyById(exchangeTransferMoneyRequestDTO.getGameExchangeId()); + - //获取下一个自增id - GameExchangeMoney exchangeMoney = GameExchangeMoney - .builder() - .tenantKey(exchangeTransferMoneyRequestDTO.getTenantKey()) - .orderId(exchangeTransferMoneyRequestDTO.getOrderId()) - .quota(exchangeTransferMoneyRequestDTO.getQuota()) - .balance(exchangeTransferMoneyRequestDTO.getAmount()) - .exchangeType(exchangeTransferMoneyRequestDTO.getTransferType()) - .currencyCode(currencyDTO.getSystemCurrency()) - .memberId(member.getId()) - .transactionId(transactionId) - .platformCode(GamePlatforms.PG.getCode()) - .build(); - exchangeMoney.setCreateBy(Constants.SYSTEM); //获取余额 String type = TransferType.ALL.getCode().equals(exchangeTransferMoneyRequestDTO.getTransferType()) ? NGTransferType.TRANSFER_OUT.getValue() : NGTransferType.TRANSFER_IN.getValue(); //获取当前游戏币 MemberInfoRequestDTO gamesBaseRequestDTO = MemberInfoRequestDTO.builder() - .accounts(member.getGameAccount()) + .accounts(exchangeTransferMoneyRequestDTO.getAccount()) .agentId(exchangeTransferMoneyRequestDTO.getAgentId()) .agentKey(exchangeTransferMoneyRequestDTO.getAgentKey()) - .currency(currencyDTO.getCurrency()) + .currency(exchangeTransferMoneyRequestDTO.getCurrency()) .build(); - MemberInfoResponseDTO memberInfo = this.getMemberInfo(gamesBaseRequestDTO); + //判断是不是转出 if (NGTransferType.TRANSFER_OUT.getValue().equals(type)) { + MemberInfoResponseDTO memberInfo = this.getMemberInfo(gamesBaseRequestDTO); exchangeTransferMoneyRequestDTO.setAmount(memberInfo.getBalance()); + if (exchangeTransferMoneyRequestDTO.getAmount().compareTo(BigDecimal.ZERO) <= 0) { + throw new ApiException(ErrorCode.INSUFFICIENT_PLAYER_BALANCE.getCode()); + } } Map paramsMap = new HashMap<>(); paramsMap.put("platType", NGPlatforms.PG.getCode()); paramsMap.put("playerId", exchangeTransferMoneyRequestDTO.getAccount()); - paramsMap.put("currency", currencyDTO.getCurrency()); + paramsMap.put("currency", exchangeTransferMoneyRequestDTO.getCurrency()); paramsMap.put("type", type); paramsMap.put("amount", exchangeTransferMoneyRequestDTO.getAmount()); - paramsMap.put("orderId", transactionId); + paramsMap.put("orderId", exchangeTransferMoneyRequestDTO.getTransactionId()); Map key = this.getKey(exchangeTransferMoneyRequestDTO); @@ -404,16 +343,27 @@ public class GamesPGServiceImpl implements IGamesService { if (this.getIsSuccess(apiNGResponseDTO.getCode())) { //更新数据 exchangeMoney.setBalance(exchangeTransferMoneyRequestDTO.getAmount()); - exchangeMoney.setStatus(StatusType.IN_PROGRESS.getValue()); - gameExchangeMoneyService.insertGameExchangeMoney(exchangeMoney); + exchangeMoney.setStep(GameExchangeStep.PLATFORM_TRANSACTION.getCode()); + exchangeMoney.setStepStatus(GameExchangeStepStatus.SUCCESS.getCode()); + gameExchangeMoneyService.updateGameExchangeMoney(exchangeMoney); ExchangeTransferStatusRequestDTO exchangeTransferStatusRequestDTO = new ExchangeTransferStatusRequestDTO(); exchangeTransferStatusRequestDTO.setAccount(exchangeTransferMoneyRequestDTO.getAccount()); - exchangeTransferStatusRequestDTO.setCurrency(currencyDTO.getCurrency()); - exchangeTransferStatusRequestDTO.setOrderId(transactionId); + exchangeTransferStatusRequestDTO.setCurrency(exchangeTransferMoneyRequestDTO.getCurrency()); + exchangeTransferStatusRequestDTO.setOrderId(exchangeTransferMoneyRequestDTO.getTransactionId()); exchangeTransferStatusRequestDTO.setAgentId(exchangeTransferMoneyRequestDTO.getAgentId()); exchangeTransferStatusRequestDTO.setAgentKey(exchangeTransferMoneyRequestDTO.getAgentKey()); - this.exchangeTransferStatus(exchangeTransferStatusRequestDTO); + ExchangeTransferStatusResponseDTO statusResponseDTO = this.exchangeTransferStatus(exchangeTransferStatusRequestDTO); + //更新钱 + exchangeMoney.setBalance(statusResponseDTO.getBalance()); + exchangeMoney.setCoinBefore(statusResponseDTO.getCoinBefore()); + exchangeMoney.setCoinAfter(statusResponseDTO.getCoinAfter()); + exchangeMoney.setCurrencyBefore(exchangeMoney.getCoinBefore()); + exchangeMoney.setCurrencyAfter(exchangeMoney.getCoinAfter()); + gameExchangeMoneyService.updateGameExchangeMoney(exchangeMoney); } else { + exchangeMoney.setStep(GameExchangeStep.PLATFORM_TRANSACTION.getCode()); + exchangeMoney.setStepStatus(GameExchangeStepStatus.FAILURE.getCode()); + gameExchangeMoneyService.updateGameExchangeMoney(exchangeMoney); log.error("GamesPGServiceImpl [exchangeTransferByAgentId] 金额转移失败,错误代码{},错误信息{}", apiNGResponseDTO.getCode(), apiNGResponseDTO.getMsg()); throw new BaseException(apiNGResponseDTO.getMsg()); } @@ -427,8 +377,9 @@ public class GamesPGServiceImpl implements IGamesService { * @return {@link Boolean } */ @Override - public Boolean exchangeTransferStatus(ExchangeTransferStatusRequestDTO exchangeTransferMoneyRequestDTO) { + public ExchangeTransferStatusResponseDTO exchangeTransferStatus(ExchangeTransferStatusRequestDTO exchangeTransferMoneyRequestDTO) { + SleepUtil.sleep(1000); Map paramsMap = new HashMap<>(); paramsMap.put("playerId", exchangeTransferMoneyRequestDTO.getAccount()); @@ -436,32 +387,24 @@ public class GamesPGServiceImpl implements IGamesService { paramsMap.put("orderId", exchangeTransferMoneyRequestDTO.getOrderId()); Map key = this.getKey(exchangeTransferMoneyRequestDTO); ApiNGResponseDTO apiNGResponseDTO = ngClient.exchangeTransferStatus(paramsMap, key); + Integer status = StatusType.IN_PROGRESS.getValue(); if (this.getIsSuccess(apiNGResponseDTO.getCode())) { - ApiExchangeTransferStatusResponseDTO apiNGResponseDTOData = apiNGResponseDTO.getData(); - List gameExchangeMonies = gameExchangeMoneyService.selectGameExchangeMoneyList( - GameExchangeMoney.builder() - .platformCode(GamePlatforms.PG.getCode()) - .transactionId(exchangeTransferMoneyRequestDTO.getOrderId()) - .build() - ); - - for (GameExchangeMoney exchangeMoney : gameExchangeMonies) { - //更新数据 - exchangeMoney.setBalance(apiNGResponseDTOData.getAmount().abs()); - exchangeMoney.setCoinBefore(NumberUtil.sub(apiNGResponseDTOData.getAfterBalance(), apiNGResponseDTOData.getAmount())); - exchangeMoney.setCoinAfter(apiNGResponseDTOData.getAfterBalance()); - exchangeMoney.setCurrencyBefore(exchangeMoney.getCoinBefore()); - exchangeMoney.setCurrencyAfter(exchangeMoney.getCoinAfter()); - exchangeMoney.setStatus(apiNGResponseDTOData.getStatus()); - gameExchangeMoneyService.updateGameExchangeMoney(exchangeMoney); - } - return Boolean.TRUE; + status = StatusType.SUCCESS.getValue(); } else { - log.error("GamesPGServiceImpl [exchangeTransferStatus]错误代码{},错误信息{}", apiNGResponseDTO.getCode(), apiNGResponseDTO.getMsg()); - return Boolean.FALSE; + status = StatusType.FAILURE.getValue(); + } + ExchangeTransferStatusResponseDTO transferStatusResponseDTO = ExchangeTransferStatusResponseDTO.builder() + .statusType(status) + .build(); + ApiExchangeTransferStatusResponseDTO apiNGResponseDTOData = apiNGResponseDTO.getData(); + if (!ObjectUtils.isEmpty(apiNGResponseDTOData)) { + transferStatusResponseDTO.setBalance(apiNGResponseDTOData.getAmount().abs()); + transferStatusResponseDTO.setCoinBefore(NumberUtil.sub(apiNGResponseDTOData.getAmount(), apiNGResponseDTOData.getAfterBalance()).abs()); + transferStatusResponseDTO.setCoinAfter(apiNGResponseDTOData.getAfterBalance()); } + return transferStatusResponseDTO; } @@ -474,19 +417,13 @@ public class GamesPGServiceImpl implements IGamesService { @Override public Boolean getBetRecordByTime(BetRecordByTimeDTO betRecordByTimeDTO) { - GameSecretKeyCurrencyDTO gameSecretKeyDTO = new GameSecretKeyCurrencyDTO(); - gameSecretKeyDTO.setPlatformCodes(NGPlatforms.getAllPlatforms()); - List currencyDTOList = gameSecretKeyCurrencyService.findByGameSecretKeyCurrencyDTOList(gameSecretKeyDTO); - List currencys = currencyDTOList.stream() - .map(GameSecretKeyCurrencyDTO::getCurrency) - .distinct() - .collect(Collectors.toList()); - + Platform platform = betRecordByTimeDTO.getVendor(); Set cacheSet = redisCache.getCacheSet(CacheConstants.PG_GAMES_BET_CURRENCY); if (CollectionUtils.isEmpty(cacheSet)) { cacheSet = new HashSet<>(); } + List currencys = new ArrayList<>(platform.getCurrencyInfo().values()); //如果长度一致则清空缓存循环币种 if (cacheSet.size() >= currencys.size()) { cacheSet = new HashSet<>(); @@ -497,22 +434,17 @@ public class GamesPGServiceImpl implements IGamesService { String firstCurrency = currencys.get(0); - GameSecretKeyCurrencyDTO currencyDTO = gameSecretKeyCurrencyService.findByGameSecretKeyCurrencyDTO(GameSecretKeyCurrencyDTO.builder() - .platformCode(GamePlatforms.PG.getCode()) - .currency(firstCurrency) - .build()); - - betRecordByTimeDTO.setAgentId(currencyDTO.getCode()); - betRecordByTimeDTO.setAgentKey(currencyDTO.getKey()); int pageNo = 1; int pageSize = 2000; Map paramsMap = new HashMap<>(); - paramsMap.put("currency", currencyDTO.getCurrency()); + paramsMap.put("currency", /*currencyDTO.getCurrency()*/ firstCurrency); paramsMap.put("pageNo", pageNo); paramsMap.put("pageSize", pageSize); Map key = this.getKey(betRecordByTimeDTO); + String systemCurrency = platform.getOurCurrency(firstCurrency); + ApiNGResponseDTO betRecordByTime = ngClient.getBetRecordByTime(paramsMap, key); @@ -526,7 +458,7 @@ public class GamesPGServiceImpl implements IGamesService { ApiGameBetRecordPageResponseDTO data = result.getData(); //数据组装 - this.batchInsert(data); + this.batchInsert(data, systemCurrency, firstCurrency); //总页数 // 计算总页数,确保不会遗漏 @@ -537,19 +469,19 @@ public class GamesPGServiceImpl implements IGamesService { pageNoAtomic.incrementAndGet(); //请求参数 Map paramMap = new HashMap<>(); - paramMap.put("currency", currencyDTO.getCurrency()); + paramMap.put("currency", /*currencyDTO.getCurrency()*/firstCurrency); paramMap.put("pageNo", pageNoAtomic.get()); paramMap.put("pageSize", pageSize); SleepUtil.sleep(10000); ApiNGResponseDTO betRecordByTimePage = ngClient.getBetRecordByTime(paramMap, key); data = betRecordByTimePage.getData(); //数据组装 - this.batchInsert(data); + this.batchInsert(data, systemCurrency, firstCurrency); } } - getBetRecordByHistoryTime(betRecordByTimeDTO, currencyDTO); + getBetRecordByHistoryTime(betRecordByTimeDTO, systemCurrency, firstCurrency); return Boolean.TRUE; } @@ -557,9 +489,9 @@ public class GamesPGServiceImpl implements IGamesService { * 按历史时间获取投注记录 * * @param betRecordByTimeDTO 按时间dto投注记录 - * @param currencyDTO 货币dto + * @param currency 货币 */ - private void getBetRecordByHistoryTime(BetRecordByTimeDTO betRecordByTimeDTO, GameSecretKeyCurrencyDTO currencyDTO) { + private void getBetRecordByHistoryTime(BetRecordByTimeDTO betRecordByTimeDTO, String systemCurrency, String currency /*GameSecretKeyCurrencyDTO currencyDTO*/) { //捞取指定30分钟前的数据 Long startTimes = DateUtils.addOrSubtractMinutes(DateUtils.getNowDate(), -30); @@ -587,12 +519,12 @@ public class GamesPGServiceImpl implements IGamesService { .format(Instant.ofEpochMilli(betRecordByTimeDTO.getEndTime())); - betRecordByTimeDTO.setAgentId(currencyDTO.getCode()); - betRecordByTimeDTO.setAgentKey(currencyDTO.getKey()); + //betRecordByTimeDTO.setAgentId(currencyDTO.getCode()); + //betRecordByTimeDTO.setAgentKey(currencyDTO.getKey()); int pageNo = 1; int pageSize = 2000; Map paramsMap = new HashMap<>(); - paramsMap.put("currency", currencyDTO.getCurrency()); + paramsMap.put("currency", /*currencyDTO.getCurrency()*/ currency); paramsMap.put("pageNo", pageNo); paramsMap.put("pageSize", pageSize); paramsMap.put("startTime", startTime); @@ -610,7 +542,7 @@ public class GamesPGServiceImpl implements IGamesService { ApiGameBetRecordPageResponseDTO data = result.getData(); //数据组装 - this.batchInsert(data); + this.batchInsert(data, systemCurrency, currency); //总页数 // 计算总页数,确保不会遗漏 @@ -621,7 +553,7 @@ public class GamesPGServiceImpl implements IGamesService { pageNoAtomic.incrementAndGet(); //请求参数 Map paramMap = new HashMap<>(); - paramMap.put("currency", currencyDTO.getCurrency()); + paramMap.put("currency", /*currencyDTO.getCurrency()*/ currency); paramMap.put("pageNo", pageNoAtomic.get()); paramMap.put("pageSize", pageSize); paramMap.put("startTime", startTime); @@ -630,13 +562,14 @@ public class GamesPGServiceImpl implements IGamesService { ApiNGResponseDTO betRecordByTimePage = ngClient.getBetRecordByTime(paramMap, key); data = betRecordByTimePage.getData(); //数据组装 - this.batchInsert(data); + this.batchInsert(data, systemCurrency, currency); } }); } } + /** * 按历史时间获取投注记录 * @@ -645,7 +578,7 @@ public class GamesPGServiceImpl implements IGamesService { */ @Override public Boolean getBetRecordByHistoryTime(BetRecordByTimeDTO betRecordByTimeDTO) { - return null; + throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); } @@ -659,7 +592,7 @@ public class GamesPGServiceImpl implements IGamesService { public Boolean createFreeSpin(CreateFreeSpinRequestDTO createFreeSpinRequest) { - return null; + throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); } /** @@ -689,7 +622,7 @@ public class GamesPGServiceImpl implements IGamesService { @Override public Boolean kickMember(KickMemberRequestDTO kickMemberRequestDTO) { - return null; + throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); } /** @@ -701,7 +634,7 @@ public class GamesPGServiceImpl implements IGamesService { @Override public Boolean kickMemberAll(KickMemberAllDTO kickMemberAllDTO) { - return null; + throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); } /** @@ -714,7 +647,7 @@ public class GamesPGServiceImpl implements IGamesService { public List getFreeSpinDashflow(GetFreeSpinDashflowRequestDTO getFreeSpinDashflowRequestDTO) { - return Collections.emptyList(); + throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); } /** @@ -726,7 +659,18 @@ public class GamesPGServiceImpl implements IGamesService { @Override public Boolean cancelFreeSpin(CancelFreeSpinRequestDTO cancelFreeSpinRequestDTO) { - return null; + throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); + } + + /** + * 游戏演示登录 + * + * @param gameDemoLoginRequestDTO 游戏演示登录请求dto + * @return {@link GameDemoLoginResponseDTO } + */ + @Override + public GameDemoLoginResponseDTO gameDemoLogin(GameDemoLoginRequestDTO gameDemoLoginRequestDTO) { + throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); } @@ -748,15 +692,14 @@ public class GamesPGServiceImpl implements IGamesService { } String platform = ngPlatforms.getPlatform(); - List games = gameService.selectGameDTOList(GameDTO.builder().gameName(resultBean.getGameName()).platformCode(platform).build()); + List games = gameService.selectGameDTOList(GameDTO.builder() + .gameName(resultBean.getGameName()) + .platformCode(platform) + .build()); if (CollectionUtils.isEmpty(games)) { return null; } Game gamesDataDTO = games.get(0); - GameSecretKeyCurrency currencyDTO = gameSecretKeyCurrencyService.findByGameSecretKeyCurrencyDTO(GameSecretKeyCurrencyDTO.builder() - .platformCodes(NGPlatforms.getAllPlatforms()) - .currency(resultBean.getCurrency()) - .build()); Member member = memberService.selectMemberByGameAccount(resultBean.getPlayerId()); if (ObjectUtils.isEmpty(member)) { @@ -776,12 +719,12 @@ public class GamesPGServiceImpl implements IGamesService { GameBettingDetails gameBettingDetails = GameBettingDetails.builder() .tenantKey(member.getTenantKey()) //保存我们的币种id - .currencyCode(currencyDTO.getSystemCurrency()) + .currencyCode(gamesDataBuildDTO.getSystemCurrencyCode()) .memberId(member.getId()) .gameCode(gamesDataDTO.getGameCode()) .gameType(NGGameType.findSystemByCode(resultBean.getGameType())) .platformCode(NGPlatforms.getByCode(resultBean.getPlatType()).getPlatform()) - .gameId(gamesDataDTO.getId()) + .gameId(gamesDataDTO.getGameId()) .gameName(gamesDataDTO.getGameName()) .gameStatus(gameStatus) .gameStatusType(1) @@ -812,12 +755,15 @@ public class GamesPGServiceImpl implements IGamesService { * * @param data 数据 */ - private synchronized void batchInsert(ApiGameBetRecordPageResponseDTO data) { + private synchronized void batchInsert(ApiGameBetRecordPageResponseDTO data, String systemCurrency, String currency) { List gameBettingDetails = new ArrayList<>(); List wagersIds = new ArrayList<>(); //数据转化 for (ApiGameBetRecordPageResponseDTO.GameBetRecord bean : data.getList()) { - GameBettingDetails bettingDetails = this.dataBuild(GamesDataBuildDTO.builder().data(bean).build()); + GameBettingDetails bettingDetails = this.dataBuild(GamesDataBuildDTO.builder() + .systemCurrencyCode(systemCurrency) + .currencyCode(currency) + .data(bean).build()); if (!ObjectUtils.isEmpty(bettingDetails)) { bettingDetails.setId(IdUtil.getSnowflakeNextId()); gameBettingDetails.add(bettingDetails); @@ -826,7 +772,7 @@ public class GamesPGServiceImpl implements IGamesService { } if (!CollectionUtils.isEmpty(gameBettingDetails)) { //查询重复数据id - List removeWagersIds = gameBettingDetailsService.selectGameBettingDetailsByWagersId(wagersIds); + List removeWagersIds = gameBettingDetailsService.selectGameBettingDetailsByWagersId(wagersIds, NGPlatforms.PG.getPlatform()); //用steam流清除list中与wagersIds集合相同的数据 gameBettingDetails = gameBettingDetails.stream() .filter(detail -> !removeWagersIds.contains(detail.getWagersId())) diff --git a/ff-game/src/main/java/com/ff/game/api/pgt/address/MyPGTAddressSource.java b/ff-game/src/main/java/com/ff/game/api/pgt/address/MyPGTAddressSource.java new file mode 100644 index 0000000..f8e4654 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/pgt/address/MyPGTAddressSource.java @@ -0,0 +1,35 @@ +package com.ff.game.api.pgt.address; + +import com.dtflys.forest.callback.AddressSource; +import com.dtflys.forest.http.ForestAddress; +import com.dtflys.forest.http.ForestRequest; +import com.ff.base.constant.Constants; +import com.ff.base.enums.GamePlatforms; +import com.ff.base.system.service.ISysConfigService; +import com.ff.game.service.IPlatformService; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + + +/** + * 我 pt 泰国来源 + * + * @author shi + * @date 2025/02/10 + */ +@Component +public class MyPGTAddressSource implements AddressSource { + @Resource + private IPlatformService platformService; + @Resource + private ISysConfigService configService; + + + @Override + public ForestAddress getAddress(ForestRequest request) { + String apiBaseUrl = platformService.get(GamePlatforms.PGT.getCode()) + .getUrlInfo().getUrl(); + return new ForestAddress("https",apiBaseUrl, 443,""); + } +} \ No newline at end of file diff --git a/ff-game/src/main/java/com/ff/game/api/pgt/client/PGTClient.java b/ff-game/src/main/java/com/ff/game/api/pgt/client/PGTClient.java new file mode 100644 index 0000000..14952d5 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/pgt/client/PGTClient.java @@ -0,0 +1,139 @@ +package com.ff.game.api.pgt.client; + +import com.dtflys.forest.annotation.*; +import com.ff.game.api.dg.dto.DGResponse; +import com.ff.game.api.fc.dto.ApiFCGameListResponseDTO; +import com.ff.game.api.jili.dto.JILIKickMemberAllDTO; +import com.ff.game.api.jili.dto.JILIKickMemberDTO; +import com.ff.game.api.ng.dto.ApiExchangeTransferStatusResponseDTO; +import com.ff.game.api.ng.dto.ApiNGResponseDTO; +import com.ff.game.api.pgt.address.MyPGTAddressSource; +import com.ff.game.api.pgt.dto.*; +import com.ff.game.api.pgx.dto.PGXPlayerStatusResponse; +import com.ff.game.api.success.MySuccessCondition; +import com.ff.game.api.xk.dto.XKKickMemberAllDTO; + +import java.util.Map; + +/** + * pt 泰国 + * + * @author shi + * @date 2025/02/10 + */ +@Address(source = MyPGTAddressSource.class) +@Success(condition = MySuccessCondition.class) +public interface PGTClient { + /** + * 创建成员 + * + * @param parameters 范围 + * @param headerMap 标题映射 + * @return {@link String } + */ + @Post("/member") + PGTCreateMemberResponse createMember(@JSONBody Map parameters, @Header Map headerMap); + + /** + * 获取会员信息 + * + * @param parameters 范围 + * @return {@link PGTBalanceResponse } + */ + @Get("/balance?${parameters}") + PGTBalanceResponse getMemberInfo(@Var("parameters") String parameters, @Header Map headerMap); + + + + + + /** + * 无重定向登录 + * + * @param parameters 范围 + * @return {@link PGTLoginResponse } + */ + @Post("/logIn") + PGTLoginResponse loginWithoutRedirect(@JSONBody Map parameters, @Header Map headerMap); + + + /** + * 获取游戏列表 + * + * @param parameters 范围 + * @param headerMap 标题映射 + * @return {@link PGTGameListResponse } + */ + @Get("/games?${parameters}") + PGTGameListResponse getGameList(@Var("parameters") String parameters, @Header Map headerMap); + + + /** + * 押金 + * + * @param parameters 范围 + * @param headerMap 标题映射 + * @return {@link PGTExchangeTransferResponse } + */ + @Post(url = "/deposit") + PGTExchangeTransferResponse deposit(@JSONBody Map parameters, @Header Map headerMap); + + + /** + * 收回 + * + * @param parameters 范围 + * @param headerMap 标题映射 + * @return {@link PGTExchangeTransferResponse } + */ + @Post(url = "/withdraw") + PGTExchangeTransferResponse withdraw(@JSONBody Map parameters, @Header Map headerMap); + + /** + * 汇兑转移状态 + * + * @param parameters 范围 + * @param headerMap 标题映射 + * @return {@link ApiNGResponseDTO }<{@link ApiExchangeTransferStatusResponseDTO }> + */ + @Post(url = "/verifyDepositWithdraw") + PGTTransactionResponse exchangeTransferStatus(@JSONBody Map parameters, @Header Map headerMap); + + + /** + * 按时间获取投注记录 + * + * @param parameters 范围 + * @param headerMap 标题映射 + * @return {@link PGTTransactionDetailsResponse } + */ + @Get(url = "/betTransactionsV2?{parameters}") + PGTTransactionDetailsResponse getBetRecordByTime(@Var("parameters") String parameters, @Header Map headerMap); + + + /** + * 投注交易回放 + * + * @param parameters 范围 + * @param headerMap 标题映射 + * @return {@link PGTReplayUrlResponseDTO } + */ + @Get(url = "/betTransactionReplay?{parameters}") + PGTReplayUrlResponseDTO betTransactionReplay(@Var("parameters") String parameters, @Header Map headerMap); + + + + /** + * 踢出队员 + * + * @param parameters 范围 + * @param headerMap 标题映射 + * @return {@link PGTKickMemberResponse } + */ + @Post("/seamless/kickOutPlayer") + PGTKickMemberResponse kickMember(@JSONBody Map parameters, @Header Map headerMap); + + + + +} diff --git a/ff-game/src/main/java/com/ff/game/api/pgt/dto/PGTBalanceResponse.java b/ff-game/src/main/java/com/ff/game/api/pgt/dto/PGTBalanceResponse.java new file mode 100644 index 0000000..d60c33e --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/pgt/dto/PGTBalanceResponse.java @@ -0,0 +1,62 @@ +package com.ff.game.api.pgt.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.math.BigDecimal; + +/** + * PG平衡响应 + * + * @author shi + * @date 2025/04/03 + */ +@Data +public class PGTBalanceResponse { + + /** + * 每个请求的唯一引用 + */ + @JsonProperty("reqId") + private String reqId; + + /** + * 响应状态,通常为 0 表示成功,其他值表示错误 + */ + @JsonProperty("code") + private int code; + + /** + * 关于响应状态的其他信息 + */ + @JsonProperty("message") + private String message; + + /** + * 获取余额数据 + */ + @JsonProperty("data") + private BalanceData data; + + @Data + public static class BalanceData { + + /** + * 用户名 + */ + @JsonProperty("username") + private String username; + + /** + * 每个 productId 的当前余额 + */ + @JsonProperty("balance") + private BigDecimal balance; + + /** + * 响应状态 + */ + @JsonProperty("status") + private String status; + } +} diff --git a/ff-game/src/main/java/com/ff/game/api/pgt/dto/PGTCreateMemberResponse.java b/ff-game/src/main/java/com/ff/game/api/pgt/dto/PGTCreateMemberResponse.java new file mode 100644 index 0000000..8f7537a --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/pgt/dto/PGTCreateMemberResponse.java @@ -0,0 +1,60 @@ +package com.ff.game.api.pgt.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +/** + * pgtcreate成员响应 + * + * @author shi + * @date 2025/04/03 + */ +@Data +public class PGTCreateMemberResponse { + + /** + * 请求的唯一标识符 + */ + @JsonProperty("reqId") + private String reqId; + + /** + * 状态码,0 表示成功,其他值表示错误 + */ + @JsonProperty("code") + private int code; + + /** + * 响应消息,通常用于提供请求处理的结果 + */ + @JsonProperty("message") + private String message; + + /** + * 响应的实际数据 + */ + @JsonProperty("data") + private ResponseData data; + + @Data + public static class ResponseData { + + /** + * 用户名 + */ + @JsonProperty("username") + private String username; + + /** + * 货币类型 + */ + @JsonProperty("currency") + private String currency; + + /** + * 操作状态 + */ + @JsonProperty("status") + private String status; + } +} diff --git a/ff-game/src/main/java/com/ff/game/api/pgt/dto/PGTExchangeTransferResponse.java b/ff-game/src/main/java/com/ff/game/api/pgt/dto/PGTExchangeTransferResponse.java new file mode 100644 index 0000000..9bb67a7 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/pgt/dto/PGTExchangeTransferResponse.java @@ -0,0 +1,80 @@ +package com.ff.game.api.pgt.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.math.BigDecimal; + +/** + * pgtexchange传输响应 + * + * @author shi + * @date 2025/04/03 + */ +@Data +public class PGTExchangeTransferResponse { + + /** + * 每个请求的唯一引用 + */ + @JsonProperty("reqId") + private String reqId; + + /** + * 响应状态,通常为 0 表示成功,其他值表示错误 + */ + @JsonProperty("code") + private int code; + + /** + * 关于响应状态的其他信息 + */ + @JsonProperty("message") + private String message; + + /** + * 包含余额相关的数据 + */ + @JsonProperty("data") + private BalanceData data; + + @Data + public static class BalanceData { + + /** + * 响应状态,成功/失败 + */ + @JsonProperty("status") + private String status; + + /** + * 存款金额(十进制 2 位数字) + */ + @JsonProperty("amount") + private BigDecimal amount; + + /** + * 存款后每个 productId 的余额(十进制 2 位数字) + */ + @JsonProperty("balance") + private BigDecimal balance; + + /** + * 交易 ID + */ + @JsonProperty("txId") + private String txId; + + /** + * 用户名 + */ + @JsonProperty("username") + private String username; + + /** + * 存款前每个 productId 的余额(十进制 2 位数字 + */ + @JsonProperty("beforeBalance") + private BigDecimal beforeBalance; + } +} diff --git a/ff-game/src/main/java/com/ff/game/api/pgt/dto/PGTGameListResponse.java b/ff-game/src/main/java/com/ff/game/api/pgt/dto/PGTGameListResponse.java new file mode 100644 index 0000000..717680e --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/pgt/dto/PGTGameListResponse.java @@ -0,0 +1,133 @@ +package com.ff.game.api.pgt.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.util.List; + +/** + * pgtgame列表响应 + * + * @author shi + * @date 2025/04/07 + */ +@Data +public class PGTGameListResponse { + /** + * 每个请求的唯一引用 + */ + @JsonProperty("reqId") + private String reqId; + + /** + * 响应状态,0 表示成功,其他值表示错误 + */ + @JsonProperty("code") + private int code; + + /** + * 有关响应状态的其他信息 + */ + @JsonProperty("message") + private String message; + + /** + * 包含游戏数据的对象 + */ + @JsonProperty("data") + private GameData data; + + @Data + public static class GameData { + + /** + * 游戏列表 + */ + @JsonProperty("games") + private List games; + } + + @Data + public static class Game { + + /** + * 游戏名称 + */ + @JsonProperty("name") + private String name; + + /** + * 游戏类别 + */ + @JsonProperty("category") + private String category; + + /** + * 游戏类型 + */ + @JsonProperty("type") + private String type; + + /** + * 游戏代码 + */ + @JsonProperty("code") + private String code; + + /** + * 游戏图片链接 + */ + @JsonProperty("img") + private String img; + + /** + * 系统游戏id + */ + private String systemGameId; + + /** + * 游戏排名 + */ + @JsonProperty("rank") + private int rank; + + /** + * 游戏提供者代码 + */ + @JsonProperty("providerCode") + private String providerCode; + + + /** + * 场所 + */ + @JsonProperty("locale") + private Locale locale; + } + + /** + * 场所 + * + * @author shi + * @date 2025/04/07 + */ + @Data + public class Locale { + /** + * 泰文 + */ + @JsonProperty("TH") + private String th; + /** + * 英语 + */ + @JsonProperty("EN") + private String en; + /** + * 中国 + */ + @JsonProperty("CN") + private String cn; + } + +} diff --git a/ff-game/src/main/java/com/ff/game/api/pgt/dto/PGTKickMemberResponse.java b/ff-game/src/main/java/com/ff/game/api/pgt/dto/PGTKickMemberResponse.java new file mode 100644 index 0000000..2735bf7 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/pgt/dto/PGTKickMemberResponse.java @@ -0,0 +1,56 @@ +package com.ff.game.api.pgt.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +/** + * pgtkick成员响应 + * + * @author shi + * @date 2025/04/07 + */ +@Data +public class PGTKickMemberResponse { + + + /** + * 每个请求的唯一引用 + */ + @JsonProperty("reqId") + private String reqId; + + /** + * 响应状态代码 + * 0:成功,其他代码表示失败 + */ + @JsonProperty("code") + private int code; + + /** + * 消息描述 + */ + @JsonProperty("message") + private String message; + + /** + * 交易数据 + */ + @JsonProperty("data") + private TransactionData data; + + @Data + public static class TransactionData { + + /** + * 交易成功的状态描述 + */ + @JsonProperty("status") + private String status; + + /** + * 玩家用户名 + */ + @JsonProperty("username") + private String username; + } +} diff --git a/ff-game/src/main/java/com/ff/game/api/pgt/dto/PGTLoginResponse.java b/ff-game/src/main/java/com/ff/game/api/pgt/dto/PGTLoginResponse.java new file mode 100644 index 0000000..57590a7 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/pgt/dto/PGTLoginResponse.java @@ -0,0 +1,54 @@ +package com.ff.game.api.pgt.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +/** + * pgtlogin响应 + * + * @author shi + * @date 2025/04/03 + */ +@Data +public class PGTLoginResponse { + + /** + * 每个请求的唯一引用 + */ + @JsonProperty("reqId") + private String reqId; + + /** + * 响应状态,通常为 0 表示成功,其他值表示错误 + */ + @JsonProperty("code") + private int code; + + /** + * 关于响应状态的其他信息 + */ + @JsonProperty("message") + private String message; + + /** + * 包含登录相关数据 + */ + @JsonProperty("data") + private LoginData data; + + @Data + public static class LoginData { + + /** + * 登录 URL 链接 + */ + @JsonProperty("url") + private String url; + + /** + * 用户名 + */ + @JsonProperty("username") + private String username; + } +} diff --git a/ff-game/src/main/java/com/ff/game/api/pgt/dto/PGTReplayUrlResponseDTO.java b/ff-game/src/main/java/com/ff/game/api/pgt/dto/PGTReplayUrlResponseDTO.java new file mode 100644 index 0000000..1389e4f --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/pgt/dto/PGTReplayUrlResponseDTO.java @@ -0,0 +1,50 @@ +package com.ff.game.api.pgt.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +/** + * pgtreplay url响应dto + * + * @author shi + * @date 2025/04/08 + */ +@Data +public class PGTReplayUrlResponseDTO { + /** + * 请求 ID + */ + @JsonProperty("reqId") + private String reqId; + + /** + * 响应代码,0 表示成功 + */ + @JsonProperty("code") + private int code; + + /** + * 响应消息,描述请求的状态 + */ + @JsonProperty("message") + private String message; + + /** + * 数据,包含重播 URL 信息 + */ + @JsonProperty("data") + private Datas data; + + /** + * 内部数据类,包含重播 URL + */ + @Data + public static class Datas { + + /** + * 重播链接 + */ + @JsonProperty("url") + private String url; + } +} diff --git a/ff-game/src/main/java/com/ff/game/api/pgt/dto/PGTTransactionDetailsResponse.java b/ff-game/src/main/java/com/ff/game/api/pgt/dto/PGTTransactionDetailsResponse.java new file mode 100644 index 0000000..096183e --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/pgt/dto/PGTTransactionDetailsResponse.java @@ -0,0 +1,153 @@ +package com.ff.game.api.pgt.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.math.BigDecimal; +import java.util.Date; +import java.util.List; + +/** + * pgtt交易详情响应 + * + * @author shi + * @date 2025/04/07 + */ +@Data +public class PGTTransactionDetailsResponse { + + /** + * 每个请求的唯一引用 + */ + @JsonProperty("reqId") + private String reqId; + + /** + * 响应状态,通常为 0 表示成功,其他值表示错误 + */ + @JsonProperty("code") + private int code; + + /** + * 关于响应状态的其他信息 + */ + @JsonProperty("message") + private String message; + + /** + * 包含交易数据的对象 + */ + @JsonProperty("data") + private TransactionData data; + + @Data + public static class TransactionData { + + /** + * 下一批数据的 ID + */ + @JsonProperty("nextId") + private String nextId; + + /** + * 交易列表 + */ + @JsonProperty("txns") + private List txns; + } + + @Data + public static class Transaction { + + /** + * 交易 ID + */ + @JsonProperty("id") + private String id; + + /** + * 用户投注 ID + */ + @JsonProperty("betId") + private String betId; + + /** + * 用户名 + */ + @JsonProperty("username") + private String username; + + /** + * ISO 4217 货币代码 + */ + @JsonProperty("currency") + private String currency; + + /** + * 结算时间 + */ + @JsonProperty("accountingDate") + private Date accountingDate; + + /** + * 最新更新时间 + */ + @JsonProperty("updatedDate") + private Date updatedDate; + + /** + * 质押金额 + */ + @JsonProperty("stake") + private BigDecimal stake; + + /** + * 支付金额(包括本金) + */ + @JsonProperty("payout") + private BigDecimal payout; + + /** + * 产品 ID + */ + @JsonProperty("productId") + private String productId; + + /** + * 游戏代码 + */ + @JsonProperty("gameCode") + private String gameCode; + + /** + * 游戏名称 + */ + @JsonProperty("gameName") + private String gameName; + + /** + * 轮次 ID + */ + @JsonProperty("roundId") + private String roundId; + + /** + * 投注状态(未结、已结算、未结算、无效) + * OPEN, SETTLED, UNSETTLED, VOID + */ + @JsonProperty("betStatus") + private String betStatus; + + /** + * 支付状态(LOSE、WIN、DRAW、UNKNOWN) + */ + @JsonProperty("payoutStatus") + private String payoutStatus; + + /** + * 佣金 + */ + @JsonProperty("commission") + private double commission; + } +} diff --git a/ff-game/src/main/java/com/ff/game/api/pgt/dto/PGTTransactionResponse.java b/ff-game/src/main/java/com/ff/game/api/pgt/dto/PGTTransactionResponse.java new file mode 100644 index 0000000..d794122 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/pgt/dto/PGTTransactionResponse.java @@ -0,0 +1,92 @@ +package com.ff.game.api.pgt.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.math.BigDecimal; + +/** + * pgtt交易响应 + * + * @author shi + * @date 2025/04/07 + */ +@Data +public class PGTTransactionResponse { + + /** + * 每个请求的唯一引用 + */ + @JsonProperty("reqId") + private String reqId; + + /** + * 响应状态,通常为 0 表示成功,其他值表示错误 + */ + @JsonProperty("code") + private int code; + + /** + * 关于响应状态的其他信息 + */ + @JsonProperty("message") + private String message; + + /** + * 包含交易相关的数据 + */ + @JsonProperty("data") + private TransactionData data; + + @Data + public static class TransactionData { + + /** + * 交易是否成功 + */ + @JsonProperty("success") + private boolean success; + + /** + * 用户名 + */ + @JsonProperty("username") + private String username; + + /** + * 产品ID,例如 "SEXY" 等 + */ + @JsonProperty("productId") + private String productId; + + /** + * 货币类型,如 "THB" + */ + @JsonProperty("currency") + private String currency; + + /** + * 交易参考号 + */ + @JsonProperty("transactionRef") + private String transactionRef; + + /** + * 当前交易的金额 + */ + @JsonProperty("amount") + private BigDecimal amount; + + /** + * 交易前的余额 + */ + @JsonProperty("beforeBalance") + private BigDecimal beforeBalance; + + /** + * 交易后的余额 + */ + @JsonProperty("afterBalance") + private BigDecimal afterBalance; + } +} diff --git a/ff-game/src/main/java/com/ff/game/api/pgt/impl/GamesPGTServiceImpl.java b/ff-game/src/main/java/com/ff/game/api/pgt/impl/GamesPGTServiceImpl.java new file mode 100644 index 0000000..5a5d076 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/pgt/impl/GamesPGTServiceImpl.java @@ -0,0 +1,662 @@ +package com.ff.game.api.pgt.impl; + +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.NumberUtil; +import com.alibaba.fastjson2.JSON; +import com.ff.base.config.RedisConfig; +import com.ff.base.constant.CacheConstants; +import com.ff.base.constant.Constants; +import com.ff.base.core.redis.RedisCache; +import com.ff.base.enums.*; +import com.ff.base.exception.base.ApiException; +import com.ff.base.exception.base.BaseException; +import com.ff.base.system.service.ISysConfigService; +import com.ff.base.utils.DateUtils; +import com.ff.base.utils.JsonUtil; +import com.ff.base.utils.StringUtils; +import com.ff.base.utils.sign.Base64; +import com.ff.base.utils.uuid.IdUtils; +import com.ff.config.KeyConfig; +import com.ff.game.api.IGamesService; +import com.ff.game.api.fc.dto.ApiFCGameListResponseDTO; +import com.ff.game.api.fc.dto.ApiFCResult; +import com.ff.game.api.pgt.client.PGTClient; +import com.ff.game.api.pgt.dto.*; +import com.ff.game.api.request.*; +import com.ff.game.api.xk.dto.XKBetRecordResponseDTO; +import com.ff.game.api.xk.dto.XKGamesDTO; +import com.ff.game.domain.*; +import com.ff.game.dto.GameBettingDetailsDTO; +import com.ff.game.service.*; +import com.ff.member.domain.Member; +import com.ff.member.service.IMemberService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.Assert; +import org.springframework.util.Base64Utils; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ObjectUtils; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.nio.charset.StandardCharsets; +import java.util.*; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + + +/** + * pg泰 + * + * @author shi + * @date 2025/03/27 + */ +@Service("PGTService") +@Slf4j +public class GamesPGTServiceImpl implements IGamesService { + + + @Resource + private ISysConfigService configService; + + @Resource + private RedisCache redisCache; + + @Resource + private IGameExchangeMoneyService gameExchangeMoneyService; + + + @Resource + private IGameService gameService; + + + @Resource + private IMemberService memberService; + + @Resource + private IGameFreeRecordService gameFreeRecordService; + + + @Resource + private PGTClient pgtClient; + + + @Resource + private KeyConfig keyConfig; + + @Resource + private IGameBettingDetailsService gameBettingDetailsService; + + + String productId = "PGSOFT"; + + /** + * 获得就是成功 + * + * @param errorCode 错误代码 + * @return {@link Boolean } + */ + private Boolean getIsSuccess(Integer errorCode) { + + return 0 == errorCode; + } + + + /** + * 获取密钥 + * + * @return {@link String } + */ + private Map getKey(GamesBaseRequestDTO gamesBaseRequestDTO) { + Map headerMap = new LinkedHashMap<>(); + String auth = gamesBaseRequestDTO.getAgentId() + ":" + gamesBaseRequestDTO.getAgentKey(); + String encodedAuth = Base64Utils.encodeToString(auth.getBytes()); + headerMap.put("Authorization", "Basic " + encodedAuth); + + return headerMap; + } + + + /** + * 创建成员 + * + * @param createMemberRequestDTO 创建成员请求dto + * @return {@link Boolean } + */ + @Override + public Boolean createMember(CreateMemberRequestDTO createMemberRequestDTO) { + log.info("GamesPGTServiceImpl [createMember] 请求参数 {}", createMemberRequestDTO); + Map headerMap = this.getKey(createMemberRequestDTO); + Map params = new LinkedHashMap<>(); + params.put("username", createMemberRequestDTO.getAccount()); + params.put("productId", productId); + + PGTCreateMemberResponse member = pgtClient.createMember(params, headerMap); + if (this.getIsSuccess(member.getCode())) { + return Boolean.TRUE; + } + //判断是否获取成功 + return Boolean.FALSE; + } + + + /** + * 获取会员信息 + * + * @param memberInfoRequestDTO 会员信息请求dto + * @return {@link MemberInfoResponseDTO } + */ + @Override + public MemberInfoResponseDTO getMemberInfo(MemberInfoRequestDTO memberInfoRequestDTO) { + log.info("GamesPGTServiceImpl [getMemberInfo] 请求参数 {}", memberInfoRequestDTO); + Map params = new LinkedHashMap<>(); + params.put("username", memberInfoRequestDTO.getAccounts()); + params.put("productId", productId); + Map headerMap = this.getKey(memberInfoRequestDTO); + PGTBalanceResponse memberInfo = pgtClient.getMemberInfo(JsonUtil.mapToQueryString(params), headerMap); + //判断是否获取成功 + if (this.getIsSuccess(memberInfo.getCode())) { + MemberInfoResponseDTO memberInfoResponseDTO = MemberInfoResponseDTO.builder() + .status(GameMemberStatus.UNKNOWN.getCode()) + .balance(memberInfo.getData().getBalance()) + .account(memberInfoRequestDTO.getAccounts()) + .build(); + return memberInfoResponseDTO; + } else { + throw new BaseException(memberInfo.getMessage()); + } + } + + /** + * 无重定向登录 + * + * @param gamesLogin 游戏登录 + * @return {@link String } + */ + @Override + public String loginWithoutRedirect(GamesLogin gamesLogin) { + log.info("GamesPGTServiceImpl [loginWithoutRedirect] 请求参数 {}", gamesLogin); + Map params = new LinkedHashMap<>(); + params.put("username", gamesLogin.getAccount()); + params.put("productId", productId); + params.put("gameCode", gamesLogin.getGameId()); + params.put("isMobileLogin", PlatformHomeType.APP.getValue().equals(gamesLogin.getPlatform())); + params.put("language", gamesLogin.getLang()); + Map key = this.getKey(gamesLogin); + PGTLoginResponse pgtLoginResponse = pgtClient.loginWithoutRedirect(params, key); + //判断是否获取成功 + if (this.getIsSuccess(pgtLoginResponse.getCode())) { + return pgtLoginResponse.getData().getUrl(); + } else { + throw new BaseException(pgtLoginResponse.getMessage()); + } + } + + + /** + * 获取游戏列表 + * + * @param gamesBaseRequestDTO 游戏请求dto + * @return {@link String } + */ + @Transactional + @Override + public String getGameList(GamesBaseRequestDTO gamesBaseRequestDTO) { + List apiGameInfoResponseDTOS = redisCache.getCacheList(CacheConstants.PGT_GAMES); + if (!CollectionUtils.isEmpty(apiGameInfoResponseDTOS)) { + return CacheConstants.PGT_GAMES; + } + + + log.info("GamesPGTServiceImpl [getGameList] 请求参数 {}", gamesBaseRequestDTO); + Map paramsMap = new HashMap<>(); + paramsMap.put("productId", productId); + PGTGameListResponse gameList = pgtClient.getGameList(JsonUtil.mapToQueryString(paramsMap), this.getKey(gamesBaseRequestDTO)); + if (this.getIsSuccess(gameList.getCode())) { + + + //新增游戏 + for (PGTGameListResponse.Game gameIdKey : gameList.getData().getGames()) { + + Game game = Game.builder() + .platformCode(GamePlatforms.PGT.getCode()) + .gameCode(gameIdKey.getCode()) + .build(); + List games = gameService.selectGameList(game); + int platformType = PGTGameType.findSystemByCode(gameIdKey.getCategory()); + //不存在这个游戏 + if (CollectionUtils.isEmpty(games)) { + + game.setGameSourceType(gameIdKey.getCategory()); + game.setFreespin(Boolean.FALSE); + game.setDemoStatus(Boolean.FALSE); + game.setPlatformCode(GamePlatforms.PGT.getCode()); + game.setPlatformType(platformType); + game.setSortNo(gameService.selectMaxSortNo(platformType, GamePlatforms.PGT.getCode()) + 1); + game.setGameName(gameIdKey.getName()); + game.setCreateBy(Constants.SYSTEM); + game.setGameId(StringUtils.addSuffix(GamePlatforms.PGT.getCode(), gameIdKey.getCode())); + List nameInfos = new ArrayList<>(); + nameInfos.add(NameInfo.builder().lang("en-US").name(gameIdKey.getName()).build()); + game.setNameInfo(nameInfos); + gameService.insertGame(game); + } else { + game = games.get(0); + List nameInfos = new ArrayList<>(); + nameInfos.add(NameInfo.builder().lang("en-US").name(gameIdKey.getName()).build()); + game.setNameInfo(nameInfos); + gameService.updateGame(game); + } + gameIdKey.setSystemGameId(game.getGameId()); + } + + + redisCache.deleteObject(CacheConstants.PGT_GAMES); + redisCache.setCacheList(CacheConstants.PGT_GAMES, gameList.getData().getGames()); + redisCache.expire(CacheConstants.PGT_GAMES, 5L, TimeUnit.HOURS); + } else { + throw new ApiException(ErrorCode.ERROR.getCode()); + } + return CacheConstants.PGT_GAMES; + } + /** + * 获取交易id + * + * @param transactionIdRequestDTO 事务id请求dto + * @return {@link String } + */ + @Override + public String getTransactionId(TransactionIdRequestDTO transactionIdRequestDTO) { + return gameExchangeMoneyService.getTransactionId(GamePlatforms.PGT.getInfo(), 17); + } + /** + * 按代理id进行交换转账 + * + * @param exchangeTransferMoneyRequestDTO 外汇转账moeny dto + * @return {@link Long } + */ + @Override + @Transactional + public Long exchangeTransferByAgentId(ExchangeTransferMoneyRequestDTO exchangeTransferMoneyRequestDTO) { + log.info("GamesPGTServiceImpl [exchangeTransferByAgentId] 请求参数 {}", exchangeTransferMoneyRequestDTO); + + + + GameExchangeMoney exchangeMoney = gameExchangeMoneyService.selectGameExchangeMoneyById(exchangeTransferMoneyRequestDTO.getGameExchangeId()); + + + BigDecimal amount = exchangeTransferMoneyRequestDTO.getAmount(); + BigDecimal amountBefore = BigDecimal.ZERO; + + // 获取第三方钱包余额 + MemberInfoRequestDTO gamesBaseRequestDTO = MemberInfoRequestDTO.builder() + .accounts(exchangeTransferMoneyRequestDTO.getAccount()) + .agentId(exchangeTransferMoneyRequestDTO.getAgentId()) + .agentKey(exchangeTransferMoneyRequestDTO.getAgentKey()) + .build(); + + + //判断是不是提出 + if (TransferType.ALL.getCode().equals(exchangeTransferMoneyRequestDTO.getTransferType())) { + amountBefore = this.getMemberInfo(gamesBaseRequestDTO).getBalance(); + amount = amountBefore; + } + + + Map paramsMap = new LinkedHashMap<>(); + paramsMap.put("username", exchangeTransferMoneyRequestDTO.getAccount()); + paramsMap.put("amount", amount.setScale(2, RoundingMode.DOWN).toString()); + paramsMap.put("transactionRef", exchangeTransferMoneyRequestDTO.getTransactionId()); + paramsMap.put("productId", productId); + Map key = this.getKey(exchangeTransferMoneyRequestDTO); + PGTExchangeTransferResponse errorResponse; + //判断是不是提出 + if (TransferType.ALL.getCode().equals(exchangeTransferMoneyRequestDTO.getTransferType())) { + errorResponse = pgtClient.withdraw(paramsMap, key); + } else { + errorResponse = pgtClient.deposit(paramsMap, key); + } + + if (this.getIsSuccess(errorResponse.getCode())) { + PGTExchangeTransferResponse.BalanceData data = errorResponse.getData(); + //更新数据 + exchangeMoney.setBalance(data.getAmount()); + exchangeMoney.setCoinBefore(data.getBeforeBalance()); + exchangeMoney.setCoinAfter(data.getBalance()); + exchangeMoney.setCurrencyBefore(exchangeMoney.getCoinBefore()); + exchangeMoney.setCurrencyAfter(exchangeMoney.getCoinAfter()); + exchangeMoney.setStep(GameExchangeStep.PLATFORM_TRANSACTION.getCode()); + exchangeMoney.setStepStatus(GameExchangeStepStatus.SUCCESS.getCode()); + gameExchangeMoneyService.updateGameExchangeMoney(exchangeMoney); + + } else { + exchangeMoney.setStep(GameExchangeStep.PLATFORM_TRANSACTION.getCode()); + exchangeMoney.setStepStatus(GameExchangeStepStatus.FAILURE.getCode()); + gameExchangeMoneyService.updateGameExchangeMoney(exchangeMoney); + log.error("GamesPGTServiceImpl [exchangeTransferByAgentId] 金额转移失败,错误代码{}", errorResponse.getCode()); + throw new ApiException(ErrorCode.BALANCE_TRANSFER_FAILED.getCode()); + } + return exchangeMoney.getId(); + } + + /** + * 汇兑转移状态 + * + * @param exchangeTransferMoneyRequestDTO 兑换转账请求dto + * @return {@link Boolean } + */ + @Override + public ExchangeTransferStatusResponseDTO exchangeTransferStatus(ExchangeTransferStatusRequestDTO exchangeTransferMoneyRequestDTO) { + log.info("GamesPGTServiceImpl [exchangeTransferStatus] 请求参数 {}", exchangeTransferMoneyRequestDTO); + GameExchangeMoney gameExchangeMoney = gameExchangeMoneyService.selectGameExchangeMoneyById(exchangeTransferMoneyRequestDTO.getGameExchangeMoneyId()); + Map paramsMap = new LinkedHashMap<>(); + paramsMap.put("username", exchangeTransferMoneyRequestDTO.getAccount()); + paramsMap.put("transactionRef", exchangeTransferMoneyRequestDTO.getOrderId()); + paramsMap.put("productId", productId); + if (TransferType.ALL.getCode().equals(gameExchangeMoney.getExchangeType())) { + paramsMap.put("type", "WITHDRAW"); + } else { + paramsMap.put("type", "DEPOSIT"); + } + Map key = this.getKey(exchangeTransferMoneyRequestDTO); + PGTTransactionResponse transactionResponse = pgtClient.exchangeTransferStatus(paramsMap, key); + Integer status = StatusType.IN_PROGRESS.getValue(); + if (this.getIsSuccess(transactionResponse.getCode())) { + status = transactionResponse.getData().isSuccess() ? StatusType.SUCCESS.getValue() : StatusType.FAILURE.getValue(); + } else { + status = StatusType.FAILURE.getValue(); + } + ExchangeTransferStatusResponseDTO transferStatusResponseDTO = ExchangeTransferStatusResponseDTO.builder() + .statusType(status) + .build(); + if (!ObjectUtils.isEmpty(transactionResponse.getData())) { + transferStatusResponseDTO.setBalance(transactionResponse.getData().getAmount()); + transferStatusResponseDTO.setCoinBefore(transactionResponse.getData().getBeforeBalance()); + transferStatusResponseDTO.setCoinAfter(transactionResponse.getData().getAfterBalance()); + } + return transferStatusResponseDTO; + } + + + /** + * 按时间获取投注记录 + * + * @param betRecordByTimeDTO 按时间dto投注记录 + * @return {@link List }<{@link GameBettingDetails }> + */ + @Override + public Boolean getBetRecordByTime(BetRecordByTimeDTO betRecordByTimeDTO) { + //请求参数 + log.info("GamesPGTServiceImpl [getBetRecordByTime] 请求参数 {}", betRecordByTimeDTO); + + String startTime = DateUtils.convertTimestampToFormattedDate(betRecordByTimeDTO.getStartTime(), DateUtils.ISO_8601_FORMAT_Z, "GMT+0"); + String endTime = DateUtils.convertTimestampToFormattedDate(betRecordByTimeDTO.getEndTime(), DateUtils.ISO_8601_FORMAT_Z, "GMT+0"); + + String nextId = redisCache.getCacheObject(CacheConstants.PGT_NEXT_ID); + + + Map paramsMap = new LinkedHashMap<>(); + paramsMap.put("productId", productId); + paramsMap.put("startTime", startTime); + paramsMap.put("endTime", endTime); + paramsMap.put("nextId", nextId); + Map key = this.getKey(betRecordByTimeDTO); + + PGTTransactionDetailsResponse betRecordByTime = pgtClient.getBetRecordByTime(JsonUtil.mapToQueryString(paramsMap), key); + + if (this.getIsSuccess(betRecordByTime.getCode())) { + List txns = betRecordByTime.getData().getTxns(); + this.batchInsert(txns, betRecordByTimeDTO); + //保存本次请求的id + redisCache.setCacheObject(CacheConstants.PGT_NEXT_ID, betRecordByTime.getData().getNextId()); + return Boolean.TRUE; + } else { + log.error("GamesPGXServiceImpl [getBetRecordByTime] 获取投注记录失败,错误代码{},错误信息{}", betRecordByTime.getCode(), betRecordByTime.getMessage()); + throw new BaseException(betRecordByTime.getMessage()); + } + } + + /** + * 按历史时间获取投注记录 + * + * @param betRecordByTimeDTO 按时间dto投注记录 + * @return {@link Boolean } + */ + @Override + public Boolean getBetRecordByHistoryTime(BetRecordByTimeDTO betRecordByTimeDTO) { + //请求参数 + log.info("GamesPGTServiceImpl [getBetRecordByTime] 请求参数 {}", betRecordByTimeDTO); + + String startTime = DateUtils.convertTimestampToFormattedDate(betRecordByTimeDTO.getStartTime(), DateUtils.ISO_8601_FORMAT_Z, "GMT+0"); + String endTime = DateUtils.convertTimestampToFormattedDate(betRecordByTimeDTO.getEndTime(), DateUtils.ISO_8601_FORMAT_Z, "GMT+0"); + + String nextId = redisCache.getCacheObject(CacheConstants.PGT_NEXT_ID); + + + Map paramsMap = new LinkedHashMap<>(); + paramsMap.put("productId", productId); + paramsMap.put("startTime", startTime); + paramsMap.put("endTime", endTime); + paramsMap.put("nextId", nextId); + Map key = this.getKey(betRecordByTimeDTO); + + PGTTransactionDetailsResponse betRecordByTime = pgtClient.getBetRecordByTime(JsonUtil.mapToQueryString(paramsMap), key); + + if (this.getIsSuccess(betRecordByTime.getCode())) { + List txns = betRecordByTime.getData().getTxns(); + this.batchInsert(txns, betRecordByTimeDTO); + //保存本次请求的id + redisCache.setCacheObject(CacheConstants.PGT_NEXT_ID, betRecordByTime.getData().getNextId()); + return Boolean.TRUE; + } else { + log.error("GamesPGXServiceImpl [getBetRecordByTime] 获取投注记录失败,错误代码{},错误信息{}", betRecordByTime.getCode(), betRecordByTime.getMessage()); + throw new BaseException(betRecordByTime.getMessage()); + } + } + + /** + * 赠送免费局数 + * + * @param createFreeSpinRequest 创建自由旋转请求 + * @return {@link Boolean } + */ + @Override + public Boolean createFreeSpin(CreateFreeSpinRequestDTO createFreeSpinRequest) { + throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); + } + + /** + * 获取游戏详细信息 + * + * @param getGameDetailRequestDTO 获取游戏详细信息请求dto + * @return {@link GetGameDetailResponseDTO } + */ + @Override + public GetGameDetailResponseDTO getGameDetail(GetGameDetailRequestDTO getGameDetailRequestDTO) { + //请求参数 + log.info("GamesPGTServiceImpl [getGameDetail] 请求参数 {}", getGameDetailRequestDTO); + + List gameBettingDetails = gameBettingDetailsService.selectGameBettingDetailsList(GameBettingDetailsDTO.builder() + .wagersId(getGameDetailRequestDTO.getWagersId()) + .platformCode(GamePlatforms.PGT.getCode()) + .build()); + if (CollectionUtils.isEmpty(gameBettingDetails)) { + return null; + } + GameBettingDetails bettingDetails = gameBettingDetails.get(0); + + + Map paramsMap = new LinkedHashMap<>(); + paramsMap.put("productId", productId); + paramsMap.put("betId", getGameDetailRequestDTO.getWagersId()); + paramsMap.put("username", bettingDetails.getAccount()); + Map key = this.getKey(getGameDetailRequestDTO); + + PGTReplayUrlResponseDTO pgtReplayUrlResponseDTO = pgtClient.betTransactionReplay(JsonUtil.mapToQueryString(paramsMap), key); + + if (this.getIsSuccess(pgtReplayUrlResponseDTO.getCode())) { + return GetGameDetailResponseDTO.builder() + .url(pgtReplayUrlResponseDTO.getData().getUrl()) + .build(); + } else { + return null; + } + } + + /** + * 强制会员从游戏注销 + * + * @param kickMemberRequestDTO 踢会员请求dto + * @return {@link Boolean } + */ + @Override + public Boolean kickMember(KickMemberRequestDTO kickMemberRequestDTO) { + throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); + } + + /** + * 踢成员全部 + * + * @param kickMemberAllDTO 踢成员全部dto + * @return {@link Boolean } + */ + @Override + public Boolean kickMemberAll(KickMemberAllDTO kickMemberAllDTO) { + throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); + } + + /** + * 免费游戏玩家使用的纪录 + * + * @param getFreeSpinDashflowRequestDTO 获取自由旋转dashflow请求dto + * @return {@link List }<{@link GameFreeRecord }> + */ + @Override + public List getFreeSpinDashflow(GetFreeSpinDashflowRequestDTO getFreeSpinDashflowRequestDTO) { + throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); + } + + /** + * 取消赠送免费局数 + * + * @param cancelFreeSpinRequestDTO 取消免费旋转请求 + * @return {@link Boolean } + */ + @Override + public Boolean cancelFreeSpin(CancelFreeSpinRequestDTO cancelFreeSpinRequestDTO) { + throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); + } + + /** + * 游戏演示登录 + * + * @param gameDemoLoginRequestDTO 游戏演示登录请求dto + * @return {@link GameDemoLoginResponseDTO } + */ + @Override + public GameDemoLoginResponseDTO gameDemoLogin(GameDemoLoginRequestDTO gameDemoLoginRequestDTO) { + throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); + } + + + /** + * 批量插入 + * + * @param dataBean 数据bean + */ + private synchronized void batchInsert(List dataBean, GamesBaseRequestDTO gamesBaseRequestDTO) { + List gameBettingDetails = new ArrayList<>(); + List wagersIds = new ArrayList<>(); + + //数据转化 + for (PGTTransactionDetailsResponse.Transaction bean : dataBean) { + GameBettingDetails bettingDetails = this.dataBuild(GamesDataBuildDTO.builder().agentId(gamesBaseRequestDTO.getAgentId()) + .platform(gamesBaseRequestDTO.getVendor()) + .data(bean).build()); + if (!ObjectUtils.isEmpty(bettingDetails)) { + bettingDetails.setId(IdUtil.getSnowflakeNextId()); + gameBettingDetails.add(bettingDetails); + } + wagersIds.add(String.valueOf(bean.getId())); + } + if (!CollectionUtils.isEmpty(gameBettingDetails)) { + //查询重复数据id + List removeWagersIds = gameBettingDetailsService.selectGameBettingDetailsByWagersId(wagersIds, GamePlatforms.PGX.getInfo()); + //用steam流清除list中与wagersIds集合相同的数据 + gameBettingDetails = gameBettingDetails.stream() + .filter(detail -> !removeWagersIds.contains(detail.getWagersId())) + .collect(Collectors.toList()); + if (!CollectionUtils.isEmpty(gameBettingDetails)) { + gameBettingDetailsService.batchInsert(gameBettingDetails); + + + } + } + + } + + /** + * 数据构建 + * + * @param gamesDataBuildDTO 数据 + * @return {@link GameBettingDetails } + */ + @Override + public GameBettingDetails dataBuild(GamesDataBuildDTO gamesDataBuildDTO) { + //转化类 + PGTTransactionDetailsResponse.Transaction resultBean = (PGTTransactionDetailsResponse.Transaction) gamesDataBuildDTO.getData(); + + + //只要结算的数据 + if (!PGTBetStatus.SETTLED.getType().equals(resultBean.getBetStatus())) { + return null; + } + + + Member member = memberService.selectMemberByGameAccount(resultBean.getUsername()); + if (ObjectUtils.isEmpty(member)) { + return null; + } + List gamesDatas = redisCache.getCacheList(CacheConstants.PGT_GAMES); + Map dataDTOMap = gamesDatas.stream().collect(Collectors.toMap(PGTGameListResponse.Game::getCode, e -> e)); + PGTGameListResponse.Game gamesDataDTO = dataDTOMap.get(resultBean.getGameCode()); + Integer gameStatus =GameStatus.FLAT.getCode(); + if (resultBean.getPayout().compareTo(resultBean.getStake())>0){ + gameStatus=GameStatus.WIN.getCode(); + }else if (resultBean.getPayout().compareTo(resultBean.getStake())<0){ + gameStatus=GameStatus.FAIL.getCode(); + } + + //数据构造 + GameBettingDetails gameBettingDetails = GameBettingDetails.builder() + .tenantKey(member.getTenantKey()) + //保存我们的币种id + .currencyCode(gamesDataBuildDTO.getPlatform().getOurCurrency(resultBean.getCurrency())) + .memberId(member.getId()) + .gameCode(resultBean.getGameCode()) + .gameType(PGTGameType.findSystemByCode(gamesDataDTO.getCategory())) + .platformCode(GamePlatforms.PGT.getCode()) + //.gameId(gamesDataDTO.getSystemGameId()) + .gameId(gamesDataDTO.getSystemGameId()) + .gameName(gamesDataDTO.getName()) + .gameStatus(gameStatus) + .gameStatusType(1) + .gameCurrencyCode(resultBean.getCurrency()) + .account(resultBean.getUsername()) + .wagersId(resultBean.getBetId()) + .wagersTime(resultBean.getAccountingDate().getTime()) + .betAmount(resultBean.getStake()) + .payoffTime(resultBean.getAccountingDate().getTime()) + .payoffAmount(resultBean.getPayout()) + .settlementTime(resultBean.getAccountingDate().getTime()) + .turnover(resultBean.getStake()) + .orderNo(resultBean.getRoundId()) + .settlementStatus(SettlementStatusEnum.COMPLETED.getCode()) + .build(); + gameBettingDetails.setCreateBy(Constants.SYSTEM); + gameBettingDetails.setCreateTime(DateUtils.getNowDate()); + return gameBettingDetails; + } +} diff --git a/ff-game/src/main/java/com/ff/game/api/pgx/address/MyPGXAddressSource.java b/ff-game/src/main/java/com/ff/game/api/pgx/address/MyPGXAddressSource.java index 5bd6c65..e3349d0 100644 --- a/ff-game/src/main/java/com/ff/game/api/pgx/address/MyPGXAddressSource.java +++ b/ff-game/src/main/java/com/ff/game/api/pgx/address/MyPGXAddressSource.java @@ -3,8 +3,8 @@ package com.ff.game.api.pgx.address; import com.dtflys.forest.callback.AddressSource; import com.dtflys.forest.http.ForestAddress; import com.dtflys.forest.http.ForestRequest; -import com.ff.base.constant.Constants; -import com.ff.base.system.service.ISysConfigService; +import com.ff.base.enums.GamePlatforms; +import com.ff.game.service.IPlatformService; import org.springframework.stereotype.Component; import javax.annotation.Resource; @@ -20,12 +20,13 @@ import javax.annotation.Resource; public class MyPGXAddressSource implements AddressSource { @Resource - private ISysConfigService configService; - + private IPlatformService platformService; @Override public ForestAddress getAddress(ForestRequest request) { - String apiBaseUrl = configService.selectConfigByKey(Constants.PGX_API_BASE_URL); - return new ForestAddress("http",apiBaseUrl, 80,""); +// String apiBaseUrl = configService.selectConfigByKey(Constants.PGX_API_BASE_URL); + String apiBaseUrl = platformService.get(GamePlatforms.PGX.getCode()) + .getUrlInfo().getUrl(); + return new ForestAddress("http", apiBaseUrl, 80, ""); } } \ No newline at end of file diff --git a/ff-game/src/main/java/com/ff/game/api/pgx/client/PGXClient.java b/ff-game/src/main/java/com/ff/game/api/pgx/client/PGXClient.java index 8cb1827..d85909f 100644 --- a/ff-game/src/main/java/com/ff/game/api/pgx/client/PGXClient.java +++ b/ff-game/src/main/java/com/ff/game/api/pgx/client/PGXClient.java @@ -106,8 +106,13 @@ public interface PGXClient { * * @return {@link PGXBetHistoryResponse } */ - @Get(url = "/fetchArchieve.aspx?{parameters}") - PGXBetHistoryResponse getBetRecordByTime(@Var("parameters") String parameters); + @Get(url = "{url}/fetchbykey.aspx?{parameters}") + PGXBetHistoryResponse getBetRecordByTime(@Var("url") String url,@Var("parameters") String parameters); + + + + @Get(url = "{url}/fetchArchieve.aspx?{parameters}") + PGXBetHistoryResponse getBetRecordByHistoryTime(@Var("url") String url,@Var("parameters") String parameters); /** diff --git a/ff-game/src/main/java/com/ff/game/api/pgx/dto/PGXBetHistoryResponse.java b/ff-game/src/main/java/com/ff/game/api/pgx/dto/PGXBetHistoryResponse.java index 6e43ba3..3a587da 100644 --- a/ff-game/src/main/java/com/ff/game/api/pgx/dto/PGXBetHistoryResponse.java +++ b/ff-game/src/main/java/com/ff/game/api/pgx/dto/PGXBetHistoryResponse.java @@ -40,16 +40,16 @@ public class PGXBetHistoryResponse { public class Result { /** - * AIO注单号 (唯一值) (Int类型) + * AIO注单号 (唯一值) (Long类型) */ @JsonProperty("id") - private int id; + private Long id; /** - * 供应商注单号 (Int类型) + * 供应商注单号 (Long类型) */ @JsonProperty("ref_no") - private int refNo; + private Long refNo; /** * 供应商代号 (String类型) @@ -72,20 +72,20 @@ public class PGXBetHistoryResponse { /** * 游戏代号 (String类型) */ - @JsonProperty("gameid") + @JsonProperty("game_id") private String gameId; /** * 下注时间 (玩家实际的投注时间) 依据 GMT/UTC +0 时区 */ @JsonProperty("start_time") - private Date startTime; + private String startTime; /** * 结算时间 (String类型) 依据 GMT/UTC +0 时区 */ @JsonProperty("end_time") - private Date endTime; + private String endTime; /** * 开赛时间 (String类型) 依据 GMT/UTC +0 时区 diff --git a/ff-game/src/main/java/com/ff/game/api/pgx/dto/PGXExchangeTransferStatusResponse.java b/ff-game/src/main/java/com/ff/game/api/pgx/dto/PGXExchangeTransferStatusResponse.java index e91c2a7..30881ba 100644 --- a/ff-game/src/main/java/com/ff/game/api/pgx/dto/PGXExchangeTransferStatusResponse.java +++ b/ff-game/src/main/java/com/ff/game/api/pgx/dto/PGXExchangeTransferStatusResponse.java @@ -3,6 +3,8 @@ package com.ff.game.api.pgx.dto; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; +import java.math.BigDecimal; + /** * pgxexchange传输状态响应 * @@ -45,7 +47,7 @@ public class PGXExchangeTransferStatusResponse { /** 交易金额 (double类型) */ @JsonProperty("amount") - private double amount; + private BigDecimal amount; /** 运营商的参考ID (String类型) */ @JsonProperty("ref_id") diff --git a/ff-game/src/main/java/com/ff/game/api/pgx/dto/PGXGameListResponse.java b/ff-game/src/main/java/com/ff/game/api/pgx/dto/PGXGameListResponse.java index f53e146..500a792 100644 --- a/ff-game/src/main/java/com/ff/game/api/pgx/dto/PGXGameListResponse.java +++ b/ff-game/src/main/java/com/ff/game/api/pgx/dto/PGXGameListResponse.java @@ -48,7 +48,7 @@ public class PGXGameListResponse { /** * 系统游戏id */ - private Long systemGameId; + private String systemGameId; /** 游戏代码 (字符串类型) */ @JsonProperty("gameCode") diff --git a/ff-game/src/main/java/com/ff/game/api/pgx/impl/GamesPGXServiceImpl.java b/ff-game/src/main/java/com/ff/game/api/pgx/impl/GamesPGXServiceImpl.java index 37f1673..7469ef3 100644 --- a/ff-game/src/main/java/com/ff/game/api/pgx/impl/GamesPGXServiceImpl.java +++ b/ff-game/src/main/java/com/ff/game/api/pgx/impl/GamesPGXServiceImpl.java @@ -12,20 +12,17 @@ import com.ff.base.exception.base.BaseException; import com.ff.base.system.service.ISysConfigService; import com.ff.base.utils.DateUtils; import com.ff.base.utils.JsonUtil; +import com.ff.base.utils.StringUtils; import com.ff.base.utils.sign.Md5Utils; import com.ff.config.KeyConfig; import com.ff.game.api.IGamesService; -import com.ff.game.api.dg.dto.DGBetRecordResponseDTO; -import com.ff.game.api.ng.dto.ApiExchangeTransferStatusResponseDTO; import com.ff.game.api.pgx.client.PGXClient; import com.ff.game.api.pgx.dto.*; import com.ff.game.api.request.*; -import com.ff.game.api.xk.dto.XKBetRecordResponseDTO; -import com.ff.game.api.xk.dto.XKGamesDTO; -import com.ff.game.api.xk.dto.XKKickMemberDTO; import com.ff.game.domain.*; -import com.ff.game.dto.GameSecretKeyCurrencyDTO; -import com.ff.game.service.*; +import com.ff.game.service.IGameBettingDetailsService; +import com.ff.game.service.IGameExchangeMoneyService; +import com.ff.game.service.IGameService; import com.ff.member.domain.Member; import com.ff.member.service.IMemberService; import lombok.extern.slf4j.Slf4j; @@ -37,7 +34,10 @@ import org.springframework.util.ObjectUtils; import javax.annotation.Resource; import java.math.BigDecimal; -import java.util.*; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @@ -63,10 +63,6 @@ public class GamesPGXServiceImpl implements IGamesService { private IGameExchangeMoneyService gameExchangeMoneyService; - @Resource - private IGamePlatformService gamePlatformService; - - @Resource private IGameService gameService; @@ -74,14 +70,6 @@ public class GamesPGXServiceImpl implements IGamesService { @Resource private IMemberService memberService; - @Resource - private IGameFreeRecordService gameFreeRecordService; - @Resource - private IGameSecretKeyService gameSecretKeyService; - - @Resource - private IGameSecretKeyCurrencyService gameSecretKeyCurrencyService; - @Resource private PGXClient PGXClient; @@ -92,9 +80,6 @@ public class GamesPGXServiceImpl implements IGamesService { @Resource private IGameBettingDetailsService gameBettingDetailsService; - @Resource - private IGameNameService gameNameService; - /** * 获得就是成功 @@ -158,11 +143,11 @@ public class GamesPGXServiceImpl implements IGamesService { @Override public MemberInfoResponseDTO getMemberInfo(MemberInfoRequestDTO memberInfoRequestDTO) { log.info("GamesPGXServiceImpl [getMemberInfo] 请求参数 {}", memberInfoRequestDTO); - GameSecretKey gameSecretKey = gameSecretKeyService.selectGameSecretKeyByCode(memberInfoRequestDTO.getAgentId()); Map params = new LinkedHashMap<>(); params.put("operatorcode", memberInfoRequestDTO.getAgentId()); - params.put("password", gameSecretKey.getPassword()); - params.put("providercode", gameSecretKey.getProviderCode()); + KeyInfo keyInfo = memberInfoRequestDTO.getKeyInfo(); + params.put("password", keyInfo.getPassword()); + params.put("providercode", keyInfo.getProviderCode()); params.put("username", memberInfoRequestDTO.getAccounts()); String key = this.getKey(params, memberInfoRequestDTO); params.put("signature", key); @@ -189,11 +174,12 @@ public class GamesPGXServiceImpl implements IGamesService { @Override public String loginWithoutRedirect(GamesLogin gamesLogin) { log.info("GamesPGXServiceImpl [loginWithoutRedirect] 请求参数 {}", gamesLogin); - GameSecretKey gameSecretKey = gameSecretKeyService.selectGameSecretKeyByCode(gamesLogin.getAgentId()); + KeyInfo keyInfo = gamesLogin.getKeyInfo(); + Map params = new LinkedHashMap<>(); params.put("operatorcode", gamesLogin.getAgentId()); - params.put("password", gameSecretKey.getPassword()); - params.put("providercode", gameSecretKey.getProviderCode()); + params.put("password", keyInfo.getPassword()); + params.put("providercode", keyInfo.getProviderCode()); params.put("type", gamesLogin.getGameType()); params.put("username", gamesLogin.getAccount()); String key = this.getKey(params, gamesLogin); @@ -226,10 +212,10 @@ public class GamesPGXServiceImpl implements IGamesService { return CacheConstants.PGX_GAMES; } - GameSecretKey gameSecretKey = gameSecretKeyService.selectGameSecretKeyByCode(gamesBaseRequestDTO.getAgentId()); + KeyInfo keyInfo = gamesBaseRequestDTO.getKeyInfo(); Map params = new LinkedHashMap<>(); params.put("operatorcode", gamesBaseRequestDTO.getAgentId()); - params.put("providercode", gameSecretKey.getProviderCode()); + params.put("providercode", keyInfo.getProviderCode()); String key = this.getKey(params, gamesBaseRequestDTO); //没有中文 params.put("html5", 1); @@ -242,47 +228,35 @@ public class GamesPGXServiceImpl implements IGamesService { List gameLists = JSON.parseArray(gameList.getGamelist(), PGXGameListResponse.Game.class); for (PGXGameListResponse.Game gamesDataDTO : gameLists) { - GamePlatform gamePlatform = GamePlatform.builder() - .platformType(GPXGameType.SL.getSystemCode()) - .platformCode(GamePlatforms.PGX.getCode()) - .build(); - List gamePlatforms = gamePlatformService.selectGamePlatformList(gamePlatform); - //没有此平台就新增一个平台 - if (CollectionUtils.isEmpty(gamePlatforms)) { - gamePlatform.setPlatformName(GamePlatforms.PGX.getInfo() + XKGameType.findInfoByCode(GPXGameType.SL.getSystemCode())); - gamePlatform.setSortNo(gamePlatformService.selectMaxSortNo() + 1); - gamePlatform.setCreateBy(Constants.SYSTEM); - gamePlatformService.insertGamePlatform(gamePlatform); - } else { - gamePlatform = gamePlatforms.get(0); - } + Game game = Game.builder() - .platformId(gamePlatform.getId()) .gameCode(gamesDataDTO.getGameId()) + .platformCode(GamePlatforms.PGX.getCode()) + .platformType(GPXGameType.SL.getSystemCode()) .build(); List games = gameService.selectGameList(game); //不存在这个游戏 if (CollectionUtils.isEmpty(games)) { game.setGameSourceType(GPXGameType.SL.getCode()); game.setFreespin(Boolean.FALSE); - game.setSortNo(gameService.selectMaxSortNoByPlatformId(gamePlatform.getId()) + 1); + game.setSortNo(gameService.selectMaxSortNo(GPXGameType.SL.getSystemCode(), GamePlatforms.PGX.getCode()) + 1); game.setGameName(gamesDataDTO.getGameName()); game.setCreateBy(Constants.SYSTEM); + game.setPlatformCode(GamePlatforms.PGX.getCode()); + game.setPlatformType(GPXGameType.SL.getSystemCode()); + game.setGameId(StringUtils.addSuffix(GamePlatforms.PGX.getCode(), gamesDataDTO.getGameId())); + List nameInfos = new ArrayList<>(); + nameInfos.add(new NameInfo(gamesDataDTO.getGameName(), "en-US")); + game.setNameInfo(nameInfos); gameService.insertGame(game); } else { game = games.get(0); + List nameInfos = new ArrayList<>(); + nameInfos.add(new NameInfo(gamesDataDTO.getGameName(), "en-US")); + game.setNameInfo(nameInfos); + gameService.updateGame(game); } - gamesDataDTO.setSystemGameId(game.getId()); - List gameNames = gameNameService.selectGameNameList(GameName.builder().gameId(game.getId()).gameName(game.getGameName()).build()); - if (CollectionUtils.isEmpty(gameNames)) { - gameNameService.insertGameName(GameName.builder() - .gameId(game.getId()) - .gameName(game.getGameName()) - .langCode("en-US") - .createBy(Constants.SYSTEM) - .build()); - } - + gamesDataDTO.setSystemGameId(game.getGameId()); } @@ -307,38 +281,9 @@ public class GamesPGXServiceImpl implements IGamesService { public Long exchangeTransferByAgentId(ExchangeTransferMoneyRequestDTO exchangeTransferMoneyRequestDTO) { log.info("GamesPGXServiceImpl [exchangeTransferByAgentId] 请求参数 {}", exchangeTransferMoneyRequestDTO); - GameSecretKeyCurrency currencyDTO = gameSecretKeyCurrencyService.findByGameSecretKeyCurrencyDTO(GameSecretKeyCurrencyDTO.builder() - .platformCode(GamePlatforms.PGX.getCode()) - .code(exchangeTransferMoneyRequestDTO.getAgentId()) - .currency(exchangeTransferMoneyRequestDTO.getCurrency()) - .build()); - Member member = memberService.selectMemberByGameAccount(exchangeTransferMoneyRequestDTO.getAccount()); - String transactionId = gameExchangeMoneyService.getTransactionId(GamePlatforms.PGX.getCode(), 17); - List gameExchangeMonies = gameExchangeMoneyService.selectGameExchangeMoneyList( - GameExchangeMoney.builder() - .tenantKey(exchangeTransferMoneyRequestDTO.getTenantKey()) - .orderId(exchangeTransferMoneyRequestDTO.getOrderId()) - .build() - ); - Assert.isTrue(CollectionUtils.isEmpty(gameExchangeMonies), "订单号重复"); + GameExchangeMoney exchangeMoney = gameExchangeMoneyService.selectGameExchangeMoneyById(exchangeTransferMoneyRequestDTO.getGameExchangeId()); - GameSecretKey gameSecretKey = gameSecretKeyService.selectGameSecretKeyByCode(exchangeTransferMoneyRequestDTO.getAgentId()); - - //获取下一个自增id - GameExchangeMoney exchangeMoney = GameExchangeMoney - .builder() - .tenantKey(exchangeTransferMoneyRequestDTO.getTenantKey()) - .orderId(exchangeTransferMoneyRequestDTO.getOrderId()) - .quota(exchangeTransferMoneyRequestDTO.getQuota()) - .balance(exchangeTransferMoneyRequestDTO.getAmount()) - .exchangeType(exchangeTransferMoneyRequestDTO.getTransferType()) - .currencyCode(currencyDTO.getSystemCurrency()) - .memberId(member.getId()) - .transactionId(transactionId) - .platformCode(GamePlatforms.PGX.getCode()) - .build(); - exchangeMoney.setCreateBy(Constants.SYSTEM); //获取余额 String type = TransferType.ALL.getCode().equals(exchangeTransferMoneyRequestDTO.getTransferType()) ? PGXTransferType.WITHDRAW.getCode() : PGXTransferType.DEPOSIT.getCode(); @@ -350,6 +295,10 @@ public class GamesPGXServiceImpl implements IGamesService { MemberInfoRequestDTO gamesBaseRequestDTO = MemberInfoRequestDTO.builder() .accounts(exchangeTransferMoneyRequestDTO.getAccount()) .agentId(exchangeTransferMoneyRequestDTO.getAgentId()) + .vendor(exchangeTransferMoneyRequestDTO.getVendor()) + .keyInfo(exchangeTransferMoneyRequestDTO.getKeyInfo()) + .systemCurrency(exchangeTransferMoneyRequestDTO.getSystemCurrency()) + .currency(exchangeTransferMoneyRequestDTO.getCurrency()) .agentKey(exchangeTransferMoneyRequestDTO.getAgentKey()) .build(); @@ -362,12 +311,13 @@ public class GamesPGXServiceImpl implements IGamesService { } + KeyInfo keyInfo = exchangeTransferMoneyRequestDTO.getKeyInfo(); Map paramsMap = new LinkedHashMap<>(); paramsMap.put("amount", amount); paramsMap.put("operatorcode", exchangeTransferMoneyRequestDTO.getAgentId()); - paramsMap.put("password", gameSecretKey.getPassword()); - paramsMap.put("providercode", gameSecretKey.getProviderCode()); - paramsMap.put("referenceid", transactionId); + paramsMap.put("password", keyInfo.getPassword()); + paramsMap.put("providercode", keyInfo.getProviderCode()); + paramsMap.put("referenceid", exchangeTransferMoneyRequestDTO.getTransactionId()); paramsMap.put("type", type); paramsMap.put("username", exchangeTransferMoneyRequestDTO.getAccount()); String key = this.getKey(paramsMap, exchangeTransferMoneyRequestDTO); @@ -386,16 +336,13 @@ public class GamesPGXServiceImpl implements IGamesService { exchangeMoney.setCurrencyBefore(exchangeMoney.getCoinBefore()); exchangeMoney.setCurrencyAfter(exchangeMoney.getCoinAfter()); exchangeMoney.setStatus(StatusType.IN_PROGRESS.getValue()); - - gameExchangeMoneyService.insertGameExchangeMoney(exchangeMoney); - //确认状态 - ExchangeTransferStatusRequestDTO exchangeTransferStatusRequestDTO = new ExchangeTransferStatusRequestDTO(); - exchangeTransferStatusRequestDTO.setAccount(member.getGameAccount()); - exchangeTransferStatusRequestDTO.setOrderId(exchangeMoney.getTransactionId()); - exchangeTransferStatusRequestDTO.setAgentId(gameSecretKey.getCode()); - exchangeTransferStatusRequestDTO.setAgentKey(gameSecretKey.getKey()); - this.exchangeTransferStatus(exchangeTransferStatusRequestDTO); + exchangeMoney.setStep(GameExchangeStep.PLATFORM_TRANSACTION.getCode()); + exchangeMoney.setStepStatus(GameExchangeStepStatus.SUCCESS.getCode()); + gameExchangeMoneyService.updateGameExchangeMoney(exchangeMoney); } else { + exchangeMoney.setStep(GameExchangeStep.PLATFORM_TRANSACTION.getCode()); + exchangeMoney.setStepStatus(GameExchangeStepStatus.FAILURE.getCode()); + gameExchangeMoneyService.updateGameExchangeMoney(exchangeMoney); log.error("GamesFCServiceImpl [exchangeTransferByAgentId] 金额转移失败,错误代码{}", errorResponse.getErrCode()); throw new ApiException(ErrorCode.BALANCE_TRANSFER_FAILED.getCode()); } @@ -409,7 +356,7 @@ public class GamesPGXServiceImpl implements IGamesService { * @return {@link Boolean } */ @Override - public Boolean exchangeTransferStatus(ExchangeTransferStatusRequestDTO exchangeTransferMoneyRequestDTO) { + public ExchangeTransferStatusResponseDTO exchangeTransferStatus(ExchangeTransferStatusRequestDTO exchangeTransferMoneyRequestDTO) { log.info("GamesPGXServiceImpl [exchangeTransferStatus] 请求参数 {}", exchangeTransferMoneyRequestDTO); Map paramsMap = new LinkedHashMap<>(); paramsMap.put("operatorcode", exchangeTransferMoneyRequestDTO.getAgentId()); @@ -418,24 +365,16 @@ public class GamesPGXServiceImpl implements IGamesService { paramsMap.put("signature", key); PGXExchangeTransferStatusResponse exchangeTransferStatusResponse = PGXClient.exchangeTransferStatus(JsonUtil.mapToQueryString(paramsMap)); + Integer status = StatusType.IN_PROGRESS.getValue(); if (this.getIsSuccess(exchangeTransferStatusResponse.getErrCode())) { - List gameExchangeMonies = gameExchangeMoneyService.selectGameExchangeMoneyList( - GameExchangeMoney.builder() - .platformCode(GamePlatforms.PGX.getCode()) - .transactionId(exchangeTransferMoneyRequestDTO.getOrderId()) - .build() - ); - - for (GameExchangeMoney exchangeMoney : gameExchangeMonies) { - //更新数据 - exchangeMoney.setStatus(PGXTransactionStatus.findValueByCode(exchangeTransferStatusResponse.getStatus())); - gameExchangeMoneyService.updateGameExchangeMoney(exchangeMoney); - } - return Boolean.TRUE; + status= PGXTransactionStatus.findValueByCode(exchangeTransferStatusResponse.getStatus()); } else { - log.error("GamesPGXServiceImpl [exchangeTransferStatus]错误代码{},错误信息{}", exchangeTransferStatusResponse.getErrCode(), exchangeTransferStatusResponse.getErrMsg()); - return Boolean.FALSE; + status = StatusType.FAILURE.getValue(); } + return ExchangeTransferStatusResponseDTO.builder() + .statusType(status) + .balance(exchangeTransferStatusResponse.getAmount()) + .build(); } @@ -454,7 +393,8 @@ public class GamesPGXServiceImpl implements IGamesService { String key = this.getKey(paramsMap, betRecordByTimeDTO); paramsMap.put("versionkey", 0); paramsMap.put("signature", key); - PGXBetHistoryResponse betRecordByTime = PGXClient.getBetRecordByTime(JsonUtil.mapToQueryString(paramsMap)); + String betUrl = betRecordByTimeDTO.getVendor().getUrlInfo().getBetUrl(); + PGXBetHistoryResponse betRecordByTime = PGXClient.getBetRecordByTime(betUrl,JsonUtil.mapToQueryString(paramsMap)); if (this.getIsSuccess(betRecordByTime.getErrCode())) { List results = JSON.parseArray(betRecordByTime.getResult(), PGXBetHistoryResponse.Result.class); @@ -474,9 +414,41 @@ public class GamesPGXServiceImpl implements IGamesService { */ @Override public Boolean getBetRecordByHistoryTime(BetRecordByTimeDTO betRecordByTimeDTO) { - return null; + //请求参数 + log.info("GamesPGXServiceImpl [getBetRecordByHistoryTime] 请求参数 {}", betRecordByTimeDTO); + Map paramsMap = new LinkedHashMap<>(); + paramsMap.put("operatorcode", betRecordByTimeDTO.getAgentId()); + String key = this.getKey(paramsMap, betRecordByTimeDTO); + paramsMap.put("versionkey", 0); + paramsMap.put("signature", key); + String betUrl = betRecordByTimeDTO.getVendor().getUrlInfo().getBetUrl(); + PGXBetHistoryResponse betRecordByTime = PGXClient.getBetRecordByHistoryTime(betUrl,JsonUtil.mapToQueryString(paramsMap)); + + if (this.getIsSuccess(betRecordByTime.getErrCode())) { + List results = JSON.parseArray(betRecordByTime.getResult(), PGXBetHistoryResponse.Result.class); + this.batchInsert(results, betRecordByTimeDTO); + return Boolean.TRUE; + } else { + log.error("GamesPGXServiceImpl [getBetRecordByHistoryTime] 获取投注记录失败,错误代码{},错误信息{}", betRecordByTime.getErrCode(), betRecordByTime.getErrMsg()); + throw new BaseException(betRecordByTime.getErrMsg()); + } } + + + /** + * 获取交易id + * + * @param transactionIdRequestDTO 事务id请求dto + * @return {@link String } + */ + @Override + public String getTransactionId(TransactionIdRequestDTO transactionIdRequestDTO) { + return gameExchangeMoneyService.getTransactionId(GamePlatforms.PGX.getInfo(), 17); + } + + + /** * 赠送免费局数 * @@ -543,19 +515,34 @@ public class GamesPGXServiceImpl implements IGamesService { throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); } + /** + * 游戏演示登录 + * + * @param gameDemoLoginRequestDTO 游戏演示登录请求dto + * @return {@link GameDemoLoginResponseDTO } + */ + @Override + public GameDemoLoginResponseDTO gameDemoLogin(GameDemoLoginRequestDTO gameDemoLoginRequestDTO) { + throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); + } + /** * 批量插入 * * @param dataBean 数据bean */ - private void batchInsert(List dataBean, GamesBaseRequestDTO gamesBaseRequestDTO) { + private void batchInsert(List dataBean, BetRecordByTimeDTO gamesBaseRequestDTO) { List gameBettingDetails = new ArrayList<>(); List wagersIds = new ArrayList<>(); //数据转化 for (PGXBetHistoryResponse.Result bean : dataBean) { - GameBettingDetails bettingDetails = this.dataBuild(GamesDataBuildDTO.builder().agentId(gamesBaseRequestDTO.getAgentId()).data(bean).build()); + GameBettingDetails bettingDetails = this.dataBuild(GamesDataBuildDTO.builder() + .currencyCode(gamesBaseRequestDTO.getCurrency()) + .systemCurrencyCode(gamesBaseRequestDTO.getSystemCurrency()) + .agentId(gamesBaseRequestDTO.getAgentId()) + .data(bean).build()); if (!ObjectUtils.isEmpty(bettingDetails)) { bettingDetails.setId(IdUtil.getSnowflakeNextId()); gameBettingDetails.add(bettingDetails); @@ -564,7 +551,7 @@ public class GamesPGXServiceImpl implements IGamesService { } if (!CollectionUtils.isEmpty(gameBettingDetails)) { //查询重复数据id - List removeWagersIds = gameBettingDetailsService.selectGameBettingDetailsByWagersId(wagersIds); + List removeWagersIds = gameBettingDetailsService.selectGameBettingDetailsByWagersId(wagersIds, GamePlatforms.PGX.getInfo()); //用steam流清除list中与wagersIds集合相同的数据 gameBettingDetails = gameBettingDetails.stream() .filter(detail -> !removeWagersIds.contains(detail.getWagersId())) @@ -595,10 +582,7 @@ public class GamesPGXServiceImpl implements IGamesService { //转化类 PGXBetHistoryResponse.Result resultBean = (PGXBetHistoryResponse.Result) gamesDataBuildDTO.getData(); - GameSecretKeyCurrency currencyDTO = gameSecretKeyCurrencyService.findByGameSecretKeyCurrencyDTO(GameSecretKeyCurrencyDTO.builder() - .platformCode(GamePlatforms.PGX.getInfo()) - .code(gamesDataBuildDTO.getAgentId()) - .build()); + Member member = memberService.selectMemberByGameAccount(resultBean.getMember()); if (ObjectUtils.isEmpty(member)) { @@ -620,11 +604,12 @@ public class GamesPGXServiceImpl implements IGamesService { payoffAmount = NumberUtil.sub(payout, resultBean.getBet()).negate(); gameStatus = GameStatus.FAIL.getCode(); } + long endTime = DateUtils.convertToMillisWithTimezone(resultBean.getEndTime(), "UTC"); //数据构造 GameBettingDetails gameBettingDetails = GameBettingDetails.builder() .tenantKey(member.getTenantKey()) //保存我们的币种id - .currencyCode(currencyDTO.getSystemCurrency()) + .currencyCode(/*currencyDTO.getSystemCurrency()*/gamesDataBuildDTO.getSystemCurrencyCode()) .memberId(member.getId()) .gameCode(resultBean.getGameId()) .gameType(GPXGameType.SL.getSystemCode()) @@ -634,14 +619,14 @@ public class GamesPGXServiceImpl implements IGamesService { .gameStatus(gameStatus) .gameStatusType(1) .betContent(resultBean.getBetDetail()) - .gameCurrencyCode(currencyDTO.getCurrency()) + .gameCurrencyCode(/*currencyDTO.getCurrency()*/gamesDataBuildDTO.getCurrencyCode()) .account(resultBean.getMember()) .wagersId(String.valueOf(resultBean.getId())) - .wagersTime(resultBean.getStartTime().getTime()) + .wagersTime(DateUtils.convertToMillisWithTimezone(resultBean.getStartTime(),"UTC")) .betAmount(resultBean.getBet()) - .payoffTime(resultBean.getEndTime().getTime()) + .payoffTime(endTime) .payoffAmount(payoffAmount) - .settlementTime(resultBean.getEndTime().getTime()) + .settlementTime(endTime) .turnover(resultBean.getTurnover()) .settlementStatus(PGXBetRecordStatus.findSystemCodeByCode(resultBean.getStatus())) .build(); diff --git a/ff-game/src/main/java/com/ff/game/api/request/BetRecordByTimeDTO.java b/ff-game/src/main/java/com/ff/game/api/request/BetRecordByTimeDTO.java index a0bb724..61dccb9 100644 --- a/ff-game/src/main/java/com/ff/game/api/request/BetRecordByTimeDTO.java +++ b/ff-game/src/main/java/com/ff/game/api/request/BetRecordByTimeDTO.java @@ -30,13 +30,6 @@ public class BetRecordByTimeDTO extends GamesBaseRequestDTO { * 游戏id */ private Integer gameId; - /** - * 指定平台 - */ - private String gamePlatform; - - - } diff --git a/ff-game/src/main/java/com/ff/game/api/request/CreateMemberRequestDTO.java b/ff-game/src/main/java/com/ff/game/api/request/CreateMemberRequestDTO.java index 46ec0ab..b6d1dac 100644 --- a/ff-game/src/main/java/com/ff/game/api/request/CreateMemberRequestDTO.java +++ b/ff-game/src/main/java/com/ff/game/api/request/CreateMemberRequestDTO.java @@ -6,6 +6,8 @@ import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.SuperBuilder; +import java.util.Map; + /** * 创建成员请求dto * @@ -22,5 +24,15 @@ public class CreateMemberRequestDTO extends GamesBaseRequestDTO { */ private String account; + /** + * ae 平台 投注限额 + */ + private Map>> betLimit; + + /** + * 平台类型 0 桌面 1 移动 + */ + private Integer platformType; + } diff --git a/ff-game/src/main/java/com/ff/game/api/request/ExchangeTransferMoneyRequestDTO.java b/ff-game/src/main/java/com/ff/game/api/request/ExchangeTransferMoneyRequestDTO.java index b9b1dfa..fcd104c 100644 --- a/ff-game/src/main/java/com/ff/game/api/request/ExchangeTransferMoneyRequestDTO.java +++ b/ff-game/src/main/java/com/ff/game/api/request/ExchangeTransferMoneyRequestDTO.java @@ -27,15 +27,7 @@ public class ExchangeTransferMoneyRequestDTO extends GamesBaseRequestDTO { */ private String account; - /** - * 租户密钥 - */ - private String tenantKey; - /** - * 订单id - */ - private String orderId; /** * 金额 */ @@ -43,9 +35,14 @@ public class ExchangeTransferMoneyRequestDTO extends GamesBaseRequestDTO { /** - * 租户额度 + * 游戏交换id */ - private BigDecimal quota; + private Long gameExchangeId; + + /** + * 交易编号 + */ + private String transactionId; /** diff --git a/ff-game/src/main/java/com/ff/game/api/request/ExchangeTransferStatusRequestDTO.java b/ff-game/src/main/java/com/ff/game/api/request/ExchangeTransferStatusRequestDTO.java index 353c3fd..8739091 100644 --- a/ff-game/src/main/java/com/ff/game/api/request/ExchangeTransferStatusRequestDTO.java +++ b/ff-game/src/main/java/com/ff/game/api/request/ExchangeTransferStatusRequestDTO.java @@ -29,5 +29,8 @@ public class ExchangeTransferStatusRequestDTO extends GamesBaseRequestDTO { */ private String orderId; - + /** + * 游戏兑换货币id + */ + private Long gameExchangeMoneyId; } diff --git a/ff-game/src/main/java/com/ff/game/api/request/ExchangeTransferStatusResponseDTO.java b/ff-game/src/main/java/com/ff/game/api/request/ExchangeTransferStatusResponseDTO.java new file mode 100644 index 0000000..7f4a698 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/request/ExchangeTransferStatusResponseDTO.java @@ -0,0 +1,41 @@ +package com.ff.game.api.request; + +import com.ff.base.annotation.Excel; +import com.ff.base.enums.StatusType; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.math.BigDecimal; + +/** + * 交易所转账状态响应数据 + * + * @author shi + * @date 2025/04/08 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class ExchangeTransferStatusResponseDTO { + + + /** + * 状态类型 StatusType 枚举 + */ + private Integer statusType; + + + /** 操作金额 */ + private BigDecimal balance; + + /** 转账前金额(游戏币) */ + private BigDecimal coinBefore; + + /** 转账后金额(游戏币) */ + private BigDecimal coinAfter; + + +} diff --git a/ff-game/src/main/java/com/ff/game/api/request/GameDemoLoginRequestDTO.java b/ff-game/src/main/java/com/ff/game/api/request/GameDemoLoginRequestDTO.java new file mode 100644 index 0000000..31d095c --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/request/GameDemoLoginRequestDTO.java @@ -0,0 +1,34 @@ +package com.ff.game.api.request; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * 游戏演示登录请求dto + * + * @author shi + * @date 2025/04/03 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@SuperBuilder +public class GameDemoLoginRequestDTO extends GamesBaseRequestDTO{ + /** + * 语言 + */ + private String lang; + + + /** + * 游戏类型 + */ + private String gameType; + + /** + * 游戏id + */ + private String gameId; +} diff --git a/ff-game/src/main/java/com/ff/game/api/request/GameDemoLoginResponseDTO.java b/ff-game/src/main/java/com/ff/game/api/request/GameDemoLoginResponseDTO.java new file mode 100644 index 0000000..6f9a2aa --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/request/GameDemoLoginResponseDTO.java @@ -0,0 +1,23 @@ +package com.ff.game.api.request; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 游戏演示登录响应dto + * + * @author shi + * @date 2025/04/03 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class GameDemoLoginResponseDTO { + /** + * 网址 + */ + private String url; +} diff --git a/ff-game/src/main/java/com/ff/game/api/request/GamesBaseRequestDTO.java b/ff-game/src/main/java/com/ff/game/api/request/GamesBaseRequestDTO.java index 072657c..e55b059 100644 --- a/ff-game/src/main/java/com/ff/game/api/request/GamesBaseRequestDTO.java +++ b/ff-game/src/main/java/com/ff/game/api/request/GamesBaseRequestDTO.java @@ -1,7 +1,8 @@ package com.ff.game.api.request; +import com.ff.game.domain.KeyInfo; +import com.ff.game.domain.Platform; import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.SuperBuilder; @@ -36,12 +37,15 @@ public class GamesBaseRequestDTO implements Serializable { private String query; - - /** * 货币 */ private String currency; + private Platform vendor; + + private KeyInfo keyInfo; + + private String systemCurrency; } diff --git a/ff-game/src/main/java/com/ff/game/api/request/GamesDataBuildDTO.java b/ff-game/src/main/java/com/ff/game/api/request/GamesDataBuildDTO.java index 73548ee..23cb419 100644 --- a/ff-game/src/main/java/com/ff/game/api/request/GamesDataBuildDTO.java +++ b/ff-game/src/main/java/com/ff/game/api/request/GamesDataBuildDTO.java @@ -1,5 +1,6 @@ package com.ff.game.api.request; +import com.ff.game.domain.Platform; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -39,5 +40,7 @@ public class GamesDataBuildDTO */ private String agentId; + private Platform platform; + } diff --git a/ff-game/src/main/java/com/ff/game/api/request/GamesLogin.java b/ff-game/src/main/java/com/ff/game/api/request/GamesLogin.java index d46d7fd..e73320c 100644 --- a/ff-game/src/main/java/com/ff/game/api/request/GamesLogin.java +++ b/ff-game/src/main/java/com/ff/game/api/request/GamesLogin.java @@ -6,6 +6,8 @@ import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.SuperBuilder; +import java.util.Map; + /** * 游戏登录 * @@ -46,4 +48,10 @@ public class GamesLogin extends GamesBaseRequestDTO{ * 游戏类型 */ private String gameType; + + + /** + * ae 平台 投注限额 + */ + private Map>> betLimit; } diff --git a/ff-game/src/main/java/com/ff/game/api/request/GetGameDetailResponseDTO.java b/ff-game/src/main/java/com/ff/game/api/request/GetGameDetailResponseDTO.java index 373d4ed..b3debb2 100644 --- a/ff-game/src/main/java/com/ff/game/api/request/GetGameDetailResponseDTO.java +++ b/ff-game/src/main/java/com/ff/game/api/request/GetGameDetailResponseDTO.java @@ -1,5 +1,7 @@ package com.ff.game.api.request; +import lombok.AllArgsConstructor; +import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; @@ -11,6 +13,8 @@ import lombok.NoArgsConstructor; */ @NoArgsConstructor @Data +@AllArgsConstructor +@Builder public class GetGameDetailResponseDTO { diff --git a/ff-game/src/main/java/com/ff/game/api/request/MemberInfoRequestDTO.java b/ff-game/src/main/java/com/ff/game/api/request/MemberInfoRequestDTO.java index 40a3182..78c20cd 100644 --- a/ff-game/src/main/java/com/ff/game/api/request/MemberInfoRequestDTO.java +++ b/ff-game/src/main/java/com/ff/game/api/request/MemberInfoRequestDTO.java @@ -6,7 +6,7 @@ import lombok.NoArgsConstructor; import lombok.experimental.SuperBuilder; /** - * 创建成员请求dto + * 查询用户信息 * * @author shi * @date 2024/10/22 @@ -19,7 +19,7 @@ public class MemberInfoRequestDTO extends GamesBaseRequestDTO { /** * 账户 */ - private String accounts; + private String accounts; } diff --git a/ff-game/src/main/java/com/ff/game/api/request/TransactionIdRequestDTO.java b/ff-game/src/main/java/com/ff/game/api/request/TransactionIdRequestDTO.java new file mode 100644 index 0000000..2a285fa --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/request/TransactionIdRequestDTO.java @@ -0,0 +1,25 @@ +package com.ff.game.api.request; + +import com.ff.base.annotation.Excel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * 事务id请求dto + * + * @author shi + * @date 2025/04/11 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class TransactionIdRequestDTO { + /** 转出类型 1游戏商转入到用户全部转出 2 用户转移到游戏商 3 游戏商转移额度到平台商 */ + private Integer exchangeType; + + /** 游戏账号 */ + private String gameAccount; +} diff --git a/ff-game/src/main/java/com/ff/game/api/sa/address/MySAAddressSource.java b/ff-game/src/main/java/com/ff/game/api/sa/address/MySAAddressSource.java index 5ee8a89..de51edf 100644 --- a/ff-game/src/main/java/com/ff/game/api/sa/address/MySAAddressSource.java +++ b/ff-game/src/main/java/com/ff/game/api/sa/address/MySAAddressSource.java @@ -3,8 +3,8 @@ package com.ff.game.api.sa.address; import com.dtflys.forest.callback.AddressSource; import com.dtflys.forest.http.ForestAddress; import com.dtflys.forest.http.ForestRequest; -import com.ff.base.constant.Constants; -import com.ff.base.system.service.ISysConfigService; +import com.ff.base.enums.GamePlatforms; +import com.ff.game.service.IPlatformService; import org.springframework.stereotype.Component; import javax.annotation.Resource; @@ -20,12 +20,14 @@ import javax.annotation.Resource; public class MySAAddressSource implements AddressSource { @Resource - private ISysConfigService configService; + private IPlatformService platformService; @Override public ForestAddress getAddress(ForestRequest request) { - String apiBaseUrl = configService.selectConfigByKey(Constants.SA_API_BASE_URL); - return new ForestAddress("https",apiBaseUrl, 443,"api"); +// String apiBaseUrl = configService.selectConfigByKey(Constants.SA_API_BASE_URL); + String apiBaseUrl = platformService.get(GamePlatforms.SA.getCode()) + .getUrlInfo().getUrl(); + return new ForestAddress("https", apiBaseUrl, 443, "api"); } } \ No newline at end of file diff --git a/ff-game/src/main/java/com/ff/game/api/sa/client/SAClient.java b/ff-game/src/main/java/com/ff/game/api/sa/client/SAClient.java index 8631f0d..886e95d 100644 --- a/ff-game/src/main/java/com/ff/game/api/sa/client/SAClient.java +++ b/ff-game/src/main/java/com/ff/game/api/sa/client/SAClient.java @@ -65,6 +65,14 @@ public interface SAClient { String exchangeTransferByInto(@Body String params); + + @Post( url ="/api.aspx/CheckOrderDetailsDV", + headers = { + "Content-type: application/x-www-form-urlencoded" + }) + String exchangeTransferStatus(@Body String params); + + /** * 外汇转出 * diff --git a/ff-game/src/main/java/com/ff/game/api/sa/dto/SACheckOrderDetailsResponse.java b/ff-game/src/main/java/com/ff/game/api/sa/dto/SACheckOrderDetailsResponse.java new file mode 100644 index 0000000..0132407 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/sa/dto/SACheckOrderDetailsResponse.java @@ -0,0 +1,74 @@ +package com.ff.game.api.sa.dto; + +import lombok.Data; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; +import javax.xml.bind.annotation.XmlRootElement; +import java.math.BigDecimal; +import java.util.Date; + +/** + * CheckOrderDetailsResponse - XML 响应的 Java 类映射 + */ +@Data +@XmlAccessorType(XmlAccessType.FIELD) +@XmlRootElement(name = "CheckOrderDetailsResponse") +public class SACheckOrderDetailsResponse { + + /** + * 错误消息ID + */ + @XmlElement(name = "ErrorMsgId") + private Integer errorMsgId; + + /** + * 错误消息 + */ + @XmlElement(name = "ErrorMsg") + private String errorMsg; + + /** + * 是否存在 + */ + @XmlElement(name = "isExist") + private Boolean isExist; + + /** + * 日期 + */ + @XmlElement(name = "Date") + private Date date; + + /** + * 类型 + */ + @XmlElement(name = "Type") + private Integer type; + + /** + * 货币 + */ + @XmlElement(name = "Currency") + private String currency; + + /** + * 金额 + */ + @XmlElement(name = "Amount") + private BigDecimal amount; + + /** + * 上一余额 + */ + @XmlElement(name = "PreviousBalance") + private BigDecimal previousBalance; + + /** + * 当前余额 + */ + @XmlElement(name = "Balance") + private BigDecimal balance; + +} \ No newline at end of file diff --git a/ff-game/src/main/java/com/ff/game/api/sa/impl/GamesSAServiceImpl.java b/ff-game/src/main/java/com/ff/game/api/sa/impl/GamesSAServiceImpl.java index ac9c0d2..5b78a26 100644 --- a/ff-game/src/main/java/com/ff/game/api/sa/impl/GamesSAServiceImpl.java +++ b/ff-game/src/main/java/com/ff/game/api/sa/impl/GamesSAServiceImpl.java @@ -5,10 +5,8 @@ import cn.hutool.core.util.NumberUtil; import com.ff.base.constant.CacheConstants; import com.ff.base.constant.ConfigConstants; import com.ff.base.constant.Constants; -import com.ff.base.core.redis.RedisCache; import com.ff.base.enums.*; import com.ff.base.exception.base.ApiException; -import com.ff.base.exception.base.BaseException; import com.ff.base.system.service.ISysConfigService; import com.ff.base.utils.*; import com.ff.base.utils.sign.Md5Utils; @@ -18,10 +16,10 @@ import com.ff.game.api.IGamesService; import com.ff.game.api.request.*; import com.ff.game.api.sa.client.SAClient; import com.ff.game.api.sa.dto.*; -import com.ff.game.api.xk.dto.*; import com.ff.game.domain.*; -import com.ff.game.dto.GameSecretKeyCurrencyDTO; -import com.ff.game.service.*; +import com.ff.game.service.IGameBettingDetailsService; +import com.ff.game.service.IGameExchangeMoneyService; +import com.ff.game.service.IGameService; import com.ff.member.domain.Member; import com.ff.member.service.IMemberService; import lombok.extern.slf4j.Slf4j; @@ -33,8 +31,10 @@ import org.springframework.util.ObjectUtils; import javax.annotation.Resource; import java.math.BigDecimal; -import java.util.*; -import java.util.concurrent.TimeUnit; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; import java.util.stream.Collectors; @@ -52,17 +52,9 @@ public class GamesSAServiceImpl implements IGamesService { @Resource private ISysConfigService configService; - @Resource - private RedisCache redisCache; - @Resource private IGameExchangeMoneyService gameExchangeMoneyService; - - @Resource - private IGamePlatformService gamePlatformService; - - @Resource private IGameService gameService; @@ -70,14 +62,6 @@ public class GamesSAServiceImpl implements IGamesService { @Resource private IMemberService memberService; - @Resource - private IGameFreeRecordService gameFreeRecordService; - @Resource - private IGameSecretKeyService gameSecretKeyService; - - @Resource - private IGameSecretKeyCurrencyService gameSecretKeyCurrencyService; - @Resource private SAClient SAClient; @@ -88,9 +72,6 @@ public class GamesSAServiceImpl implements IGamesService { @Resource private IGameBettingDetailsService gameBettingDetailsService; - @Resource - private IGameNameService gameNameService; - /** * 游戏id */ @@ -241,44 +222,53 @@ public class GamesSAServiceImpl implements IGamesService { @Transactional @Override public String getGameList(GamesBaseRequestDTO gamesBaseRequestDTO) { - GamePlatform gamePlatform = gamePlatformService.selectGamePlatformById(PLATFORM_ID); - //没有此平台就新增一个平台 - if (ObjectUtils.isEmpty(gamePlatform)) { - gamePlatform = new GamePlatform(); - gamePlatform.setId(PLATFORM_ID); - gamePlatform.setPlatformCode(GamePlatforms.SA.getInfo()); - gamePlatform.setPlatformType(PlatformType.CARD_GAME.getCode()); - gamePlatform.setPlatformName(GamePlatforms.SA.getInfo() + PlatformType.CARD_GAME.getName()); - gamePlatform.setSortNo(gamePlatformService.selectMaxSortNo() + 1); - gamePlatform.setCreateBy(Constants.SYSTEM); - gamePlatformService.insertGamePlatform(gamePlatform); - } + Game game = gameService.selectGameById(GAME_ID); + Integer platformType = PlatformType.VIDEO.getCode(); //不存在这个游戏 if (ObjectUtils.isEmpty(game)) { game = new Game(); game.setId(GAME_ID); - game.setSortNo(gameService.selectMaxSortNoByPlatformId(gamePlatform.getId()) + 1); - game.setPlatformId(gamePlatform.getId()); + game.setSortNo(gameService.selectMaxSortNo(platformType, GamePlatforms.SA.getCode()) + 1); + game.setPlatformCode(GamePlatforms.SA.getCode()); + game.setPlatformType(platformType); game.setGameCode("1"); game.setGameSourceType(String.valueOf(1)); game.setGameName("真人棋牌"); game.setCreateBy(Constants.SYSTEM); - gameService.insertGame(game); - } - GameName gameName = gameNameService.selectGameNameById(GAME_NAME_ID); - if (ObjectUtils.isEmpty(gameName)) { - gameNameService.insertGameName(GameName.builder() - .id(GAME_NAME_ID) - .gameId(game.getId()) - .gameName(game.getGameName()) - .langCode("zh-CN") - .createBy(Constants.SYSTEM) - .build()); + List nameInfos = new ArrayList<>(); + nameInfos.add(new NameInfo("真人棋牌", "zh-CN")); + game.setGameId(StringUtils.addSuffix(GamePlatforms.SA.getCode(), 1)); + game.setNameInfo(nameInfos); + gameService.updateGame(game); + }else { + List nameInfos = new ArrayList<>(); + nameInfos.add(new NameInfo("真人棋牌", "zh-CN"));; + game.setNameInfo(nameInfos); + gameService.updateGame(game); } + return CacheConstants.SA_GAMES; } + /** + * 获取交易id + * + * @param transactionIdRequestDTO 事务id请求dto + * @return {@link String } + */ + @Override + public String getTransactionId(TransactionIdRequestDTO transactionIdRequestDTO) { + //判断是转入还是转出 + String transactionId = "OUT" + DateUtils.dateTimeNow() + transactionIdRequestDTO.getGameAccount(); + if (!TransferType.ALL.getCode().equals(transactionIdRequestDTO.getExchangeType())) { + transactionId = "IN" + DateUtils.dateTimeNow() + transactionIdRequestDTO.getGameAccount(); + } + + return transactionId; + } + + /** * 按代理id进行交换转账 * @@ -289,45 +279,16 @@ public class GamesSAServiceImpl implements IGamesService { @Transactional public Long exchangeTransferByAgentId(ExchangeTransferMoneyRequestDTO exchangeTransferMoneyRequestDTO) { log.info("GamesSAServiceImpl [exchangeTransferByAgentId] 请求参数 {}", exchangeTransferMoneyRequestDTO); - GameSecretKeyCurrency currencyDTO = gameSecretKeyCurrencyService.findByGameSecretKeyCurrencyDTO(GameSecretKeyCurrencyDTO.builder() - .platformCode(GamePlatforms.SA.getInfo()) - .code(exchangeTransferMoneyRequestDTO.getAgentId()) - .build()); - - Member member = memberService.selectMemberByGameAccount(exchangeTransferMoneyRequestDTO.getAccount()); - - List gameExchangeMonies = gameExchangeMoneyService.selectGameExchangeMoneyList( - GameExchangeMoney.builder() - .tenantKey(exchangeTransferMoneyRequestDTO.getTenantKey()) - .orderId(exchangeTransferMoneyRequestDTO.getOrderId()) - .build() - ); - Assert.isTrue(CollectionUtils.isEmpty(gameExchangeMonies), "订单号重复"); - //判断是转入还是转出 - String transactionId = "OUT" + DateUtils.dateTimeNow() + exchangeTransferMoneyRequestDTO.getAccount(); - if (!TransferType.ALL.getCode().equals(exchangeTransferMoneyRequestDTO.getTransferType())) { - transactionId = "IN" + DateUtils.dateTimeNow() + exchangeTransferMoneyRequestDTO.getAccount(); - } - //获取下一个自增id - GameExchangeMoney exchangeMoney = GameExchangeMoney - .builder() - .tenantKey(exchangeTransferMoneyRequestDTO.getTenantKey()) - .orderId(exchangeTransferMoneyRequestDTO.getOrderId()) - .quota(exchangeTransferMoneyRequestDTO.getQuota()) - .balance(exchangeTransferMoneyRequestDTO.getAmount()) - .exchangeType(exchangeTransferMoneyRequestDTO.getTransferType()) - .currencyCode(currencyDTO.getSystemCurrency()) - .memberId(member.getId()) - .transactionId(transactionId) - .platformCode(GamePlatforms.SA.getCode()) - .build(); - exchangeMoney.setCreateBy(Constants.SYSTEM); + GameExchangeMoney exchangeMoney = gameExchangeMoneyService.selectGameExchangeMoneyById(exchangeTransferMoneyRequestDTO.getGameExchangeId()); + + + if (TransferType.ALL.getCode().equals(exchangeTransferMoneyRequestDTO.getTransferType())) { Map params = new LinkedHashMap<>(); params.put("Username", exchangeTransferMoneyRequestDTO.getAccount()); - params.put("OrderId", exchangeMoney.getTransactionId()); + params.put("OrderId", exchangeTransferMoneyRequestDTO.getTransactionId()); String query = JsonUtil.mapToQueryString(params); exchangeTransferMoneyRequestDTO.setQuery(query); String key = this.getKey(exchangeTransferMoneyRequestDTO, "DebitAllBalanceDV"); @@ -344,18 +305,22 @@ public class GamesSAServiceImpl implements IGamesService { exchangeMoney.setCoinAfter(BigDecimal.ZERO); exchangeMoney.setCurrencyBefore(exchangeMoney.getCurrencyBefore()); exchangeMoney.setCurrencyAfter(exchangeMoney.getCurrencyAfter()); - exchangeMoney.setStatus(StatusType.SUCCESS.getValue()); - gameExchangeMoneyService.insertGameExchangeMoney(exchangeMoney); + exchangeMoney.setStep(GameExchangeStep.PLATFORM_TRANSACTION.getCode()); + exchangeMoney.setStepStatus(GameExchangeStepStatus.SUCCESS.getCode()); + gameExchangeMoneyService.updateGameExchangeMoney(exchangeMoney); } else { + exchangeMoney.setStep(GameExchangeStep.PLATFORM_TRANSACTION.getCode()); + exchangeMoney.setStepStatus(GameExchangeStepStatus.FAILURE.getCode()); + gameExchangeMoneyService.updateGameExchangeMoney(exchangeMoney); log.error("GamesXKServiceImpl [exchangeTransferByAgentId] 金额转移失败,错误代码{}", errorCode); throw new ApiException(ErrorCode.BALANCE_TRANSFER_FAILED.getCode()); } } else { Map params = new LinkedHashMap<>(); params.put("Username", exchangeTransferMoneyRequestDTO.getAccount()); - params.put("OrderId", exchangeMoney.getTransactionId()); + params.put("OrderId", exchangeTransferMoneyRequestDTO.getTransactionId()); params.put("CreditAmount", exchangeTransferMoneyRequestDTO.getAmount().stripTrailingZeros().toPlainString()); - params.put("CurrencyType", currencyDTO.getCurrency()); + params.put("CurrencyType", exchangeTransferMoneyRequestDTO.getCurrency()); String query = JsonUtil.mapToQueryString(params); exchangeTransferMoneyRequestDTO.setQuery(query); String key = this.getKey(exchangeTransferMoneyRequestDTO, "CreditBalanceDV"); @@ -372,9 +337,13 @@ public class GamesSAServiceImpl implements IGamesService { exchangeMoney.setCoinAfter(saCreditBalanceResponse.getBalance()); exchangeMoney.setCurrencyBefore(exchangeMoney.getCoinBefore()); exchangeMoney.setCurrencyAfter(exchangeMoney.getCoinAfter()); - exchangeMoney.setStatus(StatusType.SUCCESS.getValue()); - gameExchangeMoneyService.insertGameExchangeMoney(exchangeMoney); + exchangeMoney.setStep(GameExchangeStep.PLATFORM_TRANSACTION.getCode()); + exchangeMoney.setStepStatus(GameExchangeStepStatus.SUCCESS.getCode()); + gameExchangeMoneyService.updateGameExchangeMoney(exchangeMoney); } else { + exchangeMoney.setStep(GameExchangeStep.PLATFORM_TRANSACTION.getCode()); + exchangeMoney.setStepStatus(GameExchangeStepStatus.FAILURE.getCode()); + gameExchangeMoneyService.updateGameExchangeMoney(exchangeMoney); log.error("GamesXKServiceImpl [exchangeTransferByAgentId] 金额转移失败,错误代码{}", errorCode); throw new ApiException(ErrorCode.BALANCE_TRANSFER_FAILED.getCode()); } @@ -391,8 +360,29 @@ public class GamesSAServiceImpl implements IGamesService { * @return {@link Boolean } */ @Override - public Boolean exchangeTransferStatus(ExchangeTransferStatusRequestDTO exchangeTransferMoneyRequestDTO) { - throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); + public ExchangeTransferStatusResponseDTO exchangeTransferStatus(ExchangeTransferStatusRequestDTO exchangeTransferMoneyRequestDTO) { + Map params = new LinkedHashMap<>(); + params.put("OrderId", exchangeTransferMoneyRequestDTO.getOrderId()); + String query = JsonUtil.mapToQueryString(params); + exchangeTransferMoneyRequestDTO.setQuery(query); + String key = this.getKey(exchangeTransferMoneyRequestDTO, "CheckOrderDetailsDV"); + String result = SAClient.exchangeTransferByInto(key); + SACheckOrderDetailsResponse saCheckOrderDetailsResponse = XmlUtils.xmlDecrypt(result, SACheckOrderDetailsResponse.class); + Integer errorCode = saCheckOrderDetailsResponse.getErrorMsgId(); + //判断是否转移成功 + Integer status = StatusType.IN_PROGRESS.getValue(); + if (this.getIsSuccess(errorCode)) { + status = StatusType.SUCCESS.getValue(); + } else { + status = StatusType.FAILURE.getValue(); + } + + return ExchangeTransferStatusResponseDTO.builder() + .statusType(status) + .balance(saCheckOrderDetailsResponse.getAmount()) + .coinBefore(saCheckOrderDetailsResponse.getPreviousBalance()) + .coinAfter(saCheckOrderDetailsResponse.getBalance()) + .build(); } @@ -424,11 +414,11 @@ public class GamesSAServiceImpl implements IGamesService { //判断是否获取成功 if (this.getIsSuccess(errorCode)) { //数据组装 - this.batchInsert(saGetAllBetDetailsResponse); + this.batchInsert(saGetAllBetDetailsResponse, betRecordByTimeDTO); return Boolean.TRUE; } else { - log.error("GamesXKServiceImpl [getBetRecordByTime] 获取投注记录失败,错误代码{}", errorCode); + log.error("GamesSAServiceImpl [getBetRecordByTime] 获取投注记录失败,错误代码{}", errorCode); } return Boolean.FALSE; } @@ -441,7 +431,33 @@ public class GamesSAServiceImpl implements IGamesService { */ @Override public Boolean getBetRecordByHistoryTime(BetRecordByTimeDTO betRecordByTimeDTO) { - return Boolean.TRUE; + String startTime = DateUtils.convertTimeZone(betRecordByTimeDTO.getStartTime(), "Asia/Shanghai", DateUtils.YYYY_MM_DD_HH_MM_SS); + String endTime = DateUtils.convertTimeZone(betRecordByTimeDTO.getEndTime(), "Asia/Shanghai", DateUtils.YYYY_MM_DD_HH_MM_SS); + + //请求参数 + log.info("GamesSAServiceImpl [getBetRecordByHistoryTime] 请求参数 {}", betRecordByTimeDTO); + Map params = new LinkedHashMap<>(); + params.put("FromTime", startTime); + params.put("ToTime", endTime); + String query = JsonUtil.mapToQueryString(params); + betRecordByTimeDTO.setQuery(query); + String key = this.getKey(betRecordByTimeDTO, "GetAllBetDetailsForTimeIntervalDV"); + + String result = SAClient.getBetRecordByTime(key); + SAGetAllBetDetailsResponse saGetAllBetDetailsResponse = XmlUtils.xmlDecrypt(result, SAGetAllBetDetailsResponse.class); + Integer errorCode = saGetAllBetDetailsResponse.getErrorMsgId(); + + + //判断是否获取成功 + if (this.getIsSuccess(errorCode)) { + //数据组装 + this.batchInsert(saGetAllBetDetailsResponse, betRecordByTimeDTO); + + return Boolean.TRUE; + } else { + log.error("GamesSAServiceImpl [getBetRecordByHistoryTime] 获取投注记录失败,错误代码{}", errorCode); + } + return Boolean.FALSE; } /** @@ -524,20 +540,34 @@ public class GamesSAServiceImpl implements IGamesService { throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); } + /** + * 游戏演示登录 + * + * @param gameDemoLoginRequestDTO 游戏演示登录请求dto + * @return {@link GameDemoLoginResponseDTO } + */ + @Override + public GameDemoLoginResponseDTO gameDemoLogin(GameDemoLoginRequestDTO gameDemoLoginRequestDTO) { + throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); + } + /** * 批量插入 * * @param saGetAllBetDetailsResponse sa获取所有投注详细信息响应 */ - private void batchInsert(SAGetAllBetDetailsResponse saGetAllBetDetailsResponse) { + private void batchInsert(SAGetAllBetDetailsResponse saGetAllBetDetailsResponse, BetRecordByTimeDTO betRecordByTimeDTO) { List gameBettingDetails = new ArrayList<>(); List wagersIds = new ArrayList<>(); //数据组装 List result = saGetAllBetDetailsResponse.getBetDetailList(); //数据转化 for (SAGetAllBetDetailsResponse.BetDetail bean : result) { - GameBettingDetails bettingDetails = this.dataBuild(GamesDataBuildDTO.builder().data(bean).build()); + GameBettingDetails bettingDetails = this.dataBuild(GamesDataBuildDTO.builder() + .platform(betRecordByTimeDTO.getVendor()) + .data(bean) + .build()); if (!ObjectUtils.isEmpty(bettingDetails)) { bettingDetails.setId(IdUtil.getSnowflakeNextId()); gameBettingDetails.add(bettingDetails); @@ -546,7 +576,7 @@ public class GamesSAServiceImpl implements IGamesService { } if (!CollectionUtils.isEmpty(gameBettingDetails)) { //查询重复数据id - List removeWagersIds = gameBettingDetailsService.selectGameBettingDetailsByWagersId(wagersIds); + List removeWagersIds = gameBettingDetailsService.selectGameBettingDetailsByWagersId(wagersIds, GamePlatforms.SA.getInfo()); //用steam流清除list中与wagersIds集合相同的数据 gameBettingDetails = gameBettingDetails.stream() .filter(detail -> !removeWagersIds.contains(detail.getWagersId())) @@ -569,10 +599,6 @@ public class GamesSAServiceImpl implements IGamesService { //转化类 SAGetAllBetDetailsResponse.BetDetail resultBean = (SAGetAllBetDetailsResponse.BetDetail) gamesDataBuildDTO.getData(); - GameSecretKeyCurrency currencyDTO = gameSecretKeyCurrencyService.findByGameSecretKeyCurrencyDTO(GameSecretKeyCurrencyDTO.builder() - .platformCode(GamePlatforms.SA.getInfo()) - .currency(resultBean.getCurrency()) - .build()); Member member = memberService.selectMemberByGameAccount(resultBean.getUsername()); if (ObjectUtils.isEmpty(member)) { @@ -591,16 +617,17 @@ public class GamesSAServiceImpl implements IGamesService { } + String systemCurrency = gamesDataBuildDTO.getPlatform().getOurCurrency(resultBean.getCurrency()); //数据构造 GameBettingDetails gameBettingDetails = GameBettingDetails.builder() .tenantKey(member.getTenantKey()) //保存我们的币种id - .currencyCode(currencyDTO.getSystemCurrency()) + .currencyCode(systemCurrency) .memberId(member.getId()) .gameCode(resultBean.getGameID()) .gameType(PlatformType.CARD_GAME.getCode()) - .platformCode(GamePlatforms.SA.getCode()) - .gameId(GAME_ID) + .platformCode(GamePlatforms.SA.getInfo()) + .gameId(/*GAME_ID*/game.getGameId()) .gameName(game.getGameName()) .gameStatus(gameStatus) .gameStatusType(1) diff --git a/ff-game/src/main/java/com/ff/game/api/success/MySuccessCondition.java b/ff-game/src/main/java/com/ff/game/api/success/MySuccessCondition.java new file mode 100644 index 0000000..f1c97d2 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/success/MySuccessCondition.java @@ -0,0 +1,31 @@ +package com.ff.game.api.success; + + +import com.dtflys.forest.callback.SuccessWhen; +import com.dtflys.forest.http.ForestRequest; +import com.dtflys.forest.http.ForestResponse; + +/** + * 我kmsuccess状态 + * + * @author shi + * @date 2025/04/02 + */ +public class MySuccessCondition implements SuccessWhen { + + /** + * 请求成功条件 + * @param req Forest请求对象 + * @param res Forest响应对象 + * @return 是否成功,true: 请求成功,false: 请求失败 + */ + @Override + public boolean successWhen(ForestRequest req, ForestResponse res) { + // req 为Forest请求对象,即 ForestRequest 类实例 + // res 为Forest响应对象,即 ForestResponse 类实例 + // 返回值为 ture 则表示请求成功,false 表示请求失败 + return res.noException(); + // 当然在这里也可以写其它条件,比如 通过 res.getResult() 或 res.getContent() 获取业务数据 + // 再根据业务数据判断是否成功 + } +} diff --git a/ff-game/src/main/java/com/ff/game/api/sv388/address/SV388Adrress.java b/ff-game/src/main/java/com/ff/game/api/sv388/address/SV388Adrress.java new file mode 100644 index 0000000..4474614 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/sv388/address/SV388Adrress.java @@ -0,0 +1,31 @@ +package com.ff.game.api.sv388.address; + +import com.dtflys.forest.callback.AddressSource; +import com.dtflys.forest.http.ForestAddress; +import com.dtflys.forest.http.ForestRequest; +import com.ff.base.enums.GamePlatforms; +import com.ff.game.service.IPlatformService; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + + +/** + * 我jili address来源 + * + * @author shi + * @date 2025/02/10 + */ +@Component +public class SV388Adrress implements AddressSource { + + @Resource + private IPlatformService platformService; + + @Override + public ForestAddress getAddress(ForestRequest request) { + String apiBaseUrl = platformService.get(GamePlatforms.SV388.getCode()) + .getUrlInfo().getUrl(); + return new ForestAddress("https", apiBaseUrl, 443, ""); + } +} \ No newline at end of file diff --git a/ff-game/src/main/java/com/ff/game/api/sv388/client/SV388Client.java b/ff-game/src/main/java/com/ff/game/api/sv388/client/SV388Client.java new file mode 100644 index 0000000..7f57520 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/sv388/client/SV388Client.java @@ -0,0 +1,136 @@ +package com.ff.game.api.sv388.client; + +import com.dtflys.forest.annotation.*; +import com.ff.game.api.jili.dto.JILIExchangeMoneyResponseDTO; +import com.ff.game.api.jili.dto.JILIKickMemberAllDTO; +import com.ff.game.api.jili.dto.JILIKickMemberDTO; +import com.ff.game.api.sv388.address.SV388Adrress; +import com.ff.game.api.sv388.dto.*; +import com.ff.game.api.xk.dto.XKKickMemberAllDTO; +import com.ff.game.api.xk.dto.XKKickMemberDTO; + +import java.util.Map; + +/** + * xk 请求 + * + * @author shi + * @date 2025/02/10 + */ +@Address(source = SV388Adrress.class) +public interface SV388Client { + /** + * 创建成员 + * + * @param params 参数 + * @return {@link String } + */ + @Post(url ="/wallet/createMember", + headers = { + "Content-type: application/x-www-form-urlencoded" + }) + SV388Response createMember(@Body Map params); + + /** + * 获取会员信息 + * + * @param params 参数 + * @return {@link SV388MemberInfo } + */ + @Post(url ="/wallet/getBalance", + headers = { + "Content-type: application/x-www-form-urlencoded" + }) + SV388MemberInfo getMemberInfo(@Body Map params); + + /** + * 无重定向登录 + * + * @param params 参数 + * @return {@link SV388LoginResponse } + */ + @Post("/wallet/login") + SV388LoginResponse loginWithoutRedirect(@Body Map params); + + + + /** + * 按代理id进行交换转账 + * + * @param params 参数 + * @return {@link JILIExchangeMoneyResponseDTO } + */ + @Post(url ="/wallet/deposit", + headers = { + "Content-type: application/x-www-form-urlencoded" + }) + SV388AETransactionResponse deposit(@Body Map params); + + + @Post(url ="/wallet/withdraw", + headers = { + "Content-type: application/x-www-form-urlencoded" + }) + SV388AETransactionResponse withdraw(@Body Map params); + + + /** + * 汇兑转移状态 + * + * @param params 参数 + * @return {@link SV388ExchangeTransferStatusResponse } + */ + @Post(url ="/wallet/checkTransferOperation", + headers = { + "Content-type: application/x-www-form-urlencoded" + }) + SV388ExchangeTransferStatusResponse exchangeTransferStatus(@Body Map params); + + /** + * 按时间获取投注记录 + * + * @param params 参数 + * @return {@link SV388BetRecordResponse } + */ + @Post(url ="{fetchUrl}/fetch/gzip/getTransactionByUpdateDate", + headers = { + "Content-type: application/x-www-form-urlencoded" + }) + SV388BetRecordResponse getBetRecordByTime(@Body Map params, + @Var("fetchUrl") String fetchUrl); + + /** + * 按时间获取投注历史记录 + * + * @param params 参数 + * @return {@link SV388BetRecordResponse } + */ + @Post(url ="{fetchUrl}/fetch/gzip/getTransactionByTxTime", + headers = { + "Content-type: application/x-www-form-urlencoded" + }) + SV388BetRecordResponse getBetHistoryRecordByTime(@Body Map params, + @Var("fetchUrl") String fetchUrl); + /** + * 踢出队员 + * + * @param params 参数 + * @return {@link JILIKickMemberDTO } + */ + @Post(url ="/wallet/logout", + headers = { + "Content-type: application/x-www-form-urlencoded" + }) + XKKickMemberDTO kickMember(@Body Map params); + + /** + * 踢出所有队员 + * + * @param params 参数 + * @return {@link JILIKickMemberAllDTO } + */ + @Get("/kickMemberAll") + XKKickMemberAllDTO kickMemberAll(@JSONBody Map params); + + +} diff --git a/ff-game/src/main/java/com/ff/game/api/sv388/dto/SV388AETransactionResponse.java b/ff-game/src/main/java/com/ff/game/api/sv388/dto/SV388AETransactionResponse.java new file mode 100644 index 0000000..5e029e0 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/sv388/dto/SV388AETransactionResponse.java @@ -0,0 +1,60 @@ +package com.ff.game.api.sv388.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.ZonedDateTime; + +/** + * 电子交易响应 + * + * @author shi + * @date 2025/04/01 + */ +@Data +public class SV388AETransactionResponse { + + /** + * 响应状态 + */ + @JsonProperty("status") + private String status; + + + /** + * 金额 + */ + @JsonProperty("amount") + private BigDecimal amount; + + /** + * 交易方法(如:DEPOSIT, WITHDRAW) + */ + @JsonProperty("method") + private String method; + + /** + * 数据库ID + */ + @JsonProperty("databaseId") + private int databaseId; + + /** + * 当前余额 + */ + @JsonProperty("currentBalance") + private BigDecimal currentBalance; + + /** + * 最后修改时间 + */ + @JsonProperty("lastModified") + private ZonedDateTime lastModified; + + /** + * 交易代码 + */ + @JsonProperty("txCode") + private String txCode; +} diff --git a/ff-game/src/main/java/com/ff/game/api/sv388/dto/SV388BetRecordResponse.java b/ff-game/src/main/java/com/ff/game/api/sv388/dto/SV388BetRecordResponse.java new file mode 100644 index 0000000..0303e08 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/sv388/dto/SV388BetRecordResponse.java @@ -0,0 +1,186 @@ +package com.ff.game.api.sv388.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.math.BigDecimal; +import java.util.Date; +import java.util.List; + +/** + * sv388记录响应 + * + * @author shi + * @date 2025/04/01 + */ +@Data +public class SV388BetRecordResponse { + + /** + * 状态代码 + */ + @JsonProperty("status") + private Integer status; + + /** + * 描述信息 (String类型) + * "Success" - 请求成功 + * 其他 - 错误信息 + */ + private String desc; + /** + * 交易记录 + */ + @JsonProperty("transactions") + private List transactions; + + @Data + public static class Transaction { + + /** + * 游戏类型 + */ + @JsonProperty("gameType") + private String gameType; + + /** + * 返还金额(包含下注金额) + */ + @JsonProperty("winAmount") + private BigDecimal winAmount; + + /** + * 交易时间 + */ + @JsonProperty("txTime") + private Date txTime; + + /** + * 结算状态 + */ + @JsonProperty("settleStatus") + private Integer settleStatus; + + /** + * 游戏信息 + */ + @JsonProperty("gameInfo") + private String gameInfo; + + /** + * 真实返还金额 + */ + @JsonProperty("realWinAmount") + private BigDecimal realWinAmount; + + /** + * 更新时间 + */ + @JsonProperty("updateTime") + private String updateTime; + + /** + * 真实下注金额 + */ + @JsonProperty("realBetAmount") + private BigDecimal realBetAmount; + + /** + * 用户ID + */ + @JsonProperty("userId") + private String userId; + + /** + * 下注类型 + */ + @JsonProperty("betType") + private String betType; + + /** + * 平台名称 + */ + @JsonProperty("platform") + private String platform; + + /** + * 交易状态 + */ + @JsonProperty("txStatus") + private Integer txStatus; + + /** + * 下注金额 + */ + @JsonProperty("betAmount") + private BigDecimal betAmount; + + /** + * 游戏名称 + */ + @JsonProperty("gameName") + private String gameName; + + /** + * 平台注单号 + */ + @JsonProperty("platformTxId") + private String platformTxId; + + /** + * 下注时间 + */ + @JsonProperty("betTime") + private Date betTime; + + /** + * 平台游戏代码 + */ + @JsonProperty("gameCode") + private String gameCode; + + /** + * 玩家货币代码 + */ + @JsonProperty("currency") + private String currency; + + /** + * 累积奖金的获胜金额 + */ + @JsonProperty("jackpotWinAmount") + private BigDecimal jackpotWinAmount; + + /** + * 累积奖金贡献金额 + */ + @JsonProperty("jackpotBetAmount") + private BigDecimal jackpotBetAmount; + + /** + * 平台有效投注 + */ + @JsonProperty("turnover") + private BigDecimal turnover; + + /** + * 游戏商的回合识别码 + */ + @JsonProperty("roundId") + private String roundId; + + + + /** + * 子注单号 + */ + @JsonProperty("refPlatformTxId") + private String refPlatformTxId; + + /** + * 是否为特殊收费游戏 + */ + @JsonProperty("isPremium") + private Boolean isPremium; + } +} diff --git a/ff-game/src/main/java/com/ff/game/api/sv388/dto/SV388ExchangeTransferStatusResponse.java b/ff-game/src/main/java/com/ff/game/api/sv388/dto/SV388ExchangeTransferStatusResponse.java new file mode 100644 index 0000000..a773ad1 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/sv388/dto/SV388ExchangeTransferStatusResponse.java @@ -0,0 +1,56 @@ +package com.ff.game.api.sv388.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.math.BigDecimal; + + +/** + * aeexchange传输状态响应 + * + * @author shi + * @date 2025/04/01 + */ +@Data +public class SV388ExchangeTransferStatusResponse { + + /** + * 响应状态 + */ + @JsonProperty("status") + private String status; + + /** + * 情境 1:响应 status = 0000 & txStatus = 1 表示存款/提款成功 + * 情境 2:响应 status = 0000 & txStatus = 0 表示存款/提款失败 + * 情境 3:响应 status = 0000 & txStatus = 2 表示存款/提款处理中,可 3 秒后调用 checkTransferOperation API 确认回覆直到 txStatus = 0 或 1 的回覆 + * 情境 4:响应 status = 1017 表示交易不存在 + */ + @JsonProperty("txStatus") + private String txStatus; + + /** + * 当前余额 + */ + @JsonProperty("balance") + private BigDecimal balance; + + /** + * 转账金额 + */ + @JsonProperty("transferAmount") + private BigDecimal transferAmount; + + /** + * 转账类型(如:DEPOSIT 或 WITHDRAW) + */ + @JsonProperty("transferType") + private String transferType; + + /** + * 交易代码 + */ + @JsonProperty("txCode") + private String txCode; +} diff --git a/ff-game/src/main/java/com/ff/game/api/sv388/dto/SV388LoginResponse.java b/ff-game/src/main/java/com/ff/game/api/sv388/dto/SV388LoginResponse.java new file mode 100644 index 0000000..033abbf --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/sv388/dto/SV388LoginResponse.java @@ -0,0 +1,41 @@ +package com.ff.game.api.sv388.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.util.List; + +/** + * aelogin回应 + * + * @author shi + * @date 2025/04/01 + */ +@Data +public class SV388LoginResponse { + /** + * 响应状态 + */ + @JsonProperty("status") + private Integer status; + + + /** + * 描述信息 (String类型) + * "Success" - 请求成功 + * 其他 - 错误信息 + */ + private String desc; + + /** + * 登录 URL + */ + @JsonProperty("url") + private String url; + + /** + * 扩展字段,类型为列表,可以存储多项数据 + */ + @JsonProperty("extension") + private List extension; +} diff --git a/ff-game/src/main/java/com/ff/game/api/sv388/dto/SV388LogoutUserResponse.java b/ff-game/src/main/java/com/ff/game/api/sv388/dto/SV388LogoutUserResponse.java new file mode 100644 index 0000000..b345034 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/sv388/dto/SV388LogoutUserResponse.java @@ -0,0 +1,33 @@ +package com.ff.game.api.sv388.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.util.List; + +/** + * 注销用户响应 + * + * @author shi + * @date 2025/04/01 + */ +@Data +public class SV388LogoutUserResponse { + /** + * 状态代码 + */ + @JsonProperty("status") + private String status; + + /** + * 已注销的用户列表 + */ + @JsonProperty("logoutUsers") + private List logoutUsers; + + /** + * 用户数量 + */ + @JsonProperty("count") + private Integer count; +} diff --git a/ff-game/src/main/java/com/ff/game/api/sv388/dto/SV388MemberInfo.java b/ff-game/src/main/java/com/ff/game/api/sv388/dto/SV388MemberInfo.java new file mode 100644 index 0000000..f50c61f --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/sv388/dto/SV388MemberInfo.java @@ -0,0 +1,64 @@ +package com.ff.game.api.sv388.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.math.BigDecimal; +import java.util.Date; +import java.util.List; + +/** + * AEMEMBER信息 + * + * @author shi + * @date 2025/03/31 + */ +@Data +public class SV388MemberInfo { + /** + * 响应结果列表,包含用户信息 + */ + @JsonProperty("results") + private List result; + + /** + * 记录数量 + */ + @JsonProperty("count") + private int count; + + /** + * 查询时间 + */ + @JsonProperty("querytime") + private Date queryTime; + + /** + * 响应状态 + */ + @JsonProperty("status") + private Integer status; + + @Data + public static class UserInfo { + + /** + * 用户ID + */ + @JsonProperty("userId") + private String userId; + + /** + * 用户余额 + */ + @JsonProperty("balance") + private BigDecimal balance; + + /** + * 最后修改时间 + */ + @JsonProperty("lastModified") + private Date lastModified; + } + +} diff --git a/ff-game/src/main/java/com/ff/game/api/sv388/dto/SV388Response.java b/ff-game/src/main/java/com/ff/game/api/sv388/dto/SV388Response.java new file mode 100644 index 0000000..85bc006 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/sv388/dto/SV388Response.java @@ -0,0 +1,26 @@ +package com.ff.game.api.sv388.dto; + +import lombok.Data; + +/** + * 航空响应 + * + * @author shi + * @date 2025/03/28 + */ +@Data +public class SV388Response { + /** + * 状态码 (String类型) + * 0000 - 成功 + * 其他 - 错误状态码 + */ + private String status; + + /** + * 描述信息 (String类型) + * "Success" - 请求成功 + * 其他 - 错误信息 + */ + private String desc; +} diff --git a/ff-game/src/main/java/com/ff/game/api/sv388/impl/SV388GamesServiceImpl.java b/ff-game/src/main/java/com/ff/game/api/sv388/impl/SV388GamesServiceImpl.java new file mode 100644 index 0000000..97fc897 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/sv388/impl/SV388GamesServiceImpl.java @@ -0,0 +1,636 @@ +package com.ff.game.api.sv388.impl; + +import cn.hutool.core.util.IdUtil; +import cn.hutool.core.util.NumberUtil; +import com.ff.base.constant.CacheConstants; +import com.ff.base.constant.Constants; +import com.ff.base.core.redis.RedisCache; +import com.ff.base.enums.*; +import com.ff.base.exception.base.ApiException; +import com.ff.base.exception.base.BaseException; +import com.ff.base.utils.DateUtils; +import com.ff.base.utils.JsonUtil; +import com.ff.base.utils.StringUtils; +import com.ff.base.utils.uuid.IdUtils; +import com.ff.delay.DelayService; +import com.ff.delay.DelayTask; +import com.ff.game.api.IGamesService; +import com.ff.game.api.request.*; +import com.ff.game.api.sv388.client.SV388Client; +import com.ff.game.api.sv388.dto.*; +import com.ff.game.api.xk.dto.XKKickMemberDTO; +import com.ff.game.domain.*; +import com.ff.game.service.IGameBettingDetailsService; +import com.ff.game.service.IGameExchangeMoneyService; +import com.ff.game.service.IGameService; +import com.ff.member.domain.Member; +import com.ff.member.service.IMemberService; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.Assert; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ObjectUtils; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.util.*; +import java.util.stream.Collectors; + + +/** + * AE 游戏 impl + * + * @author shi + * @date 2024/11/12 + */ +@Service("SV388Service") +@Slf4j +public class SV388GamesServiceImpl implements IGamesService { + + + @Resource + private RedisCache redisCache; + + @Resource + private IGameExchangeMoneyService gameExchangeMoneyService; + + @Resource + private IGameService gameService; + + @Resource + private IMemberService memberService; + + @Resource + private SV388Client sv388Client; + + @Resource + private IGameBettingDetailsService gameBettingDetailsService; + + @Resource + private DelayService delayService; + + /** + * 游戏id + */ + private static final Long GAME_ID = 1122L; + + + /** + * 获得就是成功 + * + * @param errorCode 错误代码 + * @return {@link Boolean } + */ + private Boolean getIsSuccess(Integer errorCode) { + return 0 == errorCode; + } + + + /** + * 获取密钥 + * + * @param gamesBaseRequestDTO 游戏请求dto + * @return {@link Map }<{@link String }, {@link Object }> + */ + private Map getKey(GamesBaseRequestDTO gamesBaseRequestDTO) { + Map params = new LinkedHashMap<>(); + params.put("cert", gamesBaseRequestDTO.getAgentKey()); + params.put("agentId", gamesBaseRequestDTO.getAgentId()); + return params; + } + + /** + * 创建成员 + * + * @param createMemberRequestDTO 创建成员请求dto + * @return {@link Boolean } + */ + @Override + public Boolean createMember(CreateMemberRequestDTO createMemberRequestDTO) { + + Platform platform = createMemberRequestDTO.getVendor(); + Object o = platform.getExtInfo().getBetLimit().get(createMemberRequestDTO.getSystemCurrency()); + if (!(o instanceof Map)) { + throw new ApiException(ErrorCode.Miss_Config.getCode()); + } + Map betLimit = new HashMap<>(); + betLimit.put(GamePlatforms.SV388.getCode(), new HashMap() {{ + put("LIVE", new HashMap((Map) o) {{ + remove("@type"); + }}); + }} + ); + Map params = this.getKey(createMemberRequestDTO); + params.put("userId", createMemberRequestDTO.getAccount()); + params.put("currency", createMemberRequestDTO.getCurrency()); + params.put("betLimit", JsonUtil.objToString(betLimit)); + SV388Response aeResponse = sv388Client.createMember(params); + String errorCode = aeResponse.getStatus(); + if (this.getIsSuccess(Integer.valueOf(errorCode))) { + return Boolean.TRUE; + } + //判断是否获取成功 + return Boolean.FALSE; + } + + + /** + * 获取会员信息 + * + * @param memberInfoRequestDTO 会员信息请求dto + * @return {@link MemberInfoResponseDTO } + */ + @Override + public MemberInfoResponseDTO getMemberInfo(MemberInfoRequestDTO memberInfoRequestDTO) { + Map params = this.getKey(memberInfoRequestDTO); + params.put("alluser", 0); + params.put("userIds", memberInfoRequestDTO.getAccounts()); + SV388MemberInfo memberInfo = sv388Client.getMemberInfo(params); + //判断是否获取成功 + if (this.getIsSuccess(memberInfo.getStatus())) { + SV388MemberInfo.UserInfo userInfo = memberInfo.getResult().get(0); + return MemberInfoResponseDTO.builder() + .status(GameMemberStatus.UNKNOWN.getCode()) + .balance(userInfo.getBalance()) + .account(memberInfoRequestDTO.getAccounts()) + .build(); + } else { + throw new ApiException(ErrorCode.ERROR.getCode()); + } + } + + /** + * 无重定向登录 + * + * @param gamesLogin 游戏登录 + * @return {@link String } + */ + @Override + public String loginWithoutRedirect(GamesLogin gamesLogin) { + Map params = this.getKey(gamesLogin); + params.put("userId", gamesLogin.getAccount()); + params.put("externalURL", gamesLogin.getHomeUrl()); + params.put("language", gamesLogin.getLang()); + params.put("betLimit", gamesLogin.getBetLimit()); + SV388LoginResponse aeLoginResponse = sv388Client.loginWithoutRedirect(params); + //判断是否获取成功 + if (this.getIsSuccess(aeLoginResponse.getStatus())) { + return aeLoginResponse.getUrl(); + } else { + throw new BaseException(aeLoginResponse.getDesc()); + } + } + + + /** + * 获取游戏列表 + * + * @param gamesBaseRequestDTO 游戏请求dto + * @return {@link String } + */ + @Transactional + @Override + public String getGameList(GamesBaseRequestDTO gamesBaseRequestDTO) { + int platformType = PlatformType.VIDEO.getCode(); + Game condition = new Game(); + condition.setPlatformCode(GamePlatforms.SV388.getCode()); + condition.setPlatformType(platformType); + List gameList = gameService.selectGameList(condition); + Platform platform = gamesBaseRequestDTO.getVendor(); + //不存在这个游戏 + if (CollectionUtils.isEmpty(gameList)) { + Game game = new Game(); + game.setId(IdUtil.getSnowflakeNextId()); + game.setSortNo(gameService.selectMaxSortNo(platformType, GamePlatforms.SV388.getCode()) + 1); + game.setPlatformCode(platform.getPlatformCode()); + game.setPlatformType(platformType); + game.setGameCode("1"); + game.setGameSourceType(String.valueOf(1)); + game.setGameName("SV388真人"); + game.setCreateBy(Constants.SYSTEM); + NameInfo nameInfo = new NameInfo(); + nameInfo.setLang("zh-CN"); + nameInfo.setName("SV388真人"); + game.setNameInfo(Collections.singletonList(nameInfo)); + game.setGameId(StringUtils.addSuffix(GamePlatforms.SV388.getCode(), 1)); + gameService.insertGame(game); + }else { + for (Game game : gameList) { + NameInfo nameInfo = new NameInfo(); + nameInfo.setLang("zh-CN"); + nameInfo.setName("SV388真人"); + game.setNameInfo(Collections.singletonList(nameInfo)); + gameService.updateGame(game); + } + + } + return CacheConstants.SV388_GAMES; + } + + /** + * 按代理id进行交换转账 + * + * @param exchangeTransferMoneyRequestDTO 外汇转账moeny dto + * @return {@link Long } + */ + @Override + @Transactional + public Long exchangeTransferByAgentId(ExchangeTransferMoneyRequestDTO exchangeTransferMoneyRequestDTO) { + + GameExchangeMoney exchangeMoney = gameExchangeMoneyService.selectGameExchangeMoneyById(exchangeTransferMoneyRequestDTO.getGameExchangeId()); + + + + Map params = this.getKey(exchangeTransferMoneyRequestDTO); + SV388AETransactionResponse deposit = null; + try { + if (TransferType.GAMES.getCode().equals(exchangeTransferMoneyRequestDTO.getTransferType())) { + + params.put("userId", exchangeTransferMoneyRequestDTO.getAccount()); + params.put("txCode", exchangeTransferMoneyRequestDTO.getTransactionId()); + params.put("transferAmount", exchangeTransferMoneyRequestDTO.getAmount()); + deposit = sv388Client.deposit(params); + + } else { + params.put("userId", exchangeTransferMoneyRequestDTO.getAccount()); + params.put("txCode", exchangeTransferMoneyRequestDTO.getTransactionId()); + params.put("withdrawType", 1); + deposit = sv388Client.withdraw(params); + } + } finally { + BigDecimal coinBefore; + if (TransferType.GAMES.getCode().equals(exchangeTransferMoneyRequestDTO.getTransferType())) { + coinBefore = NumberUtil.sub(deposit.getCurrentBalance(), deposit.getAmount()); + } else { + coinBefore = NumberUtil.add(deposit.getCurrentBalance(), deposit.getAmount()); + } + //判断是否转移成功 + if ("0000".equals(deposit.getStatus())) { + exchangeMoney.setStep(GameExchangeStep.PLATFORM_TRANSACTION.getCode()); + exchangeMoney.setStepStatus(GameExchangeStepStatus.SUCCESS.getCode()); + } else { + exchangeMoney.setStep(GameExchangeStep.PLATFORM_TRANSACTION.getCode()); + exchangeMoney.setStepStatus(GameExchangeStepStatus.IN_PROGRESS.getCode()); + } + //更新数据 + exchangeMoney.setBalance(deposit.getAmount()); + exchangeMoney.setCoinBefore(coinBefore); + exchangeMoney.setCoinAfter(deposit.getCurrentBalance()); + exchangeMoney.setCurrencyBefore(exchangeMoney.getCoinBefore()); + exchangeMoney.setCurrencyAfter(exchangeMoney.getCoinAfter()); + gameExchangeMoneyService.updateGameExchangeMoney(exchangeMoney); + } + + return exchangeMoney.getId(); + } + /** + * 获取交易id + * + * @param transactionIdRequestDTO 事务id请求dto + * @return {@link String } + */ + @Override + public String getTransactionId(TransactionIdRequestDTO transactionIdRequestDTO) { + return GamePlatforms.SV388.getCode() + IdUtils.simpleUUID(); + } + + + /** + * 汇兑转移状态 + * + * @param exchangeTransferMoneyRequestDTO 兑换转账请求dto + * @return {@link ExchangeTransferStatusResponseDTO } + */ + @Override + public ExchangeTransferStatusResponseDTO exchangeTransferStatus(ExchangeTransferStatusRequestDTO exchangeTransferMoneyRequestDTO) { + + Map paramsMap = this.getKey(exchangeTransferMoneyRequestDTO); + paramsMap.put("txCode", exchangeTransferMoneyRequestDTO.getOrderId()); + + SV388ExchangeTransferStatusResponse exchangeTransferStatusResponse = sv388Client.exchangeTransferStatus(paramsMap); + Integer status = StatusType.IN_PROGRESS.getValue(); + if ("0000".equals(exchangeTransferStatusResponse.getStatus()) && "1".equals(exchangeTransferStatusResponse.getTxStatus())) { + status = StatusType.SUCCESS.getValue(); + } else if ("0000".equals(exchangeTransferStatusResponse.getStatus()) && "0".equals(exchangeTransferStatusResponse.getTxStatus())) { + status = StatusType.FAILURE.getValue(); + } else if ("1017".equals(exchangeTransferStatusResponse.getStatus())) { + status = StatusType.FAILURE.getValue(); + } + GameExchangeMoney exchangeMoney = gameExchangeMoneyService.selectGameExchangeMoneyById(exchangeTransferMoneyRequestDTO.getGameExchangeMoneyId()); + //更新 + BigDecimal coinBefore; + if (TransferType.GAMES.getCode().equals(exchangeMoney.getExchangeType())) { + coinBefore = NumberUtil.sub(exchangeTransferStatusResponse.getBalance(), exchangeTransferStatusResponse.getTransferAmount()); + } else { + coinBefore = NumberUtil.add(exchangeTransferStatusResponse.getBalance(), exchangeTransferStatusResponse.getTransferAmount()); + } + + + return ExchangeTransferStatusResponseDTO.builder() + .statusType(status) + .balance(exchangeTransferStatusResponse.getTransferAmount()) + .coinBefore(coinBefore) + .coinAfter(exchangeTransferStatusResponse.getBalance()) + .build(); + } + + + class GetRealtimeRecordTask extends DelayTask { + BetRecordByTimeDTO betRecordByTimeDTO; + + public GetRealtimeRecordTask(BetRecordByTimeDTO betRecordByTimeDTO) { + this.betRecordByTimeDTO = betRecordByTimeDTO; + } + + @Override + public void execute() { + getRealtimeRecord(betRecordByTimeDTO); + } + } + + void getRealtimeRecord(BetRecordByTimeDTO betRecordByTimeDTO) { + //请求参数 + Map params = this.getKey(betRecordByTimeDTO); + + String timeFrom = redisCache.getCacheObject(CacheConstants.SV388_TIME_FROM); + if (StringUtils.isEmpty(timeFrom)) { + timeFrom = DateUtils.convertTimestampToFormattedDate(betRecordByTimeDTO.getStartTime(), DateUtils.ISO_8601_FORMAT, "GMT+8") + "+08:00"; + } + + params.put("timeFrom", timeFrom); + params.put("platform", GamePlatforms.SV388.getCode()); + params.put("delayTime", 10000); + SV388BetRecordResponse aeBetRecordResponse = sv388Client.getBetRecordByTime(params, betRecordByTimeDTO.getVendor().getUrlInfo().getBetUrl()); + + //判断是否获取成功 + if (this.getIsSuccess(aeBetRecordResponse.getStatus())) { + //数据组装 + this.batchInsert(aeBetRecordResponse, betRecordByTimeDTO); + if (aeBetRecordResponse.getTransactions().size() >= 20000) { + delayService.addTask(new GetRealtimeRecordTask(betRecordByTimeDTO)); + } + } else { + redisCache.deleteObject(CacheConstants.SV388_TIME_FROM); + log.error("获取投注记录失败,错误代码{},错误信息{}", aeBetRecordResponse.getStatus(), aeBetRecordResponse.getDesc()); + } + } + + void getHistoryRecord(BetRecordByTimeDTO betRecordByTimeDTO) { + Map params = this.getKey(betRecordByTimeDTO); + String startTime = DateUtils.convertTimestampToFormattedDate(betRecordByTimeDTO.getStartTime(), DateUtils.ISO_8601_FORMAT, "GMT+8") + "+08:00"; + String endTime = DateUtils.convertTimestampToFormattedDate(betRecordByTimeDTO.getStartTime(), DateUtils.ISO_8601_FORMAT, "GMT+8") + "+08:00"; + + params.put("startTime", startTime); + params.put("endTime", endTime); + params.put("platform", /*"SEXYBCRT"*/ GamePlatforms.SV388.getCode()); + + SV388BetRecordResponse aeBetRecordResponse = sv388Client.getBetHistoryRecordByTime(params, betRecordByTimeDTO.getVendor().getUrlInfo().getBetUrl()); + + //判断是否获取成功 + if (this.getIsSuccess(aeBetRecordResponse.getStatus())) { + //数据组装 + this.batchInsert(aeBetRecordResponse, betRecordByTimeDTO); + if (aeBetRecordResponse.getTransactions().size() >= 20000) { + delayService.addTask(new GetHistoryRecordTask(betRecordByTimeDTO)); + } + } else { + log.error("获取投注记录失败,错误代码{},错误信息{}", aeBetRecordResponse.getStatus(), aeBetRecordResponse.getDesc()); + } + } + + class GetHistoryRecordTask extends DelayTask { + BetRecordByTimeDTO betRecordByTimeDTO; + + public GetHistoryRecordTask(BetRecordByTimeDTO betRecordByTimeDTO) { + this.betRecordByTimeDTO = betRecordByTimeDTO; + } + + @Override + public void execute() { + getHistoryRecord(betRecordByTimeDTO); + } + } + + /** + * 按时间获取投注记录 + * + * @param betRecordByTimeDTO 按时间dto投注记录 + * @return {@link List }<{@link GameBettingDetails }> + */ + @Override + public Boolean getBetRecordByTime(BetRecordByTimeDTO betRecordByTimeDTO) { + delayService.addTask(new GetRealtimeRecordTask(betRecordByTimeDTO)); + return Boolean.TRUE; + } + + /** + * 按历史时间获取投注记录 + * + * @param betRecordByTimeDTO 按时间dto投注记录 + * @return {@link Boolean } + */ + @Override + public Boolean getBetRecordByHistoryTime(BetRecordByTimeDTO betRecordByTimeDTO) { + delayService.addTask(new GetHistoryRecordTask(betRecordByTimeDTO)); + return Boolean.TRUE; + } + + /** + * 赠送免费局数 + * + * @param createFreeSpinRequest 创建自由旋转请求 + * @return {@link Boolean } + */ + @Override + public Boolean createFreeSpin(CreateFreeSpinRequestDTO createFreeSpinRequest) { + throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); + } + + /** + * 获取游戏详细信息 + * + * @param getGameDetailRequestDTO 获取游戏详细信息请求dto + * @return {@link GetGameDetailResponseDTO } + */ + @Override + public GetGameDetailResponseDTO getGameDetail(GetGameDetailRequestDTO getGameDetailRequestDTO) { + throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); + } + + /** + * 强制会员从游戏注销 + * + * @param kickMemberRequestDTO 踢会员请求dto + * @return {@link Boolean } + */ + @Override + public Boolean kickMember(KickMemberRequestDTO kickMemberRequestDTO) { + Map params = this.getKey(kickMemberRequestDTO); + params.put("userIds", kickMemberRequestDTO.getAccount()); + XKKickMemberDTO xkKickMemberDTO = sv388Client.kickMember(params); + //判断是否获取成功 + if (this.getIsSuccess(xkKickMemberDTO.getCode())) { + return Boolean.TRUE; + } else { + throw new BaseException(xkKickMemberDTO.getMsg()); + } + } + + /** + * 踢成员全部 + * + * @param kickMemberAllDTO 踢成员全部dto + * @return {@link Boolean } + */ + @Override + public Boolean kickMemberAll(KickMemberAllDTO kickMemberAllDTO) { + throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); + } + + /** + * 免费游戏玩家使用的纪录 + * + * @param getFreeSpinDashflowRequestDTO 获取自由旋转dashflow请求dto + * @return {@link List }<{@link GameFreeRecord }> + */ + @Override + public List getFreeSpinDashflow(GetFreeSpinDashflowRequestDTO getFreeSpinDashflowRequestDTO) { + throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); + } + + /** + * 取消赠送免费局数 + * + * @param cancelFreeSpinRequestDTO 取消免费旋转请求 + * @return {@link Boolean } + */ + @Override + public Boolean cancelFreeSpin(CancelFreeSpinRequestDTO cancelFreeSpinRequestDTO) { + throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); + } + + /** + * 游戏演示登录 + * + * @param gameDemoLoginRequestDTO 游戏演示登录请求dto + * @return {@link GameDemoLoginResponseDTO } + */ + @Override + public GameDemoLoginResponseDTO gameDemoLogin(GameDemoLoginRequestDTO gameDemoLoginRequestDTO) { + throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); + } + + + /** + * 批量插入 + * + * @param aeBetRecordResponse ae下注记录响应dto + */ + private void batchInsert(SV388BetRecordResponse aeBetRecordResponse, BetRecordByTimeDTO betRecordByTimeDTO) { + List gameBettingDetails = new ArrayList<>(); + List wagersIds = new ArrayList<>(); + //数据组装 + List dataBean = aeBetRecordResponse.getTransactions(); + + if (CollectionUtils.isEmpty(dataBean)) { + return; + } + + String timeFrom = null; + //数据转化 + for (SV388BetRecordResponse.Transaction bean : dataBean) { + GameBettingDetails bettingDetails = this.dataBuild(GamesDataBuildDTO.builder() + .platform(betRecordByTimeDTO.getVendor()) + .data(bean).build()); + if (!ObjectUtils.isEmpty(bettingDetails)) { + bettingDetails.setId(IdUtil.getSnowflakeNextId()); + gameBettingDetails.add(bettingDetails); + } + wagersIds.add(bean.getPlatform() + bean.getPlatformTxId()); + timeFrom = bean.getUpdateTime(); + } + if (!CollectionUtils.isEmpty(gameBettingDetails)) { + //查询重复数据id + List removeWagersIds = gameBettingDetailsService.selectGameBettingDetailsByWagersId(wagersIds, GamePlatforms.SV388.getCode()); + //用steam流清除list中与wagersIds集合相同的数据 + gameBettingDetails = gameBettingDetails.stream() + .filter(detail -> !removeWagersIds.contains(detail.getWagersId())) + .collect(Collectors.toList()); + if (!CollectionUtils.isEmpty(gameBettingDetails)) { + gameBettingDetailsService.batchInsert(gameBettingDetails); + } + } + if (StringUtils.isEmpty(timeFrom)) { + timeFrom = DateUtils.convertTimestampToFormattedDate(DateUtils.getNowDate(), DateUtils.ISO_8601_FORMAT, "UTC+8") + "+08:00"; + } + redisCache.setCacheObject(CacheConstants.SV388_TIME_FROM, timeFrom); + + } + + /** + * 数据构建 + * + * @param gamesDataBuildDTO 数据 + * @return {@link GameBettingDetails } + */ + @Override + public GameBettingDetails dataBuild(GamesDataBuildDTO gamesDataBuildDTO) { + //转化类 + SV388BetRecordResponse.Transaction resultBean = (SV388BetRecordResponse.Transaction) gamesDataBuildDTO.getData(); + + + Member member = memberService.selectMemberByGameAccount(resultBean.getUserId()); + if (ObjectUtils.isEmpty(member)) { + return null; + } + + + // 判断输赢 + Integer gameStatus = GameStatus.FLAT.getCode(); + BigDecimal payoffAmount = BigDecimal.ZERO; + if (resultBean.getRealWinAmount().compareTo(resultBean.getRealBetAmount()) > 0) { + gameStatus = GameStatus.WIN.getCode(); + payoffAmount = resultBean.getRealWinAmount().subtract(resultBean.getRealBetAmount()); + } else if (resultBean.getRealWinAmount().compareTo(resultBean.getRealBetAmount()) < 0) { + gameStatus = GameStatus.FAIL.getCode(); + payoffAmount = resultBean.getRealWinAmount().subtract(resultBean.getRealBetAmount()).abs(); + } + + //结算状态 + int settlementStatus = SettlementStatusEnum.REVOKED.getCode(); + if (resultBean.getTxStatus() == 1) { + settlementStatus = SettlementStatusEnum.COMPLETED.getCode(); + } + + //数据构造 + GameBettingDetails gameBettingDetails = GameBettingDetails.builder() + .tenantKey(member.getTenantKey()) + //保存我们的币种id + .currencyCode(gamesDataBuildDTO.getPlatform().getOurCurrency(resultBean.getCurrency())) + .memberId(member.getId()) + .gameCode(resultBean.getGameCode()) + .gameType(PlatformType.VIDEO.getCode()) + .platformCode(GamePlatforms.SV388.getCode()) + .gameId(/*GAME_ID*/GamePlatforms.SV388.getCode() + "_" + 1) + .gameName(resultBean.getGameName()) + .gameStatus(gameStatus) + .gameStatusType(resultBean.getSettleStatus()) + .gameCurrencyCode(resultBean.getCurrency()) + .account(resultBean.getUserId()) + .wagersId(resultBean.getPlatform() + resultBean.getPlatformTxId()) + .wagersTime(resultBean.getBetTime().getTime()) + .betAmount(resultBean.getRealBetAmount()) + .payoffTime(resultBean.getTxTime().getTime()) + .payoffAmount(payoffAmount) + .betContent(resultBean.getGameInfo()) + .settlementTime(resultBean.getTxTime().getTime()) + .turnover(resultBean.getTurnover()) + .orderNo(String.valueOf(resultBean.getRoundId())) + .settlementStatus(settlementStatus) + .build(); + gameBettingDetails.setCreateBy(Constants.SYSTEM); + gameBettingDetails.setCreateTime(DateUtils.getNowDate()); + return gameBettingDetails; + } +} diff --git a/ff-game/src/main/java/com/ff/game/api/xk/address/MyXKAddressSource.java b/ff-game/src/main/java/com/ff/game/api/xk/address/MyXKAddressSource.java index 56ecda7..64144db 100644 --- a/ff-game/src/main/java/com/ff/game/api/xk/address/MyXKAddressSource.java +++ b/ff-game/src/main/java/com/ff/game/api/xk/address/MyXKAddressSource.java @@ -3,8 +3,8 @@ package com.ff.game.api.xk.address; import com.dtflys.forest.callback.AddressSource; import com.dtflys.forest.http.ForestAddress; import com.dtflys.forest.http.ForestRequest; -import com.ff.base.constant.Constants; -import com.ff.base.system.service.ISysConfigService; +import com.ff.base.enums.GamePlatforms; +import com.ff.game.service.IPlatformService; import org.springframework.stereotype.Component; import javax.annotation.Resource; @@ -20,12 +20,13 @@ import javax.annotation.Resource; public class MyXKAddressSource implements AddressSource { @Resource - private ISysConfigService configService; - + private IPlatformService platformService; @Override public ForestAddress getAddress(ForestRequest request) { - String apiBaseUrl = configService.selectConfigByKey(Constants.XK_API_BASE_URL); - return new ForestAddress("https",apiBaseUrl, 443,"api"); +// String apiBaseUrl = configService.selectConfigByKey(Constants.XK_API_BASE_URL); + String apiBaseUrl = platformService.get(GamePlatforms.XK.getCode()) + .getUrlInfo().getUrl(); + return new ForestAddress("https", apiBaseUrl, 443, "api"); } } \ No newline at end of file diff --git a/ff-game/src/main/java/com/ff/game/api/xk/client/XKClient.java b/ff-game/src/main/java/com/ff/game/api/xk/client/XKClient.java index af567fd..d84a42f 100644 --- a/ff-game/src/main/java/com/ff/game/api/xk/client/XKClient.java +++ b/ff-game/src/main/java/com/ff/game/api/xk/client/XKClient.java @@ -61,6 +61,16 @@ public interface XKClient { @Post(url = "/exchangeTransferByAgentId") XKExchangeMoneyResponseDTO exchangeTransferByAgentId( @JSONBody Map params); + + /** + * 按代理id进行交换转账 + * + * @param params 参数 + * @return {@link XKCheckTransferByTransactionIdDTO } + */ + @Post(url = "/getTransferRecordByTransactionId") + XKCheckTransferByTransactionIdDTO checkTransferByTransactionId( @JSONBody Map params); + /** * 按时间获取投注记录 * diff --git a/ff-game/src/main/java/com/ff/game/api/xk/dto/XKCheckTransferByTransactionIdDTO.java b/ff-game/src/main/java/com/ff/game/api/xk/dto/XKCheckTransferByTransactionIdDTO.java new file mode 100644 index 0000000..8c8cabd --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/api/xk/dto/XKCheckTransferByTransactionIdDTO.java @@ -0,0 +1,76 @@ +package com.ff.game.api.xk.dto; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.math.BigDecimal; + +/** + * xkcheck按交易id dto转账 + * + * @author shi + * @date 2025/04/09 + */ +@Data +public class XKCheckTransferByTransactionIdDTO { + /** + * 响应码 + */ + @JsonProperty("code") + private Integer code; + + /** + * 响应消息 + */ + @JsonProperty("msg") + private String msg; + + /** + * 响应数据 + */ + @JsonProperty("data") + private TransactionData data; + + /** + * 交易数据 + */ + @Data + public static class TransactionData { + + /** + * 会员唯一识别值 + */ + @JsonProperty("account") + private String account; + + /** + * 交易序号,额度转移纪录唯一值 + */ + @JsonProperty("transactionId") + private String transactionId; + + /** + * 交易时间(时间戳,单位毫秒) + */ + @JsonProperty("transferTime") + private Long transferTime; + + /** + * 交易金额(Decimal(16,4)) + */ + @JsonProperty("amount") + private BigDecimal amount; + + /** + * 转账类型 + */ + @JsonProperty("transferType") + private Integer transferType; + + /** + * 状态 + */ + @JsonProperty("status") + private Integer status; + } +} diff --git a/ff-game/src/main/java/com/ff/game/api/xk/dto/XKGamesDTO.java b/ff-game/src/main/java/com/ff/game/api/xk/dto/XKGamesDTO.java index da08376..d430ae8 100644 --- a/ff-game/src/main/java/com/ff/game/api/xk/dto/XKGamesDTO.java +++ b/ff-game/src/main/java/com/ff/game/api/xk/dto/XKGamesDTO.java @@ -43,7 +43,7 @@ public class XKGamesDTO { /** *自己系统游戏id */ - private Long systemGameId; + private String systemGameId; /** * jp */ diff --git a/ff-game/src/main/java/com/ff/game/api/xk/service/impl/GamesXKServiceImpl.java b/ff-game/src/main/java/com/ff/game/api/xk/service/impl/GamesXKServiceImpl.java index 82675d3..3aea090 100644 --- a/ff-game/src/main/java/com/ff/game/api/xk/service/impl/GamesXKServiceImpl.java +++ b/ff-game/src/main/java/com/ff/game/api/xk/service/impl/GamesXKServiceImpl.java @@ -8,10 +8,9 @@ import com.ff.base.core.redis.RedisCache; import com.ff.base.enums.*; import com.ff.base.exception.base.ApiException; import com.ff.base.exception.base.BaseException; -import com.ff.base.system.service.ISysConfigService; import com.ff.base.utils.DateUtils; import com.ff.base.utils.JsonUtil; -import com.ff.base.utils.MessageUtils; +import com.ff.base.utils.StringUtils; import com.ff.base.utils.sign.Md5Utils; import com.ff.base.utils.uuid.IdUtils; import com.ff.config.KeyConfig; @@ -20,8 +19,9 @@ import com.ff.game.api.request.*; import com.ff.game.api.xk.client.XKClient; import com.ff.game.api.xk.dto.*; import com.ff.game.domain.*; -import com.ff.game.dto.GameSecretKeyCurrencyDTO; -import com.ff.game.service.*; +import com.ff.game.service.IGameBettingDetailsService; +import com.ff.game.service.IGameExchangeMoneyService; +import com.ff.game.service.IGameService; import com.ff.member.domain.Member; import com.ff.member.service.IMemberService; import lombok.extern.slf4j.Slf4j; @@ -48,49 +48,27 @@ import java.util.stream.Collectors; @Slf4j public class GamesXKServiceImpl implements IGamesService { - - @Resource - private ISysConfigService configService; - @Resource private RedisCache redisCache; @Resource private IGameExchangeMoneyService gameExchangeMoneyService; - - @Resource - private IGamePlatformService gamePlatformService; - - @Resource private IGameService gameService; - @Resource private IMemberService memberService; - @Resource - private IGameFreeRecordService gameFreeRecordService; - @Resource - private IGameSecretKeyService gameSecretKeyService; - - @Resource - private IGameSecretKeyCurrencyService gameSecretKeyCurrencyService; - @Resource private XKClient xkClient; - @Resource private KeyConfig keyConfig; @Resource private IGameBettingDetailsService gameBettingDetailsService; - @Resource - private IGameNameService gameNameService; - /** * 获得就是成功 @@ -219,7 +197,16 @@ public class GamesXKServiceImpl implements IGamesService { throw new BaseException(xkLoginWithoutRedirectResponseDTO.getMsg()); } } - + /** + * 获取交易id + * + * @param transactionIdRequestDTO 事务id请求dto + * @return {@link String } + */ + @Override + public String getTransactionId(TransactionIdRequestDTO transactionIdRequestDTO) { + return GamePlatforms.XK.getCode() + IdUtils.simpleUUID(); + } /** * 获取游戏列表 @@ -249,22 +236,10 @@ public class GamesXKServiceImpl implements IGamesService { if (this.getIsSuccess(xkGamesDTO.getCode())) { for (XKGamesDTO.DataBean gamesDataDTO : xkGamesDTO.getData()) { - GamePlatform gamePlatform = GamePlatform.builder() - .platformType(XKGameType.findSystemByCode(gamesDataDTO.getGameCategoryId())) - .platformCode(GamePlatforms.XK.getCode()) - .build(); - List gamePlatforms = gamePlatformService.selectGamePlatformList(gamePlatform); - //没有此平台就新增一个平台 - if (CollectionUtils.isEmpty(gamePlatforms)) { - gamePlatform.setPlatformName(GamePlatforms.XK.getInfo() + XKGameType.findInfoByCode(gamesDataDTO.getGameCategoryId())); - gamePlatform.setSortNo(gamePlatformService.selectMaxSortNo() + 1); - gamePlatform.setCreateBy(Constants.SYSTEM); - gamePlatformService.insertGamePlatform(gamePlatform); - } else { - gamePlatform = gamePlatforms.get(0); - } + Integer platformType = XKGameType.findSystemByCode(gamesDataDTO.getGameCategoryId()); Game game = Game.builder() - .platformId(gamePlatform.getId()) + .platformCode(GamePlatforms.XK.getCode()) + .platformType(platformType) .gameCode(String.valueOf(gamesDataDTO.getGameId())) .build(); List games = gameService.selectGameList(game); @@ -272,24 +247,26 @@ public class GamesXKServiceImpl implements IGamesService { if (CollectionUtils.isEmpty(games)) { game.setGameSourceType(String.valueOf(gamesDataDTO.getGameCategoryId())); game.setFreespin(gamesDataDTO.isFreeSpin()); - game.setSortNo(gameService.selectMaxSortNoByPlatformId(gamePlatform.getId()) + 1); + game.setSortNo(gameService.selectMaxSortNo(platformType, GamePlatforms.XK.getCode()) + 1); + game.setPlatformCode(GamePlatforms.XK.getCode()); + game.setPlatformType(platformType); game.setGameName(gamesDataDTO.getName()); game.setCreateBy(Constants.SYSTEM); + game.setGameId(StringUtils.addSuffix(GamePlatforms.XK.getCode(), gamesDataDTO.getGameId())); + List nameInfos = new ArrayList<>(); + nameInfos.add(new NameInfo(gamesDataDTO.getName(), "zh-CN")); + game.setNameInfo(nameInfos); + gameService.insertGame(game); } else { game = games.get(0); - } - gamesDataDTO.setSystemGameId(game.getId()); - List gameNames = gameNameService.selectGameNameList(GameName.builder().gameId(game.getId()).gameName(game.getGameName()).build()); - if (CollectionUtils.isEmpty(gameNames)){ - gameNameService.insertGameName(GameName.builder() - .gameId(game.getId()) - .gameName(game.getGameName()) - .langCode("zh-CN") - .createBy(Constants.SYSTEM) - .build()); - } + List nameInfos = new ArrayList<>(); + nameInfos.add(new NameInfo(gamesDataDTO.getName(), "zh-CN")); + game.setNameInfo(nameInfos); + gameService.updateGame(game); + } + gamesDataDTO.setSystemGameId(game.getGameId()); } redisCache.deleteObject(CacheConstants.XK_GAMES); @@ -313,40 +290,16 @@ public class GamesXKServiceImpl implements IGamesService { @Transactional public Long exchangeTransferByAgentId(ExchangeTransferMoneyRequestDTO exchangeTransferMoneyRequestDTO) { log.info("GamesXKServiceImpl [exchangeTransferByAgentId] 请求参数 {}", exchangeTransferMoneyRequestDTO); - GameSecretKeyCurrency currencyDTO = gameSecretKeyCurrencyService.findByGameSecretKeyCurrencyDTO(GameSecretKeyCurrencyDTO.builder() - .platformCode(GamePlatforms.XK.getInfo()) - .code(exchangeTransferMoneyRequestDTO.getAgentId()) - .build()); - Member member = memberService.selectMemberByGameAccount(exchangeTransferMoneyRequestDTO.getAccount()); - String transactionId = GamePlatforms.XK.getCode() + IdUtils.simpleUUID(); - List gameExchangeMonies = gameExchangeMoneyService.selectGameExchangeMoneyList( - GameExchangeMoney.builder() - .tenantKey(exchangeTransferMoneyRequestDTO.getTenantKey()) - .orderId(exchangeTransferMoneyRequestDTO.getOrderId()) - .build() - ); - Assert.isTrue(CollectionUtils.isEmpty(gameExchangeMonies), "订单号重复"); - //获取下一个自增id - GameExchangeMoney exchangeMoney = GameExchangeMoney - .builder() - .tenantKey(exchangeTransferMoneyRequestDTO.getTenantKey()) - .orderId(exchangeTransferMoneyRequestDTO.getOrderId()) - .quota(exchangeTransferMoneyRequestDTO.getQuota()) - .balance(exchangeTransferMoneyRequestDTO.getAmount()) - .exchangeType(exchangeTransferMoneyRequestDTO.getTransferType()) - .currencyCode(currencyDTO.getSystemCurrency()) - .memberId(member.getId()) - .transactionId(transactionId) - .platformCode(GamePlatforms.XK.getCode()) - .build(); - exchangeMoney.setCreateBy(Constants.SYSTEM); - //接口限制限制50字符 - exchangeMoney.setTransactionId(GamePlatforms.XK.getCode() + IdUtils.simpleUUID()); + GameExchangeMoney exchangeMoney = gameExchangeMoneyService.selectGameExchangeMoneyById(exchangeTransferMoneyRequestDTO.getGameExchangeId()); + + + + Map params = new LinkedHashMap<>(); params.put("account", exchangeTransferMoneyRequestDTO.getAccount()); - params.put("transactionId", exchangeMoney.getTransactionId()); + params.put("transactionId", exchangeTransferMoneyRequestDTO.getTransactionId()); params.put("amount", exchangeTransferMoneyRequestDTO.getAmount().stripTrailingZeros().toPlainString()); params.put("transferType", exchangeTransferMoneyRequestDTO.getTransferType()); params.put("agentId", exchangeTransferMoneyRequestDTO.getAgentId()); @@ -366,9 +319,16 @@ public class GamesXKServiceImpl implements IGamesService { exchangeMoney.setCoinAfter(exchangeMoneyResponseData.getCoinAfter()); exchangeMoney.setCurrencyBefore(exchangeMoneyResponseData.getCurrencyBefore()); exchangeMoney.setCurrencyAfter(exchangeMoneyResponseData.getCurrencyAfter()); - exchangeMoney.setStatus(exchangeMoneyResponseData.getStatus()); - gameExchangeMoneyService.insertGameExchangeMoney(exchangeMoney); + + exchangeMoney.setStep(GameExchangeStep.PLATFORM_TRANSACTION.getCode()); + exchangeMoney.setStepStatus(exchangeMoneyResponseData.getStatus()); + gameExchangeMoneyService.updateGameExchangeMoney(exchangeMoney); + } else { + exchangeMoney.setStep(GameExchangeStep.PLATFORM_TRANSACTION.getCode()); + exchangeMoney.setStepStatus(GameExchangeStepStatus.FAILURE.getCode()); + gameExchangeMoneyService.updateGameExchangeMoney(exchangeMoney); + log.error("GamesXKServiceImpl [exchangeTransferByAgentId] 金额转移失败,错误代码{},错误信息{}", exchangeMoneyResponse.getCode(), exchangeMoneyResponse.getMsg()); throw new BaseException(exchangeMoneyResponse.getMsg()); } @@ -383,8 +343,28 @@ public class GamesXKServiceImpl implements IGamesService { * @return {@link Boolean } */ @Override - public Boolean exchangeTransferStatus(ExchangeTransferStatusRequestDTO exchangeTransferMoneyRequestDTO) { - return Boolean.TRUE; + public ExchangeTransferStatusResponseDTO exchangeTransferStatus(ExchangeTransferStatusRequestDTO exchangeTransferMoneyRequestDTO) { + Map params = new LinkedHashMap<>(); + params.put("transactionId", exchangeTransferMoneyRequestDTO.getOrderId()); + params.put("agentId", exchangeTransferMoneyRequestDTO.getAgentId()); + String query = JsonUtil.mapToQueryString(params); + exchangeTransferMoneyRequestDTO.setQuery(query); + String key = this.getKey(exchangeTransferMoneyRequestDTO); + params.put("key", key); + XKCheckTransferByTransactionIdDTO xkCheckTransferByTransactionIdDTO = xkClient.checkTransferByTransactionId(params); + //判断是否转移成功 + if (this.getIsSuccess(xkCheckTransferByTransactionIdDTO.getCode())) { + XKCheckTransferByTransactionIdDTO.TransactionData data = xkCheckTransferByTransactionIdDTO.getData(); + return ExchangeTransferStatusResponseDTO.builder() + .statusType(data.getStatus()) + .balance(data.getAmount()) + .build(); + } else { + return ExchangeTransferStatusResponseDTO.builder() + .statusType(StatusType.FAILURE.getValue()) + .build(); + } + } @@ -396,7 +376,6 @@ public class GamesXKServiceImpl implements IGamesService { */ @Override public Boolean getBetRecordByTime(BetRecordByTimeDTO betRecordByTimeDTO) { - List gameBettingDetails = new ArrayList<>(); //请求参数 log.info("GamesXKServiceImpl [getBetRecordByTime] 请求参数 {}", betRecordByTimeDTO); Map params = new LinkedHashMap<>(); @@ -415,7 +394,7 @@ public class GamesXKServiceImpl implements IGamesService { if (this.getIsSuccess(xkBetRecordResponseDTO.getCode())) { //数据组装 XKBetRecordResponseDTO.DataBean dataBean = xkBetRecordResponseDTO.getData(); - this.batchInsert(xkBetRecordResponseDTO); + this.batchInsert(xkBetRecordResponseDTO, betRecordByTimeDTO); //获取下一页数据 while (!Objects.equals(dataBean.getCurrentPage(), dataBean.getTotalPages()) && dataBean.getTotalPages() > 0) { @@ -432,7 +411,8 @@ public class GamesXKServiceImpl implements IGamesService { key = this.getKey(betRecordByTimeDTO); params.put("key", key); xkBetRecordResponseDTO = xkClient.getBetRecordByTime(params); - this.batchInsert(xkBetRecordResponseDTO); + dataBean = xkBetRecordResponseDTO.getData(); + this.batchInsert(xkBetRecordResponseDTO, betRecordByTimeDTO); } @@ -452,7 +432,51 @@ public class GamesXKServiceImpl implements IGamesService { */ @Override public Boolean getBetRecordByHistoryTime(BetRecordByTimeDTO betRecordByTimeDTO) { - return null; + //请求参数 + log.info("GamesXKServiceImpl [getBetRecordByHistoryTime] 请求参数 {}", betRecordByTimeDTO); + Map params = new LinkedHashMap<>(); + params.put("startTime", betRecordByTimeDTO.getStartTime()); + params.put("endTime", betRecordByTimeDTO.getEndTime()); + params.put("page", betRecordByTimeDTO.getPage()); + params.put("pageLimit", betRecordByTimeDTO.getPageLimit()); + params.put("agentId", betRecordByTimeDTO.getAgentId()); + String query = JsonUtil.mapToQueryString(params); + betRecordByTimeDTO.setQuery(query); + String key = this.getKey(betRecordByTimeDTO); + params.put("key", key); + XKBetRecordResponseDTO xkBetRecordResponseDTO = xkClient.getBetRecordByTime(params); + + //判断是否获取成功 + if (this.getIsSuccess(xkBetRecordResponseDTO.getCode())) { + //数据组装 + XKBetRecordResponseDTO.DataBean dataBean = xkBetRecordResponseDTO.getData(); + this.batchInsert(xkBetRecordResponseDTO, betRecordByTimeDTO); + + //获取下一页数据 + while (!Objects.equals(dataBean.getCurrentPage(), dataBean.getTotalPages()) && dataBean.getTotalPages() > 0) { + betRecordByTimeDTO.setPage(dataBean.getCurrentPage() + 1); + //请求参数 + params = new LinkedHashMap<>(); + params.put("startTime", betRecordByTimeDTO.getStartTime()); + params.put("endTime", betRecordByTimeDTO.getEndTime()); + params.put("page", betRecordByTimeDTO.getPage()); + params.put("pageLimit", betRecordByTimeDTO.getPageLimit()); + params.put("agentId", betRecordByTimeDTO.getAgentId()); + query = JsonUtil.mapToQueryString(params); + betRecordByTimeDTO.setQuery(query); + key = this.getKey(betRecordByTimeDTO); + params.put("key", key); + xkBetRecordResponseDTO = xkClient.getBetRecordByTime(params); + dataBean = xkBetRecordResponseDTO.getData(); + this.batchInsert(xkBetRecordResponseDTO, betRecordByTimeDTO); + } + + + return Boolean.TRUE; + } else { + log.error("GamesXKServiceImpl [getBetRecordByHistoryTime] 获取投注记录失败,错误代码{},错误信息{}", xkBetRecordResponseDTO.getCode(), xkBetRecordResponseDTO.getMsg()); + throw new BaseException(xkBetRecordResponseDTO.getMsg()); + } } /** @@ -463,7 +487,7 @@ public class GamesXKServiceImpl implements IGamesService { */ @Override public Boolean createFreeSpin(CreateFreeSpinRequestDTO createFreeSpinRequest) { - throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); + throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); } /** @@ -474,7 +498,7 @@ public class GamesXKServiceImpl implements IGamesService { */ @Override public GetGameDetailResponseDTO getGameDetail(GetGameDetailRequestDTO getGameDetailRequestDTO) { - throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); + throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); } /** @@ -510,7 +534,7 @@ public class GamesXKServiceImpl implements IGamesService { */ @Override public Boolean kickMemberAll(KickMemberAllDTO kickMemberAllDTO) { - throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); + throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); } /** @@ -521,7 +545,7 @@ public class GamesXKServiceImpl implements IGamesService { */ @Override public List getFreeSpinDashflow(GetFreeSpinDashflowRequestDTO getFreeSpinDashflowRequestDTO) { - throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); + throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); } /** @@ -532,7 +556,18 @@ public class GamesXKServiceImpl implements IGamesService { */ @Override public Boolean cancelFreeSpin(CancelFreeSpinRequestDTO cancelFreeSpinRequestDTO) { - throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); + throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); + } + + /** + * 游戏演示登录 + * + * @param gameDemoLoginRequestDTO 游戏演示登录请求dto + * @return {@link GameDemoLoginResponseDTO } + */ + @Override + public GameDemoLoginResponseDTO gameDemoLogin(GameDemoLoginRequestDTO gameDemoLoginRequestDTO) { + throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); } @@ -541,14 +576,19 @@ public class GamesXKServiceImpl implements IGamesService { * * @param xkBetRecordResponseDTO xk下注记录响应dto */ - private void batchInsert(XKBetRecordResponseDTO xkBetRecordResponseDTO) { + private synchronized void batchInsert(XKBetRecordResponseDTO xkBetRecordResponseDTO, BetRecordByTimeDTO betRecordByTimeDTO) { List gameBettingDetails = new ArrayList<>(); List wagersIds = new ArrayList<>(); //数据组装 XKBetRecordResponseDTO.DataBean dataBean = xkBetRecordResponseDTO.getData(); //数据转化 for (XKBetRecordResponseDTO.DataBean.ResultBean bean : dataBean.getResult()) { - GameBettingDetails bettingDetails = this.dataBuild(GamesDataBuildDTO.builder().data(bean).build()); + GameBettingDetails bettingDetails = this.dataBuild(GamesDataBuildDTO.builder() + .platform(betRecordByTimeDTO.getVendor()) + .systemCurrencyCode(betRecordByTimeDTO.getSystemCurrency()) + .currencyCode(betRecordByTimeDTO.getCurrency()) + .data(bean) + .build()); if (!ObjectUtils.isEmpty(bettingDetails)) { bettingDetails.setId(IdUtil.getSnowflakeNextId()); gameBettingDetails.add(bettingDetails); @@ -557,7 +597,7 @@ public class GamesXKServiceImpl implements IGamesService { } if (!CollectionUtils.isEmpty(gameBettingDetails)) { //查询重复数据id - List removeWagersIds = gameBettingDetailsService.selectGameBettingDetailsByWagersId(wagersIds); + List removeWagersIds = gameBettingDetailsService.selectGameBettingDetailsByWagersId(wagersIds, GamePlatforms.XK.getInfo()); //用steam流清除list中与wagersIds集合相同的数据 gameBettingDetails = gameBettingDetails.stream() .filter(detail -> !removeWagersIds.contains(detail.getWagersId())) @@ -580,10 +620,10 @@ public class GamesXKServiceImpl implements IGamesService { //转化类 XKBetRecordResponseDTO.DataBean.ResultBean resultBean = (XKBetRecordResponseDTO.DataBean.ResultBean) gamesDataBuildDTO.getData(); - GameSecretKeyCurrency currencyDTO = gameSecretKeyCurrencyService.findByGameSecretKeyCurrencyDTO(GameSecretKeyCurrencyDTO.builder() - .platformCode(GamePlatforms.XK.getInfo()) - .code(resultBean.getAgentId()) - .build()); +// GameSecretKeyCurrency currencyDTO = gameSecretKeyCurrencyService.findByGameSecretKeyCurrencyDTO(GameSecretKeyCurrencyDTO.builder() +// .platformCode(GamePlatforms.XK.getInfo()) +// .code(resultBean.getAgentId()) +// .build()); Member member = memberService.selectMemberByGameAccount(resultBean.getAccount()); if (ObjectUtils.isEmpty(member)) { @@ -603,7 +643,7 @@ public class GamesXKServiceImpl implements IGamesService { GameBettingDetails gameBettingDetails = GameBettingDetails.builder() .tenantKey(member.getTenantKey()) //保存我们的币种id - .currencyCode(currencyDTO.getSystemCurrency()) + .currencyCode(gamesDataBuildDTO.getSystemCurrencyCode()) .memberId(member.getId()) .gameCode(resultBean.getGameId()) .gameType(XKGameType.findSystemByCode(resultBean.getGameCategoryId())) diff --git a/ff-game/src/main/java/com/ff/game/controller/GamePlatformController.java b/ff-game/src/main/java/com/ff/game/controller/GamePlatformController.java index 4719b5f..cca88be 100644 --- a/ff-game/src/main/java/com/ff/game/controller/GamePlatformController.java +++ b/ff-game/src/main/java/com/ff/game/controller/GamePlatformController.java @@ -1,27 +1,15 @@ package com.ff.game.controller; -import java.util.List; -import javax.servlet.http.HttpServletResponse; - -import com.ff.base.enums.GamePlatforms; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; -import com.ff.base.annotation.Log; import com.ff.base.core.controller.BaseController; import com.ff.base.core.domain.AjaxResult; -import com.ff.base.enums.BusinessType; -import com.ff.game.domain.GamePlatform; -import com.ff.game.service.IGamePlatformService; -import com.ff.base.utils.poi.ExcelUtil; -import com.ff.base.core.page.TableDataInfo; +import com.ff.base.enums.GamePlatforms; +import com.ff.game.service.IPlatformService; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; /** * 平台管理Controller @@ -32,19 +20,10 @@ import com.ff.base.core.page.TableDataInfo; @RestController @RequestMapping("/game/platform") public class GamePlatformController extends BaseController { - @Autowired - private IGamePlatformService gamePlatformService; - /** - * 查询平台管理列表 - */ - @PreAuthorize("@ss.hasPermi('game:platform:list')") - @GetMapping("/list") - public TableDataInfo list(GamePlatform gamePlatform) { - startPage(); - List list = gamePlatformService.selectGamePlatformList(gamePlatform); - return getDataTable(list); - } + + @Resource + private IPlatformService platformService; /** * 选择 @@ -56,54 +35,16 @@ public class GamePlatformController extends BaseController { return AjaxResult.success(GamePlatforms.getCodes()); } - /** - * 导出平台管理列表 - */ - @PreAuthorize("@ss.hasPermi('game:platform:export')") - @Log(title = "平台管理", businessType = BusinessType.EXPORT) - @PostMapping("/export") - public void export(HttpServletResponse response, GamePlatform gamePlatform) { - List list = gamePlatformService.selectGamePlatformList(gamePlatform); - ExcelUtil util = new ExcelUtil(GamePlatform.class); - util.exportExcel(response, list, "平台管理数据"); - } /** - * 获取平台管理详细信息 + * 所有 + * + * @return {@link AjaxResult } */ - @PreAuthorize("@ss.hasPermi('game:platform:query')") - @GetMapping(value = "/{id}") - public AjaxResult getInfo(@PathVariable("id") Long id) { - return success(gamePlatformService.selectGamePlatformById(id)); - } - - /** - * 新增平台管理 - */ - @PreAuthorize("@ss.hasPermi('game:platform:add')") - @Log(title = "平台管理", businessType = BusinessType.INSERT) - @PostMapping - public AjaxResult add(@RequestBody GamePlatform gamePlatform) { - return toAjax(gamePlatformService.insertGamePlatform(gamePlatform)); - } - - /** - * 修改平台管理 - */ - @PreAuthorize("@ss.hasPermi('game:platform:edit')") - @Log(title = "平台管理", businessType = BusinessType.UPDATE) - @PutMapping - public AjaxResult edit(@RequestBody GamePlatform gamePlatform) { - return toAjax(gamePlatformService.updateGamePlatform(gamePlatform)); - } - - /** - * 删除平台管理 - */ - @PreAuthorize("@ss.hasPermi('game:platform:remove')") - @Log(title = "平台管理", businessType = BusinessType.DELETE) - @DeleteMapping("/{ids}") - public AjaxResult remove(@PathVariable Long[] ids) { - return toAjax(gamePlatformService.deleteGamePlatformByIds(ids)); + @PreAuthorize("@ss.hasPermi('game:platform:all')") + @GetMapping("/all") + public AjaxResult all() { + platformService.loadToCache(); + return AjaxResult.success(); } } diff --git a/ff-game/src/main/java/com/ff/game/controller/GameSecretKeyController.java b/ff-game/src/main/java/com/ff/game/controller/GameSecretKeyController.java deleted file mode 100644 index 627fc8d..0000000 --- a/ff-game/src/main/java/com/ff/game/controller/GameSecretKeyController.java +++ /dev/null @@ -1,104 +0,0 @@ -package com.ff.game.controller; - -import java.util.List; -import javax.servlet.http.HttpServletResponse; -import org.springframework.security.access.prepost.PreAuthorize; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; -import com.ff.base.annotation.Log; -import com.ff.base.core.controller.BaseController; -import com.ff.base.core.domain.AjaxResult; -import com.ff.base.enums.BusinessType; -import com.ff.game.domain.GameSecretKey; -import com.ff.game.service.IGameSecretKeyService; -import com.ff.base.utils.poi.ExcelUtil; -import com.ff.base.core.page.TableDataInfo; - -/** - * 游戏平台密钥管理Controller - * - * @author shi - * @date 2025-02-10 - */ -@RestController -@RequestMapping("/game/key") -public class GameSecretKeyController extends BaseController -{ - @Autowired - private IGameSecretKeyService gameSecretKeyService; - - /** - * 查询游戏平台密钥管理列表 - */ - @PreAuthorize("@ss.hasPermi('game:key:list')") - @GetMapping("/list") - public TableDataInfo list(GameSecretKey gameSecretKey) - { - startPage(); - List list = gameSecretKeyService.selectGameSecretKeyList(gameSecretKey); - return getDataTable(list); - } - - /** - * 导出游戏平台密钥管理列表 - */ - @PreAuthorize("@ss.hasPermi('game:key:export')") - @Log(title = "游戏平台密钥管理", businessType = BusinessType.EXPORT) - @PostMapping("/export") - public void export(HttpServletResponse response, GameSecretKey gameSecretKey) - { - List list = gameSecretKeyService.selectGameSecretKeyList(gameSecretKey); - ExcelUtil util = new ExcelUtil(GameSecretKey.class); - util.exportExcel(response, list, "游戏平台密钥管理数据"); - } - - /** - * 获取游戏平台密钥管理详细信息 - */ - @PreAuthorize("@ss.hasPermi('game:key:query')") - @GetMapping(value = "/{id}") - public AjaxResult getInfo(@PathVariable("id") Long id) - { - return success(gameSecretKeyService.selectGameSecretKeyById(id)); - } - - /** - * 新增游戏平台密钥管理 - */ - @PreAuthorize("@ss.hasPermi('game:key:add')") - @Log(title = "游戏平台密钥管理", businessType = BusinessType.INSERT) - @PostMapping - public AjaxResult add(@RequestBody GameSecretKey gameSecretKey) - { - return toAjax(gameSecretKeyService.insertGameSecretKey(gameSecretKey)); - } - - /** - * 修改游戏平台密钥管理 - */ - @PreAuthorize("@ss.hasPermi('game:key:edit')") - @Log(title = "游戏平台密钥管理", businessType = BusinessType.UPDATE) - @PutMapping - public AjaxResult edit(@RequestBody GameSecretKey gameSecretKey) - { - return toAjax(gameSecretKeyService.updateGameSecretKey(gameSecretKey)); - } - - /** - * 删除游戏平台密钥管理 - */ - @PreAuthorize("@ss.hasPermi('game:key:remove')") - @Log(title = "游戏平台密钥管理", businessType = BusinessType.DELETE) - @DeleteMapping("/{ids}") - public AjaxResult remove(@PathVariable Long[] ids) - { - return toAjax(gameSecretKeyService.deleteGameSecretKeyByIds(ids)); - } -} diff --git a/ff-game/src/main/java/com/ff/game/domain/CurrencyInfo.java b/ff-game/src/main/java/com/ff/game/domain/CurrencyInfo.java new file mode 100644 index 0000000..173c9b5 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/domain/CurrencyInfo.java @@ -0,0 +1,15 @@ +package com.ff.game.domain; + +import lombok.Data; + +import java.io.Serializable; +import java.util.HashMap; + +/** + * key:我们的币种 + * + * @author cengy + */ +@Data +public class CurrencyInfo extends HashMap implements Serializable { +} diff --git a/ff-game/src/main/java/com/ff/game/domain/ExtInfo.java b/ff-game/src/main/java/com/ff/game/domain/ExtInfo.java new file mode 100644 index 0000000..0818b06 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/domain/ExtInfo.java @@ -0,0 +1,41 @@ +package com.ff.game.domain; + +import lombok.Data; +import org.springframework.util.ObjectUtils; + +import java.io.Serializable; +import java.util.Map; + +/** + * @author cengy + */ +@Data +public class ExtInfo implements Serializable { + + // 币种信息,key为其它平台的币种id,value为我们自己的币种 + private Map currency; + /** + * 超时时间 + */ + private Map timeout; + + private Map betLimit; + + public String getOurCurrency(String currencyId) { + return currency == null ? null : currency.get(currencyId); + } + + /** + * 获取超时 + * + * @param key 钥匙 + * @return {@link Long } + */ + public Long getTimeout(String key) { + Map timeout = this.timeout; + if (!ObjectUtils.isEmpty(timeout) && timeout.containsKey(key)) { + return timeout.get(key); + } + return 5000L; + } +} diff --git a/ff-game/src/main/java/com/ff/game/domain/Game.java b/ff-game/src/main/java/com/ff/game/domain/Game.java index 27b4b5f..5b65e5b 100644 --- a/ff-game/src/main/java/com/ff/game/domain/Game.java +++ b/ff-game/src/main/java/com/ff/game/domain/Game.java @@ -5,11 +5,12 @@ import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; import com.ff.base.annotation.Excel; import com.ff.base.core.domain.BaseEntity; import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.SuperBuilder; +import java.util.List; + /** * 平台子游戏管理对象 ff_game * @@ -20,24 +21,31 @@ import lombok.experimental.SuperBuilder; @AllArgsConstructor @NoArgsConstructor @SuperBuilder -public class Game extends BaseEntity -{ +public class Game extends BaseEntity { private static final long serialVersionUID = 1L; - /** 主键id */ + /** + * 主键id + */ @JsonSerialize(using = ToStringSerializer.class) private Long id; - /** 排序 */ + /** + * 排序 + */ @Excel(name = "排序") private Integer sortNo; - /** 游戏平台id */ + /** + * 游戏平台id + */ @Excel(name = "游戏平台id") @JsonSerialize(using = ToStringSerializer.class) private Long platformId; - /** 游戏第三方id */ + /** + * 游戏第三方id + */ @Excel(name = "游戏第三方id") private String gameCode; @@ -46,27 +54,53 @@ public class Game extends BaseEntity */ private Integer ingress; - /** 第三方来源分类 */ + /** + * 第三方来源分类 + */ @Excel(name = "第三方来源分类") private String gameSourceType; - /** 游戏名称 */ + /** + * 游戏名称 + */ @Excel(name = "游戏名称") private String gameName; - /** 是否支持免费游戏 1 支持 0 不支持 */ + /** + * 是否支持免费游戏 1 支持 0 不支持 + */ @Excel(name = "是否支持免费游戏 1 支持 0 不支持") private Boolean freespin; - /** 是否支持试玩 0关闭 1开启 */ + /** + * 是否支持试玩 0关闭 1开启 + */ @Excel(name = "是否支持试玩 0关闭 1开启") private Boolean demoStatus; - /** 维护开关 维护状态 */ + /** + * 维护开关 维护状态 + */ @Excel(name = "维护开关 ") private Boolean stopStatus; + /** + * 平台code + */ + private String platformCode; + /** + * 平台类型 + */ + private Integer platformType; + /** + * 名称信息 + */ + private List nameInfo; + /** + * 游戏id + */ + private String gameId; } diff --git a/ff-game/src/main/java/com/ff/game/domain/GameBettingDetails.java b/ff-game/src/main/java/com/ff/game/domain/GameBettingDetails.java index 04eb913..3853137 100644 --- a/ff-game/src/main/java/com/ff/game/domain/GameBettingDetails.java +++ b/ff-game/src/main/java/com/ff/game/domain/GameBettingDetails.java @@ -53,7 +53,7 @@ public class GameBettingDetails extends BaseEntity /** 游戏id */ @Excel(name = "游戏id") @JsonSerialize(using = ToStringSerializer.class) - private Long gameId; + private String gameId; /** 游戏类型 ff_game_type 字典 */ @Excel(name = "游戏类型 ff_game_type 字典") @@ -67,8 +67,8 @@ public class GameBettingDetails extends BaseEntity @Excel(name = "游戏名称") private String gameName; - /** 注单状态 1: 赢 2: 输 3: 平局 */ - @Excel(name = "注单状态 1: 赢 2: 输 3: 平局") + /** 注单状态 1: 赢 2: 输 3: 平局 4 未知 */ + @Excel(name = "注单状态 1: 赢 2: 输 3: 平局 4 未知") private Integer gameStatus; /** 注单类型 @@ -82,6 +82,12 @@ public class GameBettingDetails extends BaseEntity 28 旋转奖金 DG (1:注单,2:红包小费) + AE + 正常状况: + 预设:0 + 结果更改过状况: + Resettle / Unsettle / Voidsettle / Unvoidsettle: 1 + Voidbet: -1 */ @Excel(name = "注单类型") diff --git a/ff-game/src/main/java/com/ff/game/domain/GameExchangeMoney.java b/ff-game/src/main/java/com/ff/game/domain/GameExchangeMoney.java index 6721e0b..336dd12 100644 --- a/ff-game/src/main/java/com/ff/game/domain/GameExchangeMoney.java +++ b/ff-game/src/main/java/com/ff/game/domain/GameExchangeMoney.java @@ -90,5 +90,13 @@ public class GameExchangeMoney extends BaseEntity @Excel(name = "状态 1 成功 2失败") private Integer status; + /** + * 步 GameExchangeStep 枚举 + */ + private Integer step; + /** + * 步骤状态 GameExchangeStepStatus 枚举 + */ + private Integer stepStatus; } diff --git a/ff-game/src/main/java/com/ff/game/domain/GameName.java b/ff-game/src/main/java/com/ff/game/domain/GameName.java deleted file mode 100644 index 144a9e4..0000000 --- a/ff-game/src/main/java/com/ff/game/domain/GameName.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.ff.game.domain; - -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; -import com.ff.base.annotation.Excel; -import com.ff.base.core.domain.BaseEntity; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; -import lombok.experimental.SuperBuilder; - -/** - * 平台子游戏名称管理对象 ff_game_name - * - * @author shi - * @date 2025-03-13 - */ -@Data -@AllArgsConstructor -@SuperBuilder -@NoArgsConstructor -public class GameName extends BaseEntity { - private static final long serialVersionUID = 1L; - - /** - * $column.columnComment - */ - private Long id; - - /** - * 游戏id - */ - @JsonSerialize(using = ToStringSerializer.class) - @Excel(name = "游戏id", width = 30, dateFormat = "yyyy-MM-dd") - private Long gameId; - - /** - * 游戏名称 - */ - @Excel(name = "游戏名称") - private String gameName; - - /** - * 语言代码 - */ - @Excel(name = "语言代码") - private String langCode; - - -} diff --git a/ff-game/src/main/java/com/ff/game/domain/GamePlatform.java b/ff-game/src/main/java/com/ff/game/domain/GamePlatform.java deleted file mode 100644 index 2d2ee66..0000000 --- a/ff-game/src/main/java/com/ff/game/domain/GamePlatform.java +++ /dev/null @@ -1,58 +0,0 @@ -package com.ff.game.domain; - -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; -import com.ff.base.annotation.Excel; -import com.ff.base.core.domain.BaseEntity; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import lombok.experimental.SuperBuilder; - -/** - * 平台管理对象 ff_game_platform - * - * @author shi - * @date 2025-02-10 - */ -@Data -@AllArgsConstructor -@NoArgsConstructor -@SuperBuilder -public class GamePlatform extends BaseEntity -{ - private static final long serialVersionUID = 1L; - - /** 主键id */ - @JsonSerialize(using = ToStringSerializer.class) - private Long id; - - /** 排序 */ - @Excel(name = "排序") - private Integer sortNo; - - /** 平台编码 */ - @Excel(name = "平台编码") - private String platformCode; - - /** 平台类型 ff_game_platform_type 字典 */ - @Excel(name = "平台类型 ff_game_platform_type 字典") - private Integer platformType; - - /** 平台名称 */ - @Excel(name = "平台名称") - private String platformName; - - /** 维护开关 维护状态 */ - @Excel(name = "维护开关 维护状态 ") - private Boolean stopStatus; - - /** 平台开关 平台开关状态 */ - @Excel(name = "平台开关 平台开关状态 ") - private Boolean platformStatus; - - - - -} diff --git a/ff-game/src/main/java/com/ff/game/domain/GameSecretKey.java b/ff-game/src/main/java/com/ff/game/domain/GameSecretKey.java deleted file mode 100644 index d263f9b..0000000 --- a/ff-game/src/main/java/com/ff/game/domain/GameSecretKey.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.ff.game.domain; - -import com.ff.base.annotation.Excel; -import com.ff.base.core.domain.BaseEntity; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; -import lombok.experimental.SuperBuilder; - -/** - * 游戏平台密钥管理对象 ff_game_secret_key - * - * @author shi - * @date 2025-03-13 - */ -@Data -@AllArgsConstructor -@SuperBuilder -@NoArgsConstructor -public class GameSecretKey extends BaseEntity -{ - private static final long serialVersionUID = 1L; - - /** $column.columnComment */ - private Long id; - - /** 平台 */ - @Excel(name = "平台") - private String platform; - - /** - * 供应商号 - */ - private String providerCode; - - /** - * 供应商号密码 - */ - private String password; - - /** 代码 */ - @Excel(name = "代码") - private String code; - - /** 密钥 */ - @Excel(name = "密钥") - private String key; - - -} diff --git a/ff-game/src/main/java/com/ff/game/domain/GameSecretKeyCurrency.java b/ff-game/src/main/java/com/ff/game/domain/GameSecretKeyCurrency.java deleted file mode 100644 index c081e8a..0000000 --- a/ff-game/src/main/java/com/ff/game/domain/GameSecretKeyCurrency.java +++ /dev/null @@ -1,55 +0,0 @@ -package com.ff.game.domain; - -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; -import com.ff.base.annotation.Excel; -import com.ff.base.core.domain.BaseEntity; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import lombok.experimental.SuperBuilder; - -/** - * 游戏平台币种管理对象 ff_game_secret_key_currency - * - * @author shi - * @date 2025-03-13 - */ -@Data -@SuperBuilder -@AllArgsConstructor -@NoArgsConstructor -public class GameSecretKeyCurrency extends BaseEntity { - private static final long serialVersionUID = 1L; - - /** - * $column.columnComment - */ - private Long id; - - /** - * 平台 - */ - @JsonSerialize(using = ToStringSerializer.class) - @Excel(name = "平台", width = 30, dateFormat = "yyyy-MM-dd") - private Long gameSecretKeyId; - - /** - * 货币id - */ - private String currencyId; - /** - * 币种 - */ - @Excel(name = "币种") - private String currency; - - /** - * 系统代码 - */ - @Excel(name = "系统代码") - private String systemCurrency; - - -} diff --git a/ff-game/src/main/java/com/ff/game/domain/GameSecretKeyLang.java b/ff-game/src/main/java/com/ff/game/domain/GameSecretKeyLang.java deleted file mode 100644 index 91212da..0000000 --- a/ff-game/src/main/java/com/ff/game/domain/GameSecretKeyLang.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.ff.game.domain; - -import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; -import com.ff.base.annotation.Excel; -import com.ff.base.core.domain.BaseEntity; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; -import lombok.experimental.SuperBuilder; - -/** - * 游戏平台语言管理对象 ff_game_secret_key_lang - * - * @author shi - * @date 2025-03-13 - */ -@Data -@AllArgsConstructor -@NoArgsConstructor -@SuperBuilder -public class GameSecretKeyLang extends BaseEntity -{ - private static final long serialVersionUID = 1L; - - /** $column.columnComment */ - private Long id; - - /** 平台 */ - @JsonSerialize(using = ToStringSerializer.class) - @Excel(name = "平台", width = 30, dateFormat = "yyyy-MM-dd") - private Long gameSecretKeyId; - - /** 语言 */ - @Excel(name = "语言") - private String lang; - - /** 系统语种id */ - @Excel(name = "系统语种id") - private String systemLangCode; - - -} diff --git a/ff-game/src/main/java/com/ff/game/domain/KeyInfo.java b/ff-game/src/main/java/com/ff/game/domain/KeyInfo.java new file mode 100644 index 0000000..2b671a4 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/domain/KeyInfo.java @@ -0,0 +1,21 @@ +package com.ff.game.domain; + +import lombok.Data; + +import java.io.Serializable; + +/** + * 其它字段按需加 + * + * @author cengy + */ +@Data +public class KeyInfo implements Serializable { + + private String code; + private String key; + private String currency; + private String password; + private String providerCode; + +} diff --git a/ff-game/src/main/java/com/ff/game/domain/LangInfo.java b/ff-game/src/main/java/com/ff/game/domain/LangInfo.java new file mode 100644 index 0000000..3ef380d --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/domain/LangInfo.java @@ -0,0 +1,14 @@ +package com.ff.game.domain; + +import java.io.Serializable; +import java.util.HashMap; + +/** + * @author cengy + */ +public class LangInfo extends HashMap implements Serializable { + + public String get(String lang) { + return super.get(lang); + } +} diff --git a/ff-game/src/main/java/com/ff/game/domain/NameInfo.java b/ff-game/src/main/java/com/ff/game/domain/NameInfo.java new file mode 100644 index 0000000..f5896a9 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/domain/NameInfo.java @@ -0,0 +1,26 @@ +package com.ff.game.domain; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +/** + * @author cengy + */ +@Data +@AllArgsConstructor +@Builder +@NoArgsConstructor +public class NameInfo implements Serializable { + /** + * 名称 + */ + private String name; + /** + * 长 + */ + private String lang; +} diff --git a/ff-game/src/main/java/com/ff/game/domain/Platform.java b/ff-game/src/main/java/com/ff/game/domain/Platform.java new file mode 100644 index 0000000..f786d52 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/domain/Platform.java @@ -0,0 +1,82 @@ +package com.ff.game.domain; + +import com.ff.base.core.domain.BaseEntity; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.Getter; + +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * @author cengy + */ +@Data +public class Platform extends BaseEntity { + + /** + * 排序 + */ + private Integer sortNo; + /** + * 平台code + */ + private String platformCode; + /** + * 平台名称 + */ + private String platformName; + + /** + * 状态:true:启用 false:停用 + */ + private Boolean stopStatus; + + private List platformInfo; + private List keyInfo; + private LangInfo langInfo; + private CurrencyInfo currencyInfo; + private UrlInfo urlInfo; + /** + * 代理类型 0:代理单币种 1:代理多币种 + */ + private Integer type; + + private ExtInfo extInfo; + + + @Getter + @AllArgsConstructor + public enum Type { + /** + * 代理类型 0:代理单币种 1:代理多币种 + */ + SINGLE(0, "代理单币种"), + MULTI(1, "代理多币种"); + + private Integer code; + private String name; + + } + + public boolean isMultiAgent() { + return this.type == Type.MULTI.getCode(); + } + + /** + * 获取我们货币 + * + * @param currency 它们的货币 + * @return {@link String } + */ + public String getOurCurrency(String currency) { + Set> entrySet= currencyInfo.entrySet(); + for (Map.Entry entry : entrySet) { + if (entry.getValue().equals(currency)) { + return entry.getKey(); + } + } + return null; + } +} diff --git a/ff-game/src/main/java/com/ff/game/domain/PlatformInfo.java b/ff-game/src/main/java/com/ff/game/domain/PlatformInfo.java new file mode 100644 index 0000000..b236435 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/domain/PlatformInfo.java @@ -0,0 +1,15 @@ +package com.ff.game.domain; + +import lombok.Data; + +import java.io.Serializable; + +/** + * @author cengy + */ +@Data +public class PlatformInfo implements Serializable { + private String code; + private String name; + private int type; +} diff --git a/ff-game/src/main/java/com/ff/game/domain/UrlInfo.java b/ff-game/src/main/java/com/ff/game/domain/UrlInfo.java new file mode 100644 index 0000000..e76a9b5 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/domain/UrlInfo.java @@ -0,0 +1,29 @@ +package com.ff.game.domain; + +import lombok.Data; + +import java.io.Serializable; + +/** + * @author cengy + */ +@Data +public class UrlInfo implements Serializable { + + private String url; + private String loginUrl; + private String hallCode; + /** + * HTTPS协议 + */ + private String https; + + /** + * 端口 + */ + private String host; + /** + * 投注网址 + */ + private String betUrl; +} diff --git a/ff-game/src/main/java/com/ff/game/dto/GameExchangeMoneyDTO.java b/ff-game/src/main/java/com/ff/game/dto/GameExchangeMoneyDTO.java index f505d6b..066940c 100644 --- a/ff-game/src/main/java/com/ff/game/dto/GameExchangeMoneyDTO.java +++ b/ff-game/src/main/java/com/ff/game/dto/GameExchangeMoneyDTO.java @@ -2,7 +2,10 @@ package com.ff.game.dto; import com.ff.game.domain.GameBettingDetails; import com.ff.game.domain.GameExchangeMoney; +import lombok.AllArgsConstructor; import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; /** * 游戏兑换货币dto @@ -11,6 +14,9 @@ import lombok.Data; * @date 2025/02/27 */ @Data +@SuperBuilder +@AllArgsConstructor +@NoArgsConstructor public class GameExchangeMoneyDTO extends GameExchangeMoney { /** * 会员帐户 diff --git a/ff-game/src/main/java/com/ff/game/dto/GameNameDTO.java b/ff-game/src/main/java/com/ff/game/dto/GameNameDTO.java deleted file mode 100644 index f4d187f..0000000 --- a/ff-game/src/main/java/com/ff/game/dto/GameNameDTO.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.ff.game.dto; - -import com.ff.game.domain.GameName; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; -import lombok.experimental.SuperBuilder; - -@Data -@AllArgsConstructor -@NoArgsConstructor -@SuperBuilder -public class GameNameDTO extends GameName { - /** - * 平台代码 - */ - private String platformCode; - - /** - * 默认名称 - */ - private String defaultName; - - /** - * 游戏代码 - */ - private String gameCode; -} diff --git a/ff-game/src/main/java/com/ff/game/dto/GameSecretKeyCurrencyDTO.java b/ff-game/src/main/java/com/ff/game/dto/GameSecretKeyCurrencyDTO.java deleted file mode 100644 index 5c0dbff..0000000 --- a/ff-game/src/main/java/com/ff/game/dto/GameSecretKeyCurrencyDTO.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.ff.game.dto; - -import com.ff.game.domain.GameSecretKeyCurrency; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import lombok.experimental.SuperBuilder; - -import java.util.List; - -/** - * 游戏密钥货币dto - * - * @author shi - * @date 2025/03/13 - */ -@Data -@SuperBuilder -@AllArgsConstructor -@NoArgsConstructor -public class GameSecretKeyCurrencyDTO extends GameSecretKeyCurrency { - - /** - * 平台 - */ - private String platformCode; - - - /** - * 平台代码 - */ - private List platformCodes; - - /** - * API code - */ - private String code; - - /** - * 游戏密钥id - */ - private Long gameSecretKeyId; - - /** - * 密钥 - */ - private String key; - - -} diff --git a/ff-game/src/main/java/com/ff/game/dto/GameSecretKeyDTO.java b/ff-game/src/main/java/com/ff/game/dto/GameSecretKeyDTO.java deleted file mode 100644 index 3a769b9..0000000 --- a/ff-game/src/main/java/com/ff/game/dto/GameSecretKeyDTO.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.ff.game.dto; - -import com.ff.game.domain.GameSecretKey; -import lombok.Data; - -import java.util.List; - - -/** - * 游戏密钥dto - * - * @author shi - * @date 2025/03/12 - */ -@Data -public class GameSecretKeyDTO extends GameSecretKey { - /** - * 平台 - */ - private List platforms; -} diff --git a/ff-game/src/main/java/com/ff/game/dto/GameSecretKeyLangDTO.java b/ff-game/src/main/java/com/ff/game/dto/GameSecretKeyLangDTO.java deleted file mode 100644 index af56c2f..0000000 --- a/ff-game/src/main/java/com/ff/game/dto/GameSecretKeyLangDTO.java +++ /dev/null @@ -1,41 +0,0 @@ -package com.ff.game.dto; - -import com.ff.game.domain.GameSecretKeyLang; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.NoArgsConstructor; -import lombok.experimental.SuperBuilder; - -/** - * 游戏密钥lang dto - * - * @author shi - * @date 2025/03/13 - */ -@Data -@AllArgsConstructor -@NoArgsConstructor -@SuperBuilder -public class GameSecretKeyLangDTO extends GameSecretKeyLang { - - /** - * 平台 - */ - private String platformCode; - - /** - * API code - */ - private String code; - - /** - * 游戏密钥id - */ - private Long gameSecretKeyId; - - /** - * 密钥 - */ - private String key; - -} diff --git a/ff-game/src/main/java/com/ff/game/mapper/GameBettingDetailsMapper.java b/ff-game/src/main/java/com/ff/game/mapper/GameBettingDetailsMapper.java index a5ca8cb..d4b5da3 100644 --- a/ff-game/src/main/java/com/ff/game/mapper/GameBettingDetailsMapper.java +++ b/ff-game/src/main/java/com/ff/game/mapper/GameBettingDetailsMapper.java @@ -26,10 +26,11 @@ public interface GameBettingDetailsMapper /** * 按投注id选择游戏投注详细信息 * - * @param wagersIds 投注ID + * @param wagersIds 投注ID + * @param platformCode 平台代码 * @return {@link List }<{@link Long }> */ - List selectGameBettingDetailsByWagersId(@Param("wagersIds") List wagersIds); + List selectGameBettingDetailsByWagersId(@Param("wagersIds") List wagersIds, @Param("platformCode") String platformCode); /** diff --git a/ff-game/src/main/java/com/ff/game/mapper/GameMapper.java b/ff-game/src/main/java/com/ff/game/mapper/GameMapper.java index a9db62d..09ed960 100644 --- a/ff-game/src/main/java/com/ff/game/mapper/GameMapper.java +++ b/ff-game/src/main/java/com/ff/game/mapper/GameMapper.java @@ -1,77 +1,86 @@ package com.ff.game.mapper; -import java.util.List; - import com.ff.api.response.GameResponse; import com.ff.game.api.request.GameUniqueDTO; import com.ff.game.domain.Game; import com.ff.game.dto.GameDTO; +import org.apache.ibatis.annotations.Param; + +import java.util.List; /** * 平台子游戏管理Mapper接口 - * + * * @author shi * @date 2025-02-10 */ -public interface GameMapper -{ +public interface GameMapper { /** * 查询平台子游戏管理 - * + * * @param id 平台子游戏管理主键 * @return 平台子游戏管理 */ - Game selectGameById(Long id); + Game selectGameById(Long id); + + + /** + * 按游戏id选择游戏 + * + * @param gameId 游戏id + * @return {@link Game } + */ + Game selectGameByGameId(String gameId); /** * 查询平台子游戏管理列表 - * + * * @param game 平台子游戏管理 * @return 平台子游戏管理集合 */ - List selectGameList(Game game); + List selectGameList(Game game); /** * 新增平台子游戏管理 - * + * * @param game 平台子游戏管理 * @return 结果 */ - int insertGame(Game game); + int insertGame(Game game); /** * 修改平台子游戏管理 - * + * * @param game 平台子游戏管理 * @return 结果 */ - int updateGame(Game game); + int updateGame(Game game); /** * 删除平台子游戏管理 - * + * * @param id 平台子游戏管理主键 * @return 结果 */ - int deleteGameById(Long id); + int deleteGameById(Long id); /** * 批量删除平台子游戏管理 - * + * * @param ids 需要删除的数据主键集合 * @return 结果 */ - int deleteGameByIds(Long[] ids); + int deleteGameByIds(Long[] ids); /** - * 按平台id选择最大排序号 + * 根据平台code与平台类型选择最大序号 * - * @param platformId 平台id - * @return {@link Integer } + * @param platformType + * @param platformCode + * @return */ - Integer selectMaxSortNoByPlatformId(Long platformId); - + Integer selectMaxSortNoBy(@Param("platformType") Integer platformType, @Param("platformCode") String platformCode); /** * 选择游戏唯一列表 @@ -79,7 +88,7 @@ public interface GameMapper * @param gameUniqueDTO 游戏独有dto * @return {@link List }<{@link Game }> */ - List selectGameUniqueList(GameUniqueDTO gameUniqueDTO); + List selectGameUniqueList(GameUniqueDTO gameUniqueDTO); /** * 选择游戏响应列表 diff --git a/ff-game/src/main/java/com/ff/game/mapper/GameNameMapper.java b/ff-game/src/main/java/com/ff/game/mapper/GameNameMapper.java deleted file mode 100644 index 435b093..0000000 --- a/ff-game/src/main/java/com/ff/game/mapper/GameNameMapper.java +++ /dev/null @@ -1,72 +0,0 @@ -package com.ff.game.mapper; - -import com.ff.game.domain.GameName; -import com.ff.game.dto.GameDTO; -import com.ff.game.dto.GameNameDTO; - -import java.util.List; - -/** - * 平台子游戏名称管理Mapper接口 - * - * @author shi - * @date 2025-03-13 - */ -public interface GameNameMapper -{ - /** - * 查询平台子游戏名称管理 - * - * @param id 平台子游戏名称管理主键 - * @return 平台子游戏名称管理 - */ - GameName selectGameNameById(Long id); - - /** - * 查询平台子游戏名称管理列表 - * - * @param gameName 平台子游戏名称管理 - * @return 平台子游戏名称管理集合 - */ - List selectGameNameList(GameName gameName); - - /** - * 新增平台子游戏名称管理 - * - * @param gameName 平台子游戏名称管理 - * @return 结果 - */ - int insertGameName(GameName gameName); - - /** - * 修改平台子游戏名称管理 - * - * @param gameName 平台子游戏名称管理 - * @return 结果 - */ - int updateGameName(GameName gameName); - - /** - * 删除平台子游戏名称管理 - * - * @param id 平台子游戏名称管理主键 - * @return 结果 - */ - int deleteGameNameById(Long id); - - /** - * 批量删除平台子游戏名称管理 - * - * @param ids 需要删除的数据主键集合 - * @return 结果 - */ - int deleteGameNameByIds(Long[] ids); - - /** - * 选择游戏名称数据列表 - * - * @param gameNameDTO 游戏dto - * @return {@link List }<{@link GameDTO }> - */ - List selectGameNameDTOList(GameNameDTO gameNameDTO); -} diff --git a/ff-game/src/main/java/com/ff/game/mapper/GamePlatformMapper.java b/ff-game/src/main/java/com/ff/game/mapper/GamePlatformMapper.java deleted file mode 100644 index e938093..0000000 --- a/ff-game/src/main/java/com/ff/game/mapper/GamePlatformMapper.java +++ /dev/null @@ -1,70 +0,0 @@ -package com.ff.game.mapper; - -import java.util.List; -import com.ff.game.domain.GamePlatform; - -/** - * 平台管理Mapper接口 - * - * @author shi - * @date 2025-02-10 - */ -public interface GamePlatformMapper -{ - /** - * 查询平台管理 - * - * @param id 平台管理主键 - * @return 平台管理 - */ - GamePlatform selectGamePlatformById(Long id); - - /** - * 查询平台管理列表 - * - * @param gamePlatform 平台管理 - * @return 平台管理集合 - */ - List selectGamePlatformList(GamePlatform gamePlatform); - - /** - * 新增平台管理 - * - * @param gamePlatform 平台管理 - * @return 结果 - */ - int insertGamePlatform(GamePlatform gamePlatform); - - /** - * 修改平台管理 - * - * @param gamePlatform 平台管理 - * @return 结果 - */ - int updateGamePlatform(GamePlatform gamePlatform); - - /** - * 删除平台管理 - * - * @param id 平台管理主键 - * @return 结果 - */ - int deleteGamePlatformById(Long id); - - /** - * 批量删除平台管理 - * - * @param ids 需要删除的数据主键集合 - * @return 结果 - */ - int deleteGamePlatformByIds(Long[] ids); - - - /** - * 选择最大排序号 - * - * @return {@link Integer } - */ - Integer selectMaxSortNo(); - -} diff --git a/ff-game/src/main/java/com/ff/game/mapper/GameSecretKeyCurrencyMapper.java b/ff-game/src/main/java/com/ff/game/mapper/GameSecretKeyCurrencyMapper.java deleted file mode 100644 index df58ee8..0000000 --- a/ff-game/src/main/java/com/ff/game/mapper/GameSecretKeyCurrencyMapper.java +++ /dev/null @@ -1,79 +0,0 @@ -package com.ff.game.mapper; - -import java.util.List; -import com.ff.game.domain.GameSecretKeyCurrency; -import com.ff.game.dto.GameSecretKeyCurrencyDTO; - -/** - * 游戏平台币种管理Mapper接口 - * - * @author shi - * @date 2025-03-13 - */ -public interface GameSecretKeyCurrencyMapper -{ - /** - * 查询游戏平台币种管理 - * - * @param id 游戏平台币种管理主键 - * @return 游戏平台币种管理 - */ - GameSecretKeyCurrency selectGameSecretKeyCurrencyById(Long id); - - /** - * 查询游戏平台币种管理列表 - * - * @param gameSecretKeyCurrency 游戏平台币种管理 - * @return 游戏平台币种管理集合 - */ - List selectGameSecretKeyCurrencyList(GameSecretKeyCurrency gameSecretKeyCurrency); - - /** - * 新增游戏平台币种管理 - * - * @param gameSecretKeyCurrency 游戏平台币种管理 - * @return 结果 - */ - int insertGameSecretKeyCurrency(GameSecretKeyCurrency gameSecretKeyCurrency); - - /** - * 修改游戏平台币种管理 - * - * @param gameSecretKeyCurrency 游戏平台币种管理 - * @return 结果 - */ - int updateGameSecretKeyCurrency(GameSecretKeyCurrency gameSecretKeyCurrency); - - /** - * 删除游戏平台币种管理 - * - * @param id 游戏平台币种管理主键 - * @return 结果 - */ - int deleteGameSecretKeyCurrencyById(Long id); - - /** - * 批量删除游戏平台币种管理 - * - * @param ids 需要删除的数据主键集合 - * @return 结果 - */ - int deleteGameSecretKeyCurrencyByIds(Long[] ids); - - - /** - * 按游戏找到密钥货币dto - * - * @param gameSecretKeyCurrencyDTO 游戏密钥货币dto - * @return {@link GameSecretKeyCurrencyDTO } - */ - GameSecretKeyCurrencyDTO findByGameSecretKeyCurrencyDTO(GameSecretKeyCurrencyDTO gameSecretKeyCurrencyDTO); - - /** - * 按游戏查找密钥货币数据列表 - * - * @param gameSecretKeyCurrencyDTO 游戏密钥货币dto - * @return {@link List }<{@link GameSecretKeyCurrencyDTO }> - */ - List findByGameSecretKeyCurrencyDTOList(GameSecretKeyCurrencyDTO gameSecretKeyCurrencyDTO); -} diff --git a/ff-game/src/main/java/com/ff/game/mapper/GameSecretKeyLangMapper.java b/ff-game/src/main/java/com/ff/game/mapper/GameSecretKeyLangMapper.java deleted file mode 100644 index afa304f..0000000 --- a/ff-game/src/main/java/com/ff/game/mapper/GameSecretKeyLangMapper.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.ff.game.mapper; - -import java.util.List; -import com.ff.game.domain.GameSecretKeyLang; -import com.ff.game.dto.GameSecretKeyCurrencyDTO; -import com.ff.game.dto.GameSecretKeyLangDTO; - -/** - * 游戏平台语言管理Mapper接口 - * - * @author shi - * @date 2025-03-13 - */ -public interface GameSecretKeyLangMapper -{ - /** - * 查询游戏平台语言管理 - * - * @param id 游戏平台语言管理主键 - * @return 游戏平台语言管理 - */ - GameSecretKeyLang selectGameSecretKeyLangById(Long id); - - /** - * 查询游戏平台语言管理列表 - * - * @param gameSecretKeyLang 游戏平台语言管理 - * @return 游戏平台语言管理集合 - */ - List selectGameSecretKeyLangList(GameSecretKeyLang gameSecretKeyLang); - - /** - * 新增游戏平台语言管理 - * - * @param gameSecretKeyLang 游戏平台语言管理 - * @return 结果 - */ - int insertGameSecretKeyLang(GameSecretKeyLang gameSecretKeyLang); - - /** - * 修改游戏平台语言管理 - * - * @param gameSecretKeyLang 游戏平台语言管理 - * @return 结果 - */ - int updateGameSecretKeyLang(GameSecretKeyLang gameSecretKeyLang); - - /** - * 删除游戏平台语言管理 - * - * @param id 游戏平台语言管理主键 - * @return 结果 - */ - int deleteGameSecretKeyLangById(Long id); - - /** - * 批量删除游戏平台语言管理 - * - * @param ids 需要删除的数据主键集合 - * @return 结果 - */ - int deleteGameSecretKeyLangByIds(Long[] ids); - - /** - * 查找游戏密钥货币dto - * - * @param gameSecretKeyLangDTO 游戏密钥货币dto - * @return {@link GameSecretKeyLangDTO } - */ - GameSecretKeyLangDTO findGameSecretKeyLangDTO(GameSecretKeyLangDTO gameSecretKeyLangDTO); -} diff --git a/ff-game/src/main/java/com/ff/game/mapper/GameSecretKeyMapper.java b/ff-game/src/main/java/com/ff/game/mapper/GameSecretKeyMapper.java deleted file mode 100644 index eb4f84a..0000000 --- a/ff-game/src/main/java/com/ff/game/mapper/GameSecretKeyMapper.java +++ /dev/null @@ -1,72 +0,0 @@ -package com.ff.game.mapper; - -import java.util.List; -import com.ff.game.domain.GameSecretKey; - -/** - * 游戏平台密钥管理Mapper接口 - * - * @author shi - * @date 2025-03-13 - */ -public interface GameSecretKeyMapper -{ - /** - * 查询游戏平台密钥管理 - * - * @param id 游戏平台密钥管理主键 - * @return 游戏平台密钥管理 - */ - GameSecretKey selectGameSecretKeyById(Long id); - - /** - * 查询游戏平台密钥管理列表 - * - * @param gameSecretKey 游戏平台密钥管理 - * @return 游戏平台密钥管理集合 - */ - List selectGameSecretKeyList(GameSecretKey gameSecretKey); - - - - /** - * 按代码选择游戏密钥 - * - * @param code 代码 - * @return {@link GameSecretKey } - */ - GameSecretKey selectGameSecretKeyByCode(String code); - - - /** - * 新增游戏平台密钥管理 - * - * @param gameSecretKey 游戏平台密钥管理 - * @return 结果 - */ - int insertGameSecretKey(GameSecretKey gameSecretKey); - - /** - * 修改游戏平台密钥管理 - * - * @param gameSecretKey 游戏平台密钥管理 - * @return 结果 - */ - int updateGameSecretKey(GameSecretKey gameSecretKey); - - /** - * 删除游戏平台密钥管理 - * - * @param id 游戏平台密钥管理主键 - * @return 结果 - */ - int deleteGameSecretKeyById(Long id); - - /** - * 批量删除游戏平台密钥管理 - * - * @param ids 需要删除的数据主键集合 - * @return 结果 - */ - int deleteGameSecretKeyByIds(Long[] ids); -} diff --git a/ff-game/src/main/java/com/ff/game/mapper/PlatformMapper.java b/ff-game/src/main/java/com/ff/game/mapper/PlatformMapper.java new file mode 100644 index 0000000..c6664b1 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/mapper/PlatformMapper.java @@ -0,0 +1,24 @@ +package com.ff.game.mapper; + +import com.ff.game.domain.Platform; + +import java.util.List; + +/** + * @author cengy + */ +public interface PlatformMapper { + + + List selectList(Platform platform); + + Platform selectByPlatformCode(String platformCode); + + int updatePlatform(Platform platform); + + int insertPlatform(Platform platform); + + int deleteById(Long id); + + int deleteByIds(String ids); +} diff --git a/ff-game/src/main/java/com/ff/game/service/IGameBettingDetailsService.java b/ff-game/src/main/java/com/ff/game/service/IGameBettingDetailsService.java index 7f7135d..3ef3fc3 100644 --- a/ff-game/src/main/java/com/ff/game/service/IGameBettingDetailsService.java +++ b/ff-game/src/main/java/com/ff/game/service/IGameBettingDetailsService.java @@ -29,7 +29,7 @@ public interface IGameBettingDetailsService * @param wagersIds 投注ID * @return {@link List }<{@link Long }> */ - List selectGameBettingDetailsByWagersId(List wagersIds); + List selectGameBettingDetailsByWagersId(List wagersIds,String platformCode); diff --git a/ff-game/src/main/java/com/ff/game/service/IGameNameService.java b/ff-game/src/main/java/com/ff/game/service/IGameNameService.java deleted file mode 100644 index 7bde767..0000000 --- a/ff-game/src/main/java/com/ff/game/service/IGameNameService.java +++ /dev/null @@ -1,74 +0,0 @@ -package com.ff.game.service; - -import com.ff.game.domain.GameName; -import com.ff.game.dto.GameDTO; -import com.ff.game.dto.GameNameDTO; - -import java.util.List; - -/** - * 平台子游戏名称管理Service接口 - * - * @author shi - * @date 2025-03-13 - */ -public interface IGameNameService -{ - /** - * 查询平台子游戏名称管理 - * - * @param id 平台子游戏名称管理主键 - * @return 平台子游戏名称管理 - */ - GameName selectGameNameById(Long id); - - /** - * 查询平台子游戏名称管理列表 - * - * @param gameName 平台子游戏名称管理 - * @return 平台子游戏名称管理集合 - */ - List selectGameNameList(GameName gameName); - - /** - * 新增平台子游戏名称管理 - * - * @param gameName 平台子游戏名称管理 - * @return 结果 - */ - int insertGameName(GameName gameName); - - /** - * 修改平台子游戏名称管理 - * - * @param gameName 平台子游戏名称管理 - * @return 结果 - */ - int updateGameName(GameName gameName); - - /** - * 批量删除平台子游戏名称管理 - * - * @param ids 需要删除的平台子游戏名称管理主键集合 - * @return 结果 - */ - int deleteGameNameByIds(Long[] ids); - - /** - * 删除平台子游戏名称管理信息 - * - * @param id 平台子游戏名称管理主键 - * @return 结果 - */ - int deleteGameNameById(Long id); - - /** - * 选择游戏名称数据列表 - * - * @param gameNameDTO 游戏dto - * @return {@link List }<{@link GameDTO }> - */ - List selectGameNameDTOList(GameNameDTO gameNameDTO); - - -} diff --git a/ff-game/src/main/java/com/ff/game/service/IGamePlatformService.java b/ff-game/src/main/java/com/ff/game/service/IGamePlatformService.java deleted file mode 100644 index a616d2a..0000000 --- a/ff-game/src/main/java/com/ff/game/service/IGamePlatformService.java +++ /dev/null @@ -1,71 +0,0 @@ -package com.ff.game.service; - -import java.util.List; -import com.ff.game.domain.GamePlatform; - -/** - * 平台管理Service接口 - * - * @author shi - * @date 2025-02-10 - */ -public interface IGamePlatformService -{ - /** - * 查询平台管理 - * - * @param id 平台管理主键 - * @return 平台管理 - */ - GamePlatform selectGamePlatformById(Long id); - - /** - * 查询平台管理列表 - * - * @param gamePlatform 平台管理 - * @return 平台管理集合 - */ - List selectGamePlatformList(GamePlatform gamePlatform); - - /** - * 新增平台管理 - * - * @param gamePlatform 平台管理 - * @return 结果 - */ - int insertGamePlatform(GamePlatform gamePlatform); - - /** - * 修改平台管理 - * - * @param gamePlatform 平台管理 - * @return 结果 - */ - int updateGamePlatform(GamePlatform gamePlatform); - - /** - * 批量删除平台管理 - * - * @param ids 需要删除的平台管理主键集合 - * @return 结果 - */ - int deleteGamePlatformByIds(Long[] ids); - - /** - * 删除平台管理信息 - * - * @param id 平台管理主键 - * @return 结果 - */ - int deleteGamePlatformById(Long id); - - - /** - * 选择最大排序号 - * - * @return {@link Integer } - */ - Integer selectMaxSortNo(); - - -} diff --git a/ff-game/src/main/java/com/ff/game/service/IGameSecretKeyCurrencyService.java b/ff-game/src/main/java/com/ff/game/service/IGameSecretKeyCurrencyService.java deleted file mode 100644 index f14b93a..0000000 --- a/ff-game/src/main/java/com/ff/game/service/IGameSecretKeyCurrencyService.java +++ /dev/null @@ -1,86 +0,0 @@ -package com.ff.game.service; - -import java.util.List; - -import com.ff.game.domain.GameName; -import com.ff.game.domain.GameSecretKey; -import com.ff.game.domain.GameSecretKeyCurrency; -import com.ff.game.dto.GameSecretKeyCurrencyDTO; -import com.ff.game.dto.GameSecretKeyDTO; - -/** - * 游戏平台币种管理Service接口 - * - * @author shi - * @date 2025-03-13 - */ -public interface IGameSecretKeyCurrencyService -{ - /** - * 查询游戏平台币种管理 - * - * @param id 游戏平台币种管理主键 - * @return 游戏平台币种管理 - */ - GameSecretKeyCurrency selectGameSecretKeyCurrencyById(Long id); - - /** - * 查询游戏平台币种管理列表 - * - * @param gameSecretKeyCurrency 游戏平台币种管理 - * @return 游戏平台币种管理集合 - */ - List selectGameSecretKeyCurrencyList(GameSecretKeyCurrency gameSecretKeyCurrency); - - /** - * 新增游戏平台币种管理 - * - * @param gameSecretKeyCurrency 游戏平台币种管理 - * @return 结果 - */ - int insertGameSecretKeyCurrency(GameSecretKeyCurrency gameSecretKeyCurrency); - - /** - * 修改游戏平台币种管理 - * - * @param gameSecretKeyCurrency 游戏平台币种管理 - * @return 结果 - */ - int updateGameSecretKeyCurrency(GameSecretKeyCurrency gameSecretKeyCurrency); - - /** - * 批量删除游戏平台币种管理 - * - * @param ids 需要删除的游戏平台币种管理主键集合 - * @return 结果 - */ - int deleteGameSecretKeyCurrencyByIds(Long[] ids); - - /** - * 删除游戏平台币种管理信息 - * - * @param id 游戏平台币种管理主键 - * @return 结果 - */ - int deleteGameSecretKeyCurrencyById(Long id); - - /** - * 按游戏找到密钥货币dto - * - * @param gameSecretKeyCurrencyDTO 游戏密钥货币dto - * @return {@link GameSecretKeyCurrencyDTO } - */ - GameSecretKeyCurrencyDTO findByGameSecretKeyCurrencyDTO(GameSecretKeyCurrencyDTO gameSecretKeyCurrencyDTO); - - - /** - * 按游戏查找密钥货币数据列表 - * - * @param gameSecretKeyCurrencyDTO 游戏密钥货币dto - * @return {@link List }<{@link GameSecretKeyCurrencyDTO }> - */ - List findByGameSecretKeyCurrencyDTOList(GameSecretKeyCurrencyDTO gameSecretKeyCurrencyDTO); - - - -} diff --git a/ff-game/src/main/java/com/ff/game/service/IGameSecretKeyLangService.java b/ff-game/src/main/java/com/ff/game/service/IGameSecretKeyLangService.java deleted file mode 100644 index 6858764..0000000 --- a/ff-game/src/main/java/com/ff/game/service/IGameSecretKeyLangService.java +++ /dev/null @@ -1,72 +0,0 @@ -package com.ff.game.service; - -import java.util.List; - -import com.ff.game.domain.GameSecretKeyLang; -import com.ff.game.dto.GameSecretKeyCurrencyDTO; -import com.ff.game.dto.GameSecretKeyDTO; -import com.ff.game.dto.GameSecretKeyLangDTO; - -/** - * 游戏平台语言管理Service接口 - * - * @author shi - * @date 2025-03-13 - */ -public interface IGameSecretKeyLangService { - /** - * 查询游戏平台语言管理 - * - * @param id 游戏平台语言管理主键 - * @return 游戏平台语言管理 - */ - GameSecretKeyLang selectGameSecretKeyLangById(Long id); - - /** - * 查询游戏平台语言管理列表 - * - * @param gameSecretKeyLang 游戏平台语言管理 - * @return 游戏平台语言管理集合 - */ - List selectGameSecretKeyLangList(GameSecretKeyLang gameSecretKeyLang); - - /** - * 新增游戏平台语言管理 - * - * @param gameSecretKeyLang 游戏平台语言管理 - * @return 结果 - */ - int insertGameSecretKeyLang(GameSecretKeyLang gameSecretKeyLang); - - /** - * 修改游戏平台语言管理 - * - * @param gameSecretKeyLang 游戏平台语言管理 - * @return 结果 - */ - int updateGameSecretKeyLang(GameSecretKeyLang gameSecretKeyLang); - - /** - * 批量删除游戏平台语言管理 - * - * @param ids 需要删除的游戏平台语言管理主键集合 - * @return 结果 - */ - int deleteGameSecretKeyLangByIds(Long[] ids); - - /** - * 删除游戏平台语言管理信息 - * - * @param id 游戏平台语言管理主键 - * @return 结果 - */ - int deleteGameSecretKeyLangById(Long id); - - /** - * 查找游戏密钥货币dto - * - * @param gameSecretKeyLangDTO 游戏密钥货币dto - * @return {@link GameSecretKeyLangDTO } - */ - GameSecretKeyLangDTO findGameSecretKeyLangDTO(GameSecretKeyLangDTO gameSecretKeyLangDTO); -} diff --git a/ff-game/src/main/java/com/ff/game/service/IGameSecretKeyService.java b/ff-game/src/main/java/com/ff/game/service/IGameSecretKeyService.java deleted file mode 100644 index 713b050..0000000 --- a/ff-game/src/main/java/com/ff/game/service/IGameSecretKeyService.java +++ /dev/null @@ -1,72 +0,0 @@ -package com.ff.game.service; - -import java.util.List; - -import com.ff.game.domain.Game; -import com.ff.game.domain.GameSecretKey; - -/** - * 游戏平台密钥管理Service接口 - * - * @author shi - * @date 2025-03-13 - */ -public interface IGameSecretKeyService -{ - /** - * 查询游戏平台密钥管理 - * - * @param id 游戏平台密钥管理主键 - * @return 游戏平台密钥管理 - */ - GameSecretKey selectGameSecretKeyById(Long id); - - - /** - * 按代码选择游戏密钥 - * - * @param code 代码 - * @return {@link GameSecretKey } - */ - GameSecretKey selectGameSecretKeyByCode(String code); - - /** - * 查询游戏平台密钥管理列表 - * - * @param gameSecretKey 游戏平台密钥管理 - * @return 游戏平台密钥管理集合 - */ - List selectGameSecretKeyList(GameSecretKey gameSecretKey); - - /** - * 新增游戏平台密钥管理 - * - * @param gameSecretKey 游戏平台密钥管理 - * @return 结果 - */ - int insertGameSecretKey(GameSecretKey gameSecretKey); - - /** - * 修改游戏平台密钥管理 - * - * @param gameSecretKey 游戏平台密钥管理 - * @return 结果 - */ - int updateGameSecretKey(GameSecretKey gameSecretKey); - - /** - * 批量删除游戏平台密钥管理 - * - * @param ids 需要删除的游戏平台密钥管理主键集合 - * @return 结果 - */ - int deleteGameSecretKeyByIds(Long[] ids); - - /** - * 删除游戏平台密钥管理信息 - * - * @param id 游戏平台密钥管理主键 - * @return 结果 - */ - int deleteGameSecretKeyById(Long id); -} diff --git a/ff-game/src/main/java/com/ff/game/service/IGameService.java b/ff-game/src/main/java/com/ff/game/service/IGameService.java index 07e47ee..bab4681 100644 --- a/ff-game/src/main/java/com/ff/game/service/IGameService.java +++ b/ff-game/src/main/java/com/ff/game/service/IGameService.java @@ -1,35 +1,43 @@ package com.ff.game.service; -import java.util.List; - import com.ff.api.response.GameResponse; import com.ff.game.api.request.GameUniqueDTO; import com.ff.game.domain.Game; import com.ff.game.dto.GameDTO; +import java.util.List; + /** * 平台子游戏管理Service接口 - * + * * @author shi * @date 2025-02-10 */ -public interface IGameService -{ +public interface IGameService { /** * 查询平台子游戏管理 - * + * * @param id 平台子游戏管理主键 * @return 平台子游戏管理 */ - Game selectGameById(Long id); + Game selectGameById(Long id); + + + /** + * 按游戏id选择游戏 + * + * @param gameId 游戏id + * @return {@link Game } + */ + Game selectGameByGameId(String gameId); /** * 查询平台子游戏管理列表 - * + * * @param game 平台子游戏管理 * @return 平台子游戏管理集合 */ - List selectGameList(Game game); + List selectGameList(Game game); /** @@ -42,43 +50,42 @@ public interface IGameService /** * 新增平台子游戏管理 - * + * * @param game 平台子游戏管理 * @return 结果 */ - int insertGame(Game game); + int insertGame(Game game); /** * 修改平台子游戏管理 - * + * * @param game 平台子游戏管理 * @return 结果 */ - int updateGame(Game game); + int updateGame(Game game); /** * 批量删除平台子游戏管理 - * + * * @param ids 需要删除的平台子游戏管理主键集合 * @return 结果 */ - int deleteGameByIds(Long[] ids); + int deleteGameByIds(Long[] ids); /** * 删除平台子游戏管理信息 - * + * * @param id 平台子游戏管理主键 * @return 结果 */ - int deleteGameById(Long id); + int deleteGameById(Long id); /** * 按平台id选择最大排序号 * - * @param platformId 平台id * @return {@link Integer } */ - Integer selectMaxSortNoByPlatformId(Long platformId); + Integer selectMaxSortNo(Integer platformType, String platformCode); /** * 选择游戏唯一列表 diff --git a/ff-game/src/main/java/com/ff/game/service/IPlatformService.java b/ff-game/src/main/java/com/ff/game/service/IPlatformService.java new file mode 100644 index 0000000..2a8b704 --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/service/IPlatformService.java @@ -0,0 +1,27 @@ +package com.ff.game.service; + +import com.ff.game.domain.Platform; + +import java.util.List; + +/** + * @author cengy + */ +public interface IPlatformService { + + List selectList(Platform platform); + + Platform selectByPlatformCode(String platformCode); + + int updatePlatform(Platform platform); + + int insertPlatform(Platform platform); + + int deleteById(Long id); + + int deleteByIds(String ids); + + void loadToCache(); + + Platform get(String platformCode); +} diff --git a/ff-game/src/main/java/com/ff/game/service/impl/GameBettingDetailsServiceImpl.java b/ff-game/src/main/java/com/ff/game/service/impl/GameBettingDetailsServiceImpl.java index 2c41c68..62ffbfe 100644 --- a/ff-game/src/main/java/com/ff/game/service/impl/GameBettingDetailsServiceImpl.java +++ b/ff-game/src/main/java/com/ff/game/service/impl/GameBettingDetailsServiceImpl.java @@ -43,8 +43,8 @@ public class GameBettingDetailsServiceImpl implements IGameBettingDetailsService * @return {@link List }<{@link Long }> */ @Override - public List selectGameBettingDetailsByWagersId(List wagersIds) { - return gameBettingDetailsMapper.selectGameBettingDetailsByWagersId(wagersIds); + public List selectGameBettingDetailsByWagersId(List wagersIds, String platformCode) { + return gameBettingDetailsMapper.selectGameBettingDetailsByWagersId(wagersIds,platformCode); } /** diff --git a/ff-game/src/main/java/com/ff/game/service/impl/GameExchangeMoneyServiceImpl.java b/ff-game/src/main/java/com/ff/game/service/impl/GameExchangeMoneyServiceImpl.java index 9018a3f..059ede3 100644 --- a/ff-game/src/main/java/com/ff/game/service/impl/GameExchangeMoneyServiceImpl.java +++ b/ff-game/src/main/java/com/ff/game/service/impl/GameExchangeMoneyServiceImpl.java @@ -14,6 +14,7 @@ import com.ff.game.mapper.GameExchangeMoneyMapper; import com.ff.game.domain.GameExchangeMoney; import com.ff.game.service.IGameExchangeMoneyService; import org.springframework.util.CollectionUtils; +import org.springframework.util.ObjectUtils; /** * 会员金额转移记录Service业务层处理 @@ -65,7 +66,9 @@ public class GameExchangeMoneyServiceImpl implements IGameExchangeMoneyService @Override public int insertGameExchangeMoney(GameExchangeMoney gameExchangeMoney) { - gameExchangeMoney.setId(IdUtil.getSnowflakeNextId()); + if (ObjectUtils.isEmpty(gameExchangeMoney.getId())){ + gameExchangeMoney.setId(IdUtil.getSnowflakeNextId()); + } gameExchangeMoney.setCreateTime(DateUtils.getNowDate()); return gameExchangeMoneyMapper.insertGameExchangeMoney(gameExchangeMoney); } diff --git a/ff-game/src/main/java/com/ff/game/service/impl/GameNameServiceImpl.java b/ff-game/src/main/java/com/ff/game/service/impl/GameNameServiceImpl.java deleted file mode 100644 index f358ec4..0000000 --- a/ff-game/src/main/java/com/ff/game/service/impl/GameNameServiceImpl.java +++ /dev/null @@ -1,110 +0,0 @@ -package com.ff.game.service.impl; - -import java.util.Collections; -import java.util.List; - -import com.ff.base.utils.DateUtils; -import com.ff.game.domain.GameName; -import com.ff.game.dto.GameDTO; -import com.ff.game.dto.GameNameDTO; -import com.ff.game.mapper.GameNameMapper; -import com.ff.game.service.IGameNameService; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import cn.hutool.core.util.IdUtil; - - -/** - * 平台子游戏名称管理Service业务层处理 - * - * @author shi - * @date 2025-03-13 - */ -@Service -public class GameNameServiceImpl implements IGameNameService { - @Autowired - private GameNameMapper gameNameMapper; - - /** - * 查询平台子游戏名称管理 - * - * @param id 平台子游戏名称管理主键 - * @return 平台子游戏名称管理 - */ - @Override - public GameName selectGameNameById(Long id) { - return gameNameMapper.selectGameNameById(id); - } - - /** - * 查询平台子游戏名称管理列表 - * - * @param gameName 平台子游戏名称管理 - * @return 平台子游戏名称管理 - */ - @Override - public List selectGameNameList(GameName gameName) { - return gameNameMapper.selectGameNameList(gameName); - } - - /** - * 新增平台子游戏名称管理 - * - * @param gameName 平台子游戏名称管理 - * @return 结果 - */ - @Override - public int insertGameName(GameName gameName) { - if (gameName.getId() == null) { - gameName.setId(IdUtil.getSnowflakeNextId()); - } - - gameName.setCreateTime(DateUtils.getNowDate()); - return gameNameMapper.insertGameName(gameName); - } - - /** - * 修改平台子游戏名称管理 - * - * @param gameName 平台子游戏名称管理 - * @return 结果 - */ - @Override - public int updateGameName(GameName gameName) { - gameName.setUpdateTime(DateUtils.getNowDate()); - return gameNameMapper.updateGameName(gameName); - } - - /** - * 批量删除平台子游戏名称管理 - * - * @param ids 需要删除的平台子游戏名称管理主键 - * @return 结果 - */ - @Override - public int deleteGameNameByIds(Long[] ids) { - return gameNameMapper.deleteGameNameByIds(ids); - } - - /** - * 删除平台子游戏名称管理信息 - * - * @param id 平台子游戏名称管理主键 - * @return 结果 - */ - @Override - public int deleteGameNameById(Long id) { - return gameNameMapper.deleteGameNameById(id); - } - - /** - * 选择游戏名称数据列表 - * - * @param gameNameDTO 游戏dto - * @return {@link List }<{@link GameDTO }> - */ - @Override - public List selectGameNameDTOList(GameNameDTO gameNameDTO) { - return gameNameMapper.selectGameNameDTOList(gameNameDTO); - } -} diff --git a/ff-game/src/main/java/com/ff/game/service/impl/GamePlatformServiceImpl.java b/ff-game/src/main/java/com/ff/game/service/impl/GamePlatformServiceImpl.java deleted file mode 100644 index 2639438..0000000 --- a/ff-game/src/main/java/com/ff/game/service/impl/GamePlatformServiceImpl.java +++ /dev/null @@ -1,107 +0,0 @@ -package com.ff.game.service.impl; - -import java.util.List; - -import cn.hutool.core.util.IdUtil; -import com.ff.base.utils.DateUtils; -import com.ff.base.utils.StringUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import com.ff.game.mapper.GamePlatformMapper; -import com.ff.game.domain.GamePlatform; -import com.ff.game.service.IGamePlatformService; -import org.springframework.util.ObjectUtils; - -/** - * 平台管理Service业务层处理 - * - * @author shi - * @date 2025-02-10 - */ -@Service -public class GamePlatformServiceImpl implements IGamePlatformService { - @Autowired - private GamePlatformMapper gamePlatformMapper; - - /** - * 查询平台管理 - * - * @param id 平台管理主键 - * @return 平台管理 - */ - @Override - public GamePlatform selectGamePlatformById(Long id) { - return gamePlatformMapper.selectGamePlatformById(id); - } - - /** - * 查询平台管理列表 - * - * @param gamePlatform 平台管理 - * @return 平台管理 - */ - @Override - public List selectGamePlatformList(GamePlatform gamePlatform) { - return gamePlatformMapper.selectGamePlatformList(gamePlatform); - } - - /** - * 新增平台管理 - * - * @param gamePlatform 平台管理 - * @return 结果 - */ - @Override - public int insertGamePlatform(GamePlatform gamePlatform) { - if (ObjectUtils.isEmpty(gamePlatform.getId())) { - gamePlatform.setId(IdUtil.getSnowflakeNextId()); - } - gamePlatform.setCreateTime(DateUtils.getNowDate()); - return gamePlatformMapper.insertGamePlatform(gamePlatform); - } - - /** - * 修改平台管理 - * - * @param gamePlatform 平台管理 - * @return 结果 - */ - @Override - public int updateGamePlatform(GamePlatform gamePlatform) { - gamePlatform.setUpdateTime(DateUtils.getNowDate()); - return gamePlatformMapper.updateGamePlatform(gamePlatform); - } - - /** - * 批量删除平台管理 - * - * @param ids 需要删除的平台管理主键 - * @return 结果 - */ - @Override - public int deleteGamePlatformByIds(Long[] ids) { - return gamePlatformMapper.deleteGamePlatformByIds(ids); - } - - /** - * 删除平台管理信息 - * - * @param id 平台管理主键 - * @return 结果 - */ - @Override - public int deleteGamePlatformById(Long id) { - return gamePlatformMapper.deleteGamePlatformById(id); - } - - - /** - * 选择最大排序号 - * - * @return {@link Integer } - */ - @Override - public Integer selectMaxSortNo() { - return gamePlatformMapper.selectMaxSortNo(); - } -} diff --git a/ff-game/src/main/java/com/ff/game/service/impl/GameSecretKeyCurrencyServiceImpl.java b/ff-game/src/main/java/com/ff/game/service/impl/GameSecretKeyCurrencyServiceImpl.java deleted file mode 100644 index aab9c01..0000000 --- a/ff-game/src/main/java/com/ff/game/service/impl/GameSecretKeyCurrencyServiceImpl.java +++ /dev/null @@ -1,123 +0,0 @@ -package com.ff.game.service.impl; - -import java.util.Collections; -import java.util.List; -import com.ff.base.utils.DateUtils; -import com.ff.game.dto.GameSecretKeyCurrencyDTO; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import com.ff.game.mapper.GameSecretKeyCurrencyMapper; -import com.ff.game.domain.GameSecretKeyCurrency; -import com.ff.game.service.IGameSecretKeyCurrencyService; -import cn.hutool.core.util.IdUtil; - - -/** - * 游戏平台币种管理Service业务层处理 - * - * @author shi - * @date 2025-03-13 - */ -@Service -public class GameSecretKeyCurrencyServiceImpl implements IGameSecretKeyCurrencyService -{ - @Autowired - private GameSecretKeyCurrencyMapper gameSecretKeyCurrencyMapper; - - /** - * 查询游戏平台币种管理 - * - * @param id 游戏平台币种管理主键 - * @return 游戏平台币种管理 - */ - @Override - public GameSecretKeyCurrency selectGameSecretKeyCurrencyById(Long id) - { - return gameSecretKeyCurrencyMapper.selectGameSecretKeyCurrencyById(id); - } - - /** - * 查询游戏平台币种管理列表 - * - * @param gameSecretKeyCurrency 游戏平台币种管理 - * @return 游戏平台币种管理 - */ - @Override - public List selectGameSecretKeyCurrencyList(GameSecretKeyCurrency gameSecretKeyCurrency) - { - return gameSecretKeyCurrencyMapper.selectGameSecretKeyCurrencyList(gameSecretKeyCurrency); - } - - /** - * 新增游戏平台币种管理 - * - * @param gameSecretKeyCurrency 游戏平台币种管理 - * @return 结果 - */ - @Override - public int insertGameSecretKeyCurrency(GameSecretKeyCurrency gameSecretKeyCurrency) - { - gameSecretKeyCurrency.setId(IdUtil.getSnowflakeNextId()); - gameSecretKeyCurrency.setCreateTime(DateUtils.getNowDate()); - return gameSecretKeyCurrencyMapper.insertGameSecretKeyCurrency(gameSecretKeyCurrency); - } - - /** - * 修改游戏平台币种管理 - * - * @param gameSecretKeyCurrency 游戏平台币种管理 - * @return 结果 - */ - @Override - public int updateGameSecretKeyCurrency(GameSecretKeyCurrency gameSecretKeyCurrency) - { - gameSecretKeyCurrency.setUpdateTime(DateUtils.getNowDate()); - return gameSecretKeyCurrencyMapper.updateGameSecretKeyCurrency(gameSecretKeyCurrency); - } - - /** - * 批量删除游戏平台币种管理 - * - * @param ids 需要删除的游戏平台币种管理主键 - * @return 结果 - */ - @Override - public int deleteGameSecretKeyCurrencyByIds(Long[] ids) - { - return gameSecretKeyCurrencyMapper.deleteGameSecretKeyCurrencyByIds(ids); - } - - /** - * 删除游戏平台币种管理信息 - * - * @param id 游戏平台币种管理主键 - * @return 结果 - */ - @Override - public int deleteGameSecretKeyCurrencyById(Long id) - { - return gameSecretKeyCurrencyMapper.deleteGameSecretKeyCurrencyById(id); - } - - /** - * 按游戏找到密钥货币dto - * - * @param gameSecretKeyCurrencyDTO 游戏密钥货币dto - * @return {@link GameSecretKeyCurrency } - */ - @Override - public GameSecretKeyCurrencyDTO findByGameSecretKeyCurrencyDTO(GameSecretKeyCurrencyDTO gameSecretKeyCurrencyDTO) { - return gameSecretKeyCurrencyMapper.findByGameSecretKeyCurrencyDTO(gameSecretKeyCurrencyDTO); - } - - /** - * 按游戏查找密钥货币数据列表 - * - * @param gameSecretKeyCurrencyDTO 游戏密钥货币dto - * @return {@link List }<{@link GameSecretKeyCurrencyDTO }> - */ - @Override - public List findByGameSecretKeyCurrencyDTOList(GameSecretKeyCurrencyDTO gameSecretKeyCurrencyDTO) { - return gameSecretKeyCurrencyMapper.findByGameSecretKeyCurrencyDTOList(gameSecretKeyCurrencyDTO); - } -} diff --git a/ff-game/src/main/java/com/ff/game/service/impl/GameSecretKeyLangServiceImpl.java b/ff-game/src/main/java/com/ff/game/service/impl/GameSecretKeyLangServiceImpl.java deleted file mode 100644 index 695a073..0000000 --- a/ff-game/src/main/java/com/ff/game/service/impl/GameSecretKeyLangServiceImpl.java +++ /dev/null @@ -1,106 +0,0 @@ -package com.ff.game.service.impl; - -import java.util.List; - -import com.ff.base.utils.DateUtils; -import com.ff.game.dto.GameSecretKeyCurrencyDTO; -import com.ff.game.dto.GameSecretKeyLangDTO; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import com.ff.game.mapper.GameSecretKeyLangMapper; -import com.ff.game.domain.GameSecretKeyLang; -import com.ff.game.service.IGameSecretKeyLangService; -import cn.hutool.core.util.IdUtil; - - -/** - * 游戏平台语言管理Service业务层处理 - * - * @author shi - * @date 2025-03-13 - */ -@Service -public class GameSecretKeyLangServiceImpl implements IGameSecretKeyLangService { - @Autowired - private GameSecretKeyLangMapper gameSecretKeyLangMapper; - - /** - * 查询游戏平台语言管理 - * - * @param id 游戏平台语言管理主键 - * @return 游戏平台语言管理 - */ - @Override - public GameSecretKeyLang selectGameSecretKeyLangById(Long id) { - return gameSecretKeyLangMapper.selectGameSecretKeyLangById(id); - } - - /** - * 查询游戏平台语言管理列表 - * - * @param gameSecretKeyLang 游戏平台语言管理 - * @return 游戏平台语言管理 - */ - @Override - public List selectGameSecretKeyLangList(GameSecretKeyLang gameSecretKeyLang) { - return gameSecretKeyLangMapper.selectGameSecretKeyLangList(gameSecretKeyLang); - } - - /** - * 新增游戏平台语言管理 - * - * @param gameSecretKeyLang 游戏平台语言管理 - * @return 结果 - */ - @Override - public int insertGameSecretKeyLang(GameSecretKeyLang gameSecretKeyLang) { - gameSecretKeyLang.setId(IdUtil.getSnowflakeNextId()); - gameSecretKeyLang.setCreateTime(DateUtils.getNowDate()); - return gameSecretKeyLangMapper.insertGameSecretKeyLang(gameSecretKeyLang); - } - - /** - * 修改游戏平台语言管理 - * - * @param gameSecretKeyLang 游戏平台语言管理 - * @return 结果 - */ - @Override - public int updateGameSecretKeyLang(GameSecretKeyLang gameSecretKeyLang) { - gameSecretKeyLang.setUpdateTime(DateUtils.getNowDate()); - return gameSecretKeyLangMapper.updateGameSecretKeyLang(gameSecretKeyLang); - } - - /** - * 批量删除游戏平台语言管理 - * - * @param ids 需要删除的游戏平台语言管理主键 - * @return 结果 - */ - @Override - public int deleteGameSecretKeyLangByIds(Long[] ids) { - return gameSecretKeyLangMapper.deleteGameSecretKeyLangByIds(ids); - } - - /** - * 删除游戏平台语言管理信息 - * - * @param id 游戏平台语言管理主键 - * @return 结果 - */ - @Override - public int deleteGameSecretKeyLangById(Long id) { - return gameSecretKeyLangMapper.deleteGameSecretKeyLangById(id); - } - - /** - * 查找游戏密钥货币dto - * - * @param gameSecretKeyLangDTO 游戏密钥货币dto - * @return {@link GameSecretKeyLangDTO } - */ - @Override - public GameSecretKeyLangDTO findGameSecretKeyLangDTO(GameSecretKeyLangDTO gameSecretKeyLangDTO) { - return gameSecretKeyLangMapper.findGameSecretKeyLangDTO(gameSecretKeyLangDTO); - } -} diff --git a/ff-game/src/main/java/com/ff/game/service/impl/GameSecretKeyServiceImpl.java b/ff-game/src/main/java/com/ff/game/service/impl/GameSecretKeyServiceImpl.java deleted file mode 100644 index 2c34ac1..0000000 --- a/ff-game/src/main/java/com/ff/game/service/impl/GameSecretKeyServiceImpl.java +++ /dev/null @@ -1,110 +0,0 @@ -package com.ff.game.service.impl; - -import java.util.List; -import com.ff.base.utils.DateUtils; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import com.ff.game.mapper.GameSecretKeyMapper; -import com.ff.game.domain.GameSecretKey; -import com.ff.game.service.IGameSecretKeyService; -import cn.hutool.core.util.IdUtil; - - -/** - * 游戏平台密钥管理Service业务层处理 - * - * @author shi - * @date 2025-03-13 - */ -@Service -public class GameSecretKeyServiceImpl implements IGameSecretKeyService -{ - @Autowired - private GameSecretKeyMapper gameSecretKeyMapper; - - /** - * 查询游戏平台密钥管理 - * - * @param id 游戏平台密钥管理主键 - * @return 游戏平台密钥管理 - */ - @Override - public GameSecretKey selectGameSecretKeyById(Long id) - { - return gameSecretKeyMapper.selectGameSecretKeyById(id); - } - - /** - * 按代码选择游戏密钥 - * - * @param code 代码 - * @return {@link GameSecretKey } - */ - @Override - public GameSecretKey selectGameSecretKeyByCode(String code) { - return gameSecretKeyMapper.selectGameSecretKeyByCode(code); - } - - /** - * 查询游戏平台密钥管理列表 - * - * @param gameSecretKey 游戏平台密钥管理 - * @return 游戏平台密钥管理 - */ - @Override - public List selectGameSecretKeyList(GameSecretKey gameSecretKey) - { - return gameSecretKeyMapper.selectGameSecretKeyList(gameSecretKey); - } - - /** - * 新增游戏平台密钥管理 - * - * @param gameSecretKey 游戏平台密钥管理 - * @return 结果 - */ - @Override - public int insertGameSecretKey(GameSecretKey gameSecretKey) - { - gameSecretKey.setId(IdUtil.getSnowflakeNextId()); - gameSecretKey.setCreateTime(DateUtils.getNowDate()); - return gameSecretKeyMapper.insertGameSecretKey(gameSecretKey); - } - - /** - * 修改游戏平台密钥管理 - * - * @param gameSecretKey 游戏平台密钥管理 - * @return 结果 - */ - @Override - public int updateGameSecretKey(GameSecretKey gameSecretKey) - { - gameSecretKey.setUpdateTime(DateUtils.getNowDate()); - return gameSecretKeyMapper.updateGameSecretKey(gameSecretKey); - } - - /** - * 批量删除游戏平台密钥管理 - * - * @param ids 需要删除的游戏平台密钥管理主键 - * @return 结果 - */ - @Override - public int deleteGameSecretKeyByIds(Long[] ids) - { - return gameSecretKeyMapper.deleteGameSecretKeyByIds(ids); - } - - /** - * 删除游戏平台密钥管理信息 - * - * @param id 游戏平台密钥管理主键 - * @return 结果 - */ - @Override - public int deleteGameSecretKeyById(Long id) - { - return gameSecretKeyMapper.deleteGameSecretKeyById(id); - } -} diff --git a/ff-game/src/main/java/com/ff/game/service/impl/GameServiceImpl.java b/ff-game/src/main/java/com/ff/game/service/impl/GameServiceImpl.java index 1dcab48..4a1a969 100644 --- a/ff-game/src/main/java/com/ff/game/service/impl/GameServiceImpl.java +++ b/ff-game/src/main/java/com/ff/game/service/impl/GameServiceImpl.java @@ -1,22 +1,22 @@ package com.ff.game.service.impl; -import java.util.Collections; -import java.util.List; - import cn.hutool.core.util.IdUtil; import com.ff.api.response.GameResponse; -import com.ff.base.constant.ConfigConstants; import com.ff.base.utils.DateUtils; +import com.ff.game.api.IGamesService; import com.ff.game.api.request.GameUniqueDTO; +import com.ff.game.domain.Game; import com.ff.game.dto.GameDTO; +import com.ff.game.mapper.GameMapper; +import com.ff.game.service.IGameService; import com.ff.member.service.IMemberService; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import com.ff.game.mapper.GameMapper; -import com.ff.game.domain.Game; -import com.ff.game.service.IGameService; import javax.annotation.Resource; +import java.util.List; +import java.util.Map; /** * 平台子游戏管理Service业务层处理 @@ -25,14 +25,18 @@ import javax.annotation.Resource; * @date 2025-02-10 */ @Service -public class GameServiceImpl implements IGameService -{ +@Slf4j +public class GameServiceImpl implements IGameService { + @Autowired private GameMapper gameMapper; @Resource private IMemberService memberService; + @Autowired + private Map gamesService; + /** * 查询平台子游戏管理 * @@ -40,11 +44,21 @@ public class GameServiceImpl implements IGameService * @return 平台子游戏管理 */ @Override - public Game selectGameById(Long id) - { + public Game selectGameById(Long id) { return gameMapper.selectGameById(id); } + /** + * 按游戏id选择游戏 + * + * @param gameId 游戏id + * @return {@link Game } + */ + @Override + public Game selectGameByGameId(String gameId) { + return gameMapper.selectGameByGameId(gameId); + } + /** * 查询平台子游戏管理列表 * @@ -52,8 +66,7 @@ public class GameServiceImpl implements IGameService * @return 平台子游戏管理 */ @Override - public List selectGameList(Game game) - { + public List selectGameList(Game game) { return gameMapper.selectGameList(game); } @@ -75,9 +88,8 @@ public class GameServiceImpl implements IGameService * @return 结果 */ @Override - public int insertGame(Game game) - { - if (game.getId() == null){ + public int insertGame(Game game) { + if (game.getId() == null) { game.setId(IdUtil.getSnowflakeNextId()); } game.setCreateTime(DateUtils.getNowDate()); @@ -91,8 +103,7 @@ public class GameServiceImpl implements IGameService * @return 结果 */ @Override - public int updateGame(Game game) - { + public int updateGame(Game game) { game.setUpdateTime(DateUtils.getNowDate()); return gameMapper.updateGame(game); } @@ -104,8 +115,7 @@ public class GameServiceImpl implements IGameService * @return 结果 */ @Override - public int deleteGameByIds(Long[] ids) - { + public int deleteGameByIds(Long[] ids) { return gameMapper.deleteGameByIds(ids); } @@ -116,25 +126,10 @@ public class GameServiceImpl implements IGameService * @return 结果 */ @Override - public int deleteGameById(Long id) - { + public int deleteGameById(Long id) { return gameMapper.deleteGameById(id); } - - /** - * 按平台id选择最大排序号 - * - * @param platformId 平台id - * @return {@link Integer } - */ - @Override - public Integer selectMaxSortNoByPlatformId(Long platformId) { - return gameMapper.selectMaxSortNoByPlatformId(platformId); - } - - - /** * 选择游戏唯一列表 * @@ -156,5 +151,10 @@ public class GameServiceImpl implements IGameService return gameMapper.selectGameResponseList(); } + @Override + public Integer selectMaxSortNo(Integer platformType, String platformCode) { + return gameMapper.selectMaxSortNoBy(platformType, platformCode); + } + } diff --git a/ff-game/src/main/java/com/ff/game/service/impl/PlatformServiceImpl.java b/ff-game/src/main/java/com/ff/game/service/impl/PlatformServiceImpl.java new file mode 100644 index 0000000..6dd8f6b --- /dev/null +++ b/ff-game/src/main/java/com/ff/game/service/impl/PlatformServiceImpl.java @@ -0,0 +1,79 @@ +package com.ff.game.service.impl; + +import com.ff.base.constant.CacheConstants; +import com.ff.base.core.redis.RedisCache; +import com.ff.base.datasource.DynamicDataSourceContextHolder; +import com.ff.game.domain.Platform; +import com.ff.game.mapper.PlatformMapper; +import com.ff.game.service.IPlatformService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import javax.sql.DataSource; +import java.util.List; +import java.util.Map; + +/** + * @author cengy + */ +@Service +public class PlatformServiceImpl implements IPlatformService { + + @Autowired + PlatformMapper platformMapper; + @Autowired + RedisCache redisCache; + + @Override + public List selectList(Platform platform) { + return platformMapper.selectList(platform); + } + + @Override + public Platform selectByPlatformCode(String platformCode) { + return platformMapper.selectByPlatformCode(platformCode); + } + + @Override + public int updatePlatform(Platform platform) { + return platformMapper.updatePlatform(platform); + } + + @Override + public int insertPlatform(Platform platform) { + return platformMapper.insertPlatform(platform); + } + + @Override + public int deleteById(Long id) { + return platformMapper.deleteById(id); + } + + @Override + public int deleteByIds(String ids) { + return platformMapper.deleteByIds(ids); + } + + @Override + public void loadToCache() { + Map resolvedDataSources = DynamicDataSourceContextHolder.getAllDataSource(); + for (Map.Entry entry : resolvedDataSources.entrySet()) { + Object key = entry.getKey(); + // 设置数据源类型 + DynamicDataSourceContextHolder.setDataSourceType(key.toString()); + List list = selectList(new Platform()); + for (Platform pp : list) { + redisCache.setCacheObject(getCacheKey(pp.getPlatformCode()), pp); + } + } + } + + @Override + public Platform get(String platformCode) { + return redisCache.getCacheObject(getCacheKey(platformCode)); + } + + private String getCacheKey(String configKey) { + return CacheConstants.Platform + configKey; + } +} diff --git a/ff-game/src/main/java/com/ff/member/service/IMemberService.java b/ff-game/src/main/java/com/ff/member/service/IMemberService.java index c31748e..6aa977d 100644 --- a/ff-game/src/main/java/com/ff/member/service/IMemberService.java +++ b/ff-game/src/main/java/com/ff/member/service/IMemberService.java @@ -30,9 +30,11 @@ public interface IMemberService /** * 生成会员游戏账号 * + * @param platformCode 平台代码 + * @param tenantSn 租户sn * @return {@link String } */ - String getMemberGameAccount(String platformCode); + String getMemberGameAccount(String platformCode,String tenantSn); /** * 新增会员 diff --git a/ff-game/src/main/java/com/ff/member/service/impl/MemberServiceImpl.java b/ff-game/src/main/java/com/ff/member/service/impl/MemberServiceImpl.java index fea844d..9f1feee 100644 --- a/ff-game/src/main/java/com/ff/member/service/impl/MemberServiceImpl.java +++ b/ff-game/src/main/java/com/ff/member/service/impl/MemberServiceImpl.java @@ -53,19 +53,21 @@ public class MemberServiceImpl implements IMemberService { * @return {@link String } */ @Override - public synchronized String getMemberGameAccount(String platformCode) { + public synchronized String getMemberGameAccount(String platformCode,String tenantSn) { String gameAccount = null; - if (GamePlatforms.DG.getInfo().equals(platformCode)||GamePlatforms.PT.getInfo().equals(platformCode)) { + if (GamePlatforms.DG.getInfo().equals(platformCode) || GamePlatforms.KM.getInfo().equals(platformCode)||GamePlatforms.PT.getInfo().equals(platformCode)) { + tenantSn=tenantSn.toUpperCase(); do { - gameAccount = RandomGeneratorUtils.generateRandomAccountUpper(); + gameAccount = RandomGeneratorUtils.generateRandomAccountUpper()+tenantSn; } while (!ObjectUtils.isEmpty(memberMapper.selectMemberByGameAccount(gameAccount))); - }else if (GamePlatforms.PG.getInfo().equals(platformCode)||GamePlatforms.PGX.getInfo().equals(platformCode)){ + } else if (GamePlatforms.PG.getInfo().equals(platformCode) || GamePlatforms.PGX.getInfo().equals(platformCode) || GamePlatforms.PGT.getInfo().equals(platformCode)) { + tenantSn=tenantSn.toLowerCase(); do { - gameAccount = RandomGeneratorUtils.generateRandomAccountLower(); + gameAccount = RandomGeneratorUtils.generateRandomAccountLower()+tenantSn; } while (!ObjectUtils.isEmpty(memberMapper.selectMemberByGameAccount(gameAccount))); - }else { + } else { do { - gameAccount = RandomGeneratorUtils.generateRandomAccount(); + gameAccount = RandomGeneratorUtils.generateRandomAccount()+tenantSn; } while (!ObjectUtils.isEmpty(memberMapper.selectMemberByGameAccount(gameAccount))); } @@ -129,7 +131,7 @@ public class MemberServiceImpl implements IMemberService { */ @Override public Member selectMemberByGameAccount(String gameAccount) { - return memberMapper.selectMemberByGameAccount(gameAccount.toLowerCase()); + return memberMapper.selectMemberByGameAccount(gameAccount); } /** diff --git a/ff-game/src/main/java/com/ff/quartz/config/ScheduleConfig.java b/ff-game/src/main/java/com/ff/quartz/config/ScheduleConfig.java index c56e1bc..c5b6fe3 100644 --- a/ff-game/src/main/java/com/ff/quartz/config/ScheduleConfig.java +++ b/ff-game/src/main/java/com/ff/quartz/config/ScheduleConfig.java @@ -1,4 +1,4 @@ -package com.ff.quartz.config;//package com.ff.quartz.config; +//package com.ff.quartz.config; // //import org.springframework.context.annotation.Bean; //import org.springframework.context.annotation.Configuration; diff --git a/ff-game/src/main/java/com/ff/quartz/task/GameTask.java b/ff-game/src/main/java/com/ff/quartz/task/GameTask.java index 6675502..0a7ec13 100644 --- a/ff-game/src/main/java/com/ff/quartz/task/GameTask.java +++ b/ff-game/src/main/java/com/ff/quartz/task/GameTask.java @@ -1,46 +1,36 @@ package com.ff.quartz.task; +import com.ff.api.response.GameExchangeBalanceResponse; import com.ff.base.constant.Constants; -import com.ff.base.core.redis.RedisCache; -import com.ff.base.datasource.DynamicDataSourceContextHolder; -import com.ff.base.enums.GamePlatforms; -import com.ff.base.enums.NGPlatforms; -import com.ff.base.enums.PlatformType; -import com.ff.base.enums.StatusType; +import com.ff.base.core.domain.AjaxResult; +import com.ff.base.enums.*; +import com.ff.base.manager.AsyncManager; import com.ff.base.utils.DateUtils; +import com.ff.base.utils.StringUtils; +import com.ff.base.utils.bean.BeanUtils; import com.ff.game.api.IGamesService; +import com.ff.game.api.exchange.StepProcessorFactory; +import com.ff.game.api.exchange.dto.GameExchangeDTO; import com.ff.game.api.ng.client.NGClient; -import com.ff.game.api.ng.dto.ApiExchangeTransferStatusResponseDTO; -import com.ff.game.api.ng.dto.ApiNGResponseDTO; import com.ff.game.api.request.BetRecordByTimeDTO; import com.ff.game.api.request.ExchangeTransferStatusRequestDTO; import com.ff.game.api.request.GamesBaseRequestDTO; import com.ff.game.api.request.GetFreeSpinDashflowRequestDTO; import com.ff.game.domain.GameExchangeMoney; -import com.ff.game.domain.GameSecretKey; -import com.ff.game.dto.GameSecretKeyCurrencyDTO; -import com.ff.game.dto.GameSecretKeyDTO; +import com.ff.game.domain.KeyInfo; +import com.ff.game.domain.Platform; import com.ff.game.service.IGameExchangeMoneyService; -import com.ff.game.service.IGamePlatformService; -import com.ff.game.service.IGameSecretKeyCurrencyService; -import com.ff.game.service.IGameSecretKeyService; +import com.ff.game.service.IPlatformService; import com.ff.member.domain.Member; import com.ff.member.service.IMemberService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationEventPublisher; -import org.springframework.scheduling.annotation.AsyncConfigurationSelector; -import org.springframework.security.core.parameters.P; import org.springframework.stereotype.Component; -import org.springframework.transaction.annotation.Transactional; -import org.springframework.util.CollectionUtils; -import org.springframework.util.ObjectUtils; import javax.annotation.Resource; -import javax.sql.DataSource; -import javax.xml.crypto.dsig.keyinfo.PGPData; -import java.util.*; -import java.util.stream.Collectors; +import java.util.HashMap; +import java.util.List; +import java.util.Map; /** @@ -53,225 +43,209 @@ import java.util.stream.Collectors; @Component("gameTask") public class GameTask { - @Autowired private Map gamesService; - @Resource - private IGameSecretKeyService gameSecretKeyService; - - @Resource - private IGamePlatformService gamePlatformService; - - @Resource private NGClient ngClient; @Resource private IGameExchangeMoneyService gameExchangeMoneyService; - @Resource - private IGameSecretKeyCurrencyService gameSecretKeyCurrencyService; - @Resource private IMemberService memberService; @Resource - private RedisCache redisCache; + private IPlatformService platformService; + + @Resource + private StepProcessorFactory stepProcessorFactory; /** - * 插入游戏投注详细信息 + * 同步游戏列表 */ - - public void insertGameBettingDetails(Integer backTime) { - - //捞取指定分钟前的数据 - Long startTime = DateUtils.addOrSubtractMinutes(DateUtils.getNowDate(), backTime); - Long endTime = DateUtils.getNowDate(); - - - for (String gameKey : gamesService.keySet()) { - String platformCode = gameKey.replace(Constants.SERVICE, ""); - //特殊的平台跳过 - if (NGPlatforms.exists(platformCode)|| GamePlatforms.FC.getInfo().equals(platformCode)) { - continue; + public void syncGameList() { + for (GamePlatforms gamePlatform : GamePlatforms.values()) { + String platformCode = gamePlatform.getCode(); + try { + syncGameList(platformCode); + } catch (Exception e) { + log.error("同步游戏列表失败platformCode:{}", platformCode, e); } + } + } - List gameSecretKeys = gameSecretKeyService.selectGameSecretKeyList(GameSecretKey.builder().platform(platformCode).build()); - for (GameSecretKey gameSecretKey : gameSecretKeys) { - try { - gamesService.get(gameKey).getGameList(GamesBaseRequestDTO.builder() - .agentId(gameSecretKey.getCode()) - .agentKey(gameSecretKey.getKey()) + public void syncGameList(String platformCode) { + + Platform platform = platformService.get(platformCode); + if (null == platform) { + return; + } + List keyData = platform.getKeyInfo(); + for (KeyInfo keyInfo : keyData) { + gamesService.get(platformCode + Constants.SERVICE) + .getGameList(GamesBaseRequestDTO.builder() + .agentId(keyInfo.getCode()) + .agentKey(keyInfo.getKey()) + .keyInfo(keyInfo) + .vendor(platform) .build()); - BetRecordByTimeDTO betRecordByTimeDTO = new BetRecordByTimeDTO(); - betRecordByTimeDTO.setGamePlatform(gameSecretKey.getPlatform()); - betRecordByTimeDTO.setStartTime(startTime); - betRecordByTimeDTO.setEndTime(endTime); - betRecordByTimeDTO.setPage(1); - betRecordByTimeDTO.setPageLimit(1000); - betRecordByTimeDTO.setAgentId(gameSecretKey.getCode()); - betRecordByTimeDTO.setAgentKey(gameSecretKey.getKey()); - gamesService.get(gameKey).getBetRecordByTime(betRecordByTimeDTO); - } catch (Exception e) { - log.error("查询 币种 {} 投注记录失败,错误信息 {}", gameSecretKey.getCode(), e); - } - } - + break; } - } /** - * 插入游戏cfbetting详细信息 - */ - public void insertGameCFBettingDetails(Integer backTime) { - - - try { - //捞取指定分钟前的数据 - Long startTime = DateUtils.addOrSubtractMinutes(DateUtils.getNowDate(), backTime); - Long endTime = DateUtils.getNowDate(); - - for (String gameKey : gamesService.keySet()) { - String platformCode = gameKey.replace(Constants.SERVICE, ""); - //不是特殊的平台跳过 - if (!GamePlatforms.FC.getInfo().equals(platformCode)) { - continue; - } - List gameSecretKeys = gameSecretKeyService.selectGameSecretKeyList(GameSecretKey.builder().platform(platformCode).build()); - for (GameSecretKey gameSecretKey : gameSecretKeys) { - try { - gamesService.get(gameKey).getGameList(GamesBaseRequestDTO.builder() - .agentId(gameSecretKey.getCode()) - .agentKey(gameSecretKey.getKey()) - .build()); - BetRecordByTimeDTO betRecordByTimeDTO = new BetRecordByTimeDTO(); - betRecordByTimeDTO.setGamePlatform(gameSecretKey.getPlatform()); - betRecordByTimeDTO.setStartTime(startTime); - betRecordByTimeDTO.setEndTime(endTime); - betRecordByTimeDTO.setPage(1); - betRecordByTimeDTO.setPageLimit(1000); - betRecordByTimeDTO.setAgentId(gameSecretKey.getCode()); - betRecordByTimeDTO.setAgentKey(gameSecretKey.getKey()); - gamesService.get(gameKey).getBetRecordByTime(betRecordByTimeDTO); - } catch (Exception e) { - log.error("查询 平台 {} 投注记录失败,错误信息 {}", gameSecretKey.getCode(), e); - } - } - - } - } catch (Exception e) { - log.error("查询 FC 投注记录失败,错误信息 {}", e); - - } - - } - - /** - * 插入历史游戏投注详细信息 部分平台使用 + * 同步实时投注记录 * - * @param backTime 返回时间 + * @param platformCode + * @param backTimeMin */ - public void insertHistoryGameBettingDetails(Integer backTime) { - + public void syncRealtimeBetRecord(String platformCode, Integer backTimeMin) { + this.syncGameList(platformCode); //捞取指定分钟前的数据 - Long startTime = DateUtils.addOrSubtractMinutes(DateUtils.getNowDate(), backTime); + Long startTime = DateUtils.addOrSubtractMinutes(DateUtils.getNowDate(), backTimeMin); Long endTime = DateUtils.getNowDate(); - - for (String gameKey : gamesService.keySet()) { - String platformCode = gameKey.replace(Constants.SERVICE, ""); - - List gameSecretKeys = gameSecretKeyService.selectGameSecretKeyList(GameSecretKey.builder().platform(platformCode).build()); - for (GameSecretKey gameSecretKey : gameSecretKeys) { - try { - gamesService.get(gameKey).getGameList(GamesBaseRequestDTO.builder() - .agentId(gameSecretKey.getCode()) - .agentKey(gameSecretKey.getKey()) - .build()); - BetRecordByTimeDTO betRecordByTimeDTO = new BetRecordByTimeDTO(); - betRecordByTimeDTO.setGamePlatform(gameSecretKey.getPlatform()); - betRecordByTimeDTO.setStartTime(startTime); - betRecordByTimeDTO.setEndTime(endTime); - betRecordByTimeDTO.setPage(1); - betRecordByTimeDTO.setPageLimit(1000); - betRecordByTimeDTO.setAgentId(gameSecretKey.getCode()); - betRecordByTimeDTO.setAgentKey(gameSecretKey.getKey()); - gamesService.get(gameKey).getBetRecordByHistoryTime(betRecordByTimeDTO); - } catch (Exception e) { - log.error("查询 平台 {} 投注记录失败,错误信息 {}", gameSecretKey.getCode(), e); - } - } - + Platform platform = platformService.get(platformCode); + if (null == platform) { + return; } + List keyData = platform.getKeyInfo(); + for (KeyInfo keyInfo : keyData) { + try { + BetRecordByTimeDTO betRecordByTimeDTO = new BetRecordByTimeDTO(); + betRecordByTimeDTO.setStartTime(startTime); + betRecordByTimeDTO.setEndTime(endTime); + betRecordByTimeDTO.setPage(1); + betRecordByTimeDTO.setPageLimit(1000); + betRecordByTimeDTO.setAgentId(keyInfo.getCode()); + betRecordByTimeDTO.setAgentKey(keyInfo.getKey()); + betRecordByTimeDTO.setKeyInfo(keyInfo); + betRecordByTimeDTO.setVendor(platform); + + betRecordByTimeDTO.setSystemCurrency(keyInfo.getCurrency()); + betRecordByTimeDTO.setCurrency(platform.getCurrencyInfo().get(keyInfo.getCurrency())); + + gamesService.get(platformCode + Constants.SERVICE).getBetRecordByTime(betRecordByTimeDTO); + } catch (Exception e) { + log.error("同步平台投注记录失败platformCode:{}", platformCode, e); + } + if (platform.isMultiAgent()) { + break; + } + } } - - /** - * 插入游戏ngbetting详细信息 + * 同步历史投注记录 + * + * @param platformCode + * @param backTimeMin */ - public void insertGameNGBettingDetails(Integer backTime) { - - - try { - //捞取指定分钟前的数据 - Long startTime = DateUtils.addOrSubtractMinutes(DateUtils.getNowDate(), backTime); - Long endTime = DateUtils.getNowDate(); - BetRecordByTimeDTO betRecordByTimeDTO = new BetRecordByTimeDTO(); - betRecordByTimeDTO.setStartTime(startTime); - betRecordByTimeDTO.setEndTime(endTime); - gamesService.get(NGPlatforms.PG.getPlatform() + Constants.SERVICE).getBetRecordByTime(betRecordByTimeDTO); - } catch (Exception e) { - log.error("查询 NG 投注记录失败,错误信息 {}", e); + public void syncHistoryBetRecord(String platformCode, Integer backTimeMin) { + this.syncGameList(platformCode); + //捞取指定分钟前的数据 + Long startTime = DateUtils.addOrSubtractMinutes(DateUtils.getNowDate(), backTimeMin); + Long endTime = DateUtils.getNowDate(); + Platform platform = platformService.get(platformCode); + if (null == platform) { + return; } + List keyData = platform.getKeyInfo(); + for (KeyInfo keyInfo : keyData) { + try { + BetRecordByTimeDTO betRecordByTimeDTO = new BetRecordByTimeDTO(); + betRecordByTimeDTO.setStartTime(startTime); + betRecordByTimeDTO.setEndTime(endTime); + betRecordByTimeDTO.setPage(1); + betRecordByTimeDTO.setPageLimit(1000); + betRecordByTimeDTO.setAgentId(keyInfo.getCode()); + betRecordByTimeDTO.setAgentKey(keyInfo.getKey()); + betRecordByTimeDTO.setKeyInfo(keyInfo); + betRecordByTimeDTO.setVendor(platform); + + betRecordByTimeDTO.setSystemCurrency(keyInfo.getCurrency()); + betRecordByTimeDTO.setCurrency(platform.getCurrencyInfo().get(keyInfo.getCurrency())); + + gamesService.get(platformCode + Constants.SERVICE).getBetRecordByHistoryTime(betRecordByTimeDTO); + } catch (Exception e) { + log.error("同步平台投注记录失败platformCode:{}", platformCode, e); + } + if (platform.isMultiAgent()) { + break; + } + } } - /** - * 插入免费游戏局数情况 + * 同步免费游玩记录 */ - public void insertFreeSpinDashflow() { - Long startTime = DateUtils.addOrSubtractMinutes(DateUtils.getNowDate(), -70); - for (String gameKey : gamesService.keySet()) { - List gameSecretKeys = gameSecretKeyService.selectGameSecretKeyList(GameSecretKey.builder().platform(gameKey.replace(Constants.SERVICE, "")).build()); - for (GameSecretKey gameSecretKey : gameSecretKeys) { - try { - GetFreeSpinDashflowRequestDTO getFreeSpinDashflowRequestDTO = new GetFreeSpinDashflowRequestDTO(); - getFreeSpinDashflowRequestDTO.setStartTime(startTime); - getFreeSpinDashflowRequestDTO.setAgentId(gameSecretKey.getCode()); - getFreeSpinDashflowRequestDTO.setAgentKey(gameSecretKey.getKey()); - gamesService.get(gameKey).getFreeSpinDashflow(getFreeSpinDashflowRequestDTO); - } catch (Exception e) { - log.error("查询 币种 {} 免费游戏投注记录失败,错误信息 {}", gameSecretKey.getCode(), e.getMessage()); - } + public void syncFreeBetRecord(String platformCode, Integer backTime) { + // 捞取指定分钟前的数据 + Long startTime = DateUtils.addOrSubtractMinutes(DateUtils.getNowDate(), backTime); + + Platform platform = platformService.get(platformCode); + if (null == platform) { + return; + } + List keyData = platform.getKeyInfo(); + + for (KeyInfo keyInfo : keyData) { + try { + GetFreeSpinDashflowRequestDTO getFreeSpinDashflowRequestDTO = new GetFreeSpinDashflowRequestDTO(); + getFreeSpinDashflowRequestDTO.setStartTime(startTime); + getFreeSpinDashflowRequestDTO.setAgentId(keyInfo.getCode()); + getFreeSpinDashflowRequestDTO.setAgentKey(keyInfo.getKey()); + getFreeSpinDashflowRequestDTO.setVendor(platform); + getFreeSpinDashflowRequestDTO.setKeyInfo(keyInfo); + gamesService.get(platformCode + Constants.SERVICE).getFreeSpinDashflow(getFreeSpinDashflowRequestDTO); + + } catch (Exception e) { + log.error("免费游戏投注记录失败platformCode:{}", platformCode, e); + } + if (platform.isMultiAgent()) { + break; } - - } } - public void updateGameExchangeMoney() { - List gameExchangeMoneyList = gameExchangeMoneyService.selectGameExchangeMoneyList(GameExchangeMoney.builder().status(StatusType.IN_PROGRESS.getValue()).build()); + GameExchangeMoney gameExchangeMoney = GameExchangeMoney.builder().status(StatusType.IN_PROGRESS.getValue()).build(); + Map params=new HashMap<>(); + params.put("endTime",DateUtils.addOrSubtractMinutes( DateUtils.getNowDate(),-5)); + gameExchangeMoney.setParams(params); + List gameExchangeMoneyList = gameExchangeMoneyService.selectGameExchangeMoneyList(gameExchangeMoney); for (GameExchangeMoney exchangeMoney : gameExchangeMoneyList) { try { - GameSecretKeyCurrencyDTO gameSecretKey = gameSecretKeyCurrencyService.findByGameSecretKeyCurrencyDTO(GameSecretKeyCurrencyDTO.builder() - .platformCode(exchangeMoney.getPlatformCode()) - .systemCurrency(exchangeMoney.getCurrencyCode()).build()); Member member = memberService.selectMemberById(exchangeMoney.getMemberId()); - ExchangeTransferStatusRequestDTO exchangeTransferStatusRequestDTO = new ExchangeTransferStatusRequestDTO(); - exchangeTransferStatusRequestDTO.setAccount(member.getGameAccount()); - exchangeTransferStatusRequestDTO.setCurrency(gameSecretKey.getCurrency()); - exchangeTransferStatusRequestDTO.setOrderId(exchangeMoney.getTransactionId()); - exchangeTransferStatusRequestDTO.setAgentId(gameSecretKey.getCode()); - exchangeTransferStatusRequestDTO.setAgentKey(gameSecretKey.getKey()); - gamesService.get(exchangeMoney.getPlatformCode() + Constants.SERVICE).exchangeTransferStatus(exchangeTransferStatusRequestDTO); + Integer step = exchangeMoney.getStep(); + Integer stepStatus = exchangeMoney.getStepStatus(); + GameExchangeDTO gameExchangeDTO=new GameExchangeDTO(); + BeanUtils.copyProperties(exchangeMoney,gameExchangeDTO); + gameExchangeDTO.setTriggerType(TriggerType.TIMER.getCode()); + gameExchangeDTO.setGameAccount(member.getGameAccount()); + gameExchangeDTO.setMemberAccount(member.getMemberAccount()); + AsyncManager.me().executeOrdered( + exchangeMoney.getOrderId(), + () -> { + try { + GameExchangeStep gameExchangeStep = GameExchangeStep.getByCode(step); + if (stepStatus == GameExchangeStepStatus.SUCCESS.getCode()){ + gameExchangeStep = stepProcessorFactory.getStepProcessor(GameExchangeStep.getByCode(step)).nextStepProcessor(); + } + + stepProcessorFactory.getStepProcessor(gameExchangeStep).process(gameExchangeDTO); + } catch (Exception e) { + log.error("GameTask [updateGameExchangeMoney] 余额转移失败 gameExchangeMoneyId {}", gameExchangeDTO.getId(),e); + stepProcessorFactory.getStepProcessor(GameExchangeStep.getByCode(exchangeMoney.getStep())).rollBack(gameExchangeDTO); + } + + } + ); } catch (Exception e) { log.error("查询 更新交易记录失败,错误信息 {}", e); } diff --git a/ff-game/src/main/java/com/ff/system/SysLoginController.java b/ff-game/src/main/java/com/ff/system/SysLoginController.java index 848d244..e67eb1a 100644 --- a/ff-game/src/main/java/com/ff/system/SysLoginController.java +++ b/ff-game/src/main/java/com/ff/system/SysLoginController.java @@ -67,7 +67,7 @@ public class SysLoginController { // 生成令牌 String token = ""; // 验证码校验 - loginService.validateCaptcha(loginBody.getUsername(), loginBody.getCode(), loginBody.getUuid()); + // loginService.validateCaptcha(loginBody.getUsername(), loginBody.getCode(), loginBody.getUuid()); // 登录前置校验 loginService.loginPreCheck(loginBody.getUsername(), loginBody.getPassword()); if (LoginType.TENANT.getValue().equals(loginBody.getLoginType())) { diff --git a/ff-game/src/main/java/com/ff/utils/CalculateDateDaysAgo.java b/ff-game/src/main/java/com/ff/utils/CalculateDateDaysAgo.java new file mode 100644 index 0000000..dc5363b --- /dev/null +++ b/ff-game/src/main/java/com/ff/utils/CalculateDateDaysAgo.java @@ -0,0 +1,25 @@ +package com.ff.utils; + +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; + +/** + * @author cengy + */ +public class CalculateDateDaysAgo { + + public static LocalDate get(int daysToSubtract) { + return LocalDate.now().minusDays(daysToSubtract); + } + + public static String getStr(int daysToSubtract) { + // 获取当前日期减去指定天数 + LocalDate date = get(daysToSubtract); + + // 定义日期格式 + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + + // 返回格式化日期字符串 + return date.format(formatter); + } +} diff --git a/ff-game/src/main/java/com/ff/utils/SortByAttributeNameASC.java b/ff-game/src/main/java/com/ff/utils/SortByAttributeNameASC.java new file mode 100644 index 0000000..6e351b1 --- /dev/null +++ b/ff-game/src/main/java/com/ff/utils/SortByAttributeNameASC.java @@ -0,0 +1,40 @@ +package com.ff.utils; + +import com.alibaba.fastjson2.JSON; + +import java.lang.reflect.Field; +import java.util.Arrays; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * @author cengy + */ +public class SortByAttributeNameASC { + public static String get(Object o) { + // Create a map to store field names and values + Map fieldMap = new LinkedHashMap<>(); + + // Get all fields of the class + Field[] fields = o.getClass().getDeclaredFields(); + + // Sort field names + Arrays.sort(fields, (f1, f2) -> f1.getName().compareTo(f2.getName())); + + // Fill the map with sorted fields and their values + for (Field field : fields) { + field.setAccessible(true); // Make private fields accessible + Object value = null; + try { + value = field.get(o); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + fieldMap.put(field.getName(), value); + } + + + return JSON.toJSONString(fieldMap); + } + +} diff --git a/ff-game/src/main/java/com/ff/utils/TimestampFromString.java b/ff-game/src/main/java/com/ff/utils/TimestampFromString.java new file mode 100644 index 0000000..8a3ddd6 --- /dev/null +++ b/ff-game/src/main/java/com/ff/utils/TimestampFromString.java @@ -0,0 +1,27 @@ +package com.ff.utils; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * @author cengy + */ +public class TimestampFromString { + + public static final String PATTERN_DATE = "yyyy-MM-dd HH:mm:ss"; + + public static Long from(String date) { + SimpleDateFormat simpleDateFormat = new SimpleDateFormat(PATTERN_DATE); + try { + Date parse = simpleDateFormat.parse(date); + return parse.getTime(); + } catch (ParseException e) { + return 0L; + } + } + + public static Long to(String timestamp) { + return Long.parseLong(timestamp); + } +} diff --git a/ff-game/src/main/resources/mapper/common/TenantGameQuotaFlowMapper.xml b/ff-game/src/main/resources/mapper/common/TenantGameQuotaFlowMapper.xml index 398b666..a20678d 100644 --- a/ff-game/src/main/resources/mapper/common/TenantGameQuotaFlowMapper.xml +++ b/ff-game/src/main/resources/mapper/common/TenantGameQuotaFlowMapper.xml @@ -57,6 +57,9 @@ and quota_type = #{quotaType} + + and source_id = #{sourceId} + and member_id = #{memberId} diff --git a/ff-game/src/main/resources/mapper/game/GameBettingDetailsMapper.xml b/ff-game/src/main/resources/mapper/game/GameBettingDetailsMapper.xml index 9600ffc..722c77e 100644 --- a/ff-game/src/main/resources/mapper/game/GameBettingDetailsMapper.xml +++ b/ff-game/src/main/resources/mapper/game/GameBettingDetailsMapper.xml @@ -95,7 +95,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" where wagers_id in #{wagersId} - + and platform_code = #{platformCode} and settlement_status !=1 diff --git a/ff-game/src/main/resources/mapper/game/GameExchangeMoneyMapper.xml b/ff-game/src/main/resources/mapper/game/GameExchangeMoneyMapper.xml index 2783b81..306cb37 100644 --- a/ff-game/src/main/resources/mapper/game/GameExchangeMoneyMapper.xml +++ b/ff-game/src/main/resources/mapper/game/GameExchangeMoneyMapper.xml @@ -23,6 +23,8 @@ + + @@ -48,6 +50,8 @@ + + @@ -69,7 +73,9 @@ create_by, create_time, update_by, - update_time + update_time, + step, + step_status from ff_game_exchange_money @@ -275,6 +281,12 @@ update_time, + + step, + + + step_status, + @@ -334,6 +346,12 @@ #{updateTime}, + + #{step}, + + + #{stepStatus}, + @@ -394,6 +412,12 @@ update_time = #{updateTime}, + + step = #{step}, + + + step_status = #{stepStatus}, + where id = #{id} diff --git a/ff-game/src/main/resources/mapper/game/GameMapper.xml b/ff-game/src/main/resources/mapper/game/GameMapper.xml index abf59e2..0a3d659 100644 --- a/ff-game/src/main/resources/mapper/game/GameMapper.xml +++ b/ff-game/src/main/resources/mapper/game/GameMapper.xml @@ -7,11 +7,14 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" - + + + + @@ -22,7 +25,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" - select id, sort_no, platform_id, game_code,ingress, game_source_type, game_name, freespin, demo_status, stop_status, create_by, create_time, update_by, update_time from ff_game + select id, sort_no, game_code,ingress, game_source_type, game_name, freespin, demo_status, stop_status, create_by, create_time, update_by, update_time, name_info, game_id, platform_code, platform_type from ff_game @@ -32,7 +35,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" and sort_no = #{sortNo} - and platform_id = #{platformId} and game_code = #{gameCode} and ingress = #{ingress} and game_source_type = #{gameSourceType} @@ -40,13 +42,15 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" and freespin = #{freespin} and demo_status = #{demoStatus} and stop_status = #{stopStatus} + and platform_code = #{platformCode} + and platform_type = #{platformType} + @@ -89,11 +87,15 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" where id = #{id} + + insert into ff_game id, sort_no, - platform_id, game_code, ingress, game_source_type, @@ -105,10 +107,13 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" create_time, update_by, update_time, + name_info, + game_id, + platform_code, + platform_type, #{id}, #{sortNo}, - #{platformId}, #{gameCode}, #{ingress}, #{gameSourceType}, @@ -120,6 +125,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" #{createTime}, #{updateBy}, #{updateTime}, + #{nameInfo, typeHandler=com.ff.base.handler.JsonListHandler,javaType=com.ff.game.domain.NameInfo}, + #{gameId}, + #{platformCode}, + #{platformType}, @@ -127,7 +136,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" update ff_game sort_no = #{sortNo}, - platform_id = #{platformId}, game_code = #{gameCode}, ingress = #{ingress}, game_source_type = #{gameSourceType}, @@ -139,6 +147,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" create_time = #{createTime}, update_by = #{updateBy}, update_time = #{updateTime}, + name_info = #{nameInfo, typeHandler=com.ff.base.handler.JsonListHandler,javaType=com.ff.game.domain.NameInfo}, + game_id = #{gameId}, + platform_code = #{platformCode}, + platform_type = #{platformType}, where id = #{id} @@ -155,36 +167,38 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" - select ifnull(max(sort_no), 0) from ff_game - where platform_id = #{platformId} + where platform_type = #{platformType} and platform_code = #{platformCode} - - + - + + @@ -196,7 +210,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" and sort_no = #{sortNo} - and platform_id = #{platformId} and game_code = #{gameCode} and ingress = #{ingress} and game_source_type = #{gameSourceType} diff --git a/ff-game/src/main/resources/mapper/game/GameNameMapper.xml b/ff-game/src/main/resources/mapper/game/GameNameMapper.xml deleted file mode 100644 index a330f6b..0000000 --- a/ff-game/src/main/resources/mapper/game/GameNameMapper.xml +++ /dev/null @@ -1,124 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - select id, game_id, game_name, lang_code, create_by, create_time, update_by, update_time from ff_game_name - - - - - - - - - - insert into ff_game_name - - id, - game_id, - game_name, - lang_code, - create_by, - create_time, - update_by, - update_time, - - - #{id}, - #{gameId}, - #{gameName}, - #{langCode}, - #{createBy}, - #{createTime}, - #{updateBy}, - #{updateTime}, - - - - - update ff_game_name - - game_id = #{gameId}, - game_name = #{gameName}, - lang_code = #{langCode}, - create_by = #{createBy}, - create_time = #{createTime}, - update_by = #{updateBy}, - update_time = #{updateTime}, - - where id = #{id} - - - - delete from ff_game_name where id = #{id} - - - - delete from ff_game_name where id in - - #{id} - - - - - \ No newline at end of file diff --git a/ff-game/src/main/resources/mapper/game/GamePlatformMapper.xml b/ff-game/src/main/resources/mapper/game/GamePlatformMapper.xml deleted file mode 100644 index 3838414..0000000 --- a/ff-game/src/main/resources/mapper/game/GamePlatformMapper.xml +++ /dev/null @@ -1,99 +0,0 @@ - - - - - - - - - - - - - - - - - - - select id, sort_no, platform_code, platform_type, platform_name, stop_status, create_by, create_time, update_by, update_time from ff_game_platform - - - - - - - - insert into ff_game_platform - id, - sort_no, - platform_code, - platform_type, - platform_name, - stop_status, - create_by, - create_time, - update_by, - update_time, - - #{id}, - #{sortNo}, - #{platformCode}, - #{platformType}, - #{platformName}, - #{stopStatus}, - #{createBy}, - #{createTime}, - #{updateBy}, - #{updateTime}, - - - - - update ff_game_platform - - sort_no = #{sortNo}, - platform_code = #{platformCode}, - platform_type = #{platformType}, - platform_name = #{platformName}, - stop_status = #{stopStatus}, - create_by = #{createBy}, - create_time = #{createTime}, - update_by = #{updateBy}, - update_time = #{updateTime}, - - where id = #{id} - - - - delete from ff_game_platform where id = #{id} - - - - delete from ff_game_platform where id in - - #{id} - - - - - \ No newline at end of file diff --git a/ff-game/src/main/resources/mapper/game/GameSecretKeyCurrencyMapper.xml b/ff-game/src/main/resources/mapper/game/GameSecretKeyCurrencyMapper.xml deleted file mode 100644 index 5c988ce..0000000 --- a/ff-game/src/main/resources/mapper/game/GameSecretKeyCurrencyMapper.xml +++ /dev/null @@ -1,141 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - select id,currency_id, game_secret_key_id, currency, system_currency, create_by, create_time, update_by, update_time from ff_game_secret_key_currency - - - - - - - - insert into ff_game_secret_key_currency - - id, - game_secret_key_id, - currency_id, - currency, - system_currency, - create_by, - create_time, - update_by, - update_time, - - - #{id}, - #{gameSecretKeyId}, - #{currencyId}, - #{currency}, - #{systemCurrency}, - #{createBy}, - #{createTime}, - #{updateBy}, - #{updateTime}, - - - - - update ff_game_secret_key_currency - - game_secret_key_id = #{gameSecretKeyId}, - currency_id = #{currencyId}, - currency = #{currency}, - system_currency = #{systemCurrency}, - create_by = #{createBy}, - create_time = #{createTime}, - update_by = #{updateBy}, - update_time = #{updateTime}, - - where id = #{id} - - - - delete from ff_game_secret_key_currency where id = #{id} - - - - delete from ff_game_secret_key_currency where id in - - #{id} - - - - - - - - \ No newline at end of file diff --git a/ff-game/src/main/resources/mapper/game/GameSecretKeyLangMapper.xml b/ff-game/src/main/resources/mapper/game/GameSecretKeyLangMapper.xml deleted file mode 100644 index b137079..0000000 --- a/ff-game/src/main/resources/mapper/game/GameSecretKeyLangMapper.xml +++ /dev/null @@ -1,112 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - select id, game_secret_key_id, lang, system_lang_code, create_by, create_time, update_by, update_time from ff_game_secret_key_lang - - - - - - - - insert into ff_game_secret_key_lang - - id, - game_secret_key_id, - lang, - system_lang_code, - create_by, - create_time, - update_by, - update_time, - - - #{id}, - #{gameSecretKeyId}, - #{lang}, - #{systemLangCode}, - #{createBy}, - #{createTime}, - #{updateBy}, - #{updateTime}, - - - - - update ff_game_secret_key_lang - - game_secret_key_id = #{gameSecretKeyId}, - lang = #{lang}, - system_lang_code = #{systemLangCode}, - create_by = #{createBy}, - create_time = #{createTime}, - update_by = #{updateBy}, - update_time = #{updateTime}, - - where id = #{id} - - - - delete from ff_game_secret_key_lang where id = #{id} - - - - delete from ff_game_secret_key_lang where id in - - #{id} - - - - - \ No newline at end of file diff --git a/ff-game/src/main/resources/mapper/game/GameSecretKeyMapper.xml b/ff-game/src/main/resources/mapper/game/GameSecretKeyMapper.xml deleted file mode 100644 index 61d8240..0000000 --- a/ff-game/src/main/resources/mapper/game/GameSecretKeyMapper.xml +++ /dev/null @@ -1,100 +0,0 @@ - - - - - - - - - - - - - - - - - - - select id, platform,provider_code,password, code, `key`, create_by, create_time, update_by, update_time from ff_game_secret_key - - - - - - - - - - insert into ff_game_secret_key - - id, - platform, - provider_code, - password, - code, - key, - create_by, - create_time, - update_by, - update_time, - - - #{id}, - #{platform}, - #{providerCode}, - #{password}, - #{code}, - #{key}, - #{createBy}, - #{createTime}, - #{updateBy}, - #{updateTime}, - - - - - update ff_game_secret_key - - platform = #{platform}, - provider_code = #{providerCode}, - password = #{password}, - code = #{code}, - key = #{key}, - create_by = #{createBy}, - create_time = #{createTime}, - update_by = #{updateBy}, - update_time = #{updateTime}, - - where id = #{id} - - - - delete from ff_game_secret_key where id = #{id} - - - - delete from ff_game_secret_key where id in - - #{id} - - - \ No newline at end of file diff --git a/ff-game/src/main/resources/mapper/game/PlatformMapper.xml b/ff-game/src/main/resources/mapper/game/PlatformMapper.xml new file mode 100644 index 0000000..3955a3c --- /dev/null +++ b/ff-game/src/main/resources/mapper/game/PlatformMapper.xml @@ -0,0 +1,116 @@ + + + + + + + + + + + + + + + + + + + + + + + + + select * from ff_platform + + + + + + + insert into ff_platform + + id, + sort_no, + platform_code, + platform_name, + platform_info, + url_info, + + key_info, + lang_info, + currency_info, + ext_info, + + stop_status, + create_by, + create_time, + update_by, + update_time, + + + #{id}, + #{sortNo} + #{platformCode}, + #{platformName}, + #{platformInfo}, + #{urlInfo}, + #{keyInfo}, + #{langInfo}, + #{currencyInfo}, + #{stopStatus}, + #{createBy}, + #{createTime}, + #{updateBy}, + #{updateTime}, + + + + + update ff_platform + + sort_no = #{sortNo}, + platform_code = #{platformCode}, + platform_name = #{platformName}, + platform_info = #{platformInfo}, + url_info = #{urlInfo}, + + key_info = #{keyInfo}, + lang_info = #{langInfo}, + currency_info = #{currencyInfo}, + ext_info = #{extInfo}, + + stop_status = #{stopStatus}, + create_by = #{createBy}, + create_time = #{updateTime}, + update_by = #{updateBy}, + update_time = #{updateTime}, + + where id = #{id} + + + + delete from ff_platform where id = #{id} + + + + delete from ff_platform where id in + + #{id} + + + \ No newline at end of file