From 8ec1afd87594fe7f93b0bab302642a7cb6ef7829 Mon Sep 17 00:00:00 2001 From: cengy Date: Tue, 8 Apr 2025 17:11:31 +0800 Subject: [PATCH] =?UTF-8?q?feat(fb-sports):=20=E5=AE=9E=E7=8E=B0=20FB=20?= =?UTF-8?q?=E4=BD=93=E8=82=B2=E6=95=B0=E6=8D=AE=E5=AF=B9=E6=8E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 FB 体育类型枚举类 FBSportsType - 实现 FB 体育客户端接口,包括获取 token、订单文件列表和订单数据- 重构 FBSportsServiceImpl 类,支持按时间和历史时间获取投注记录 - 优化数据处理逻辑,实现批量插入功能 -移除不必要的定时任务配置 --- .../java/com/ff/base/enums/FBSportsType.java | 60 ++++ .../meitian/impl/MeiTianGameServiceImpl.java | 4 +- .../com/ff/quartz/config/ScheduleConfig.java | 114 ++++---- .../ff/sports/fb/address/FBSportsAddress.java | 6 +- .../ff/sports/fb/client/FBSportsClient.java | 29 +- .../com/ff/sports/fb/dto/GetTokenRequest.java | 30 ++ .../ff/sports/fb/dto/GetTokenResponse.java | 49 ++++ .../ff/sports/fb/dto/OrderFilesRequest.java | 8 + .../ff/sports/fb/dto/OrderFilesResponse.java | 2 +- .../ff/sports/fb/dto/OrderInfoRequest.java | 2 +- .../sports/fb/impl/FBSportsServiceImpl.java | 262 +++++++++++++----- .../com/ff/utils/TimestampFromString.java | 4 + 12 files changed, 437 insertions(+), 133 deletions(-) create mode 100644 ff-base/src/main/java/com/ff/base/enums/FBSportsType.java create mode 100644 ff-game/src/main/java/com/ff/sports/fb/dto/GetTokenRequest.java create mode 100644 ff-game/src/main/java/com/ff/sports/fb/dto/GetTokenResponse.java 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-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 47af3fa..305a9eb 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 @@ -746,8 +746,8 @@ public class MeiTianGameServiceImpl implements IGamesService { 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); + BigDecimal betAmount = new BigDecimal(dataBean.getBetAmount()); + int compareResult = originPayoffAmount.compareTo(betAmount); long gameTime = TimestampFromString.from(dataBean.getGameDate()); Platform platform = gamesDataBuildDTO.getPlatform(); String systemCurrency = platform.getOurCurrency(dataBean.getCurrency()); 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 475653c..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,57 +1,57 @@ -package com.ff.quartz.config; - -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.scheduling.quartz.SchedulerFactoryBean; -import javax.sql.DataSource; -import java.util.Properties; - -/** - * 定时任务配置(单机部署建议删除此类和qrtz数据库表,默认走内存会最高效) - * - * @author ff - */ -@Configuration -public class ScheduleConfig -{ - @Bean - public SchedulerFactoryBean schedulerFactoryBean(DataSource dataSource) - { - SchedulerFactoryBean factory = new SchedulerFactoryBean(); - factory.setDataSource(dataSource); - - // quartz参数 - Properties prop = new Properties(); - prop.put("org.quartz.scheduler.instanceName", "ffScheduler"); - prop.put("org.quartz.scheduler.instanceId", "AUTO"); - // 线程池配置 - prop.put("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool"); - prop.put("org.quartz.threadPool.threadCount", "20"); - prop.put("org.quartz.threadPool.threadPriority", "5"); - // JobStore配置 - prop.put("org.quartz.jobStore.class", "org.springframework.scheduling.quartz.LocalDataSourceJobStore"); - // 集群配置 - prop.put("org.quartz.jobStore.isClustered", "true"); - prop.put("org.quartz.jobStore.clusterCheckinInterval", "15000"); - prop.put("org.quartz.jobStore.maxMisfiresToHandleAtATime", "10"); - prop.put("org.quartz.jobStore.txIsolationLevelSerializable", "true"); - - // sqlserver 启用 - // prop.put("org.quartz.jobStore.selectWithLockSQL", "SELECT * FROM {0}LOCKS UPDLOCK WHERE LOCK_NAME = ?"); - prop.put("org.quartz.jobStore.misfireThreshold", "12000"); - prop.put("org.quartz.jobStore.tablePrefix", "QRTZ_"); - factory.setQuartzProperties(prop); - - factory.setSchedulerName("ffScheduler"); - // 延时启动 - factory.setStartupDelay(1); - factory.setApplicationContextSchedulerContextKey("applicationContextKey"); - // 可选,QuartzScheduler - // 启动时更新己存在的Job,这样就不用每次修改targetObject后删除qrtz_job_details表对应记录了 - factory.setOverwriteExistingJobs(true); - // 设置自动启动,默认为true - factory.setAutoStartup(true); - - return factory; - } -} +//package com.ff.quartz.config; +// +//import org.springframework.context.annotation.Bean; +//import org.springframework.context.annotation.Configuration; +//import org.springframework.scheduling.quartz.SchedulerFactoryBean; +//import javax.sql.DataSource; +//import java.util.Properties; +// +///** +// * 定时任务配置(单机部署建议删除此类和qrtz数据库表,默认走内存会最高效) +// * +// * @author ff +// */ +//@Configuration +//public class ScheduleConfig +//{ +// @Bean +// public SchedulerFactoryBean schedulerFactoryBean(DataSource dataSource) +// { +// SchedulerFactoryBean factory = new SchedulerFactoryBean(); +// factory.setDataSource(dataSource); +// +// // quartz参数 +// Properties prop = new Properties(); +// prop.put("org.quartz.scheduler.instanceName", "ffScheduler"); +// prop.put("org.quartz.scheduler.instanceId", "AUTO"); +// // 线程池配置 +// prop.put("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool"); +// prop.put("org.quartz.threadPool.threadCount", "20"); +// prop.put("org.quartz.threadPool.threadPriority", "5"); +// // JobStore配置 +// prop.put("org.quartz.jobStore.class", "org.springframework.scheduling.quartz.LocalDataSourceJobStore"); +// // 集群配置 +// prop.put("org.quartz.jobStore.isClustered", "true"); +// prop.put("org.quartz.jobStore.clusterCheckinInterval", "15000"); +// prop.put("org.quartz.jobStore.maxMisfiresToHandleAtATime", "10"); +// prop.put("org.quartz.jobStore.txIsolationLevelSerializable", "true"); +// +// // sqlserver 启用 +// // prop.put("org.quartz.jobStore.selectWithLockSQL", "SELECT * FROM {0}LOCKS UPDLOCK WHERE LOCK_NAME = ?"); +// prop.put("org.quartz.jobStore.misfireThreshold", "12000"); +// prop.put("org.quartz.jobStore.tablePrefix", "QRTZ_"); +// factory.setQuartzProperties(prop); +// +// factory.setSchedulerName("ffScheduler"); +// // 延时启动 +// factory.setStartupDelay(1); +// factory.setApplicationContextSchedulerContextKey("applicationContextKey"); +// // 可选,QuartzScheduler +// // 启动时更新己存在的Job,这样就不用每次修改targetObject后删除qrtz_job_details表对应记录了 +// factory.setOverwriteExistingJobs(true); +// // 设置自动启动,默认为true +// factory.setAutoStartup(true); +// +// return factory; +// } +//} diff --git a/ff-game/src/main/java/com/ff/sports/fb/address/FBSportsAddress.java b/ff-game/src/main/java/com/ff/sports/fb/address/FBSportsAddress.java index a1f47b8..e0aaa84 100644 --- a/ff-game/src/main/java/com/ff/sports/fb/address/FBSportsAddress.java +++ b/ff-game/src/main/java/com/ff/sports/fb/address/FBSportsAddress.java @@ -11,9 +11,9 @@ import javax.annotation.Resource; /** - * 文档地址:https://doc.newsportspro.com/apidoc_data.html#%E5%85%A5%E5%8F%82 - * @author shi - * @date 2025/02/10 + * 对接文档地址 + * + * @author cengy */ @Component public class FBSportsAddress implements AddressSource { diff --git a/ff-game/src/main/java/com/ff/sports/fb/client/FBSportsClient.java b/ff-game/src/main/java/com/ff/sports/fb/client/FBSportsClient.java index 674a4e4..dc28d2d 100644 --- a/ff-game/src/main/java/com/ff/sports/fb/client/FBSportsClient.java +++ b/ff-game/src/main/java/com/ff/sports/fb/client/FBSportsClient.java @@ -5,7 +5,8 @@ import com.ff.sports.fb.address.FBSportsAddress; import com.ff.sports.fb.dto.*; /** - * https://doc.newsportspro.com/apidoc_data.html + * 数据接口文档
+ * 网页接入文档 * * @author cengy */ @@ -68,10 +69,34 @@ public interface FBSportsClient { * FB体育用拉取订单文件的方式同步订单数据,FB体育每5分钟生成一次订单文件, * 通过此接口获取某一段时间内的文件ID列表,再通过文件ID获取具体订单数据 */ - @Post(url = "/api/v2/transfer/detail") + @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/fb/dto/GetTokenRequest.java b/ff-game/src/main/java/com/ff/sports/fb/dto/GetTokenRequest.java new file mode 100644 index 0000000..1f46602 --- /dev/null +++ b/ff-game/src/main/java/com/ff/sports/fb/dto/GetTokenRequest.java @@ -0,0 +1,30 @@ +package com.ff.sports.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/sports/fb/dto/GetTokenResponse.java b/ff-game/src/main/java/com/ff/sports/fb/dto/GetTokenResponse.java new file mode 100644 index 0000000..32a5029 --- /dev/null +++ b/ff-game/src/main/java/com/ff/sports/fb/dto/GetTokenResponse.java @@ -0,0 +1,49 @@ +package com.ff.sports.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/sports/fb/dto/OrderFilesRequest.java b/ff-game/src/main/java/com/ff/sports/fb/dto/OrderFilesRequest.java index 3d3e48b..5cbbeed 100644 --- a/ff-game/src/main/java/com/ff/sports/fb/dto/OrderFilesRequest.java +++ b/ff-game/src/main/java/com/ff/sports/fb/dto/OrderFilesRequest.java @@ -29,5 +29,13 @@ public class OrderFilesRequest implements Serializable { 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/fb/dto/OrderFilesResponse.java b/ff-game/src/main/java/com/ff/sports/fb/dto/OrderFilesResponse.java index 3042774..8d9f1b5 100644 --- a/ff-game/src/main/java/com/ff/sports/fb/dto/OrderFilesResponse.java +++ b/ff-game/src/main/java/com/ff/sports/fb/dto/OrderFilesResponse.java @@ -21,7 +21,7 @@ public class OrderFilesResponse implements Serializable { @Data public static class FileId implements Serializable { private static final long serialVersionUID = 1L; - private Integer fileId; + private Long fileId; } } diff --git a/ff-game/src/main/java/com/ff/sports/fb/dto/OrderInfoRequest.java b/ff-game/src/main/java/com/ff/sports/fb/dto/OrderInfoRequest.java index 5b75ecb..251dc02 100644 --- a/ff-game/src/main/java/com/ff/sports/fb/dto/OrderInfoRequest.java +++ b/ff-game/src/main/java/com/ff/sports/fb/dto/OrderInfoRequest.java @@ -16,7 +16,7 @@ public class OrderInfoRequest implements Serializable { /** * 文件Id,需要从/order/file/ids接口获取到 */ - private Integer fileId; + private Long fileId; public String toJSON() { Map map = new LinkedHashMap<>(); 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 f56fce4..8cc5533 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 @@ -1,6 +1,5 @@ package com.ff.sports.fb.impl; -import cn.hutool.core.lang.generator.SnowflakeGenerator; import cn.hutool.core.util.IdUtil; import com.ff.base.constant.CacheConstants; import com.ff.base.constant.Constants; @@ -9,11 +8,10 @@ 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.meitian.dto.MeiTianBetRecordResponseDTO; -import com.ff.game.api.meitian.dto.MeiTianGameDataDTO; import com.ff.game.api.request.*; import com.ff.game.domain.*; import com.ff.game.service.IGameBettingDetailsService; @@ -33,7 +31,10 @@ import org.springframework.util.ObjectUtils; import javax.annotation.Resource; import java.math.BigDecimal; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; import java.util.stream.Collectors; @@ -285,7 +286,50 @@ public class FBSportsServiceImpl implements IGamesService { */ @Override public String loginWithoutRedirect(GamesLogin requestDTO) { - GetUrlRequest request = new GetUrlRequest(); + 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, @@ -314,10 +358,12 @@ public class FBSportsServiceImpl implements IGamesService { 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; + /** * 获取游戏列表 * @@ -405,35 +451,123 @@ public class FBSportsServiceImpl implements IGamesService { /** * 按时间获取投注记录 * - * @param betRecordByTimeDTO 按时间dto投注记录 + * @param requestDTO 按时间dto投注记录 * @return {@link Boolean } */ @Override - public Boolean getBetRecordByTime(BetRecordByTimeDTO betRecordByTimeDTO) { - return doSyncRecordByRecordID(betRecordByTimeDTO); + 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; } - boolean doSyncRecordByRecordID(BetRecordByTimeDTO betRecordByTimeDTO) { + 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 + ); - return Boolean.FALSE; - } - - boolean doSyncRecordByDate(BetRecordByTimeDTO betRecordByTimeDTO, int daysToSubtract) { - return Boolean.FALSE; + 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 betRecordByTimeDTO 按时间dto投注记录 + * @param requestDTO 按时间dto投注记录 * @return {@link Boolean } */ @Override - public Boolean getBetRecordByHistoryTime(BetRecordByTimeDTO betRecordByTimeDTO) { - doSyncRecordByDate(betRecordByTimeDTO, 0); - doSyncRecordByDate(betRecordByTimeDTO, 1); // yesterday + public Boolean getBetRecordByHistoryTime(BetRecordByTimeDTO requestDTO) { + Long lend = requestDTO.getEndTime(); + Long lstart = requestDTO.getStartTime(); + //betRecordByTimeDTO.setStartTime(lstart); + //betRecordByTimeDTO.setEndTime(lend); - return true; + 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; } @@ -456,8 +590,7 @@ public class FBSportsServiceImpl implements IGamesService { */ @Override public GetGameDetailResponseDTO getGameDetail(GetGameDetailRequestDTO getGameDetailRequestDTO) { - - return null; + throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); } /** @@ -516,23 +649,22 @@ public class FBSportsServiceImpl implements IGamesService { throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode()); } - /** * 批量插入 * - * @param recordResponse 投注记录 + * @param settledOrderList 投注记录 */ - private void batchInsert(MeiTianBetRecordResponseDTO recordResponse, BetRecordByTimeDTO betRecordByTimeDTO) { + private void batchInsert(List settledOrderList, BetRecordByTimeDTO betRecordByTimeDTO) { List gameBettingDetails = new ArrayList<>(); List wagersIds = new ArrayList<>(); //数据组装 - List dataList = recordResponse.getDataList(); + List dataList = settledOrderList; if (CollectionUtils.isEmpty(dataList)) { return; } //数据转化 - for (MeiTianBetRecordResponseDTO.DataBean dataBean : dataList) { + for (OrderInfoResponse.OrderDTO dataBean : dataList) { GameBettingDetails bettingDetails = this.dataBuild(GamesDataBuildDTO.builder() .platform(betRecordByTimeDTO.getVendor()) .data(dataBean).build()); @@ -540,20 +672,21 @@ public class FBSportsServiceImpl implements IGamesService { bettingDetails.setId(IdUtil.getSnowflakeNextId()); gameBettingDetails.add(bettingDetails); } - wagersIds.add(dataBean.getRowID()); + 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)) { - //查询重复数据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); - } + gameBettingDetailsService.batchInsert(gameBettingDetails); } - } /** @@ -566,49 +699,44 @@ public class FBSportsServiceImpl implements IGamesService { 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()); + OrderInfoResponse.OrderDTO dataBean = (OrderInfoResponse.OrderDTO) gamesDataBuildDTO.getData(); + Member member = memberService.selectMemberByGameAccount(dataBean.getMerchantUserId()); 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()); // 这个值是到手的 + 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(BigDecimal.ZERO); - long gameTime = TimestampFromString.from(dataBean.getGameDate()); + 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()); + String systemCurrency = platform.getOurCurrency(dataBean.getCurrency().toString()); //数据构造 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()) + .gameCode(game.getGameCode()) + .gameType(8) // 体育 + .platformCode(GamePlatforms.FBSports.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()) - .account(dataBean.getPlayerName()) - .wagersId(dataBean.getRowID()) - .wagersTime(gameTime) - .betAmount(new BigDecimal(dataBean.getBetAmount())) - .payoffTime(gameTime) + .gameCurrencyCode(dataBean.getCurrency().toString()) + .account(dataBean.getMerchantUserId()) + .wagersId(dataBean.getId()) + .wagersTime(createTime) + .betAmount(betAmount) + .payoffTime(payoffTime) .payoffAmount(originPayoffAmount.abs()) - .settlementTime(gameTime) - .turnover(new BigDecimal(dataBean.getCommissionable())) - .orderNo(dataBean.getRowID()) + .settlementTime(payoffTime) + .turnover(betAmount) + .orderNo(dataBean.getId()) .settlementStatus(SettlementStatusEnum.COMPLETED.getCode()) .build(); gameBettingDetails.setCreateBy(Constants.SYSTEM); diff --git a/ff-game/src/main/java/com/ff/utils/TimestampFromString.java b/ff-game/src/main/java/com/ff/utils/TimestampFromString.java index 0280b2c..8a3ddd6 100644 --- a/ff-game/src/main/java/com/ff/utils/TimestampFromString.java +++ b/ff-game/src/main/java/com/ff/utils/TimestampFromString.java @@ -20,4 +20,8 @@ public class TimestampFromString { return 0L; } } + + public static Long to(String timestamp) { + return Long.parseLong(timestamp); + } }