Merge branch 'main-meitian' into main-pgt
# Conflicts: # ff-base/src/main/java/com/ff/base/enums/ErrorCode.java # ff-game/src/main/java/com/ff/common/service/impl/TenantGameQuotaServiceImpl.javamain-pgt
commit
9fa259268e
|
|
@ -92,6 +92,15 @@ public class CacheConstants {
|
|||
* dg游戏
|
||||
*/
|
||||
public static final String DG_GAMES = "dg_games:";
|
||||
/**
|
||||
* fb体育
|
||||
*/
|
||||
public static final String FB_Sports = "fp_sports:";
|
||||
|
||||
/**
|
||||
* db体育
|
||||
*/
|
||||
public static final String DB_Sports = "db_sports:";
|
||||
/**
|
||||
* pg游戏投注货币
|
||||
*/
|
||||
|
|
@ -121,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:";
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -20,8 +20,8 @@ public enum ErrorCode {
|
|||
CURRENCY_NOT_EXIST(1004, "游戏平台不支持的货币"),
|
||||
GAME_NOT_EXIST(1005, "游戏不存在"),
|
||||
CURRENCY_EXCHANGE(1006, "不支持币种的汇率"),
|
||||
FREQUENT_INTERFACE_REQUESTS (1007, "接口请求频繁"),
|
||||
BALANCE_TRANSFER_FAILED (1008, "余额转移失败"),
|
||||
FREQUENT_INTERFACE_REQUESTS(1007, "接口请求频繁"),
|
||||
BALANCE_TRANSFER_FAILED(1008, "余额转移失败"),
|
||||
LANG_NOT_EXIST(1009, "游戏平台不支持的语言"),
|
||||
ORDER_NOT_EXIST(1010, "订单不存在"),
|
||||
PLAYERS_ARE_PLAYING(1011, "玩家游玩中"),
|
||||
|
|
@ -30,7 +30,14 @@ public enum ErrorCode {
|
|||
ACCOUNT_NOT_ONLINE(1014, "账号不在线"),
|
||||
FREQUENT_BALANCE_TRANSFER(1015, "当前游戏账号余额转移频繁"),
|
||||
PLATFORM_NOT_METHODS(1016, "游戏平台不支持的方法"),
|
||||
DUPLICATE_ORDER_ID (1017, "重复的订单id"),
|
||||
Create_Member_Failure(1017, "创建会员失败"),
|
||||
Transfer_In_Failure(1018, "转入失败"),
|
||||
Transfer_Out_Failure(1019, "转出失败"),
|
||||
Get_Member_Info_Failure(1020, "获取会员信息失败"),
|
||||
Transfer_Not_Exist(1021, "转帐操作不存在"),
|
||||
Get_Url_Failure(1022, "获取URL失败"),
|
||||
Miss_Config(1023, "缺少配置"),
|
||||
DUPLICATE_ORDER_ID (1024, "重复的订单id"),
|
||||
;
|
||||
|
||||
// 获取错误码
|
||||
|
|
|
|||
|
|
@ -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<Integer> 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<String> system = Stream.of(FBSportsType.values())
|
||||
.filter(gameType -> gameType.getCode().equals(code))
|
||||
.map(FBSportsType::getInfo)
|
||||
.findFirst();
|
||||
return system.orElse(null);
|
||||
}
|
||||
}
|
||||
|
|
@ -17,7 +17,9 @@ public enum GamePlatforms {
|
|||
AE("AE", "AE"),
|
||||
KM("KM", "KM"),
|
||||
PGT("PGT", "PGT"),
|
||||
;
|
||||
FBSports("FBSports", "FB体育"),
|
||||
SV388("SV388", "SV388真人"),
|
||||
DBSports("DBSports", "DB体育");
|
||||
|
||||
private final String code;
|
||||
private final String info;
|
||||
|
|
|
|||
|
|
@ -83,9 +83,6 @@ public class ApiGameController extends BaseController {
|
|||
@Resource
|
||||
private ITenantGameQuotaService tenantGameQuotaService;
|
||||
|
||||
@Resource
|
||||
private ITenantGameQuotaFlowService tenantGameQuotaFlowService;
|
||||
|
||||
@Resource
|
||||
private IGameBettingDetailsService gameBettingDetailsService;
|
||||
|
||||
|
|
|
|||
|
|
@ -289,14 +289,11 @@ public class TenantGameQuotaServiceImpl implements ITenantGameQuotaService {
|
|||
ApiException.notNull(tenantPlatform, ErrorCode.PLATFORM_NOT_EXIST.getCode());
|
||||
|
||||
|
||||
|
||||
// 获取用户信息
|
||||
Member member = memberService.selectMemberByAccount(gameBalanceExchange.getAccount(), gameBalanceExchange.getCurrencyCode(), gameBalanceExchange.getPlatformCode());
|
||||
ApiException.notNull(member, ErrorCode.ACCOUNT_NOT_EXIST.getCode());
|
||||
|
||||
|
||||
|
||||
|
||||
// 检查用户是否存在,否则抛出异常
|
||||
ApiException.notNull(member, ErrorCode.ACCOUNT_NOT_EXIST.getCode());
|
||||
|
||||
|
|
@ -326,6 +323,9 @@ public class TenantGameQuotaServiceImpl implements ITenantGameQuotaService {
|
|||
.agentKey(gameBalanceExchange.getAgentKey())
|
||||
.build();
|
||||
balanceRequestAmount = iGamesService.getMemberInfo(gamesBaseRequestDTO).getBalance();
|
||||
if (balanceRequestAmount.compareTo(BigDecimal.ZERO) <= 0) {
|
||||
throw new ApiException(ErrorCode.INSUFFICIENT_PLAYER_BALANCE.getCode());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -390,12 +390,10 @@ public class TenantGameQuotaServiceImpl implements ITenantGameQuotaService {
|
|||
// 如果是扣账操作,首先处理假额度
|
||||
String falseTenantQuotaType = QuotaUtils.getFalseTenantQuota(gameBalanceExchange.getPlatformCode(), gameBalanceExchange.getCurrencyCode());
|
||||
TenantGameQuota falseTenantQuota = selectTenantGameQuotaByTenantKey(tenantSecretKey.getTenantKey(), falseTenantQuotaType);
|
||||
balanceRequestAmount = NumberUtil.add(gameBalanceExchange.getAmount(), NumberUtil.mul(gameBalanceExchange.getAmount(), NumberUtil.div(tenantPlatform.getUseCost(), Constants.HUNDRED)));
|
||||
balanceRequestAmount = NumberUtil.add(gameBalanceExchange.getAmount(), NumberUtil.mul(gameBalanceExchange.getAmount(), NumberUtil.div(tenantPlatform.getUseCost(), Constants.HUNDRED)));
|
||||
if (falseTenantQuota.getBalance().compareTo(BigDecimal.ZERO) > 0) {
|
||||
|
||||
|
||||
|
||||
|
||||
BigDecimal falseQuotaBalance = falseTenantQuota.getBalance();
|
||||
if (falseQuotaBalance.compareTo(balanceRequestAmount) >= 0) {
|
||||
// 假额度足够扣除本次所需金额
|
||||
|
|
|
|||
|
|
@ -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<DelayTask> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
@ -16,10 +16,13 @@ import com.ff.base.utils.uuid.IdUtils;
|
|||
import com.ff.common.dto.GameBalanceExchange;
|
||||
import com.ff.common.service.ITenantGameQuotaService;
|
||||
import com.ff.config.KeyConfig;
|
||||
import com.ff.delay.DelayService;
|
||||
import com.ff.delay.DelayTask;
|
||||
import com.ff.game.api.IGamesService;
|
||||
import com.ff.game.api.ae.client.AEClient;
|
||||
import com.ff.game.api.ae.dto.*;
|
||||
import com.ff.game.api.request.*;
|
||||
import com.ff.game.api.sv388.impl.SV388GamesServiceImpl;
|
||||
import com.ff.game.api.xk.dto.XKKickMemberDTO;
|
||||
import com.ff.game.domain.*;
|
||||
import com.ff.game.service.IGameBettingDetailsService;
|
||||
|
|
@ -79,6 +82,9 @@ public class GamesAEServiceImpl implements IGamesService {
|
|||
@Resource
|
||||
private IGameBettingDetailsService gameBettingDetailsService;
|
||||
|
||||
@Resource
|
||||
private DelayService delayService;
|
||||
|
||||
/**
|
||||
* 游戏id
|
||||
*/
|
||||
|
|
@ -319,15 +325,20 @@ public class GamesAEServiceImpl implements IGamesService {
|
|||
.build();
|
||||
}
|
||||
|
||||
class GetRealtimeRecordTask extends DelayTask {
|
||||
BetRecordByTimeDTO betRecordByTimeDTO;
|
||||
|
||||
/**
|
||||
* 按时间获取投注记录
|
||||
*
|
||||
* @param betRecordByTimeDTO 按时间dto投注记录
|
||||
* @return {@link List }<{@link GameBettingDetails }>
|
||||
*/
|
||||
@Override
|
||||
public Boolean getBetRecordByTime(BetRecordByTimeDTO betRecordByTimeDTO) {
|
||||
public GetRealtimeRecordTask(BetRecordByTimeDTO betRecordByTimeDTO) {
|
||||
this.betRecordByTimeDTO = betRecordByTimeDTO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
getRealtimeRecord(betRecordByTimeDTO);
|
||||
}
|
||||
}
|
||||
|
||||
void getRealtimeRecord(BetRecordByTimeDTO betRecordByTimeDTO) {
|
||||
//请求参数
|
||||
log.info("GamesAEServiceImpl [getBetRecordByTime] 请求参数 {}", betRecordByTimeDTO);
|
||||
Map<String, Object> params = this.getKey(betRecordByTimeDTO);
|
||||
|
|
@ -347,23 +358,32 @@ public class GamesAEServiceImpl implements IGamesService {
|
|||
if (this.getIsSuccess(aeBetRecordResponse.getStatus())) {
|
||||
//数据组装
|
||||
this.batchInsert(aeBetRecordResponse, betRecordByTimeDTO);
|
||||
return Boolean.TRUE;
|
||||
if (aeBetRecordResponse.getTransactions().size() >= 20000) {
|
||||
delayService.addTask(new GetRealtimeRecordTask(betRecordByTimeDTO));
|
||||
}
|
||||
//return Boolean.TRUE;
|
||||
} else {
|
||||
redisCache.deleteObject(CacheConstants.AE_TIME_FROM);
|
||||
log.error("GamesAEServiceImpl [getBetRecordByTime] 获取投注记录失败,错误代码{},错误信息{}", aeBetRecordResponse.getStatus(), aeBetRecordResponse.getDesc());
|
||||
throw new BaseException(aeBetRecordResponse.getDesc());
|
||||
//throw new BaseException(aeBetRecordResponse.getDesc());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 按历史时间获取投注记录
|
||||
*
|
||||
* @param betRecordByTimeDTO 按时间dto投注记录
|
||||
* @return {@link Boolean }
|
||||
*/
|
||||
@Override
|
||||
public Boolean getBetRecordByHistoryTime(BetRecordByTimeDTO betRecordByTimeDTO) {
|
||||
class GetHistoryRecordTask extends DelayTask {
|
||||
BetRecordByTimeDTO betRecordByTimeDTO;
|
||||
|
||||
public GetHistoryRecordTask(BetRecordByTimeDTO betRecordByTimeDTO) {
|
||||
this.betRecordByTimeDTO = betRecordByTimeDTO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
getHistoryRecord(betRecordByTimeDTO);
|
||||
}
|
||||
}
|
||||
|
||||
void getHistoryRecord(BetRecordByTimeDTO betRecordByTimeDTO) {
|
||||
log.info("GamesAEServiceImpl [getBetRecordByHistoryTime] 请求参数 {}", betRecordByTimeDTO);
|
||||
Map<String, Object> params = this.getKey(betRecordByTimeDTO);
|
||||
String startTime = DateUtils.convertTimestampToFormattedDate(betRecordByTimeDTO.getStartTime(), DateUtils.ISO_8601_FORMAT, "GMT+8") + "+08:00";
|
||||
|
|
@ -379,13 +399,40 @@ public class GamesAEServiceImpl implements IGamesService {
|
|||
if (this.getIsSuccess(aeBetRecordResponse.getStatus())) {
|
||||
//数据组装
|
||||
this.batchInsert(aeBetRecordResponse, betRecordByTimeDTO);
|
||||
return Boolean.TRUE;
|
||||
if (aeBetRecordResponse.getTransactions().size() >= 20000) {
|
||||
delayService.addTask(new GetHistoryRecordTask(betRecordByTimeDTO));
|
||||
}
|
||||
// return Boolean.TRUE;
|
||||
} else {
|
||||
log.error("GamesAEServiceImpl [getBetRecordByHistoryTime] 获取投注记录失败,错误代码{},错误信息{}", aeBetRecordResponse.getStatus(), aeBetRecordResponse.getDesc());
|
||||
throw new BaseException(aeBetRecordResponse.getDesc());
|
||||
// throw new BaseException(aeBetRecordResponse.getDesc());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 按时间获取投注记录
|
||||
*
|
||||
* @param betRecordByTimeDTO 按时间dto投注记录
|
||||
* @return {@link List }<{@link GameBettingDetails }>
|
||||
*/
|
||||
@Override
|
||||
public Boolean getBetRecordByTime(BetRecordByTimeDTO betRecordByTimeDTO) {
|
||||
delayService.addTask(new GetRealtimeRecordTask(betRecordByTimeDTO));
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 按历史时间获取投注记录
|
||||
*
|
||||
* @param betRecordByTimeDTO 按时间dto投注记录
|
||||
* @return {@link Boolean }
|
||||
*/
|
||||
@Override
|
||||
public Boolean getBetRecordByHistoryTime(BetRecordByTimeDTO betRecordByTimeDTO) {
|
||||
delayService.addTask(new GetHistoryRecordTask(betRecordByTimeDTO));
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 赠送免费局数
|
||||
*
|
||||
|
|
@ -558,7 +605,7 @@ public class GamesAEServiceImpl implements IGamesService {
|
|||
.gameCode(resultBean.getGameCode())
|
||||
.gameType(PlatformType.GAME_HALL.getCode())
|
||||
.platformCode(GamePlatforms.AE.getCode())
|
||||
.gameId(GAME_ID)
|
||||
.gameId(/*GAME_ID*/ StringUtils.addSuffix(GamePlatforms.AE.getCode(), 1))
|
||||
.gameName(resultBean.getGameName())
|
||||
.gameStatus(gameStatus)
|
||||
.gameStatusType(resultBean.getSettleStatus())
|
||||
|
|
|
|||
|
|
@ -553,7 +553,8 @@ public class GamesDGServiceImpl implements IGamesService {
|
|||
.gameCode(String.valueOf(resultBean.getGameId()))
|
||||
.gameType(PlatformType.CARD_GAME.getCode())
|
||||
.platformCode(GamePlatforms.DG.getCode())
|
||||
.gameId(GAME_ID)
|
||||
//.gameId(GAME_ID)
|
||||
.gameId(game.getGameId())
|
||||
.gameName(game.getGameName())
|
||||
.gameStatus(gameStatus)
|
||||
.gameStatusType(resultBean.getGameType())
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ public class ApiFCGameListResponseDTO {
|
|||
/**
|
||||
* 系统游戏id
|
||||
*/
|
||||
private Long systemGameId;
|
||||
private String systemGameId;
|
||||
/**
|
||||
* 游戏id
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -285,7 +285,7 @@ public class GamesFCServiceImpl implements IGamesService {
|
|||
game = games.get(0);
|
||||
|
||||
}
|
||||
gameDetails.setSystemGameId(game.getId());
|
||||
gameDetails.setSystemGameId(game.getGameId());
|
||||
gameDetails.setGameId(gameIdKey);
|
||||
gameDetailsList.add(gameDetails);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ public class JILIGamesDataDTO {
|
|||
/**
|
||||
*自己系统游戏id
|
||||
*/
|
||||
private Long systemGameId;
|
||||
private String systemGameId;
|
||||
|
||||
/**
|
||||
* 名称
|
||||
|
|
|
|||
|
|
@ -253,7 +253,7 @@ public class GamesJILIServiceImpl implements IGamesService {
|
|||
} else {
|
||||
game = games.get(0);
|
||||
}
|
||||
gamesDataDTO.setSystemGameId(game.getId());
|
||||
gamesDataDTO.setSystemGameId(game.getGameId());
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -788,7 +788,7 @@ public class GamesJILIServiceImpl implements IGamesService {
|
|||
.gameCode(jiliBetRecordDataResponseDTO.getGameId())
|
||||
.gameType(JILIGameType.findSystemByCode(jiliBetRecordDataResponseDTO.getGameCategoryId()))
|
||||
.platformCode(GamePlatforms.JILI.getInfo())
|
||||
.gameId(gamesDataDTO.getSystemGameId())
|
||||
.gameId(/*gamesDataDTO.getSystemGameId()*/gamesDataDTO.getSystemGameId())
|
||||
.gameName(gamesDataDTO.getName().getZhCN())
|
||||
.gameStatus(jiliBetRecordDataResponseDTO.getStatus())
|
||||
.gameStatusType(jiliBetRecordDataResponseDTO.getType())
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ public class KMGameResponse {
|
|||
/**
|
||||
* 系统游戏id
|
||||
*/
|
||||
private Long systemGameId;
|
||||
private String systemGameId;
|
||||
|
||||
/**
|
||||
* 游戏是否提供试玩
|
||||
|
|
|
|||
|
|
@ -302,7 +302,7 @@ public class GamesKMServiceImpl implements IGamesService {
|
|||
} else {
|
||||
game = games.get(0);
|
||||
}
|
||||
gamesDataDTO.setSystemGameId(game.getId());
|
||||
gamesDataDTO.setSystemGameId(game.getGameId());
|
||||
}
|
||||
return gameList.getGames();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ public class MeiTianGameDataDTO {
|
|||
/**
|
||||
*自己系统游戏id
|
||||
*/
|
||||
private Long systemGameId;
|
||||
private String systemGameId;
|
||||
private String gameId;
|
||||
private String cnName;
|
||||
private String enName;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
/**
|
||||
* 获得就是成功
|
||||
*
|
||||
|
|
@ -245,8 +248,7 @@ public class MeiTianGameServiceImpl implements IGamesService {
|
|||
} else {
|
||||
game = games.get(0);
|
||||
}
|
||||
gamesDataDTO.setSystemGameId(game.getId());
|
||||
|
||||
gamesDataDTO.setSystemGameId(game.getGameId());
|
||||
}
|
||||
|
||||
redisCache.deleteObject(CacheConstants.MeiTian_GAMES);
|
||||
|
|
@ -276,7 +278,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())
|
||||
|
|
@ -316,7 +318,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));
|
||||
|
|
@ -349,7 +351,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));
|
||||
|
|
@ -389,7 +391,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();
|
||||
|
|
@ -403,6 +405,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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 按时间获取投注记录
|
||||
*
|
||||
|
|
@ -411,18 +441,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<String, Object> rawMap = new LinkedHashMap<>();
|
||||
rawMap.put("recordID", recordID);
|
||||
|
|
@ -448,7 +481,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);
|
||||
|
|
@ -457,7 +492,7 @@ public class MeiTianGameServiceImpl implements IGamesService {
|
|||
} else {
|
||||
config.setConfigValue(dataBean.getRecordID());
|
||||
sysConfigServiceImpl.updateConfig(config);
|
||||
}
|
||||
}*/
|
||||
// 它每次返回25000条,所以需要判断,如果大于25000条,则继续拉取
|
||||
if (dataList.size() >= 25000) {
|
||||
doSyncRecordByRecordID(betRecordByTimeDTO);
|
||||
|
|
@ -473,22 +508,7 @@ public class MeiTianGameServiceImpl implements IGamesService {
|
|||
|
||||
String date = getDateStr(daysToSubtract);
|
||||
String configKey = GamePlatforms.MT.getCode() + ":lastSyncDate";
|
||||
String syncDateStr = sysConfigServiceImpl.selectConfigByKey(configKey);
|
||||
Map<String, Long> 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<String, Object> rawMap = new LinkedHashMap<>();
|
||||
rawMap.put("rowID", recordID);
|
||||
|
|
@ -516,8 +536,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);
|
||||
|
|
@ -526,7 +547,7 @@ public class MeiTianGameServiceImpl implements IGamesService {
|
|||
} else {
|
||||
config.setConfigValue(JSON.toJSONString(syncDateMap));
|
||||
sysConfigServiceImpl.updateConfig(config);
|
||||
}
|
||||
}*/
|
||||
|
||||
// 它每次返回25000条,所以需要判断,如果大于25000条,则继续拉取
|
||||
if (dataList.size() >= 25000) {
|
||||
|
|
@ -547,9 +568,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;
|
||||
}
|
||||
|
||||
|
|
@ -779,10 +801,6 @@ public class MeiTianGameServiceImpl implements IGamesService {
|
|||
}
|
||||
}
|
||||
|
||||
public LocalDate getDate(int daysToSubtract) {
|
||||
return LocalDate.now().minusDays(daysToSubtract); // 获取当前日期减去两天
|
||||
}
|
||||
|
||||
public String getDateStr(int daysToSubtract) {
|
||||
// 获取当前日期减去指定天数
|
||||
LocalDate date = LocalDate.now().minusDays(daysToSubtract);
|
||||
|
|
|
|||
|
|
@ -685,7 +685,7 @@ public class GamesPGServiceImpl implements IGamesService {
|
|||
.gameCode(gamesDataDTO.getGameCode())
|
||||
.gameType(NGGameType.findSystemByCode(resultBean.getGameType()))
|
||||
.platformCode(NGPlatforms.getByCode(resultBean.getPlatType()).getPlatform())
|
||||
.gameId(gamesDataDTO.getId())
|
||||
.gameId(gamesDataDTO.getGameId())
|
||||
.gameName(gamesDataDTO.getGameName())
|
||||
.gameStatus(gameStatus)
|
||||
.gameStatusType(1)
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ public class PGTGameListResponse {
|
|||
/**
|
||||
* 系统游戏id
|
||||
*/
|
||||
private Long systemGameId;
|
||||
private String systemGameId;
|
||||
|
||||
/**
|
||||
* 游戏排名
|
||||
|
|
|
|||
|
|
@ -244,7 +244,7 @@ public class GamesPGTServiceImpl implements IGamesService {
|
|||
} else {
|
||||
game = games.get(0);
|
||||
}
|
||||
gameIdKey.setSystemGameId(game.getId());
|
||||
gameIdKey.setSystemGameId(game.getGameId());
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -619,6 +619,7 @@ public class GamesPGTServiceImpl implements IGamesService {
|
|||
.gameCode(resultBean.getGameCode())
|
||||
.gameType(PGTGameType.findSystemByCode(gamesDataDTO.getCategory()))
|
||||
.platformCode(GamePlatforms.PGT.getCode())
|
||||
//.gameId(gamesDataDTO.getSystemGameId())
|
||||
.gameId(gamesDataDTO.getSystemGameId())
|
||||
.gameName(gamesDataDTO.getName())
|
||||
.gameStatus(PGTPayoutStatus.getByCode(resultBean.getPayoutStatus()).getSystemCode())
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ public class PGXGameListResponse {
|
|||
/**
|
||||
* 系统游戏id
|
||||
*/
|
||||
private Long systemGameId;
|
||||
private String systemGameId;
|
||||
|
||||
/** 游戏代码 (字符串类型) */
|
||||
@JsonProperty("gameCode")
|
||||
|
|
|
|||
|
|
@ -252,7 +252,7 @@ public class GamesPGXServiceImpl implements IGamesService {
|
|||
} else {
|
||||
game = games.get(0);
|
||||
}
|
||||
gamesDataDTO.setSystemGameId(game.getId());
|
||||
gamesDataDTO.setSystemGameId(game.getGameId());
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import lombok.NoArgsConstructor;
|
|||
import lombok.experimental.SuperBuilder;
|
||||
|
||||
/**
|
||||
* 创建成员请求dto
|
||||
* 查询用户信息
|
||||
*
|
||||
* @author shi
|
||||
* @date 2024/10/22
|
||||
|
|
@ -19,7 +19,7 @@ public class MemberInfoRequestDTO extends GamesBaseRequestDTO {
|
|||
/**
|
||||
* 账户
|
||||
*/
|
||||
private String accounts;
|
||||
private String accounts;
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -582,7 +582,7 @@ public class GamesSAServiceImpl implements IGamesService {
|
|||
.gameCode(resultBean.getGameID())
|
||||
.gameType(PlatformType.CARD_GAME.getCode())
|
||||
.platformCode(GamePlatforms.SA.getInfo())
|
||||
.gameId(GAME_ID)
|
||||
.gameId(/*GAME_ID*/game.getGameId())
|
||||
.gameName(game.getGameName())
|
||||
.gameStatus(gameStatus)
|
||||
.gameStatusType(1)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
package com.ff.game.api.sv388.address;
|
||||
|
||||
import com.dtflys.forest.callback.AddressSource;
|
||||
import com.dtflys.forest.http.ForestAddress;
|
||||
import com.dtflys.forest.http.ForestRequest;
|
||||
import com.ff.base.enums.GamePlatforms;
|
||||
import com.ff.game.service.IPlatformService;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
|
||||
/**
|
||||
* 我jili address来源
|
||||
*
|
||||
* @author shi
|
||||
* @date 2025/02/10
|
||||
*/
|
||||
@Component
|
||||
public class SV388Adrress implements AddressSource {
|
||||
|
||||
@Resource
|
||||
private IPlatformService platformService;
|
||||
|
||||
@Override
|
||||
public ForestAddress getAddress(ForestRequest request) {
|
||||
String apiBaseUrl = platformService.get(GamePlatforms.SV388.getCode())
|
||||
.getUrlInfo().getUrl();
|
||||
return new ForestAddress("https", apiBaseUrl, 443, "");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,136 @@
|
|||
package com.ff.game.api.sv388.client;
|
||||
|
||||
import com.dtflys.forest.annotation.*;
|
||||
import com.ff.game.api.jili.dto.JILIExchangeMoneyResponseDTO;
|
||||
import com.ff.game.api.jili.dto.JILIKickMemberAllDTO;
|
||||
import com.ff.game.api.jili.dto.JILIKickMemberDTO;
|
||||
import com.ff.game.api.sv388.address.SV388Adrress;
|
||||
import com.ff.game.api.sv388.dto.*;
|
||||
import com.ff.game.api.xk.dto.XKKickMemberAllDTO;
|
||||
import com.ff.game.api.xk.dto.XKKickMemberDTO;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* xk 请求
|
||||
*
|
||||
* @author shi
|
||||
* @date 2025/02/10
|
||||
*/
|
||||
@Address(source = SV388Adrress.class)
|
||||
public interface SV388Client {
|
||||
/**
|
||||
* 创建成员
|
||||
*
|
||||
* @param params 参数
|
||||
* @return {@link String }
|
||||
*/
|
||||
@Post(url ="/wallet/createMember",
|
||||
headers = {
|
||||
"Content-type: application/x-www-form-urlencoded"
|
||||
})
|
||||
SV388Response createMember(@Body Map<String, Object> params);
|
||||
|
||||
/**
|
||||
* 获取会员信息
|
||||
*
|
||||
* @param params 参数
|
||||
* @return {@link SV388MemberInfo }
|
||||
*/
|
||||
@Post(url ="/wallet/getBalance",
|
||||
headers = {
|
||||
"Content-type: application/x-www-form-urlencoded"
|
||||
})
|
||||
SV388MemberInfo getMemberInfo(@Body Map<String, Object> params);
|
||||
|
||||
/**
|
||||
* 无重定向登录
|
||||
*
|
||||
* @param params 参数
|
||||
* @return {@link SV388LoginResponse }
|
||||
*/
|
||||
@Post("/wallet/login")
|
||||
SV388LoginResponse loginWithoutRedirect(@Body Map<String, Object> params);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 按代理id进行交换转账
|
||||
*
|
||||
* @param params 参数
|
||||
* @return {@link JILIExchangeMoneyResponseDTO }
|
||||
*/
|
||||
@Post(url ="/wallet/deposit",
|
||||
headers = {
|
||||
"Content-type: application/x-www-form-urlencoded"
|
||||
})
|
||||
SV388AETransactionResponse deposit(@Body Map<String, Object> params);
|
||||
|
||||
|
||||
@Post(url ="/wallet/withdraw",
|
||||
headers = {
|
||||
"Content-type: application/x-www-form-urlencoded"
|
||||
})
|
||||
SV388AETransactionResponse withdraw(@Body Map<String, Object> params);
|
||||
|
||||
|
||||
/**
|
||||
* 汇兑转移状态
|
||||
*
|
||||
* @param params 参数
|
||||
* @return {@link SV388ExchangeTransferStatusResponse }
|
||||
*/
|
||||
@Post(url ="/wallet/checkTransferOperation",
|
||||
headers = {
|
||||
"Content-type: application/x-www-form-urlencoded"
|
||||
})
|
||||
SV388ExchangeTransferStatusResponse exchangeTransferStatus(@Body Map<String, Object> params);
|
||||
|
||||
/**
|
||||
* 按时间获取投注记录
|
||||
*
|
||||
* @param params 参数
|
||||
* @return {@link SV388BetRecordResponse }
|
||||
*/
|
||||
@Post(url ="{fetchUrl}/fetch/gzip/getTransactionByUpdateDate",
|
||||
headers = {
|
||||
"Content-type: application/x-www-form-urlencoded"
|
||||
})
|
||||
SV388BetRecordResponse getBetRecordByTime(@Body Map<String, Object> params,
|
||||
@Var("fetchUrl") String fetchUrl);
|
||||
|
||||
/**
|
||||
* 按时间获取投注历史记录
|
||||
*
|
||||
* @param params 参数
|
||||
* @return {@link SV388BetRecordResponse }
|
||||
*/
|
||||
@Post(url ="{fetchUrl}/fetch/gzip/getTransactionByTxTime",
|
||||
headers = {
|
||||
"Content-type: application/x-www-form-urlencoded"
|
||||
})
|
||||
SV388BetRecordResponse getBetHistoryRecordByTime(@Body Map<String, Object> params,
|
||||
@Var("fetchUrl") String fetchUrl);
|
||||
/**
|
||||
* 踢出队员
|
||||
*
|
||||
* @param params 参数
|
||||
* @return {@link JILIKickMemberDTO }
|
||||
*/
|
||||
@Post(url ="/wallet/logout",
|
||||
headers = {
|
||||
"Content-type: application/x-www-form-urlencoded"
|
||||
})
|
||||
XKKickMemberDTO kickMember(@Body Map<String, Object> params);
|
||||
|
||||
/**
|
||||
* 踢出所有队员
|
||||
*
|
||||
* @param params 参数
|
||||
* @return {@link JILIKickMemberAllDTO }
|
||||
*/
|
||||
@Get("/kickMemberAll")
|
||||
XKKickMemberAllDTO kickMemberAll(@JSONBody Map<String, Object> params);
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
package com.ff.game.api.sv388.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.ZonedDateTime;
|
||||
|
||||
/**
|
||||
* 电子交易响应
|
||||
*
|
||||
* @author shi
|
||||
* @date 2025/04/01
|
||||
*/
|
||||
@Data
|
||||
public class SV388AETransactionResponse {
|
||||
|
||||
/**
|
||||
* 响应状态
|
||||
*/
|
||||
@JsonProperty("status")
|
||||
private String status;
|
||||
|
||||
|
||||
/**
|
||||
* 金额
|
||||
*/
|
||||
@JsonProperty("amount")
|
||||
private BigDecimal amount;
|
||||
|
||||
/**
|
||||
* 交易方法(如:DEPOSIT, WITHDRAW)
|
||||
*/
|
||||
@JsonProperty("method")
|
||||
private String method;
|
||||
|
||||
/**
|
||||
* 数据库ID
|
||||
*/
|
||||
@JsonProperty("databaseId")
|
||||
private int databaseId;
|
||||
|
||||
/**
|
||||
* 当前余额
|
||||
*/
|
||||
@JsonProperty("currentBalance")
|
||||
private BigDecimal currentBalance;
|
||||
|
||||
/**
|
||||
* 最后修改时间
|
||||
*/
|
||||
@JsonProperty("lastModified")
|
||||
private ZonedDateTime lastModified;
|
||||
|
||||
/**
|
||||
* 交易代码
|
||||
*/
|
||||
@JsonProperty("txCode")
|
||||
private String txCode;
|
||||
}
|
||||
|
|
@ -0,0 +1,186 @@
|
|||
package com.ff.game.api.sv388.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* sv388记录响应
|
||||
*
|
||||
* @author shi
|
||||
* @date 2025/04/01
|
||||
*/
|
||||
@Data
|
||||
public class SV388BetRecordResponse {
|
||||
|
||||
/**
|
||||
* 状态代码
|
||||
*/
|
||||
@JsonProperty("status")
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 描述信息 (String类型)
|
||||
* "Success" - 请求成功
|
||||
* 其他 - 错误信息
|
||||
*/
|
||||
private String desc;
|
||||
/**
|
||||
* 交易记录
|
||||
*/
|
||||
@JsonProperty("transactions")
|
||||
private List<Transaction> transactions;
|
||||
|
||||
@Data
|
||||
public static class Transaction {
|
||||
|
||||
/**
|
||||
* 游戏类型
|
||||
*/
|
||||
@JsonProperty("gameType")
|
||||
private String gameType;
|
||||
|
||||
/**
|
||||
* 返还金额(包含下注金额)
|
||||
*/
|
||||
@JsonProperty("winAmount")
|
||||
private BigDecimal winAmount;
|
||||
|
||||
/**
|
||||
* 交易时间
|
||||
*/
|
||||
@JsonProperty("txTime")
|
||||
private Date txTime;
|
||||
|
||||
/**
|
||||
* 结算状态
|
||||
*/
|
||||
@JsonProperty("settleStatus")
|
||||
private Integer settleStatus;
|
||||
|
||||
/**
|
||||
* 游戏信息
|
||||
*/
|
||||
@JsonProperty("gameInfo")
|
||||
private String gameInfo;
|
||||
|
||||
/**
|
||||
* 真实返还金额
|
||||
*/
|
||||
@JsonProperty("realWinAmount")
|
||||
private BigDecimal realWinAmount;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
@JsonProperty("updateTime")
|
||||
private String updateTime;
|
||||
|
||||
/**
|
||||
* 真实下注金额
|
||||
*/
|
||||
@JsonProperty("realBetAmount")
|
||||
private BigDecimal realBetAmount;
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
@JsonProperty("userId")
|
||||
private String userId;
|
||||
|
||||
/**
|
||||
* 下注类型
|
||||
*/
|
||||
@JsonProperty("betType")
|
||||
private String betType;
|
||||
|
||||
/**
|
||||
* 平台名称
|
||||
*/
|
||||
@JsonProperty("platform")
|
||||
private String platform;
|
||||
|
||||
/**
|
||||
* 交易状态
|
||||
*/
|
||||
@JsonProperty("txStatus")
|
||||
private Integer txStatus;
|
||||
|
||||
/**
|
||||
* 下注金额
|
||||
*/
|
||||
@JsonProperty("betAmount")
|
||||
private BigDecimal betAmount;
|
||||
|
||||
/**
|
||||
* 游戏名称
|
||||
*/
|
||||
@JsonProperty("gameName")
|
||||
private String gameName;
|
||||
|
||||
/**
|
||||
* 平台注单号
|
||||
*/
|
||||
@JsonProperty("platformTxId")
|
||||
private String platformTxId;
|
||||
|
||||
/**
|
||||
* 下注时间
|
||||
*/
|
||||
@JsonProperty("betTime")
|
||||
private Date betTime;
|
||||
|
||||
/**
|
||||
* 平台游戏代码
|
||||
*/
|
||||
@JsonProperty("gameCode")
|
||||
private String gameCode;
|
||||
|
||||
/**
|
||||
* 玩家货币代码
|
||||
*/
|
||||
@JsonProperty("currency")
|
||||
private String currency;
|
||||
|
||||
/**
|
||||
* 累积奖金的获胜金额
|
||||
*/
|
||||
@JsonProperty("jackpotWinAmount")
|
||||
private BigDecimal jackpotWinAmount;
|
||||
|
||||
/**
|
||||
* 累积奖金贡献金额
|
||||
*/
|
||||
@JsonProperty("jackpotBetAmount")
|
||||
private BigDecimal jackpotBetAmount;
|
||||
|
||||
/**
|
||||
* 平台有效投注
|
||||
*/
|
||||
@JsonProperty("turnover")
|
||||
private BigDecimal turnover;
|
||||
|
||||
/**
|
||||
* 游戏商的回合识别码
|
||||
*/
|
||||
@JsonProperty("roundId")
|
||||
private String roundId;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 子注单号
|
||||
*/
|
||||
@JsonProperty("refPlatformTxId")
|
||||
private String refPlatformTxId;
|
||||
|
||||
/**
|
||||
* 是否为特殊收费游戏
|
||||
*/
|
||||
@JsonProperty("isPremium")
|
||||
private Boolean isPremium;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
package com.ff.game.api.sv388.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
|
||||
/**
|
||||
* aeexchange传输状态响应
|
||||
*
|
||||
* @author shi
|
||||
* @date 2025/04/01
|
||||
*/
|
||||
@Data
|
||||
public class SV388ExchangeTransferStatusResponse {
|
||||
|
||||
/**
|
||||
* 响应状态
|
||||
*/
|
||||
@JsonProperty("status")
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 情境 1:响应 status = 0000 & txStatus = 1 表示存款/提款成功
|
||||
* 情境 2:响应 status = 0000 & txStatus = 0 表示存款/提款失败
|
||||
* 情境 3:响应 status = 0000 & txStatus = 2 表示存款/提款处理中,可 3 秒后调用 checkTransferOperation API 确认回覆直到 txStatus = 0 或 1 的回覆
|
||||
* 情境 4:响应 status = 1017 表示交易不存在
|
||||
*/
|
||||
@JsonProperty("txStatus")
|
||||
private String txStatus;
|
||||
|
||||
/**
|
||||
* 当前余额
|
||||
*/
|
||||
@JsonProperty("balance")
|
||||
private BigDecimal balance;
|
||||
|
||||
/**
|
||||
* 转账金额
|
||||
*/
|
||||
@JsonProperty("transferAmount")
|
||||
private BigDecimal transferAmount;
|
||||
|
||||
/**
|
||||
* 转账类型(如:DEPOSIT 或 WITHDRAW)
|
||||
*/
|
||||
@JsonProperty("transferType")
|
||||
private String transferType;
|
||||
|
||||
/**
|
||||
* 交易代码
|
||||
*/
|
||||
@JsonProperty("txCode")
|
||||
private String txCode;
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
package com.ff.game.api.sv388.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* aelogin回应
|
||||
*
|
||||
* @author shi
|
||||
* @date 2025/04/01
|
||||
*/
|
||||
@Data
|
||||
public class SV388LoginResponse {
|
||||
/**
|
||||
* 响应状态
|
||||
*/
|
||||
@JsonProperty("status")
|
||||
private Integer status;
|
||||
|
||||
|
||||
/**
|
||||
* 描述信息 (String类型)
|
||||
* "Success" - 请求成功
|
||||
* 其他 - 错误信息
|
||||
*/
|
||||
private String desc;
|
||||
|
||||
/**
|
||||
* 登录 URL
|
||||
*/
|
||||
@JsonProperty("url")
|
||||
private String url;
|
||||
|
||||
/**
|
||||
* 扩展字段,类型为列表,可以存储多项数据
|
||||
*/
|
||||
@JsonProperty("extension")
|
||||
private List<String> extension;
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
package com.ff.game.api.sv388.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 注销用户响应
|
||||
*
|
||||
* @author shi
|
||||
* @date 2025/04/01
|
||||
*/
|
||||
@Data
|
||||
public class SV388LogoutUserResponse {
|
||||
/**
|
||||
* 状态代码
|
||||
*/
|
||||
@JsonProperty("status")
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 已注销的用户列表
|
||||
*/
|
||||
@JsonProperty("logoutUsers")
|
||||
private List<String> logoutUsers;
|
||||
|
||||
/**
|
||||
* 用户数量
|
||||
*/
|
||||
@JsonProperty("count")
|
||||
private Integer count;
|
||||
}
|
||||
|
|
@ -0,0 +1,64 @@
|
|||
package com.ff.game.api.sv388.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* AEMEMBER信息
|
||||
*
|
||||
* @author shi
|
||||
* @date 2025/03/31
|
||||
*/
|
||||
@Data
|
||||
public class SV388MemberInfo {
|
||||
/**
|
||||
* 响应结果列表,包含用户信息
|
||||
*/
|
||||
@JsonProperty("results")
|
||||
private List<UserInfo> result;
|
||||
|
||||
/**
|
||||
* 记录数量
|
||||
*/
|
||||
@JsonProperty("count")
|
||||
private int count;
|
||||
|
||||
/**
|
||||
* 查询时间
|
||||
*/
|
||||
@JsonProperty("querytime")
|
||||
private Date queryTime;
|
||||
|
||||
/**
|
||||
* 响应状态
|
||||
*/
|
||||
@JsonProperty("status")
|
||||
private Integer status;
|
||||
|
||||
@Data
|
||||
public static class UserInfo {
|
||||
|
||||
/**
|
||||
* 用户ID
|
||||
*/
|
||||
@JsonProperty("userId")
|
||||
private String userId;
|
||||
|
||||
/**
|
||||
* 用户余额
|
||||
*/
|
||||
@JsonProperty("balance")
|
||||
private BigDecimal balance;
|
||||
|
||||
/**
|
||||
* 最后修改时间
|
||||
*/
|
||||
@JsonProperty("lastModified")
|
||||
private Date lastModified;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
package com.ff.game.api.sv388.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 航空响应
|
||||
*
|
||||
* @author shi
|
||||
* @date 2025/03/28
|
||||
*/
|
||||
@Data
|
||||
public class SV388Response {
|
||||
/**
|
||||
* 状态码 (String类型)
|
||||
* 0000 - 成功
|
||||
* 其他 - 错误状态码
|
||||
*/
|
||||
private String status;
|
||||
|
||||
/**
|
||||
* 描述信息 (String类型)
|
||||
* "Success" - 请求成功
|
||||
* 其他 - 错误信息
|
||||
*/
|
||||
private String desc;
|
||||
}
|
||||
|
|
@ -0,0 +1,642 @@
|
|||
package com.ff.game.api.sv388.impl;
|
||||
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.hutool.core.util.NumberUtil;
|
||||
import com.ff.base.constant.CacheConstants;
|
||||
import com.ff.base.constant.Constants;
|
||||
import com.ff.base.core.redis.RedisCache;
|
||||
import com.ff.base.enums.*;
|
||||
import com.ff.base.exception.base.ApiException;
|
||||
import com.ff.base.exception.base.BaseException;
|
||||
import com.ff.base.utils.DateUtils;
|
||||
import com.ff.base.utils.JsonUtil;
|
||||
import com.ff.base.utils.StringUtils;
|
||||
import com.ff.base.utils.uuid.IdUtils;
|
||||
import com.ff.delay.DelayService;
|
||||
import com.ff.delay.DelayTask;
|
||||
import com.ff.game.api.IGamesService;
|
||||
import com.ff.game.api.request.*;
|
||||
import com.ff.game.api.sv388.client.SV388Client;
|
||||
import com.ff.game.api.sv388.dto.*;
|
||||
import com.ff.game.api.xk.dto.XKKickMemberDTO;
|
||||
import com.ff.game.domain.*;
|
||||
import com.ff.game.service.IGameBettingDetailsService;
|
||||
import com.ff.game.service.IGameExchangeMoneyService;
|
||||
import com.ff.game.service.IGameService;
|
||||
import com.ff.member.domain.Member;
|
||||
import com.ff.member.service.IMemberService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
||||
/**
|
||||
* AE 游戏 impl
|
||||
*
|
||||
* @author shi
|
||||
* @date 2024/11/12
|
||||
*/
|
||||
@Service("SV388Service")
|
||||
@Slf4j
|
||||
public class SV388GamesServiceImpl implements IGamesService {
|
||||
|
||||
|
||||
@Resource
|
||||
private RedisCache redisCache;
|
||||
|
||||
@Resource
|
||||
private IGameExchangeMoneyService gameExchangeMoneyService;
|
||||
|
||||
@Resource
|
||||
private IGameService gameService;
|
||||
|
||||
@Resource
|
||||
private IMemberService memberService;
|
||||
|
||||
@Resource
|
||||
private SV388Client sv388Client;
|
||||
|
||||
@Resource
|
||||
private IGameBettingDetailsService gameBettingDetailsService;
|
||||
|
||||
@Resource
|
||||
private DelayService delayService;
|
||||
|
||||
/**
|
||||
* 游戏id
|
||||
*/
|
||||
private static final Long GAME_ID = 1122L;
|
||||
|
||||
|
||||
/**
|
||||
* 获得就是成功
|
||||
*
|
||||
* @param errorCode 错误代码
|
||||
* @return {@link Boolean }
|
||||
*/
|
||||
private Boolean getIsSuccess(Integer errorCode) {
|
||||
return 0 == errorCode;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取密钥
|
||||
*
|
||||
* @param gamesBaseRequestDTO 游戏请求dto
|
||||
* @return {@link Map }<{@link String }, {@link Object }>
|
||||
*/
|
||||
private Map<String, Object> getKey(GamesBaseRequestDTO gamesBaseRequestDTO) {
|
||||
Map<String, Object> params = new LinkedHashMap<>();
|
||||
params.put("cert", gamesBaseRequestDTO.getAgentKey());
|
||||
params.put("agentId", gamesBaseRequestDTO.getAgentId());
|
||||
return params;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建成员
|
||||
*
|
||||
* @param createMemberRequestDTO 创建成员请求dto
|
||||
* @return {@link Boolean }
|
||||
*/
|
||||
@Override
|
||||
public Boolean createMember(CreateMemberRequestDTO createMemberRequestDTO) {
|
||||
|
||||
Platform platform = createMemberRequestDTO.getVendor();
|
||||
Object o = platform.getExtInfo().getBetLimit().get(createMemberRequestDTO.getSystemCurrency());
|
||||
if (!(o instanceof Map)) {
|
||||
throw new ApiException(ErrorCode.Miss_Config.getCode());
|
||||
}
|
||||
Map<String, Object> betLimit = new HashMap<>();
|
||||
betLimit.put(GamePlatforms.SV388.getCode(), new HashMap<String, Object>() {{
|
||||
put("LIVE", new HashMap<String, Object>((Map<String, ?>) o) {{
|
||||
remove("@type");
|
||||
}});
|
||||
}}
|
||||
);
|
||||
Map<String, Object> params = this.getKey(createMemberRequestDTO);
|
||||
params.put("userId", createMemberRequestDTO.getAccount());
|
||||
params.put("currency", createMemberRequestDTO.getCurrency());
|
||||
params.put("betLimit", JsonUtil.objToString(betLimit));
|
||||
SV388Response aeResponse = sv388Client.createMember(params);
|
||||
String errorCode = aeResponse.getStatus();
|
||||
if (this.getIsSuccess(Integer.valueOf(errorCode))) {
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
//判断是否获取成功
|
||||
return Boolean.FALSE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取会员信息
|
||||
*
|
||||
* @param memberInfoRequestDTO 会员信息请求dto
|
||||
* @return {@link MemberInfoResponseDTO }
|
||||
*/
|
||||
@Override
|
||||
public MemberInfoResponseDTO getMemberInfo(MemberInfoRequestDTO memberInfoRequestDTO) {
|
||||
Map<String, Object> params = this.getKey(memberInfoRequestDTO);
|
||||
params.put("alluser", 0);
|
||||
params.put("userIds", memberInfoRequestDTO.getAccounts());
|
||||
SV388MemberInfo memberInfo = sv388Client.getMemberInfo(params);
|
||||
//判断是否获取成功
|
||||
if (this.getIsSuccess(memberInfo.getStatus())) {
|
||||
SV388MemberInfo.UserInfo userInfo = memberInfo.getResult().get(0);
|
||||
return MemberInfoResponseDTO.builder()
|
||||
.status(GameMemberStatus.UNKNOWN.getCode())
|
||||
.balance(userInfo.getBalance())
|
||||
.account(memberInfoRequestDTO.getAccounts())
|
||||
.build();
|
||||
} else {
|
||||
throw new ApiException(ErrorCode.ERROR.getCode());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 无重定向登录
|
||||
*
|
||||
* @param gamesLogin 游戏登录
|
||||
* @return {@link String }
|
||||
*/
|
||||
@Override
|
||||
public String loginWithoutRedirect(GamesLogin gamesLogin) {
|
||||
Map<String, Object> params = this.getKey(gamesLogin);
|
||||
params.put("userId", gamesLogin.getAccount());
|
||||
params.put("externalURL", gamesLogin.getHomeUrl());
|
||||
params.put("language", gamesLogin.getLang());
|
||||
params.put("betLimit", gamesLogin.getBetLimit());
|
||||
SV388LoginResponse aeLoginResponse = sv388Client.loginWithoutRedirect(params);
|
||||
//判断是否获取成功
|
||||
if (this.getIsSuccess(aeLoginResponse.getStatus())) {
|
||||
return aeLoginResponse.getUrl();
|
||||
} else {
|
||||
throw new BaseException(aeLoginResponse.getDesc());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取游戏列表
|
||||
*
|
||||
* @param gamesBaseRequestDTO 游戏请求dto
|
||||
* @return {@link String }
|
||||
*/
|
||||
@Transactional
|
||||
@Override
|
||||
public String getGameList(GamesBaseRequestDTO gamesBaseRequestDTO) {
|
||||
int platformType = PlatformType.VIDEO.getCode();
|
||||
Game condition = new Game();
|
||||
condition.setPlatformCode(GamePlatforms.SV388.getCode());
|
||||
condition.setPlatformType(platformType);
|
||||
List<Game> gameList = gameService.selectGameList(condition);
|
||||
Platform platform = gamesBaseRequestDTO.getVendor();
|
||||
//不存在这个游戏
|
||||
if (ObjectUtils.isEmpty(gameList)) {
|
||||
Game game = new Game();
|
||||
game.setId(IdUtil.getSnowflakeNextId());
|
||||
game.setSortNo(gameService.selectMaxSortNo(platformType, GamePlatforms.SV388.getCode()) + 1);
|
||||
game.setPlatformCode(platform.getPlatformCode());
|
||||
game.setPlatformType(platformType);
|
||||
game.setGameCode("1");
|
||||
game.setGameSourceType(String.valueOf(1));
|
||||
game.setGameName("SV388真人");
|
||||
game.setCreateBy(Constants.SYSTEM);
|
||||
NameInfo nameInfo = new NameInfo();
|
||||
nameInfo.setLang("zh-CN");
|
||||
nameInfo.setName("SV388真人");
|
||||
game.setNameInfo(Collections.singletonList(nameInfo));
|
||||
game.setGameId(StringUtils.addSuffix(GamePlatforms.SV388.getCode(), 1));
|
||||
gameService.insertGame(game);
|
||||
}
|
||||
return CacheConstants.SV388_GAMES;
|
||||
}
|
||||
|
||||
/**
|
||||
* 按代理id进行交换转账
|
||||
*
|
||||
* @param exchangeTransferMoneyRequestDTO 外汇转账moeny dto
|
||||
* @return {@link Long }
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public Long exchangeTransferByAgentId(ExchangeTransferMoneyRequestDTO exchangeTransferMoneyRequestDTO) {
|
||||
|
||||
Member member = memberService.selectMemberByGameAccount(exchangeTransferMoneyRequestDTO.getAccount());
|
||||
String transactionId = GamePlatforms.SV388.getCode() + IdUtils.simpleUUID();
|
||||
List<GameExchangeMoney> gameExchangeMonies = gameExchangeMoneyService.selectGameExchangeMoneyList(
|
||||
GameExchangeMoney.builder()
|
||||
.tenantKey(exchangeTransferMoneyRequestDTO.getTenantKey())
|
||||
.orderId(exchangeTransferMoneyRequestDTO.getOrderId())
|
||||
.build()
|
||||
);
|
||||
Assert.isTrue(CollectionUtils.isEmpty(gameExchangeMonies), "订单号重复");
|
||||
|
||||
//获取下一个自增id
|
||||
GameExchangeMoney exchangeMoney = GameExchangeMoney
|
||||
.builder()
|
||||
.tenantKey(exchangeTransferMoneyRequestDTO.getTenantKey())
|
||||
.orderId(exchangeTransferMoneyRequestDTO.getOrderId())
|
||||
.quota(exchangeTransferMoneyRequestDTO.getQuota())
|
||||
.balance(exchangeTransferMoneyRequestDTO.getAmount())
|
||||
.exchangeType(exchangeTransferMoneyRequestDTO.getTransferType())
|
||||
.currencyCode(exchangeTransferMoneyRequestDTO.getSystemCurrency())
|
||||
.memberId(member.getId())
|
||||
.transactionId(transactionId)
|
||||
.platformCode(GamePlatforms.SV388.getCode())
|
||||
.build();
|
||||
exchangeMoney.setCreateBy(Constants.SYSTEM);
|
||||
exchangeMoney.setStatus(StatusType.IN_PROGRESS.getValue());
|
||||
exchangeMoney.setStep(GameExchangeStep.CREATE_ORDER.getCode());
|
||||
exchangeMoney.setStepStatus(GameExchangeStepStatus.SUCCESS.getCode());
|
||||
gameExchangeMoneyService.insertGameExchangeMoney(exchangeMoney);
|
||||
|
||||
|
||||
Map<String, Object> params = this.getKey(exchangeTransferMoneyRequestDTO);
|
||||
SV388AETransactionResponse deposit = null;
|
||||
try {
|
||||
if (TransferType.GAMES.getCode().equals(exchangeTransferMoneyRequestDTO.getTransferType())) {
|
||||
|
||||
params.put("userId", exchangeTransferMoneyRequestDTO.getAccount());
|
||||
params.put("txCode", transactionId);
|
||||
params.put("transferAmount", exchangeTransferMoneyRequestDTO.getAmount());
|
||||
deposit = sv388Client.deposit(params);
|
||||
|
||||
} else {
|
||||
params.put("userId", exchangeTransferMoneyRequestDTO.getAccount());
|
||||
params.put("txCode", transactionId);
|
||||
params.put("withdrawType", 1);
|
||||
deposit = sv388Client.withdraw(params);
|
||||
}
|
||||
} finally {
|
||||
BigDecimal coinBefore;
|
||||
if (TransferType.GAMES.getCode().equals(exchangeTransferMoneyRequestDTO.getTransferType())) {
|
||||
coinBefore = NumberUtil.sub(deposit.getCurrentBalance(), deposit.getAmount());
|
||||
} else {
|
||||
coinBefore = NumberUtil.add(deposit.getCurrentBalance(), deposit.getAmount());
|
||||
}
|
||||
//判断是否转移成功
|
||||
if ("0000".equals(deposit.getStatus())) {
|
||||
exchangeMoney.setStep(GameExchangeStep.PLATFORM_TRANSACTION.getCode());
|
||||
exchangeMoney.setStepStatus(GameExchangeStepStatus.SUCCESS.getCode());
|
||||
} else {
|
||||
exchangeMoney.setStep(GameExchangeStep.PLATFORM_TRANSACTION.getCode());
|
||||
exchangeMoney.setStepStatus(GameExchangeStepStatus.IN_PROGRESS.getCode());
|
||||
}
|
||||
//更新数据
|
||||
exchangeMoney.setBalance(deposit.getAmount());
|
||||
exchangeMoney.setCoinBefore(coinBefore);
|
||||
exchangeMoney.setCoinAfter(deposit.getCurrentBalance());
|
||||
exchangeMoney.setCurrencyBefore(exchangeMoney.getCoinBefore());
|
||||
exchangeMoney.setCurrencyAfter(exchangeMoney.getCoinAfter());
|
||||
gameExchangeMoneyService.updateGameExchangeMoney(exchangeMoney);
|
||||
}
|
||||
|
||||
return exchangeMoney.getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* 汇兑转移状态
|
||||
*
|
||||
* @param exchangeTransferMoneyRequestDTO 兑换转账请求dto
|
||||
* @return {@link ExchangeTransferStatusResponseDTO }
|
||||
*/
|
||||
@Override
|
||||
public ExchangeTransferStatusResponseDTO exchangeTransferStatus(ExchangeTransferStatusRequestDTO exchangeTransferMoneyRequestDTO) {
|
||||
|
||||
Map<String, Object> paramsMap = this.getKey(exchangeTransferMoneyRequestDTO);
|
||||
paramsMap.put("txCode", exchangeTransferMoneyRequestDTO.getOrderId());
|
||||
|
||||
SV388ExchangeTransferStatusResponse exchangeTransferStatusResponse = sv388Client.exchangeTransferStatus(paramsMap);
|
||||
Integer status = StatusType.IN_PROGRESS.getValue();
|
||||
if ("0000".equals(exchangeTransferStatusResponse.getStatus()) && "1".equals(exchangeTransferStatusResponse.getTxStatus())) {
|
||||
status = StatusType.SUCCESS.getValue();
|
||||
} else if ("0000".equals(exchangeTransferStatusResponse.getStatus()) && "0".equals(exchangeTransferStatusResponse.getTxStatus())) {
|
||||
status = StatusType.FAILURE.getValue();
|
||||
} else if ("1017".equals(exchangeTransferStatusResponse.getStatus())) {
|
||||
status = StatusType.FAILURE.getValue();
|
||||
}
|
||||
GameExchangeMoney exchangeMoney = gameExchangeMoneyService.selectGameExchangeMoneyById(exchangeTransferMoneyRequestDTO.getGameExchangeMoneyId());
|
||||
//更新
|
||||
BigDecimal coinBefore;
|
||||
if (TransferType.GAMES.getCode().equals(exchangeMoney.getExchangeType())) {
|
||||
coinBefore = NumberUtil.sub(exchangeTransferStatusResponse.getBalance(), exchangeTransferStatusResponse.getTransferAmount());
|
||||
} else {
|
||||
coinBefore = NumberUtil.add(exchangeTransferStatusResponse.getBalance(), exchangeTransferStatusResponse.getTransferAmount());
|
||||
}
|
||||
|
||||
|
||||
return ExchangeTransferStatusResponseDTO.builder()
|
||||
.statusType(status)
|
||||
.balance(exchangeTransferStatusResponse.getTransferAmount())
|
||||
.coinBefore(coinBefore)
|
||||
.coinAfter(exchangeTransferStatusResponse.getBalance())
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
class GetRealtimeRecordTask extends DelayTask {
|
||||
BetRecordByTimeDTO betRecordByTimeDTO;
|
||||
|
||||
public GetRealtimeRecordTask(BetRecordByTimeDTO betRecordByTimeDTO) {
|
||||
this.betRecordByTimeDTO = betRecordByTimeDTO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
getRealtimeRecord(betRecordByTimeDTO);
|
||||
}
|
||||
}
|
||||
|
||||
void getRealtimeRecord(BetRecordByTimeDTO betRecordByTimeDTO) {
|
||||
//请求参数
|
||||
Map<String, Object> params = this.getKey(betRecordByTimeDTO);
|
||||
|
||||
String timeFrom = redisCache.getCacheObject(CacheConstants.SV388_TIME_FROM);
|
||||
if (StringUtils.isEmpty(timeFrom)) {
|
||||
timeFrom = DateUtils.convertTimestampToFormattedDate(betRecordByTimeDTO.getStartTime(), DateUtils.ISO_8601_FORMAT, "GMT+8") + "+08:00";
|
||||
}
|
||||
|
||||
params.put("timeFrom", timeFrom);
|
||||
params.put("platform", GamePlatforms.SV388.getCode());
|
||||
params.put("delayTime", 10000);
|
||||
SV388BetRecordResponse aeBetRecordResponse = sv388Client.getBetRecordByTime(params, betRecordByTimeDTO.getVendor().getUrlInfo().getBetUrl());
|
||||
|
||||
//判断是否获取成功
|
||||
if (this.getIsSuccess(aeBetRecordResponse.getStatus())) {
|
||||
//数据组装
|
||||
this.batchInsert(aeBetRecordResponse, betRecordByTimeDTO);
|
||||
if (aeBetRecordResponse.getTransactions().size() >= 20000) {
|
||||
delayService.addTask(new GetRealtimeRecordTask(betRecordByTimeDTO));
|
||||
}
|
||||
} else {
|
||||
redisCache.deleteObject(CacheConstants.SV388_TIME_FROM);
|
||||
log.error("获取投注记录失败,错误代码{},错误信息{}", aeBetRecordResponse.getStatus(), aeBetRecordResponse.getDesc());
|
||||
}
|
||||
}
|
||||
|
||||
void getHistoryRecord(BetRecordByTimeDTO betRecordByTimeDTO) {
|
||||
Map<String, Object> params = this.getKey(betRecordByTimeDTO);
|
||||
String startTime = DateUtils.convertTimestampToFormattedDate(betRecordByTimeDTO.getStartTime(), DateUtils.ISO_8601_FORMAT, "GMT+8") + "+08:00";
|
||||
String endTime = DateUtils.convertTimestampToFormattedDate(betRecordByTimeDTO.getStartTime(), DateUtils.ISO_8601_FORMAT, "GMT+8") + "+08:00";
|
||||
|
||||
params.put("startTime", startTime);
|
||||
params.put("endTime", endTime);
|
||||
params.put("platform", /*"SEXYBCRT"*/ GamePlatforms.SV388.getCode());
|
||||
|
||||
SV388BetRecordResponse aeBetRecordResponse = sv388Client.getBetHistoryRecordByTime(params, betRecordByTimeDTO.getVendor().getUrlInfo().getBetUrl());
|
||||
|
||||
//判断是否获取成功
|
||||
if (this.getIsSuccess(aeBetRecordResponse.getStatus())) {
|
||||
//数据组装
|
||||
this.batchInsert(aeBetRecordResponse, betRecordByTimeDTO);
|
||||
if (aeBetRecordResponse.getTransactions().size() >= 20000) {
|
||||
delayService.addTask(new GetHistoryRecordTask(betRecordByTimeDTO));
|
||||
}
|
||||
} else {
|
||||
log.error("获取投注记录失败,错误代码{},错误信息{}", aeBetRecordResponse.getStatus(), aeBetRecordResponse.getDesc());
|
||||
}
|
||||
}
|
||||
|
||||
class GetHistoryRecordTask extends DelayTask {
|
||||
BetRecordByTimeDTO betRecordByTimeDTO;
|
||||
|
||||
public GetHistoryRecordTask(BetRecordByTimeDTO betRecordByTimeDTO) {
|
||||
this.betRecordByTimeDTO = betRecordByTimeDTO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
getHistoryRecord(betRecordByTimeDTO);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 按时间获取投注记录
|
||||
*
|
||||
* @param betRecordByTimeDTO 按时间dto投注记录
|
||||
* @return {@link List }<{@link GameBettingDetails }>
|
||||
*/
|
||||
@Override
|
||||
public Boolean getBetRecordByTime(BetRecordByTimeDTO betRecordByTimeDTO) {
|
||||
delayService.addTask(new GetRealtimeRecordTask(betRecordByTimeDTO));
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 按历史时间获取投注记录
|
||||
*
|
||||
* @param betRecordByTimeDTO 按时间dto投注记录
|
||||
* @return {@link Boolean }
|
||||
*/
|
||||
@Override
|
||||
public Boolean getBetRecordByHistoryTime(BetRecordByTimeDTO betRecordByTimeDTO) {
|
||||
delayService.addTask(new GetHistoryRecordTask(betRecordByTimeDTO));
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 赠送免费局数
|
||||
*
|
||||
* @param createFreeSpinRequest 创建自由旋转请求
|
||||
* @return {@link Boolean }
|
||||
*/
|
||||
@Override
|
||||
public Boolean createFreeSpin(CreateFreeSpinRequestDTO createFreeSpinRequest) {
|
||||
throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取游戏详细信息
|
||||
*
|
||||
* @param getGameDetailRequestDTO 获取游戏详细信息请求dto
|
||||
* @return {@link GetGameDetailResponseDTO }
|
||||
*/
|
||||
@Override
|
||||
public GetGameDetailResponseDTO getGameDetail(GetGameDetailRequestDTO getGameDetailRequestDTO) {
|
||||
throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* 强制会员从游戏注销
|
||||
*
|
||||
* @param kickMemberRequestDTO 踢会员请求dto
|
||||
* @return {@link Boolean }
|
||||
*/
|
||||
@Override
|
||||
public Boolean kickMember(KickMemberRequestDTO kickMemberRequestDTO) {
|
||||
Map<String, Object> params = this.getKey(kickMemberRequestDTO);
|
||||
params.put("userIds", kickMemberRequestDTO.getAccount());
|
||||
XKKickMemberDTO xkKickMemberDTO = sv388Client.kickMember(params);
|
||||
//判断是否获取成功
|
||||
if (this.getIsSuccess(xkKickMemberDTO.getCode())) {
|
||||
return Boolean.TRUE;
|
||||
} else {
|
||||
throw new BaseException(xkKickMemberDTO.getMsg());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 踢成员全部
|
||||
*
|
||||
* @param kickMemberAllDTO 踢成员全部dto
|
||||
* @return {@link Boolean }
|
||||
*/
|
||||
@Override
|
||||
public Boolean kickMemberAll(KickMemberAllDTO kickMemberAllDTO) {
|
||||
throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* 免费游戏玩家使用的纪录
|
||||
*
|
||||
* @param getFreeSpinDashflowRequestDTO 获取自由旋转dashflow请求dto
|
||||
* @return {@link List }<{@link GameFreeRecord }>
|
||||
*/
|
||||
@Override
|
||||
public List<GameFreeRecord> getFreeSpinDashflow(GetFreeSpinDashflowRequestDTO getFreeSpinDashflowRequestDTO) {
|
||||
throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消赠送免费局数
|
||||
*
|
||||
* @param cancelFreeSpinRequestDTO 取消免费旋转请求
|
||||
* @return {@link Boolean }
|
||||
*/
|
||||
@Override
|
||||
public Boolean cancelFreeSpin(CancelFreeSpinRequestDTO cancelFreeSpinRequestDTO) {
|
||||
throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* 游戏演示登录
|
||||
*
|
||||
* @param gameDemoLoginRequestDTO 游戏演示登录请求dto
|
||||
* @return {@link GameDemoLoginResponseDTO }
|
||||
*/
|
||||
@Override
|
||||
public GameDemoLoginResponseDTO gameDemoLogin(GameDemoLoginRequestDTO gameDemoLoginRequestDTO) {
|
||||
throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 批量插入
|
||||
*
|
||||
* @param aeBetRecordResponse ae下注记录响应dto
|
||||
*/
|
||||
private void batchInsert(SV388BetRecordResponse aeBetRecordResponse, BetRecordByTimeDTO betRecordByTimeDTO) {
|
||||
List<GameBettingDetails> gameBettingDetails = new ArrayList<>();
|
||||
List<String> wagersIds = new ArrayList<>();
|
||||
//数据组装
|
||||
List<SV388BetRecordResponse.Transaction> dataBean = aeBetRecordResponse.getTransactions();
|
||||
|
||||
if (CollectionUtils.isEmpty(dataBean)) {
|
||||
return;
|
||||
}
|
||||
|
||||
String timeFrom = null;
|
||||
//数据转化
|
||||
for (SV388BetRecordResponse.Transaction bean : dataBean) {
|
||||
GameBettingDetails bettingDetails = this.dataBuild(GamesDataBuildDTO.builder()
|
||||
.platform(betRecordByTimeDTO.getVendor())
|
||||
.data(bean).build());
|
||||
if (!ObjectUtils.isEmpty(bettingDetails)) {
|
||||
bettingDetails.setId(IdUtil.getSnowflakeNextId());
|
||||
gameBettingDetails.add(bettingDetails);
|
||||
}
|
||||
wagersIds.add(bean.getPlatform() + bean.getPlatformTxId());
|
||||
timeFrom = bean.getUpdateTime();
|
||||
}
|
||||
if (!CollectionUtils.isEmpty(gameBettingDetails)) {
|
||||
//查询重复数据id
|
||||
List<String> removeWagersIds = gameBettingDetailsService.selectGameBettingDetailsByWagersId(wagersIds, GamePlatforms.SV388.getCode());
|
||||
//用steam流清除list中与wagersIds集合相同的数据
|
||||
gameBettingDetails = gameBettingDetails.stream()
|
||||
.filter(detail -> !removeWagersIds.contains(detail.getWagersId()))
|
||||
.collect(Collectors.toList());
|
||||
if (!CollectionUtils.isEmpty(gameBettingDetails)) {
|
||||
gameBettingDetailsService.batchInsert(gameBettingDetails);
|
||||
}
|
||||
}
|
||||
if (StringUtils.isEmpty(timeFrom)) {
|
||||
timeFrom = DateUtils.convertTimestampToFormattedDate(DateUtils.getNowDate(), DateUtils.ISO_8601_FORMAT, "UTC+8") + "+08:00";
|
||||
}
|
||||
redisCache.setCacheObject(CacheConstants.SV388_TIME_FROM, timeFrom);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据构建
|
||||
*
|
||||
* @param gamesDataBuildDTO 数据
|
||||
* @return {@link GameBettingDetails }
|
||||
*/
|
||||
@Override
|
||||
public GameBettingDetails dataBuild(GamesDataBuildDTO gamesDataBuildDTO) {
|
||||
//转化类
|
||||
SV388BetRecordResponse.Transaction resultBean = (SV388BetRecordResponse.Transaction) gamesDataBuildDTO.getData();
|
||||
|
||||
|
||||
Member member = memberService.selectMemberByGameAccount(resultBean.getUserId());
|
||||
if (ObjectUtils.isEmpty(member)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
// 判断输赢
|
||||
Integer gameStatus = GameStatus.FLAT.getCode();
|
||||
BigDecimal payoffAmount = BigDecimal.ZERO;
|
||||
if (resultBean.getRealWinAmount().compareTo(resultBean.getRealBetAmount()) > 0) {
|
||||
gameStatus = GameStatus.WIN.getCode();
|
||||
payoffAmount = resultBean.getRealWinAmount().subtract(resultBean.getRealBetAmount());
|
||||
} else if (resultBean.getRealWinAmount().compareTo(resultBean.getRealBetAmount()) < 0) {
|
||||
gameStatus = GameStatus.FAIL.getCode();
|
||||
payoffAmount = resultBean.getRealWinAmount().subtract(resultBean.getRealBetAmount()).abs();
|
||||
}
|
||||
|
||||
//结算状态
|
||||
int settlementStatus = SettlementStatusEnum.REVOKED.getCode();
|
||||
if (resultBean.getTxStatus() == 1) {
|
||||
settlementStatus = SettlementStatusEnum.COMPLETED.getCode();
|
||||
}
|
||||
|
||||
//数据构造
|
||||
GameBettingDetails gameBettingDetails = GameBettingDetails.builder()
|
||||
.tenantKey(member.getTenantKey())
|
||||
//保存我们的币种id
|
||||
.currencyCode(gamesDataBuildDTO.getPlatform().getOurCurrency(resultBean.getCurrency()))
|
||||
.memberId(member.getId())
|
||||
.gameCode(resultBean.getGameCode())
|
||||
.gameType(PlatformType.VIDEO.getCode())
|
||||
.platformCode(GamePlatforms.SV388.getCode())
|
||||
.gameId(/*GAME_ID*/GamePlatforms.SV388.getCode() + "_" + 1)
|
||||
.gameName(resultBean.getGameName())
|
||||
.gameStatus(gameStatus)
|
||||
.gameStatusType(resultBean.getSettleStatus())
|
||||
.gameCurrencyCode(resultBean.getCurrency())
|
||||
.account(resultBean.getUserId())
|
||||
.wagersId(resultBean.getPlatform() + resultBean.getPlatformTxId())
|
||||
.wagersTime(resultBean.getBetTime().getTime())
|
||||
.betAmount(resultBean.getRealBetAmount())
|
||||
.payoffTime(resultBean.getTxTime().getTime())
|
||||
.payoffAmount(payoffAmount)
|
||||
.betContent(resultBean.getGameInfo())
|
||||
.settlementTime(resultBean.getTxTime().getTime())
|
||||
.turnover(resultBean.getTurnover())
|
||||
.orderNo(String.valueOf(resultBean.getRoundId()))
|
||||
.settlementStatus(settlementStatus)
|
||||
.build();
|
||||
gameBettingDetails.setCreateBy(Constants.SYSTEM);
|
||||
gameBettingDetails.setCreateTime(DateUtils.getNowDate());
|
||||
return gameBettingDetails;
|
||||
}
|
||||
}
|
||||
|
|
@ -43,7 +43,7 @@ public class XKGamesDTO {
|
|||
/**
|
||||
*自己系统游戏id
|
||||
*/
|
||||
private Long systemGameId;
|
||||
private String systemGameId;
|
||||
/**
|
||||
* jp
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -252,7 +252,7 @@ public class GamesXKServiceImpl implements IGamesService {
|
|||
} else {
|
||||
game = games.get(0);
|
||||
}
|
||||
gamesDataDTO.setSystemGameId(game.getId());
|
||||
gamesDataDTO.setSystemGameId(game.getGameId());
|
||||
}
|
||||
|
||||
redisCache.deleteObject(CacheConstants.XK_GAMES);
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ public class ExtInfo implements Serializable {
|
|||
*/
|
||||
private Map<String, Long> timeout;
|
||||
|
||||
private Map<String, Object> betLimit;
|
||||
|
||||
public String getOurCurrency(String currencyId) {
|
||||
return currency == null ? null : currency.get(currencyId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ public class GameBettingDetails extends BaseEntity
|
|||
/** 游戏id */
|
||||
@Excel(name = "游戏id")
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long gameId;
|
||||
private String gameId;
|
||||
|
||||
/** 游戏类型 ff_game_type 字典 */
|
||||
@Excel(name = "游戏类型 ff_game_type 字典")
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
// }
|
||||
//}
|
||||
|
|
|
|||
|
|
@ -1,29 +0,0 @@
|
|||
package com.ff.sports.api.fb.address;
|
||||
|
||||
import com.dtflys.forest.callback.AddressSource;
|
||||
import com.dtflys.forest.http.ForestAddress;
|
||||
import com.dtflys.forest.http.ForestRequest;
|
||||
import com.ff.base.system.service.ISysConfigService;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
|
||||
/**
|
||||
* @author shi
|
||||
* @date 2025/02/10
|
||||
*/
|
||||
@Component
|
||||
public class FbAddress implements AddressSource {
|
||||
|
||||
public static final String API_BASE_URL = "fb.api.base.url";
|
||||
@Resource
|
||||
private ISysConfigService configService;
|
||||
|
||||
|
||||
@Override
|
||||
public ForestAddress getAddress(ForestRequest request) {
|
||||
String apiBaseUrl = configService.selectConfigByKey(API_BASE_URL);
|
||||
return new ForestAddress("https", apiBaseUrl, 443, "services");
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
||||
|
||||
/**
|
||||
* <a href="http://api-doc-2.dbsporxxxw1box.com/#/login">DB体育对接文档</a>
|
||||
* 账号: 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, "");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
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/user/create",
|
||||
headers = {
|
||||
"Content-type: application/x-www-form-urlencoded"
|
||||
}
|
||||
)
|
||||
CreateUserResponse createMember(@Body CreateUserRequest request,
|
||||
@Header("requestId") @Var("requestId") String requestId,
|
||||
@Header("lang") @Var("lang") String lang);
|
||||
|
||||
/**
|
||||
* 用户金额转入到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);
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
package com.ff.sports.db.dto;
|
||||
|
||||
import com.ff.base.utils.sign.Md5Utils;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author cengy
|
||||
*/
|
||||
@Data
|
||||
public class CreateUserRequest implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String userName; // 用户名(可以包含但是不要等同于特殊字符或者空格,长度控制在30个字符以下)
|
||||
private String merchantCode; // 商户code
|
||||
private String timestamp = System.currentTimeMillis() + ""; // 13位时间戳
|
||||
private String currency; // 币种
|
||||
private String nickname; // N 昵称
|
||||
private String agentId; // N 信用网(代理id)
|
||||
private String sign; // 签名 signature =MD5(MD5(userName +”&”+ merchantCode +”&”+ timestamp) + ”&”+ key)
|
||||
|
||||
public void calcSign(String key) {
|
||||
String signature = Md5Utils.md5New(Md5Utils.md5New(userName + "&" + merchantCode + "&" + timestamp) + "&" + key);
|
||||
this.sign = signature;
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package com.ff.sports.db.dto;
|
||||
|
||||
/**
|
||||
* @author cengy
|
||||
*/
|
||||
public class Enums {
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -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<String, Object> map = new LinkedHashMap<>();
|
||||
map.put("merchantUserId", merchantUserId);
|
||||
return JSON.toJSONString(map);
|
||||
}
|
||||
}
|
||||
|
|
@ -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<Wallet> 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
|
||||
}
|
||||
}
|
||||
|
|
@ -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<String, String> map = new LinkedHashMap<>();
|
||||
map.put("merchantUserId", merchantUserId);
|
||||
map.put("platForm", platForm);
|
||||
return JSON.toJSONString(map);
|
||||
}
|
||||
}
|
||||
|
|
@ -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<Domain> 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<String> domains; // 域名集合
|
||||
}
|
||||
}
|
||||
|
|
@ -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 "{}";
|
||||
}
|
||||
}
|
||||
|
|
@ -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<UrlDTO> 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<DomainDTO> domainList; // 域名集合
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class DomainDTO implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private String domain; // 域名
|
||||
private int weight; // 权限值
|
||||
}
|
||||
}
|
||||
|
|
@ -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<String, Object> 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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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<FileId> data;
|
||||
|
||||
@Data
|
||||
public static class FileId implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private Long fileId;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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<String, Object> map = new LinkedHashMap<>();
|
||||
map.put("fileId", fileId);
|
||||
return JSON.toJSONString(map);
|
||||
}
|
||||
}
|
||||
|
|
@ -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<OrderDTO> 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<BetDTO> 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; // 数据变更标记
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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<String, Object> map = new LinkedHashMap<>();
|
||||
map.put("businessId", businessId);
|
||||
map.put("merchantUserId", merchantUserId);
|
||||
map.put("transferType", transferType);
|
||||
return JSON.toJSONString(map);
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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<String, Object> map = new LinkedHashMap<>();
|
||||
map.put("amount", amount);
|
||||
map.put("businessId", businessId);
|
||||
map.put("currencyId", currencyId);
|
||||
map.put("merchantUserId", merchantUserId);
|
||||
return JSON.toJSONString(map);
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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<String, Object> map = new LinkedHashMap<>();
|
||||
map.put("amount", amount);
|
||||
map.put("businessId", businessId);
|
||||
map.put("currencyId", currencyId);
|
||||
map.put("merchantUserId", merchantUserId);
|
||||
return JSON.toJSONString(map);
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -0,0 +1,748 @@
|
|||
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 requestDTO 创建成员请求dto
|
||||
* @return {@link Boolean }
|
||||
*/
|
||||
@Override
|
||||
public Boolean createMember(CreateMemberRequestDTO requestDTO) {
|
||||
|
||||
CreateUserRequest request = new CreateUserRequest();
|
||||
request.setUserName(requestDTO.getAccount());
|
||||
request.setMerchantCode(requestDTO.getAgentId());
|
||||
request.setCurrency(requestDTO.getCurrency());
|
||||
request.calcSign(requestDTO.getAgentKey());
|
||||
|
||||
String lang = "zh";
|
||||
String requestId = IdUtils.fastUUID();
|
||||
CreateUserResponse response = dbSportsClient.createMember(request, requestId, lang);
|
||||
if (isSuccess(response.getCode())) {
|
||||
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<GameExchangeMoney> 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<GetUrlResponse.UrlDTO> 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<Game> gameList = gameService.selectGameList(condition);
|
||||
//不存在这个游戏
|
||||
if (ObjectUtils.isEmpty(gameList)) {
|
||||
Game game = new Game();
|
||||
game.setId(IdUtil.getSnowflakeNextId());
|
||||
game.setSortNo(1);
|
||||
game.setPlatformCode(platform.getPlatformCode());
|
||||
game.setPlatformType(PlatformType.SPORTS.getCode());
|
||||
game.setGameCode("1");
|
||||
game.setGameSourceType(String.valueOf(1));
|
||||
game.setGameName(GamePlatforms.DBSports.getInfo());
|
||||
game.setCreateBy(Constants.SYSTEM);
|
||||
NameInfo nameInfo = new NameInfo();
|
||||
nameInfo.setLang("zh-CN");
|
||||
nameInfo.setName("DB体育");
|
||||
game.setNameInfo(Collections.singletonList(nameInfo));
|
||||
gameService.insertGame(game);
|
||||
}
|
||||
/*GameName gameName = gameNameService.selectGameNameById(GAME_NAME_ID);
|
||||
if (ObjectUtils.isEmpty(gameName)) {
|
||||
gameNameService.insertGameName(GameName.builder()
|
||||
.id(GAME_NAME_ID)
|
||||
.gameId(game.getId())
|
||||
.gameName(game.getGameName())
|
||||
.langCode("zh-CN")
|
||||
.createBy(Constants.SYSTEM)
|
||||
.build());
|
||||
}*/
|
||||
|
||||
return CacheConstants.DB_Sports;
|
||||
}
|
||||
|
||||
/**
|
||||
* 汇兑转移状态
|
||||
*
|
||||
* @param requestDTO 兑换转账请求dto
|
||||
* @return {@link Boolean }
|
||||
*/
|
||||
@Override
|
||||
public ExchangeTransferStatusResponseDTO exchangeTransferStatus(ExchangeTransferStatusRequestDTO requestDTO) {
|
||||
|
||||
GameExchangeMoney gameExchangeMoney = gameExchangeMoneyService.selectGameExchangeMoneyById(requestDTO.getGameExchangeMoneyId());
|
||||
if (null == gameExchangeMoney) {
|
||||
throw new ApiException(ErrorCode.Transfer_Not_Exist.getCode());
|
||||
}
|
||||
Integer status = StatusType.IN_PROGRESS.getValue();
|
||||
|
||||
if (!Objects.equals(gameExchangeMoney.getStatus(), StatusType.SUCCESS.getValue())) {
|
||||
TransferDetailRequest request = new TransferDetailRequest();
|
||||
request.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<OrderInfoResponse.OrderDTO> 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<GameFreeRecord> 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<OrderInfoResponse.OrderDTO> settledOrderList, BetRecordByTimeDTO betRecordByTimeDTO) {
|
||||
List<GameBettingDetails> gameBettingDetails = new ArrayList<>();
|
||||
List<String> wagersIds = new ArrayList<>();
|
||||
//数据组装
|
||||
List<OrderInfoResponse.OrderDTO> 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<String> 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<Game> 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("1")
|
||||
.gameType(PlatformType.SPORTS.getCode()) // 体育
|
||||
.platformCode(GamePlatforms.DBSports.getCode())
|
||||
.gameId(GamePlatforms.DBSports.getCode() + "_1")
|
||||
.gameName(GamePlatforms.DBSports.getInfo())
|
||||
.gameStatus(compareResult > 0 ? GameStatus.WIN.getCode() : compareResult < 0 ? GameStatus.FAIL.getCode() : GameStatus.FLAT.getCode())
|
||||
.gameStatusType(1) // 一般下注
|
||||
.gameCurrencyCode(dataBean.getCurrency().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;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
package com.ff.sports.fb;
|
||||
|
||||
/**
|
||||
* @author cengy
|
||||
*/
|
||||
public class A {
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
package com.ff.sports.fb.address;
|
||||
|
||||
import com.dtflys.forest.callback.AddressSource;
|
||||
import com.dtflys.forest.http.ForestAddress;
|
||||
import com.dtflys.forest.http.ForestRequest;
|
||||
import com.ff.base.enums.GamePlatforms;
|
||||
import com.ff.game.service.IPlatformService;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
|
||||
/**
|
||||
* <a href="https://doc.newsportspro.com/apidoc_data.html#%E5%85%A5%E5%8F%82">对接文档地址</a>
|
||||
*
|
||||
* @author cengy
|
||||
*/
|
||||
@Component
|
||||
public class FBSportsAddress implements AddressSource {
|
||||
|
||||
@Resource
|
||||
private IPlatformService platformService;
|
||||
|
||||
@Override
|
||||
public ForestAddress getAddress(ForestRequest request) {
|
||||
String apiBaseUrl = platformService.get(GamePlatforms.FBSports.getCode())
|
||||
.getUrlInfo().getUrl();
|
||||
return new ForestAddress("https", apiBaseUrl, 443, "fb/data");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
package com.ff.sports.fb.client;
|
||||
|
||||
import com.dtflys.forest.annotation.*;
|
||||
import com.ff.sports.fb.address.FBSportsAddress;
|
||||
import com.ff.sports.fb.dto.*;
|
||||
|
||||
/**
|
||||
* <a href="https://doc.newsportspro.com/apidoc_data.html">数据接口文档</a><br/>
|
||||
* <a href="https://doc.newsportspro.com/h5_pc_doc.html">网页接入文档</a>
|
||||
*
|
||||
* @author cengy
|
||||
*/
|
||||
@Address(source = FBSportsAddress.class)
|
||||
public interface FBSportsClient {
|
||||
/**
|
||||
* 创建投注用户
|
||||
*
|
||||
* @return {@link CreateUserResponse}
|
||||
*/
|
||||
@Post(url = "/api/v2/new/user/create")
|
||||
CreateUserResponse createMember(@JSONBody CreateUserRequest request,
|
||||
@Header("sign") @Var("sign") String sign,
|
||||
@Header("timestamp") @Var("timestamp") long timestamp,
|
||||
@Header("merchantId") @Var("merchantId") String merchantId);
|
||||
|
||||
/**
|
||||
* 用户金额转入到FB体育平台,支持两位小数,最小0.01,必须是正数
|
||||
*
|
||||
* @param request
|
||||
* @param sign
|
||||
* @param timestamp
|
||||
* @param merchantId
|
||||
* @return {@link TransferInResponse}
|
||||
*/
|
||||
@Post(url = "/api/v2/new/transfer/in")
|
||||
TransferInResponse transferIn(@JSONBody TransferInRequest request,
|
||||
@Header("sign") @Var("sign") String sign,
|
||||
@Header("timestamp") @Var("timestamp") long timestamp,
|
||||
@Header("merchantId") @Var("merchantId") String merchantId);
|
||||
|
||||
@Post(url = "/api/v2/new/transfer/out")
|
||||
TransferOutResponse transferOut(@JSONBody TransferOutRequest request,
|
||||
@Header("sign") @Var("sign") String sign,
|
||||
@Header("timestamp") @Var("timestamp") long timestamp,
|
||||
@Header("merchantId") @Var("merchantId") String merchantId);
|
||||
|
||||
@Post(url = "/api/v2/new/user/detail")
|
||||
GetMemberInfoResponse getMemberInfo(@JSONBody GetMemberInfoRequest request,
|
||||
@Header("sign") @Var("sign") String sign,
|
||||
@Header("timestamp") @Var("timestamp") long timestamp,
|
||||
@Header("merchantId") @Var("merchantId") String merchantId);
|
||||
|
||||
/**
|
||||
* 查询转账详情,当转入/转出接口遇到异常,可查询某次转账是否成功
|
||||
*/
|
||||
@Post(url = "/api/v2/transfer/detail")
|
||||
TransferDetailResponse transferDetail(@JSONBody TransferDetailRequest request,
|
||||
@Header("sign") @Var("sign") String sign,
|
||||
@Header("timestamp") @Var("timestamp") long timestamp,
|
||||
@Header("merchantId") @Var("merchantId") String merchantId);
|
||||
|
||||
@Post(url = "/api/v2/service/domain/list")
|
||||
GetUrlResponse getUrl(@JSONBody GetUrlRequest request,
|
||||
@Header("sign") @Var("sign") String sign,
|
||||
@Header("timestamp") @Var("timestamp") long timestamp,
|
||||
@Header("merchantId") @Var("merchantId") String merchantId);
|
||||
|
||||
/**
|
||||
* FB体育用拉取订单文件的方式同步订单数据,FB体育每5分钟生成一次订单文件,
|
||||
* 通过此接口获取某一段时间内的文件ID列表,再通过文件ID获取具体订单数据
|
||||
*/
|
||||
@Post(url = "/api/v2/order/file/ids")
|
||||
OrderFilesResponse orderFiles(@JSONBody OrderFilesRequest request,
|
||||
@Header("sign") @Var("sign") String sign,
|
||||
@Header("timestamp") @Var("timestamp") long timestamp,
|
||||
@Header("merchantId") @Var("merchantId") String merchantId);
|
||||
|
||||
/**
|
||||
* 拉取订单Json数据
|
||||
*/
|
||||
@Post(url = "/api/v2/order/list")
|
||||
OrderInfoResponse getOrderJsonData(@JSONBody OrderInfoRequest request,
|
||||
@Header("sign") @Var("sign") String sign,
|
||||
@Header("timestamp") @Var("timestamp") long timestamp,
|
||||
@Header("merchantId") @Var("merchantId") String merchantId);
|
||||
|
||||
|
||||
/**
|
||||
* 获取用户app端鉴权token和相关服务url,获取到的token用于app调用接口鉴权
|
||||
*
|
||||
* @param request
|
||||
* @param sign
|
||||
* @param timestamp
|
||||
* @param merchantId
|
||||
* @return
|
||||
*/
|
||||
@Post(url = "/api/v2/token/get")
|
||||
GetTokenResponse getToken(@JSONBody GetTokenRequest request,
|
||||
@Header("sign") @Var("sign") String sign,
|
||||
@Header("timestamp") @Var("timestamp") long timestamp,
|
||||
@Header("merchantId") @Var("merchantId") String merchantId);
|
||||
}
|
||||
|
|
@ -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.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<Integer> currencyIds = null; // 币种id集合 , see enum: currency
|
||||
private Integer oddsLevel = null; // 赔率级别,不传则为默认, see enum: user_odds_level_enum
|
||||
|
||||
public String toJSON() {
|
||||
Map<String, Object> map = new LinkedHashMap<>();
|
||||
map.put("currencyIds", currencyIds);
|
||||
map.put("merchantUserId", merchantUserId);
|
||||
map.put("oddsLevel", oddsLevel);
|
||||
return JSON.toJSONString(map);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
package com.ff.sports.fb.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author cengy
|
||||
*/
|
||||
@Data
|
||||
public class CreateUserResponse implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Boolean success;
|
||||
private Integer data;
|
||||
private Integer code;
|
||||
private String message;
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
package com.ff.sports.fb.dto;
|
||||
|
||||
/**
|
||||
* @author cengy
|
||||
*/
|
||||
public class Enums {
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
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 GetMemberInfoRequest implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 渠道用户id,不能为空
|
||||
*/
|
||||
private String merchantUserId;
|
||||
|
||||
public String toJSON() {
|
||||
Map<String, Object> map = new LinkedHashMap<>();
|
||||
map.put("merchantUserId", merchantUserId);
|
||||
return JSON.toJSONString(map);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
package com.ff.sports.fb.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author cengy
|
||||
*/
|
||||
@Data
|
||||
public class GetMemberInfoResponse implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Boolean success;
|
||||
private String message;
|
||||
private MemberInfo data;
|
||||
private Integer code;
|
||||
|
||||
@Data
|
||||
public static class MemberInfo implements Serializable{
|
||||
private static final long serialVersionUID = 1L;
|
||||
private String merchantUserId;
|
||||
private Integer userId; // FB体育用户id
|
||||
private Integer walletType; // 用户钱包类型 , see enum: wallet_type
|
||||
private Integer currencyType; // 用户币种类型 , see enum: currency_type
|
||||
private List<Wallet> 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
|
||||
}
|
||||
}
|
||||
|
|
@ -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<String, String> map = new LinkedHashMap<>();
|
||||
map.put("merchantUserId", merchantUserId);
|
||||
map.put("platForm", platForm);
|
||||
return JSON.toJSONString(map);
|
||||
}
|
||||
}
|
||||
|
|
@ -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<Domain> 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<String> domains; // 域名集合
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
package com.ff.sports.fb.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author cengy
|
||||
*/
|
||||
@Data
|
||||
public class GetUrlRequest implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public String toJSON() {
|
||||
return "{}";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
package com.ff.sports.fb.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author cengy
|
||||
*/
|
||||
@Data
|
||||
public class GetUrlResponse implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Boolean success;
|
||||
private String message;
|
||||
private List<UrlDTO> 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<DomainDTO> domainList; // 域名集合
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class DomainDTO implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private String domain; // 域名
|
||||
private int weight; // 权限值
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
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 OrderFilesRequest implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 开始时间戳,13位数字,不能为null
|
||||
*/
|
||||
private Long startTime;
|
||||
|
||||
/**
|
||||
* 结束时间戳,13位数字,不能为null
|
||||
*/
|
||||
private Long endTime;
|
||||
|
||||
public String toJSON() {
|
||||
Map<String, Object> 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;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
package com.ff.sports.fb.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author cengy
|
||||
*/
|
||||
@Data
|
||||
public class OrderFilesResponse implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Boolean success;
|
||||
private String message;
|
||||
private Integer code;
|
||||
|
||||
private List<FileId> data;
|
||||
|
||||
@Data
|
||||
public static class FileId implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
private Long fileId;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
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 OrderInfoRequest implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
/**
|
||||
* 文件Id,需要从/order/file/ids接口获取到
|
||||
*/
|
||||
private Long fileId;
|
||||
|
||||
public String toJSON() {
|
||||
Map<String, Object> map = new LinkedHashMap<>();
|
||||
map.put("fileId", fileId);
|
||||
return JSON.toJSONString(map);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
package com.ff.sports.fb.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author cengy
|
||||
*/
|
||||
@Data
|
||||
public class OrderInfoResponse implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Boolean success;
|
||||
private String message;
|
||||
private Integer code;
|
||||
|
||||
private List<OrderDTO> 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<BetDTO> 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; // 数据变更标记
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
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 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<String, Object> map = new LinkedHashMap<>();
|
||||
map.put("businessId", businessId);
|
||||
map.put("merchantUserId", merchantUserId);
|
||||
map.put("transferType", transferType);
|
||||
return JSON.toJSONString(map);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
package com.ff.sports.fb.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* @author cengy
|
||||
*/
|
||||
@Data
|
||||
public class TransferDetailResponse implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Boolean success;
|
||||
private String message;
|
||||
private TransferDetail data;
|
||||
private Integer code;
|
||||
|
||||
@Data
|
||||
public static class TransferDetail implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Integer id;
|
||||
private Integer userId;
|
||||
private String merchantUserId;
|
||||
private String businessId;
|
||||
// IN 转入
|
||||
// OUT 转出
|
||||
private String transferType;
|
||||
private BigDecimal beforeTransferAmount;
|
||||
private BigDecimal afterTransferAmount;
|
||||
private Integer status; // 状态 , see enum: transfer_status_enum, 1 Successful 0 Failure
|
||||
private Long createTime; // 记录创建时间
|
||||
private Integer currencyId;// 币种id , see enum: currency
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
package com.ff.sports.fb.dto;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author cengy
|
||||
*/
|
||||
@Data
|
||||
public class TransferInRequest implements Serializable {
|
||||
|
||||
/**
|
||||
* 转账金额,不能为null
|
||||
* 必须大於或等於0
|
||||
*/
|
||||
private BigDecimal amount;
|
||||
|
||||
/**
|
||||
* 业务id,不能为null
|
||||
*/
|
||||
private String businessId;
|
||||
|
||||
/**
|
||||
* 渠道用户ID,不能为null
|
||||
*/
|
||||
private String merchantUserId;
|
||||
|
||||
/**
|
||||
* 币种id,可不传入
|
||||
*/
|
||||
private Integer currencyId;
|
||||
|
||||
public String toJSON() {
|
||||
Map<String, Object> map = new LinkedHashMap<>();
|
||||
map.put("amount", amount);
|
||||
map.put("businessId", businessId);
|
||||
map.put("currencyId", currencyId);
|
||||
map.put("merchantUserId", merchantUserId);
|
||||
return JSON.toJSONString(map);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package com.ff.sports.fb.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* @author cengy
|
||||
*/
|
||||
@Data
|
||||
public class TransferInResponse implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Boolean success;
|
||||
private BigDecimal data;
|
||||
private Integer code;
|
||||
private String message;
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
package com.ff.sports.fb.dto;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author cengy
|
||||
*/
|
||||
@Data
|
||||
public class TransferOutRequest implements Serializable {
|
||||
|
||||
/**
|
||||
* 转账金额,不能为null
|
||||
* 必须大於或等於0
|
||||
*/
|
||||
private BigDecimal amount;
|
||||
|
||||
/**
|
||||
* 业务id,不能为null
|
||||
*/
|
||||
private String businessId;
|
||||
|
||||
/**
|
||||
* 渠道用户ID,不能为null
|
||||
*/
|
||||
private String merchantUserId;
|
||||
|
||||
/**
|
||||
* 币种id,可不传入
|
||||
*/
|
||||
private Integer currencyId;
|
||||
|
||||
public String toJSON() {
|
||||
Map<String, Object> map = new LinkedHashMap<>();
|
||||
map.put("amount", amount);
|
||||
map.put("businessId", businessId);
|
||||
map.put("currencyId", currencyId);
|
||||
map.put("merchantUserId", merchantUserId);
|
||||
return JSON.toJSONString(map);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package com.ff.sports.fb.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* @author cengy
|
||||
*/
|
||||
@Data
|
||||
public class TransferOutResponse implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Boolean success;
|
||||
private BigDecimal data;
|
||||
private Integer code;
|
||||
private String message;
|
||||
}
|
||||
|
|
@ -0,0 +1,755 @@
|
|||
package com.ff.sports.fb.impl;
|
||||
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import com.ff.base.constant.CacheConstants;
|
||||
import com.ff.base.constant.Constants;
|
||||
import com.ff.base.core.redis.RedisCache;
|
||||
import com.ff.base.enums.*;
|
||||
import com.ff.base.exception.base.ApiException;
|
||||
import com.ff.base.exception.base.BaseException;
|
||||
import com.ff.base.utils.DateUtils;
|
||||
import com.ff.base.utils.StringUtils;
|
||||
import com.ff.base.utils.sign.Md5Utils;
|
||||
import com.ff.base.utils.uuid.IdUtils;
|
||||
import com.ff.game.api.IGamesService;
|
||||
import com.ff.game.api.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.fb.client.FBSportsClient;
|
||||
import com.ff.sports.fb.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("FBSportsService")
|
||||
@Slf4j
|
||||
public class FBSportsServiceImpl implements IGamesService {
|
||||
|
||||
@Resource
|
||||
private RedisCache redisCache;
|
||||
|
||||
@Resource
|
||||
private IGameExchangeMoneyService gameExchangeMoneyService;
|
||||
|
||||
@Resource
|
||||
private IGameService gameService;
|
||||
|
||||
|
||||
@Resource
|
||||
private IMemberService memberService;
|
||||
|
||||
@Resource
|
||||
private FBSportsClient fbSportsClient;
|
||||
|
||||
@Resource
|
||||
private IGameBettingDetailsService gameBettingDetailsService;
|
||||
|
||||
/**
|
||||
* 获得就是成功
|
||||
*
|
||||
* @param errorCode 错误代码
|
||||
* @return {@link Boolean }
|
||||
*/
|
||||
private Boolean isSuccess(Integer errorCode) {
|
||||
return 0 == errorCode;
|
||||
}
|
||||
|
||||
String getSign(String bodyJsonString, String merchantId, String merchantApiSecret, long requestTimestamp) {
|
||||
|
||||
String stringThatNeedsToBeSigned = bodyJsonString + "." + merchantId + "." + requestTimestamp + "." + merchantApiSecret;
|
||||
String sign = Md5Utils.md5New(stringThatNeedsToBeSigned);
|
||||
return sign;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建成员
|
||||
*
|
||||
* @param createMemberRequestDTO 创建成员请求dto
|
||||
* @return {@link Boolean }
|
||||
*/
|
||||
@Override
|
||||
public Boolean createMember(CreateMemberRequestDTO createMemberRequestDTO) {
|
||||
|
||||
long timestamp = System.currentTimeMillis();
|
||||
CreateUserRequest request = new CreateUserRequest();
|
||||
request.setMerchantUserId(createMemberRequestDTO.getAccount());
|
||||
ArrayList<Integer> currencyIds = new ArrayList<>();
|
||||
currencyIds.add(Integer.parseInt(createMemberRequestDTO.getCurrency()));
|
||||
request.setCurrencyIds(currencyIds);
|
||||
String jsonBody = /*SortByAttributeNameASC.get(request)*/ request.toJSON();
|
||||
String sign = getSign(jsonBody,
|
||||
createMemberRequestDTO.getAgentId(),
|
||||
createMemberRequestDTO.getAgentKey(),
|
||||
timestamp
|
||||
);
|
||||
|
||||
CreateUserResponse response = fbSportsClient.createMember(
|
||||
request,
|
||||
sign,
|
||||
timestamp, createMemberRequestDTO.getAgentId());
|
||||
if (isSuccess(response.getCode())) {
|
||||
log.info("创建会员成功, account:{}->{}", createMemberRequestDTO.getAccount(), response.getData());
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
|
||||
log.error("创建会员失败, errorCode:{}, errorMessage:{}", response.getCode(), response.getMessage());
|
||||
throw new ApiException(ErrorCode.Create_Member_Failure.getCode());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 按代理id进行交换转账
|
||||
*
|
||||
* @param requestDTO 外汇转账moeny dto
|
||||
* @return {@link Long }
|
||||
*/
|
||||
@Override
|
||||
@Transactional
|
||||
public Long exchangeTransferByAgentId(ExchangeTransferMoneyRequestDTO requestDTO) {
|
||||
|
||||
Member member = memberService.selectMemberByGameAccount(requestDTO.getAccount());
|
||||
String transactionId = GamePlatforms.FBSports.getCode() + IdUtils.simpleUUID();
|
||||
List<GameExchangeMoney> 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.FBSports.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 = fbSportsClient.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 = fbSportsClient
|
||||
.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 = fbSportsClient.getMemberInfo(
|
||||
request,
|
||||
sign,
|
||||
timestamp,
|
||||
requestDTO.getAgentId()
|
||||
);
|
||||
//判断是否获取成功
|
||||
if (this.isSuccess(response.getCode())) {
|
||||
BigDecimal balance = new BigDecimal("0.00");
|
||||
|
||||
for (GetMemberInfoResponse.Wallet wallet : response.getData().getWallets()) {
|
||||
balance = balance.add(wallet.getBalance());
|
||||
}
|
||||
return MemberInfoResponseDTO.builder()
|
||||
.status(GameMemberStatus.UNKNOWN.getCode())
|
||||
.balance(balance)
|
||||
.account(requestDTO.getAccounts())
|
||||
.build();
|
||||
} else {
|
||||
throw new ApiException(ErrorCode.Get_Member_Info_Failure.getCode());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 无重定向登录
|
||||
*
|
||||
* @param requestDTO 游戏登录
|
||||
* @return {@link String }
|
||||
*/
|
||||
@Override
|
||||
public String loginWithoutRedirect(GamesLogin requestDTO) {
|
||||
GetTokenRequest request = new GetTokenRequest();
|
||||
request.setMerchantUserId(requestDTO.getAccount());
|
||||
request.setPlatForm(/*requestDTO.getPlatform()*/ "mobile"); // pc,h5, mobile , see enum: plat_form_enum
|
||||
long timestamp = System.currentTimeMillis();
|
||||
String jsonBody = request.toJSON();
|
||||
String sign = getSign(jsonBody,
|
||||
requestDTO.getAgentId(),
|
||||
requestDTO.getAgentKey(),
|
||||
timestamp
|
||||
);
|
||||
|
||||
GetTokenResponse response = fbSportsClient.getToken(
|
||||
request,
|
||||
sign,
|
||||
timestamp,
|
||||
requestDTO.getAgentId()
|
||||
);
|
||||
|
||||
if (this.isSuccess(response.getCode())) {
|
||||
String token = response.getData().getToken();
|
||||
Integer userId = response.getData().getUserId();
|
||||
GetTokenResponse.ServerInfo serverInfo = response.getData().getServerInfo();
|
||||
String h5Address = serverInfo.getH5Address();
|
||||
if (StringUtils.isEmpty(h5Address)) {
|
||||
throw new ApiException(ErrorCode.Get_Url_Failure.getCode());
|
||||
}
|
||||
|
||||
return h5Address +
|
||||
"/index.html#/" +
|
||||
"?token=" +
|
||||
token +
|
||||
"&nickname=" +
|
||||
userId +
|
||||
"&apiSrc=" +
|
||||
serverInfo.getApiServerAddress() +
|
||||
"&pushSrc=" +
|
||||
serverInfo.getPushServerAddress() +
|
||||
"&virtualSrc=" +
|
||||
serverInfo.getVirtualAddress() +
|
||||
"&platformName=XK体育";
|
||||
}
|
||||
|
||||
|
||||
/*GetUrlRequest request = new GetUrlRequest();
|
||||
long timestamp = System.currentTimeMillis();
|
||||
String jsonBody = request.toJSON();
|
||||
String sign = getSign(jsonBody,
|
||||
requestDTO.getAgentId(),
|
||||
requestDTO.getAgentKey(),
|
||||
timestamp
|
||||
);
|
||||
GetUrlResponse response = fbSportsClient.getUrl(
|
||||
request,
|
||||
sign,
|
||||
timestamp,
|
||||
requestDTO.getAgentId()
|
||||
);
|
||||
//判断是否获取成功
|
||||
if (this.isSuccess(response.getCode())) {
|
||||
List<GetUrlResponse.UrlDTO> urlDTOS = new ArrayList<>();
|
||||
for (GetUrlResponse.UrlDTO urlDTO : response.getData()) {
|
||||
if (urlDTO.getType() == 3) { // 3:h5
|
||||
urlDTOS.add(urlDTO);
|
||||
}
|
||||
}
|
||||
if (urlDTOS.isEmpty()){
|
||||
throw new ApiException(ErrorCode.Get_Url_Failure.getCode());
|
||||
}
|
||||
int randomIndex = new Random().nextInt(urlDTOS.size());
|
||||
GetUrlResponse.UrlDTO urlDTO = urlDTOS.get(randomIndex);
|
||||
Collections.shuffle(urlDTO.getDomainList());
|
||||
return urlDTO.getDomainList().get(0).getDomain();
|
||||
}*/
|
||||
throw new ApiException(ErrorCode.Get_Url_Failure.getCode());
|
||||
}
|
||||
|
||||
private static final Long GAME_ID = 11111L;
|
||||
|
||||
/**
|
||||
* 获取游戏列表
|
||||
*
|
||||
* @param gamesBaseRequestDTO 游戏请求dto
|
||||
* @return {@link String }
|
||||
*/
|
||||
@Transactional
|
||||
@Override
|
||||
public String getGameList(GamesBaseRequestDTO gamesBaseRequestDTO) {
|
||||
|
||||
Platform platform = gamesBaseRequestDTO.getVendor();
|
||||
Game game = gameService.selectGameById(GAME_ID);
|
||||
//不存在这个游戏
|
||||
if (ObjectUtils.isEmpty(game)) {
|
||||
game = new Game();
|
||||
game.setId(/*IdUtil.getSnowflakeNextId()*/GAME_ID);
|
||||
game.setSortNo(1);
|
||||
//game.setPlatformId(gamePlatform.getId());
|
||||
game.setPlatformCode(platform.getPlatformCode());
|
||||
game.setPlatformType(PlatformType.SPORTS.getCode());
|
||||
game.setGameCode("1");
|
||||
game.setGameSourceType(String.valueOf(1));
|
||||
game.setGameName("FB体育");
|
||||
game.setCreateBy(Constants.SYSTEM);
|
||||
NameInfo nameInfo = new NameInfo();
|
||||
nameInfo.setLang("zh-CN");
|
||||
nameInfo.setName("FB体育");
|
||||
game.setNameInfo(Collections.singletonList(nameInfo));
|
||||
gameService.insertGame(game);
|
||||
}
|
||||
/*GameName gameName = gameNameService.selectGameNameById(GAME_NAME_ID);
|
||||
if (ObjectUtils.isEmpty(gameName)) {
|
||||
gameNameService.insertGameName(GameName.builder()
|
||||
.id(GAME_NAME_ID)
|
||||
.gameId(game.getId())
|
||||
.gameName(game.getGameName())
|
||||
.langCode("zh-CN")
|
||||
.createBy(Constants.SYSTEM)
|
||||
.build());
|
||||
}*/
|
||||
|
||||
return CacheConstants.FB_Sports;
|
||||
}
|
||||
|
||||
/**
|
||||
* 汇兑转移状态
|
||||
*
|
||||
* @param requestDTO 兑换转账请求dto
|
||||
* @return {@link Boolean }
|
||||
*/
|
||||
@Override
|
||||
public ExchangeTransferStatusResponseDTO exchangeTransferStatus(ExchangeTransferStatusRequestDTO requestDTO) {
|
||||
|
||||
GameExchangeMoney gameExchangeMoney = gameExchangeMoneyService.selectGameExchangeMoneyById(requestDTO.getGameExchangeMoneyId());
|
||||
if (null == gameExchangeMoney) {
|
||||
throw new ApiException(ErrorCode.Transfer_Not_Exist.getCode());
|
||||
}
|
||||
Integer status = StatusType.IN_PROGRESS.getValue();
|
||||
|
||||
if (!Objects.equals(gameExchangeMoney.getStatus(), StatusType.SUCCESS.getValue())) {
|
||||
TransferDetailRequest request = new TransferDetailRequest();
|
||||
request.setMerchantUserId(requestDTO.getAccount());
|
||||
request.setTransferType(Objects.equals(gameExchangeMoney.getExchangeType(), TransferType.GAMES.getCode())
|
||||
? "IN" : "OUT");
|
||||
long timestamp = System.currentTimeMillis();
|
||||
String jsonBody = request.toJSON();
|
||||
String sign = getSign(jsonBody,
|
||||
requestDTO.getAgentId(),
|
||||
requestDTO.getAgentKey(),
|
||||
timestamp
|
||||
);
|
||||
TransferDetailResponse response = fbSportsClient.transferDetail(
|
||||
request,
|
||||
sign,
|
||||
timestamp,
|
||||
requestDTO.getAgentId()
|
||||
);
|
||||
if (this.isSuccess(response.getCode())) {
|
||||
status = StatusType.SUCCESS.getValue();
|
||||
}else {
|
||||
status = StatusType.FAILURE.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
return ExchangeTransferStatusResponseDTO.builder()
|
||||
.statusType(status)
|
||||
.balance(gameExchangeMoney.getBalance())
|
||||
.coinBefore(gameExchangeMoney.getCoinBefore())
|
||||
.coinAfter(gameExchangeMoney.getCoinAfter())
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 按时间获取投注记录
|
||||
*
|
||||
* @param requestDTO 按时间dto投注记录
|
||||
* @return {@link Boolean }
|
||||
*/
|
||||
@Override
|
||||
public Boolean getBetRecordByTime(BetRecordByTimeDTO requestDTO) {
|
||||
Long lend = requestDTO.getEndTime();
|
||||
Long lstart = requestDTO.getStartTime();
|
||||
//betRecordByTimeDTO.setStartTime(lstart);
|
||||
//betRecordByTimeDTO.setEndTime(lend);
|
||||
|
||||
OrderFilesRequest request = new OrderFilesRequest();
|
||||
request.setStartTime(lstart);
|
||||
request.setEndTime(lend);
|
||||
long timestamp = System.currentTimeMillis();
|
||||
String jsonBody = request.toJSON();
|
||||
String sign = getSign(jsonBody,
|
||||
requestDTO.getAgentId(),
|
||||
requestDTO.getAgentKey(),
|
||||
timestamp
|
||||
);
|
||||
OrderFilesResponse orderFilesResponse = fbSportsClient.orderFiles(
|
||||
request,
|
||||
sign,
|
||||
timestamp,
|
||||
requestDTO.getAgentId()
|
||||
);
|
||||
if (this.isSuccess(orderFilesResponse.getCode())) {
|
||||
for (OrderFilesResponse.FileId fileId : orderFilesResponse.getData()) {
|
||||
try {
|
||||
getOrderData(fileId.getFileId(), requestDTO);
|
||||
} catch (Exception e) {
|
||||
log.error("获取订单数据失败,fileId:{},agentId:{}", fileId, requestDTO.getAgentId());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
log.error("获取订单文件失败,agentId:{}", requestDTO.getAgentId());
|
||||
return false;
|
||||
}
|
||||
|
||||
void getOrderData(Long fileId, BetRecordByTimeDTO requestDTO) {
|
||||
OrderInfoRequest request = new OrderInfoRequest();
|
||||
request.setFileId(fileId);
|
||||
long timestamp = System.currentTimeMillis();
|
||||
String jsonBody = request.toJSON();
|
||||
String sign = getSign(jsonBody,
|
||||
requestDTO.getAgentId(),
|
||||
requestDTO.getAgentKey(),
|
||||
timestamp
|
||||
);
|
||||
|
||||
OrderInfoResponse orderInfoResponse = fbSportsClient.getOrderJsonData(
|
||||
request,
|
||||
sign,
|
||||
timestamp,
|
||||
requestDTO.getAgentId()
|
||||
);
|
||||
if (!this.isSuccess(orderInfoResponse.getCode())) {
|
||||
return;
|
||||
}
|
||||
List<OrderInfoResponse.OrderDTO> settledOrderList = new ArrayList<>();
|
||||
for (OrderInfoResponse.OrderDTO orderDTO : orderInfoResponse.getData()) {
|
||||
// 0 Created 未确认
|
||||
// 1 Confirming 确认中
|
||||
// 2 Rejected 已拒单
|
||||
// 3 Canceled 已取消
|
||||
// 4 Confirmed 已接单
|
||||
// 5 Settled 已结算
|
||||
if (!orderDTO.getOrderStatus().equals(5)) { // 已结算
|
||||
continue;
|
||||
}
|
||||
settledOrderList.add(orderDTO);
|
||||
}
|
||||
this.batchInsert(settledOrderList, requestDTO);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按历史时间获取投注记录
|
||||
*
|
||||
* @param requestDTO 按时间dto投注记录
|
||||
* @return {@link Boolean }
|
||||
*/
|
||||
@Override
|
||||
public Boolean getBetRecordByHistoryTime(BetRecordByTimeDTO requestDTO) {
|
||||
Long lend = requestDTO.getEndTime();
|
||||
Long lstart = requestDTO.getStartTime();
|
||||
//betRecordByTimeDTO.setStartTime(lstart);
|
||||
//betRecordByTimeDTO.setEndTime(lend);
|
||||
|
||||
OrderFilesRequest request = new OrderFilesRequest();
|
||||
request.setStartTime(lstart);
|
||||
request.setEndTime(lend);
|
||||
long timestamp = System.currentTimeMillis();
|
||||
String jsonBody = request.toJSON();
|
||||
String sign = getSign(jsonBody,
|
||||
requestDTO.getAgentId(),
|
||||
requestDTO.getAgentKey(),
|
||||
timestamp
|
||||
);
|
||||
OrderFilesResponse orderFilesResponse = fbSportsClient.orderFiles(
|
||||
request,
|
||||
sign,
|
||||
timestamp,
|
||||
requestDTO.getAgentId()
|
||||
);
|
||||
if (this.isSuccess(orderFilesResponse.getCode())) {
|
||||
for (OrderFilesResponse.FileId fileId : orderFilesResponse.getData()) {
|
||||
try {
|
||||
getOrderData(fileId.getFileId(), requestDTO);
|
||||
} catch (Exception e) {
|
||||
log.error("获取订单数据失败,fileId:{},agentId:{}", fileId, requestDTO.getAgentId());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
log.error("获取订单文件失败,agentId:{}", requestDTO.getAgentId());
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 赠送免费局数
|
||||
*
|
||||
* @param createFreeSpinRequest 创建自由旋转请求
|
||||
* @return {@link Boolean }
|
||||
*/
|
||||
@Override
|
||||
public Boolean createFreeSpin(CreateFreeSpinRequestDTO createFreeSpinRequest) {
|
||||
throw new BaseException("暂不支持免费局数");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取游戏详细信息
|
||||
*
|
||||
* @param getGameDetailRequestDTO 获取游戏详细信息请求dto
|
||||
* @return {@link GetGameDetailResponseDTO }
|
||||
*/
|
||||
@Override
|
||||
public GetGameDetailResponseDTO getGameDetail(GetGameDetailRequestDTO getGameDetailRequestDTO) {
|
||||
throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* 强制会员从游戏注销
|
||||
*
|
||||
* @param kickMemberRequestDTO 踢会员请求dto
|
||||
* @return {@link Boolean }
|
||||
*/
|
||||
@Override
|
||||
public Boolean kickMember(KickMemberRequestDTO kickMemberRequestDTO) {
|
||||
|
||||
return Boolean.FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 踢成员全部
|
||||
*
|
||||
* @param kickMemberAllDTO 踢成员全部dto
|
||||
* @return {@link Boolean }
|
||||
*/
|
||||
@Override
|
||||
public Boolean kickMemberAll(KickMemberAllDTO kickMemberAllDTO) {
|
||||
throw new ApiException(ErrorCode.PLATFORM_NOT_METHODS.getCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* 免费游戏玩家使用的纪录
|
||||
*
|
||||
* @param getFreeSpinDashflowRequestDTO 获取自由旋转dashflow请求dto
|
||||
* @return {@link List }<{@link GameFreeRecord }>
|
||||
*/
|
||||
@Override
|
||||
public List<GameFreeRecord> 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<OrderInfoResponse.OrderDTO> settledOrderList, BetRecordByTimeDTO betRecordByTimeDTO) {
|
||||
List<GameBettingDetails> gameBettingDetails = new ArrayList<>();
|
||||
List<String> wagersIds = new ArrayList<>();
|
||||
//数据组装
|
||||
List<OrderInfoResponse.OrderDTO> 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<String> removeWagersIds = gameBettingDetailsService
|
||||
.selectGameBettingDetailsByWagersId(wagersIds, GamePlatforms.FBSports.getCode());
|
||||
//用steam流清除list中与wagersIds集合相同的数据
|
||||
gameBettingDetails = gameBettingDetails.stream()
|
||||
.filter(detail -> !removeWagersIds.contains(detail.getWagersId()))
|
||||
.collect(Collectors.toList());
|
||||
if (!CollectionUtils.isEmpty(gameBettingDetails)) {
|
||||
gameBettingDetailsService.batchInsert(gameBettingDetails);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据构建
|
||||
*
|
||||
* @param gamesDataBuildDTO 数据
|
||||
* @return {@link GameBettingDetails }
|
||||
*/
|
||||
@Override
|
||||
public GameBettingDetails dataBuild(GamesDataBuildDTO gamesDataBuildDTO) {
|
||||
|
||||
//转化类
|
||||
OrderInfoResponse.OrderDTO dataBean = (OrderInfoResponse.OrderDTO) gamesDataBuildDTO.getData();
|
||||
Member member = memberService.selectMemberByGameAccount(dataBean.getMerchantUserId());
|
||||
if (ObjectUtils.isEmpty(member)) {
|
||||
return null;
|
||||
}
|
||||
List<Game> gameList = redisCache.getCacheList(CacheConstants.FB_Sports);
|
||||
Game game = gameList.get(0);
|
||||
BigDecimal originPayoffAmount = new BigDecimal(dataBean.getSettleAmount());
|
||||
BigDecimal betAmount = new BigDecimal(dataBean.getStakeAmount());
|
||||
|
||||
int compareResult = originPayoffAmount.compareTo(betAmount);
|
||||
long payoffTime = TimestampFromString.to(dataBean.getSettleTime());
|
||||
long createTime = TimestampFromString.to(dataBean.getCreateTime());
|
||||
Platform platform = gamesDataBuildDTO.getPlatform();
|
||||
String systemCurrency = platform.getOurCurrency(dataBean.getCurrency().toString());
|
||||
//数据构造
|
||||
GameBettingDetails gameBettingDetails = GameBettingDetails.builder()
|
||||
.tenantKey(member.getTenantKey())
|
||||
//保存我们的币种id
|
||||
.currencyCode(systemCurrency)
|
||||
.memberId(member.getId())
|
||||
.gameCode(game.getGameCode())
|
||||
.gameType(8) // 体育
|
||||
.platformCode(GamePlatforms.FBSports.getCode())
|
||||
.gameId(game.getGameId())
|
||||
.gameName(game.getGameName())
|
||||
.gameStatus(compareResult > 0 ? GameStatus.WIN.getCode() : compareResult < 0 ? GameStatus.FAIL.getCode() : GameStatus.FLAT.getCode())
|
||||
.gameStatusType(1) // 一般下注
|
||||
.gameCurrencyCode(dataBean.getCurrency().toString())
|
||||
.account(dataBean.getMerchantUserId())
|
||||
.wagersId(dataBean.getId())
|
||||
.wagersTime(createTime)
|
||||
.betAmount(betAmount)
|
||||
.payoffTime(payoffTime)
|
||||
.payoffAmount(originPayoffAmount.abs())
|
||||
.settlementTime(payoffTime)
|
||||
.turnover(betAmount)
|
||||
.orderNo(dataBean.getId())
|
||||
.settlementStatus(SettlementStatusEnum.COMPLETED.getCode())
|
||||
.build();
|
||||
gameBettingDetails.setCreateBy(Constants.SYSTEM);
|
||||
gameBettingDetails.setCreateTime(DateUtils.getNowDate());
|
||||
return gameBettingDetails;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package com.ff.utils;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
/**
|
||||
* @author cengy
|
||||
*/
|
||||
public class CalculateDateDaysAgo {
|
||||
|
||||
public static LocalDate get(int daysToSubtract) {
|
||||
return LocalDate.now().minusDays(daysToSubtract);
|
||||
}
|
||||
|
||||
public static String getStr(int daysToSubtract) {
|
||||
// 获取当前日期减去指定天数
|
||||
LocalDate date = get(daysToSubtract);
|
||||
|
||||
// 定义日期格式
|
||||
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
||||
|
||||
// 返回格式化日期字符串
|
||||
return date.format(formatter);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
package com.ff.utils;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author cengy
|
||||
*/
|
||||
public class SortByAttributeNameASC {
|
||||
public static String get(Object o) {
|
||||
// Create a map to store field names and values
|
||||
Map<String, Object> fieldMap = new LinkedHashMap<>();
|
||||
|
||||
// Get all fields of the class
|
||||
Field[] fields = o.getClass().getDeclaredFields();
|
||||
|
||||
// Sort field names
|
||||
Arrays.sort(fields, (f1, f2) -> f1.getName().compareTo(f2.getName()));
|
||||
|
||||
// Fill the map with sorted fields and their values
|
||||
for (Field field : fields) {
|
||||
field.setAccessible(true); // Make private fields accessible
|
||||
Object value = null;
|
||||
try {
|
||||
value = field.get(o);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
fieldMap.put(field.getName(), value);
|
||||
}
|
||||
|
||||
|
||||
return JSON.toJSONString(fieldMap);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
package com.ff.utils;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author cengy
|
||||
*/
|
||||
public class TimestampFromString {
|
||||
|
||||
public static final String PATTERN_DATE = "yyyy-MM-dd HH:mm:ss";
|
||||
|
||||
public static Long from(String date) {
|
||||
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(PATTERN_DATE);
|
||||
try {
|
||||
Date parse = simpleDateFormat.parse(date);
|
||||
return parse.getTime();
|
||||
} catch (ParseException e) {
|
||||
return 0L;
|
||||
}
|
||||
}
|
||||
|
||||
public static Long to(String timestamp) {
|
||||
return Long.parseLong(timestamp);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue