From ff36a4079945613ba76dfa6587a9a46cc1d1fc4a Mon Sep 17 00:00:00 2001 From: cengy Date: Wed, 9 Apr 2025 20:05:22 +0800 Subject: [PATCH] =?UTF-8?q?feat(sports):=20=E6=96=B0=E5=A2=9E=20DB?= =?UTF-8?q?=E4=BD=93=E8=82=B2=E5=B9=B3=E5=8F=B0=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加 DB体育相关的缓存常量、数据传输对象、接口客户端等 - 实现 DB 体育平台的服务逻辑,包括用户创建、资金转账、获取会员信息等功能 - 新增延迟任务处理机制,用于处理异步任务 - 修改错误码枚举,增加新的错误类型 - 更新游戏平台枚举,添加 DB 体育选项 --- .../com/ff/base/constant/CacheConstants.java | 14 + .../java/com/ff/base/enums/ErrorCode.java | 3 +- .../java/com/ff/base/enums/GamePlatforms.java | 4 +- .../main/java/com/ff/delay/DelayService.java | 65 ++ .../src/main/java/com/ff/delay/DelayTask.java | 44 + .../meitian/impl/MeiTianGameServiceImpl.java | 93 ++- .../ff/game/api/sv388/client/SV388Client.java | 10 +- .../api/sv388/impl/SV388GamesServiceImpl.java | 31 +- .../ff/sports/db/address/DBSportsAddress.java | 32 + .../ff/sports/db/client/DBSportsClient.java | 100 +++ .../ff/sports/db/dto/CreateUserRequest.java | 30 + .../ff/sports/db/dto/CreateUserResponse.java | 19 + .../main/java/com/ff/sports/db/dto/Enums.java | 9 + .../sports/db/dto/GetMemberInfoRequest.java | 27 + .../sports/db/dto/GetMemberInfoResponse.java | 38 + .../com/ff/sports/db/dto/GetTokenRequest.java | 30 + .../ff/sports/db/dto/GetTokenResponse.java | 49 ++ .../com/ff/sports/db/dto/GetUrlRequest.java | 17 + .../com/ff/sports/db/dto/GetUrlResponse.java | 33 + .../ff/sports/db/dto/OrderFilesRequest.java | 41 + .../ff/sports/db/dto/OrderFilesResponse.java | 27 + .../ff/sports/db/dto/OrderInfoRequest.java | 26 + .../ff/sports/db/dto/OrderInfoResponse.java | 115 +++ .../sports/db/dto/TransferDetailRequest.java | 39 + .../sports/db/dto/TransferDetailResponse.java | 39 + .../ff/sports/db/dto/TransferInRequest.java | 46 ++ .../ff/sports/db/dto/TransferInResponse.java | 20 + .../ff/sports/db/dto/TransferOutRequest.java | 46 ++ .../ff/sports/db/dto/TransferOutResponse.java | 20 + .../sports/db/impl/DBSportsServiceImpl.java | 757 ++++++++++++++++++ .../sports/fb/impl/FBSportsServiceImpl.java | 2 +- 31 files changed, 1773 insertions(+), 53 deletions(-) create mode 100644 ff-game/src/main/java/com/ff/delay/DelayService.java create mode 100644 ff-game/src/main/java/com/ff/delay/DelayTask.java create mode 100644 ff-game/src/main/java/com/ff/sports/db/address/DBSportsAddress.java create mode 100644 ff-game/src/main/java/com/ff/sports/db/client/DBSportsClient.java create mode 100644 ff-game/src/main/java/com/ff/sports/db/dto/CreateUserRequest.java create mode 100644 ff-game/src/main/java/com/ff/sports/db/dto/CreateUserResponse.java create mode 100644 ff-game/src/main/java/com/ff/sports/db/dto/Enums.java create mode 100644 ff-game/src/main/java/com/ff/sports/db/dto/GetMemberInfoRequest.java create mode 100644 ff-game/src/main/java/com/ff/sports/db/dto/GetMemberInfoResponse.java create mode 100644 ff-game/src/main/java/com/ff/sports/db/dto/GetTokenRequest.java create mode 100644 ff-game/src/main/java/com/ff/sports/db/dto/GetTokenResponse.java create mode 100644 ff-game/src/main/java/com/ff/sports/db/dto/GetUrlRequest.java create mode 100644 ff-game/src/main/java/com/ff/sports/db/dto/GetUrlResponse.java create mode 100644 ff-game/src/main/java/com/ff/sports/db/dto/OrderFilesRequest.java create mode 100644 ff-game/src/main/java/com/ff/sports/db/dto/OrderFilesResponse.java create mode 100644 ff-game/src/main/java/com/ff/sports/db/dto/OrderInfoRequest.java create mode 100644 ff-game/src/main/java/com/ff/sports/db/dto/OrderInfoResponse.java create mode 100644 ff-game/src/main/java/com/ff/sports/db/dto/TransferDetailRequest.java create mode 100644 ff-game/src/main/java/com/ff/sports/db/dto/TransferDetailResponse.java create mode 100644 ff-game/src/main/java/com/ff/sports/db/dto/TransferInRequest.java create mode 100644 ff-game/src/main/java/com/ff/sports/db/dto/TransferInResponse.java create mode 100644 ff-game/src/main/java/com/ff/sports/db/dto/TransferOutRequest.java create mode 100644 ff-game/src/main/java/com/ff/sports/db/dto/TransferOutResponse.java create mode 100644 ff-game/src/main/java/com/ff/sports/db/impl/DBSportsServiceImpl.java 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 27a3135..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 @@ -96,6 +96,11 @@ public class CacheConstants { * fb体育 */ public static final String FB_Sports = "fp_sports:"; + + /** + * db体育 + */ + public static final String DB_Sports = "db_sports:"; /** * pg游戏投注货币 */ @@ -125,6 +130,15 @@ public class CacheConstants { */ 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/enums/ErrorCode.java b/ff-base/src/main/java/com/ff/base/enums/ErrorCode.java index 29e6031..d13589b 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 @@ -35,7 +35,8 @@ public enum ErrorCode { Transfer_Out_Failure(1019, "转出失败"), Get_Member_Info_Failure(1020, "获取会员信息失败"), Transfer_Not_Exist(1021, "转帐操作不存在"), - Get_Url_Failure(1022, "获取URL失败") + Get_Url_Failure(1022, "获取URL失败"), + Miss_Config(1023, "缺少配置"), ; // 获取错误码 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 bbe4be7..e8ffc5e 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 @@ -16,8 +16,8 @@ public enum GamePlatforms { KM("KM", "KM"), PGT("PGT", "PGT"), FBSports("FBSports", "FB体育"), - SV388("SV388", "SV388"), - ; + SV388("SV388", "SV388真人"), + DBSports("DBSports", "DB体育"); private final String code; private final String info; diff --git a/ff-game/src/main/java/com/ff/delay/DelayService.java b/ff-game/src/main/java/com/ff/delay/DelayService.java new file mode 100644 index 0000000..c880667 --- /dev/null +++ b/ff-game/src/main/java/com/ff/delay/DelayService.java @@ -0,0 +1,65 @@ +package com.ff.delay; + +import com.ff.base.manager.AsyncManager; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + +import javax.annotation.PostConstruct; +import java.util.concurrent.DelayQueue; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +/** + * @author cengy + */ +@Service +@Slf4j +public class DelayService { + private DelayQueue 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/meitian/impl/MeiTianGameServiceImpl.java b/ff-game/src/main/java/com/ff/game/api/meitian/impl/MeiTianGameServiceImpl.java index c01c1aa..c67b7ae 100644 --- 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 @@ -10,14 +10,14 @@ 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.domain.SysConfig; 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.km.dto.KMBalanceTransferStatusResponseDTO; import com.ff.game.api.meitian.client.MeiTianClient; import com.ff.game.api.meitian.dto.*; import com.ff.game.api.request.*; @@ -80,6 +80,9 @@ public class MeiTianGameServiceImpl implements IGamesService { @Autowired private SysConfigServiceImpl sysConfigServiceImpl; + @Autowired + private DelayService delayService; + /** * 获得就是成功 * @@ -301,7 +304,7 @@ public class MeiTianGameServiceImpl implements IGamesService { String merchantId = exchangeTransferMoneyRequestDTO.getAgentId(); String playerName = exchangeTransferMoneyRequestDTO.getAccount(); String coins = exchangeTransferMoneyRequestDTO.getAmount().setScale(4, RoundingMode.DOWN).toString(); - if (exchangeTransferMoneyRequestDTO.getTransferType().equals(TransferType.ALL.getCode())){ + if (exchangeTransferMoneyRequestDTO.getTransferType().equals(TransferType.ALL.getCode())) { MemberInfoRequestDTO gamesBaseRequestDTO = MemberInfoRequestDTO.builder() .accounts(member.getGameAccount()) .agentId(exchangeTransferMoneyRequestDTO.getAgentId()) @@ -341,7 +344,7 @@ public class MeiTianGameServiceImpl implements IGamesService { //判断是否转移成功 if (this.isSuccess(exchangeMoneyResponse.getErrorCode())) { //更新数据 - BigDecimal transAmount =new BigDecimal(coins); + BigDecimal transAmount = new BigDecimal(coins); exchangeMoney.setBalance(transAmount); exchangeMoney.setCoinBefore(exchangeMoneyResponse.getBalance().subtract(transAmount)); @@ -374,7 +377,7 @@ public class MeiTianGameServiceImpl implements IGamesService { //判断是否转移成功 if (this.isSuccess(exchangeMoneyResponse.getErrorCode())) { //更新数据 - BigDecimal transAmount =new BigDecimal(coins); + BigDecimal transAmount = new BigDecimal(coins); exchangeMoney.setBalance(transAmount); exchangeMoney.setCoinBefore(exchangeMoneyResponse.getBalance().add(transAmount)); @@ -414,7 +417,7 @@ public class MeiTianGameServiceImpl implements IGamesService { exchangeTransferMoneyRequestDTO.getOrderId() ); Integer status = StatusType.IN_PROGRESS.getValue(); - if (this.isSuccess(meiTianBalanceTransferStatusResponseDTO.getResultCode())&& "1".equals(meiTianBalanceTransferStatusResponseDTO.getStatus())) { + if (this.isSuccess(meiTianBalanceTransferStatusResponseDTO.getResultCode()) && "1".equals(meiTianBalanceTransferStatusResponseDTO.getStatus())) { status = StatusType.SUCCESS.getValue(); } else { status = StatusType.FAILURE.getValue(); @@ -428,6 +431,34 @@ public class MeiTianGameServiceImpl implements IGamesService { } + 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); + } + } + /** * 按时间获取投注记录 * @@ -436,18 +467,21 @@ public class MeiTianGameServiceImpl implements IGamesService { */ @Override public Boolean getBetRecordByTime(BetRecordByTimeDTO betRecordByTimeDTO) { - return doSyncRecordByRecordID(betRecordByTimeDTO); + delayService.addTask(new GetRecordByTimeTask(betRecordByTimeDTO)); + return Boolean.TRUE; + //return doSyncRecordByRecordID(betRecordByTimeDTO); } boolean doSyncRecordByRecordID(BetRecordByTimeDTO betRecordByTimeDTO) { - String configKey = GamePlatforms.MT.getCode() + ":lastRecordID"; - String lastRecordID = sysConfigServiceImpl.selectConfigByKey(configKey); - long recordID = 0; - if (lastRecordID == null || lastRecordID.isEmpty()) { + 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); @@ -473,7 +507,9 @@ public class MeiTianGameServiceImpl implements IGamesService { //数据插入 this.batchInsert(recordResponse, betRecordByTimeDTO); MeiTianBetRecordResponseDTO.DataBean dataBean = dataList.get(dataList.size() - 1); - SysConfig config = sysConfigServiceImpl.getByConfigKey(configKey); + redisCache.setCacheObject(configKey, Long.parseLong(dataBean.getRowID())); + + /*SysConfig config = sysConfigServiceImpl.getByConfigKey(configKey); if (config == null) { config = new SysConfig(); config.setConfigKey(configKey); @@ -482,7 +518,7 @@ public class MeiTianGameServiceImpl implements IGamesService { } else { config.setConfigValue(dataBean.getRecordID()); sysConfigServiceImpl.updateConfig(config); - } + }*/ // 它每次返回25000条,所以需要判断,如果大于25000条,则继续拉取 if (dataList.size() >= 25000) { doSyncRecordByRecordID(betRecordByTimeDTO); @@ -498,22 +534,7 @@ public class MeiTianGameServiceImpl implements IGamesService { String date = getDateStr(daysToSubtract); String configKey = GamePlatforms.MT.getCode() + ":lastSyncDate"; - String syncDateStr = sysConfigServiceImpl.selectConfigByKey(configKey); - Map syncDateMap = new HashMap<>(); - long recordID = 0; - if (syncDateStr == null || syncDateStr.isEmpty()) { - } else { - syncDateMap = JSON.parseObject(syncDateStr, Map.class); - } - if (syncDateMap.containsKey(date)) { - recordID = syncDateMap.get(date); - if (syncDateMap.size() > 10) { - syncDateMap.clear(); - syncDateMap.put(date, recordID); - } - } else { - syncDateMap.put(date, recordID); - } + long recordID = redisCache.getCacheObject(configKey); String merchantId = betRecordByTimeDTO.getAgentId(); Map rawMap = new LinkedHashMap<>(); rawMap.put("rowID", recordID); @@ -541,8 +562,9 @@ public class MeiTianGameServiceImpl implements IGamesService { //数据插入 this.batchInsert(recordResponse, betRecordByTimeDTO); MeiTianBetRecordResponseDTO.DataBean dataBean = dataList.get(dataList.size() - 1); - syncDateMap.put(date, Long.parseLong(dataBean.getRowID())); - SysConfig config = sysConfigServiceImpl.getByConfigKey(configKey); + //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); @@ -551,7 +573,7 @@ public class MeiTianGameServiceImpl implements IGamesService { } else { config.setConfigValue(JSON.toJSONString(syncDateMap)); sysConfigServiceImpl.updateConfig(config); - } + }*/ // 它每次返回25000条,所以需要判断,如果大于25000条,则继续拉取 if (dataList.size() >= 25000) { @@ -572,9 +594,10 @@ public class MeiTianGameServiceImpl implements IGamesService { */ @Override public Boolean getBetRecordByHistoryTime(BetRecordByTimeDTO betRecordByTimeDTO) { - doSyncRecordByDate(betRecordByTimeDTO, 0); - doSyncRecordByDate(betRecordByTimeDTO, 1); // yesterday + //doSyncRecordByDate(betRecordByTimeDTO, 0); + //doSyncRecordByDate(betRecordByTimeDTO, 1); // yesterday + delayService.addTask(new GetRecordByHistoryTimeTask(betRecordByTimeDTO)); return true; } 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 index 10043a8..7f57520 100644 --- 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 @@ -92,11 +92,12 @@ public interface SV388Client { * @param params 参数 * @return {@link SV388BetRecordResponse } */ - @Post(url ="https://tttfetch.apihub55.com/fetch/gzip/getTransactionByUpdateDate", + @Post(url ="{fetchUrl}/fetch/gzip/getTransactionByUpdateDate", headers = { "Content-type: application/x-www-form-urlencoded" }) - SV388BetRecordResponse getBetRecordByTime(@Body Map params); + SV388BetRecordResponse getBetRecordByTime(@Body Map params, + @Var("fetchUrl") String fetchUrl); /** * 按时间获取投注历史记录 @@ -104,11 +105,12 @@ public interface SV388Client { * @param params 参数 * @return {@link SV388BetRecordResponse } */ - @Post(url ="https://tttfetch.apihub55.com/fetch/gzip/getTransactionByTxTime", + @Post(url ="{fetchUrl}/fetch/gzip/getTransactionByTxTime", headers = { "Content-type: application/x-www-form-urlencoded" }) - SV388BetRecordResponse getBetHistoryRecordByTime(@Body Map params); + SV388BetRecordResponse getBetHistoryRecordByTime(@Body Map params, + @Var("fetchUrl") String fetchUrl); /** * 踢出队员 * 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 index 08e19c3..a49ef4b 100644 --- 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 @@ -105,7 +105,17 @@ public class SV388GamesServiceImpl implements IGamesService { public Boolean createMember(CreateMemberRequestDTO createMemberRequestDTO) { Platform platform = createMemberRequestDTO.getVendor(); - Object betLimit = platform.getExtInfo().getBetLimit().get(createMemberRequestDTO.getSystemCurrency()); + 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()); @@ -201,7 +211,7 @@ public class SV388GamesServiceImpl implements IGamesService { game.setGameId(StringUtils.addSuffix(GamePlatforms.SV388.getCode(), 1)); gameService.insertGame(game); } - return CacheConstants.AE_GAMES; + return CacheConstants.SV388_GAMES; } /** @@ -235,7 +245,7 @@ public class SV388GamesServiceImpl implements IGamesService { .currencyCode(exchangeTransferMoneyRequestDTO.getSystemCurrency()) .memberId(member.getId()) .transactionId(transactionId) - .platformCode(GamePlatforms.AE.getInfo()) + .platformCode(GamePlatforms.SV388.getCode()) .build(); exchangeMoney.setCreateBy(Constants.SYSTEM); exchangeMoney.setStatus(StatusType.IN_PROGRESS.getValue()); @@ -338,16 +348,16 @@ public class SV388GamesServiceImpl implements IGamesService { //请求参数 Map params = this.getKey(betRecordByTimeDTO); - String timeFrom = redisCache.getCacheObject(CacheConstants.AE_TIME_FROM); + String timeFrom = redisCache.getCacheObject(CacheConstants.SV388_TIME_FROM); if (StringUtils.isEmpty(timeFrom)) { - timeFrom = DateUtils.convertTimestampToFormattedDate(betRecordByTimeDTO.getEndTime(), DateUtils.ISO_8601_FORMAT, "GMT+8") + "+08:00"; + 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); + SV388BetRecordResponse aeBetRecordResponse = sv388Client.getBetRecordByTime(params, betRecordByTimeDTO.getVendor().getUrlInfo().getBetUrl()); //判断是否获取成功 if (this.getIsSuccess(aeBetRecordResponse.getStatus())) { @@ -355,7 +365,7 @@ public class SV388GamesServiceImpl implements IGamesService { this.batchInsert(aeBetRecordResponse, betRecordByTimeDTO); return Boolean.TRUE; } else { - redisCache.deleteObject(CacheConstants.AE_TIME_FROM); + redisCache.deleteObject(CacheConstants.SV388_TIME_FROM); log.error("获取投注记录失败,错误代码{},错误信息{}", aeBetRecordResponse.getStatus(), aeBetRecordResponse.getDesc()); throw new BaseException(aeBetRecordResponse.getDesc()); } @@ -378,7 +388,8 @@ public class SV388GamesServiceImpl implements IGamesService { params.put("startTime", startTime); params.put("endTime", endTime); params.put("platform", /*"SEXYBCRT"*/ GamePlatforms.SV388.getCode()); - SV388BetRecordResponse aeBetRecordResponse = sv388Client.getBetHistoryRecordByTime(params); + + SV388BetRecordResponse aeBetRecordResponse = sv388Client.getBetHistoryRecordByTime(params, betRecordByTimeDTO.getVendor().getUrlInfo().getBetUrl()); //判断是否获取成功 if (this.getIsSuccess(aeBetRecordResponse.getStatus())) { @@ -504,7 +515,7 @@ public class SV388GamesServiceImpl implements IGamesService { } if (!CollectionUtils.isEmpty(gameBettingDetails)) { //查询重复数据id - List removeWagersIds = gameBettingDetailsService.selectGameBettingDetailsByWagersId(wagersIds, GamePlatforms.AE.getInfo()); + List removeWagersIds = gameBettingDetailsService.selectGameBettingDetailsByWagersId(wagersIds, GamePlatforms.SV388.getCode()); //用steam流清除list中与wagersIds集合相同的数据 gameBettingDetails = gameBettingDetails.stream() .filter(detail -> !removeWagersIds.contains(detail.getWagersId())) @@ -516,7 +527,7 @@ public class SV388GamesServiceImpl implements IGamesService { if (StringUtils.isEmpty(timeFrom)) { timeFrom = DateUtils.convertTimestampToFormattedDate(DateUtils.getNowDate(), DateUtils.ISO_8601_FORMAT, "UTC+8") + "+08:00"; } - redisCache.setCacheObject(CacheConstants.AE_TIME_FROM, timeFrom); + redisCache.setCacheObject(CacheConstants.SV388_TIME_FROM, timeFrom); } /** diff --git a/ff-game/src/main/java/com/ff/sports/db/address/DBSportsAddress.java b/ff-game/src/main/java/com/ff/sports/db/address/DBSportsAddress.java new file mode 100644 index 0000000..c2e1843 --- /dev/null +++ b/ff-game/src/main/java/com/ff/sports/db/address/DBSportsAddress.java @@ -0,0 +1,32 @@ +package com.ff.sports.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/sports/db/client/DBSportsClient.java b/ff-game/src/main/java/com/ff/sports/db/client/DBSportsClient.java new file mode 100644 index 0000000..6fabff8 --- /dev/null +++ b/ff-game/src/main/java/com/ff/sports/db/client/DBSportsClient.java @@ -0,0 +1,100 @@ +package com.ff.sports.db.client; + +import com.dtflys.forest.annotation.*; +import com.ff.sports.db.address.DBSportsAddress; +import com.ff.sports.db.dto.*; + +/** + * + * @author cengy + */ +@Address(source = DBSportsAddress.class) +public interface DBSportsClient { + /** + * 创建投注用户 + * + * @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/sports/db/dto/CreateUserRequest.java b/ff-game/src/main/java/com/ff/sports/db/dto/CreateUserRequest.java new file mode 100644 index 0000000..fd466fb --- /dev/null +++ b/ff-game/src/main/java/com/ff/sports/db/dto/CreateUserRequest.java @@ -0,0 +1,30 @@ +package com.ff.sports.db.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/sports/db/dto/CreateUserResponse.java b/ff-game/src/main/java/com/ff/sports/db/dto/CreateUserResponse.java new file mode 100644 index 0000000..6098450 --- /dev/null +++ b/ff-game/src/main/java/com/ff/sports/db/dto/CreateUserResponse.java @@ -0,0 +1,19 @@ +package com.ff.sports.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 success; + private Integer data; + private Integer code; + private String message; +} diff --git a/ff-game/src/main/java/com/ff/sports/db/dto/Enums.java b/ff-game/src/main/java/com/ff/sports/db/dto/Enums.java new file mode 100644 index 0000000..5cbd46b --- /dev/null +++ b/ff-game/src/main/java/com/ff/sports/db/dto/Enums.java @@ -0,0 +1,9 @@ +package com.ff.sports.db.dto; + +/** + * @author cengy + */ +public class Enums { + + +} diff --git a/ff-game/src/main/java/com/ff/sports/db/dto/GetMemberInfoRequest.java b/ff-game/src/main/java/com/ff/sports/db/dto/GetMemberInfoRequest.java new file mode 100644 index 0000000..015bc89 --- /dev/null +++ b/ff-game/src/main/java/com/ff/sports/db/dto/GetMemberInfoRequest.java @@ -0,0 +1,27 @@ +package com.ff.sports.db.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/sports/db/dto/GetMemberInfoResponse.java b/ff-game/src/main/java/com/ff/sports/db/dto/GetMemberInfoResponse.java new file mode 100644 index 0000000..60cb4c7 --- /dev/null +++ b/ff-game/src/main/java/com/ff/sports/db/dto/GetMemberInfoResponse.java @@ -0,0 +1,38 @@ +package com.ff.sports.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 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/sports/db/dto/GetTokenRequest.java b/ff-game/src/main/java/com/ff/sports/db/dto/GetTokenRequest.java new file mode 100644 index 0000000..83bfe60 --- /dev/null +++ b/ff-game/src/main/java/com/ff/sports/db/dto/GetTokenRequest.java @@ -0,0 +1,30 @@ +package com.ff.sports.db.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/sports/db/dto/GetTokenResponse.java b/ff-game/src/main/java/com/ff/sports/db/dto/GetTokenResponse.java new file mode 100644 index 0000000..3dfb0df --- /dev/null +++ b/ff-game/src/main/java/com/ff/sports/db/dto/GetTokenResponse.java @@ -0,0 +1,49 @@ +package com.ff.sports.db.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/sports/db/dto/GetUrlRequest.java b/ff-game/src/main/java/com/ff/sports/db/dto/GetUrlRequest.java new file mode 100644 index 0000000..4ccc4d6 --- /dev/null +++ b/ff-game/src/main/java/com/ff/sports/db/dto/GetUrlRequest.java @@ -0,0 +1,17 @@ +package com.ff.sports.db.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/sports/db/dto/GetUrlResponse.java b/ff-game/src/main/java/com/ff/sports/db/dto/GetUrlResponse.java new file mode 100644 index 0000000..d622169 --- /dev/null +++ b/ff-game/src/main/java/com/ff/sports/db/dto/GetUrlResponse.java @@ -0,0 +1,33 @@ +package com.ff.sports.db.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/sports/db/dto/OrderFilesRequest.java b/ff-game/src/main/java/com/ff/sports/db/dto/OrderFilesRequest.java new file mode 100644 index 0000000..315b698 --- /dev/null +++ b/ff-game/src/main/java/com/ff/sports/db/dto/OrderFilesRequest.java @@ -0,0 +1,41 @@ +package com.ff.sports.db.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/sports/db/dto/OrderFilesResponse.java b/ff-game/src/main/java/com/ff/sports/db/dto/OrderFilesResponse.java new file mode 100644 index 0000000..2367773 --- /dev/null +++ b/ff-game/src/main/java/com/ff/sports/db/dto/OrderFilesResponse.java @@ -0,0 +1,27 @@ +package com.ff.sports.db.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/sports/db/dto/OrderInfoRequest.java b/ff-game/src/main/java/com/ff/sports/db/dto/OrderInfoRequest.java new file mode 100644 index 0000000..9d51d78 --- /dev/null +++ b/ff-game/src/main/java/com/ff/sports/db/dto/OrderInfoRequest.java @@ -0,0 +1,26 @@ +package com.ff.sports.db.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/sports/db/dto/OrderInfoResponse.java b/ff-game/src/main/java/com/ff/sports/db/dto/OrderInfoResponse.java new file mode 100644 index 0000000..b6910f6 --- /dev/null +++ b/ff-game/src/main/java/com/ff/sports/db/dto/OrderInfoResponse.java @@ -0,0 +1,115 @@ +package com.ff.sports.db.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/sports/db/dto/TransferDetailRequest.java b/ff-game/src/main/java/com/ff/sports/db/dto/TransferDetailRequest.java new file mode 100644 index 0000000..8bb2c9e --- /dev/null +++ b/ff-game/src/main/java/com/ff/sports/db/dto/TransferDetailRequest.java @@ -0,0 +1,39 @@ +package com.ff.sports.db.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/sports/db/dto/TransferDetailResponse.java b/ff-game/src/main/java/com/ff/sports/db/dto/TransferDetailResponse.java new file mode 100644 index 0000000..8f56651 --- /dev/null +++ b/ff-game/src/main/java/com/ff/sports/db/dto/TransferDetailResponse.java @@ -0,0 +1,39 @@ +package com.ff.sports.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 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/sports/db/dto/TransferInRequest.java b/ff-game/src/main/java/com/ff/sports/db/dto/TransferInRequest.java new file mode 100644 index 0000000..31f13a4 --- /dev/null +++ b/ff-game/src/main/java/com/ff/sports/db/dto/TransferInRequest.java @@ -0,0 +1,46 @@ +package com.ff.sports.db.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/sports/db/dto/TransferInResponse.java b/ff-game/src/main/java/com/ff/sports/db/dto/TransferInResponse.java new file mode 100644 index 0000000..3de12e9 --- /dev/null +++ b/ff-game/src/main/java/com/ff/sports/db/dto/TransferInResponse.java @@ -0,0 +1,20 @@ +package com.ff.sports.db.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/sports/db/dto/TransferOutRequest.java b/ff-game/src/main/java/com/ff/sports/db/dto/TransferOutRequest.java new file mode 100644 index 0000000..bd26537 --- /dev/null +++ b/ff-game/src/main/java/com/ff/sports/db/dto/TransferOutRequest.java @@ -0,0 +1,46 @@ +package com.ff.sports.db.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/sports/db/dto/TransferOutResponse.java b/ff-game/src/main/java/com/ff/sports/db/dto/TransferOutResponse.java new file mode 100644 index 0000000..da1590c --- /dev/null +++ b/ff-game/src/main/java/com/ff/sports/db/dto/TransferOutResponse.java @@ -0,0 +1,20 @@ +package com.ff.sports.db.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/sports/db/impl/DBSportsServiceImpl.java b/ff-game/src/main/java/com/ff/sports/db/impl/DBSportsServiceImpl.java new file mode 100644 index 0000000..3df555c --- /dev/null +++ b/ff-game/src/main/java/com/ff/sports/db/impl/DBSportsServiceImpl.java @@ -0,0 +1,757 @@ +package com.ff.sports.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.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.sports.db.client.DBSportsClient; +import com.ff.sports.db.dto.*; +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.Assert; +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("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(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 = dbSportsClient.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) { + + Member member = memberService.selectMemberByGameAccount(requestDTO.getAccount()); + String transactionId = GamePlatforms.DBSports.getCode() + IdUtils.simpleUUID(); + List gameExchangeMonies = gameExchangeMoneyService.selectGameExchangeMoneyList( + GameExchangeMoney.builder() + .tenantKey(requestDTO.getTenantKey()) + .orderId(requestDTO.getOrderId()) + .build() + ); + Assert.isTrue(CollectionUtils.isEmpty(gameExchangeMonies), "订单号重复"); +//获取下一个自增id + GameExchangeMoney exchangeMoney = GameExchangeMoney + .builder() + .orderId(requestDTO.getOrderId()) + .tenantKey(requestDTO.getTenantKey()) + .quota(requestDTO.getQuota()) + .balance(requestDTO.getAmount()) + .exchangeType(requestDTO.getTransferType()) + .currencyCode(requestDTO.getSystemCurrency()) + .memberId(member.getId()) + .transactionId(transactionId) + .platformCode(GamePlatforms.DBSports.getCode()) + .build(); + exchangeMoney.setCreateBy(Constants.SYSTEM); + //接口限制限制50字符 + exchangeMoney.setTransactionId(transactionId); + // 转入 + if (requestDTO.getTransferType().equals(TransferType.GAMES.getCode())) { + TransferInRequest request = new TransferInRequest(); + request.setMerchantUserId(requestDTO.getAccount()); + request.setAmount(requestDTO.getAmount()); + request.setBusinessId(requestDTO.getOrderId()); + 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 = dbSportsClient.transferIn( + request, + sign, + timestamp, + requestDTO.getAgentId()); + if (isSuccess(response.getCode())) { + + exchangeMoney.setBalance(response.getData()); + BigDecimal transAmount = requestDTO.getAmount(); + exchangeMoney.setCoinBefore(response.getData().subtract(transAmount)); + exchangeMoney.setCoinAfter(response.getData()); + exchangeMoney.setCurrencyBefore(response.getData().subtract(transAmount)); + exchangeMoney.setCurrencyAfter(response.getData()); + exchangeMoney.setStatus(StatusType.SUCCESS.getValue()); // SUCCESS + gameExchangeMoneyService.insertGameExchangeMoney(exchangeMoney); + } else { + throw new ApiException(ErrorCode.Transfer_In_Failure.getCode()); + } + } else { + // 获取第三方钱包余额 + MemberInfoRequestDTO memberInfoRequestDTO = MemberInfoRequestDTO.builder() + .accounts(member.getGameAccount()) + .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.getOrderId()); + 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 = dbSportsClient + .transferOut( + request, + sign, + timestamp, + requestDTO.getAgentId() + ); + + + //判断是否转移成功 + if (this.isSuccess(response.getCode())) { + //更新数据 + exchangeMoney.setBalance(response.getData()); + BigDecimal transAmount = balance; + exchangeMoney.setCoinBefore(response.getData().add(transAmount)); + exchangeMoney.setCoinAfter(response.getData()); + exchangeMoney.setCurrencyBefore(response.getData().add(transAmount)); + exchangeMoney.setCurrencyAfter(response.getData()); + exchangeMoney.setStatus(StatusType.SUCCESS.getValue()); // SUCCESS + gameExchangeMoneyService.insertGameExchangeMoney(exchangeMoney); + } else { + 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 = dbSportsClient.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()); + } + } + + /** + * 无重定向登录 + * + * @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 = dbSportsClient.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 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("DB体育"); + 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.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 = dbSportsClient.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 = dbSportsClient.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 = dbSportsClient.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 = dbSportsClient.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.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) { + + //转化类 + OrderInfoResponse.OrderDTO dataBean = (OrderInfoResponse.OrderDTO) gamesDataBuildDTO.getData(); + Member member = memberService.selectMemberByGameAccount(dataBean.getMerchantUserId()); + if (ObjectUtils.isEmpty(member)) { + return null; + } + List gameList = redisCache.getCacheList(CacheConstants.DB_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(PlatformType.SPORTS.getCode()) // 体育 + .platformCode(GamePlatforms.DBSports.getCode()) + .gameId(game.getId()) + .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/sports/fb/impl/FBSportsServiceImpl.java b/ff-game/src/main/java/com/ff/sports/fb/impl/FBSportsServiceImpl.java index 01f3dfe..9e84d4d 100644 --- a/ff-game/src/main/java/com/ff/sports/fb/impl/FBSportsServiceImpl.java +++ b/ff-game/src/main/java/com/ff/sports/fb/impl/FBSportsServiceImpl.java @@ -383,7 +383,7 @@ public class FBSportsServiceImpl implements IGamesService { game.setSortNo(1); //game.setPlatformId(gamePlatform.getId()); game.setPlatformCode(platform.getPlatformCode()); - game.setPlatformType(PlatformType.GAME_HALL.getCode()); + game.setPlatformType(PlatformType.SPORTS.getCode()); game.setGameCode("1"); game.setGameSourceType(String.valueOf(1)); game.setGameName("FB体育");