feat(quota): 添加真实余额变动功能并实现日用额度结算- 新增 BalanceRealChangesDTO 类用于真实余额变动

- 在 ITenantGameQuotaService 中添加 balanceRealChanges 方法
- 在 TenantGameQuotaServiceImpl 中实现 balanceRealChanges 方法
- 在 ITenantGameQuotaFlowService 中添加 getBalanceByTenantKey 方法
- 在 TenantGameQuotaFlowMapper 中添加 getBalanceByTenantKey 方法的 SQL
- 在 TenantQuotaTask 中实现更新租户实际配额的逻辑- 在 OperationType 枚举中添加 REAL_BALANCE_SETTLEMENT 类型
main-p
shi 2025-02-22 15:08:01 +08:00
parent 7df30a21e1
commit 365da941c9
9 changed files with 233 additions and 22 deletions

View File

@ -0,0 +1,52 @@
package com.ff.common.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.math.BigDecimal;
/**
*
*
* @author shi
* @date 2025/02/12
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class BalanceRealChangesDTO implements Serializable {
private static final long serialVersionUID = -4864053711644163092L;
/** 充值类型 false 扣除 true 充值 */
private Boolean isOut;
/** 租户key */
private String tenantKey;
/** 游戏额度 */
private BigDecimal balance;
/** 备注 */
private String remark;
/** 操作类型 OperationType枚举 */
private Integer operationType;
/**
*
*/
private BigDecimal actualBalance;
/** 币种代码 */
private String currencyCode;
}

View File

@ -3,6 +3,7 @@ package com.ff.common.mapper;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.List; import java.util.List;
import com.ff.common.domain.TenantGameQuotaFlow; import com.ff.common.domain.TenantGameQuotaFlow;
import org.apache.ibatis.annotations.Param;
/** /**
* Mapper * Mapper
@ -68,4 +69,15 @@ public interface TenantGameQuotaFlowMapper
* @return {@link BigDecimal } * @return {@link BigDecimal }
*/ */
BigDecimal getExchangeMoneyByMemberId(TenantGameQuotaFlow tenantGameQuotaFlow); BigDecimal getExchangeMoneyByMemberId(TenantGameQuotaFlow tenantGameQuotaFlow);
/**
*
*
* @param tenantGameQuotaFlow
* @return {@link List }<{@link TenantGameQuotaFlow }>
*/
List<TenantGameQuotaFlow> getBalanceByTenantKey(TenantGameQuotaFlow tenantGameQuotaFlow);
} }

View File

@ -67,4 +67,13 @@ public interface ITenantGameQuotaFlowService
* @return {@link BigDecimal } * @return {@link BigDecimal }
*/ */
BigDecimal getExchangeMoneyByMemberId(TenantGameQuotaFlow tenantGameQuotaFlow); BigDecimal getExchangeMoneyByMemberId(TenantGameQuotaFlow tenantGameQuotaFlow);
/**
*
*
* @param tenantGameQuotaFlow
* @return {@link List }<{@link TenantGameQuotaFlow }>
*/
List<TenantGameQuotaFlow> getBalanceByTenantKey(TenantGameQuotaFlow tenantGameQuotaFlow);
} }

View File

@ -4,6 +4,7 @@ import java.math.BigDecimal;
import java.util.List; import java.util.List;
import com.ff.common.domain.TenantGameQuota; import com.ff.common.domain.TenantGameQuota;
import com.ff.common.dto.BalanceChangesDTO; import com.ff.common.dto.BalanceChangesDTO;
import com.ff.common.dto.BalanceRealChangesDTO;
import com.ff.common.dto.GameBalanceExchange; import com.ff.common.dto.GameBalanceExchange;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
@ -73,6 +74,15 @@ public interface ITenantGameQuotaService
*/ */
Boolean balanceChanges(BalanceChangesDTO balanceChangesDTO); Boolean balanceChanges(BalanceChangesDTO balanceChangesDTO);
/**
*
*
* @param balanceRealChangesDTO
* @return {@link Boolean }
*/
Boolean balanceRealChanges(BalanceRealChangesDTO balanceRealChangesDTO);
/** /**
* *
* *

View File

@ -2,6 +2,7 @@ package com.ff.common.service.impl;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.List; import java.util.List;
import com.ff.base.utils.DateUtils; import com.ff.base.utils.DateUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@ -16,8 +17,7 @@ import com.ff.common.service.ITenantGameQuotaFlowService;
* @date 2025-02-12 * @date 2025-02-12
*/ */
@Service @Service
public class TenantGameQuotaFlowServiceImpl implements ITenantGameQuotaFlowService public class TenantGameQuotaFlowServiceImpl implements ITenantGameQuotaFlowService {
{
@Autowired @Autowired
private TenantGameQuotaFlowMapper tenantGameQuotaFlowMapper; private TenantGameQuotaFlowMapper tenantGameQuotaFlowMapper;
@ -28,8 +28,7 @@ public class TenantGameQuotaFlowServiceImpl implements ITenantGameQuotaFlowServi
* @return * @return
*/ */
@Override @Override
public TenantGameQuotaFlow selectTenantGameQuotaFlowById(Long id) public TenantGameQuotaFlow selectTenantGameQuotaFlowById(Long id) {
{
return tenantGameQuotaFlowMapper.selectTenantGameQuotaFlowById(id); return tenantGameQuotaFlowMapper.selectTenantGameQuotaFlowById(id);
} }
@ -40,8 +39,7 @@ public class TenantGameQuotaFlowServiceImpl implements ITenantGameQuotaFlowServi
* @return * @return
*/ */
@Override @Override
public List<TenantGameQuotaFlow> selectTenantGameQuotaFlowList(TenantGameQuotaFlow tenantGameQuotaFlow) public List<TenantGameQuotaFlow> selectTenantGameQuotaFlowList(TenantGameQuotaFlow tenantGameQuotaFlow) {
{
return tenantGameQuotaFlowMapper.selectTenantGameQuotaFlowList(tenantGameQuotaFlow); return tenantGameQuotaFlowMapper.selectTenantGameQuotaFlowList(tenantGameQuotaFlow);
} }
@ -52,8 +50,7 @@ public class TenantGameQuotaFlowServiceImpl implements ITenantGameQuotaFlowServi
* @return * @return
*/ */
@Override @Override
public int insertTenantGameQuotaFlow(TenantGameQuotaFlow tenantGameQuotaFlow) public int insertTenantGameQuotaFlow(TenantGameQuotaFlow tenantGameQuotaFlow) {
{
tenantGameQuotaFlow.setCreateTime(DateUtils.getNowDate()); tenantGameQuotaFlow.setCreateTime(DateUtils.getNowDate());
return tenantGameQuotaFlowMapper.insertTenantGameQuotaFlow(tenantGameQuotaFlow); return tenantGameQuotaFlowMapper.insertTenantGameQuotaFlow(tenantGameQuotaFlow);
} }
@ -65,8 +62,7 @@ public class TenantGameQuotaFlowServiceImpl implements ITenantGameQuotaFlowServi
* @return * @return
*/ */
@Override @Override
public int updateTenantGameQuotaFlow(TenantGameQuotaFlow tenantGameQuotaFlow) public int updateTenantGameQuotaFlow(TenantGameQuotaFlow tenantGameQuotaFlow) {
{
tenantGameQuotaFlow.setUpdateTime(DateUtils.getNowDate()); tenantGameQuotaFlow.setUpdateTime(DateUtils.getNowDate());
return tenantGameQuotaFlowMapper.updateTenantGameQuotaFlow(tenantGameQuotaFlow); return tenantGameQuotaFlowMapper.updateTenantGameQuotaFlow(tenantGameQuotaFlow);
} }
@ -78,8 +74,7 @@ public class TenantGameQuotaFlowServiceImpl implements ITenantGameQuotaFlowServi
* @return * @return
*/ */
@Override @Override
public int deleteTenantGameQuotaFlowByIds(Long[] ids) public int deleteTenantGameQuotaFlowByIds(Long[] ids) {
{
return tenantGameQuotaFlowMapper.deleteTenantGameQuotaFlowByIds(ids); return tenantGameQuotaFlowMapper.deleteTenantGameQuotaFlowByIds(ids);
} }
@ -90,8 +85,7 @@ public class TenantGameQuotaFlowServiceImpl implements ITenantGameQuotaFlowServi
* @return * @return
*/ */
@Override @Override
public int deleteTenantGameQuotaFlowById(Long id) public int deleteTenantGameQuotaFlowById(Long id) {
{
return tenantGameQuotaFlowMapper.deleteTenantGameQuotaFlowById(id); return tenantGameQuotaFlowMapper.deleteTenantGameQuotaFlowById(id);
} }
@ -105,4 +99,16 @@ public class TenantGameQuotaFlowServiceImpl implements ITenantGameQuotaFlowServi
public BigDecimal getExchangeMoneyByMemberId(TenantGameQuotaFlow tenantGameQuotaFlow) { public BigDecimal getExchangeMoneyByMemberId(TenantGameQuotaFlow tenantGameQuotaFlow) {
return tenantGameQuotaFlowMapper.getExchangeMoneyByMemberId(tenantGameQuotaFlow); return tenantGameQuotaFlowMapper.getExchangeMoneyByMemberId(tenantGameQuotaFlow);
} }
/**
*
*
* @param tenantGameQuotaFlow
* @return {@link List }<{@link TenantGameQuotaFlow }>
*/
@Override
public List<TenantGameQuotaFlow> getBalanceByTenantKey(TenantGameQuotaFlow tenantGameQuotaFlow) {
return tenantGameQuotaFlowMapper.getBalanceByTenantKey(tenantGameQuotaFlow);
}
} }

View File

@ -17,6 +17,7 @@ import com.ff.common.domain.TenantGameQuotaFlow;
import com.ff.common.domain.TenantQuotaExchange; import com.ff.common.domain.TenantQuotaExchange;
import com.ff.common.domain.TenantSecretKey; import com.ff.common.domain.TenantSecretKey;
import com.ff.common.dto.BalanceChangesDTO; import com.ff.common.dto.BalanceChangesDTO;
import com.ff.common.dto.BalanceRealChangesDTO;
import com.ff.common.dto.GameBalanceExchange; import com.ff.common.dto.GameBalanceExchange;
import com.ff.common.service.ITenantGameQuotaFlowService; import com.ff.common.service.ITenantGameQuotaFlowService;
import com.ff.common.service.ITenantQuotaExchangeService; import com.ff.common.service.ITenantQuotaExchangeService;
@ -212,6 +213,60 @@ public class TenantGameQuotaServiceImpl implements ITenantGameQuotaService {
return changedBalanceResult; return changedBalanceResult;
} }
/**
*
*
* @param balanceRealChangesDTO
* @return {@link Boolean }
*/
@Override
public Boolean balanceRealChanges(BalanceRealChangesDTO balanceRealChangesDTO) {
TenantGameQuota tenantGameQuota = this.selectTenantGameQuotaByTenantKey(balanceRealChangesDTO.getTenantKey(),QuotaType.REAL_BALANCE.getCode());
BigDecimal balanceBefore = tenantGameQuota.getBalance();
BigDecimal balance = balanceRealChangesDTO.getBalance();
//如果有汇率 则需要计算真实扣除额度
if (!ObjectUtils.isEmpty(balanceRealChangesDTO.getActualBalance())) {
balance = NumberUtil.div(balance, balanceRealChangesDTO.getActualBalance(), 2, RoundingMode.FLOOR);
}
if (BigDecimal.ZERO.compareTo(balance) >= 0) {
return Boolean.TRUE;
}
BigDecimal balanceAfter;
//判断是充值还是扣除
if (balanceRealChangesDTO.getIsOut()) {
balanceAfter = NumberUtil.add(balanceBefore, balance);
} else {
balanceAfter = NumberUtil.sub(balanceBefore, balance);
}
//修改余额
Boolean changedBalanceResult = tenantGameQuotaMapper.changeBalance(TenantGameQuota.builder()
.tenantKey(balanceRealChangesDTO.getTenantKey())
.balance(balanceAfter)
.quotaType(QuotaType.REAL_BALANCE.getCode())
.version(tenantGameQuota.getVersion())
.build());
//插入流水
TenantGameQuotaFlow tenantGameQuotaFlow = TenantGameQuotaFlow.builder()
.quotaType(QuotaType.REAL_BALANCE.getCode())
.tenantKey(balanceRealChangesDTO.getTenantKey())
.isOut(balanceRealChangesDTO.getIsOut())
.currencyCode(balanceRealChangesDTO.getCurrencyCode())
.balanceAfter(balanceAfter)
.exchangeRatio(balanceRealChangesDTO.getActualBalance())
.exchangeMoney(balanceRealChangesDTO.getBalance())
.balance(balance)
.balanceBefore(balanceBefore)
.operationType(balanceRealChangesDTO.getOperationType())
.build();
tenantGameQuotaFlow.setRemark(balanceRealChangesDTO.getRemark());
tenantGameQuotaFlow.setCreateTime(DateUtils.getNowDate());
tenantGameQuotaFlow.setCreateBy(Constants.SYSTEM);
tenantGameQuotaFlowService.insertTenantGameQuotaFlow(tenantGameQuotaFlow);
return changedBalanceResult;
}
/** /**
* *
* *

View File

@ -1,13 +1,28 @@
package com.ff.quartz.task; package com.ff.quartz.task;
import com.ff.base.constant.Constants;
import com.ff.base.enums.OperationType;
import com.ff.base.enums.QuotaType;
import com.ff.base.utils.DateUtils;
import com.ff.common.domain.TenantGameQuota; import com.ff.common.domain.TenantGameQuota;
import com.ff.common.domain.TenantGameQuotaFlow;
import com.ff.common.domain.TenantQuotaExchange;
import com.ff.common.domain.TenantSecretKey;
import com.ff.common.dto.BalanceChangesDTO;
import com.ff.common.dto.BalanceRealChangesDTO;
import com.ff.common.service.ITenantGameQuotaFlowService;
import com.ff.common.service.ITenantGameQuotaService; import com.ff.common.service.ITenantGameQuotaService;
import com.ff.common.service.ITenantQuotaExchangeService;
import com.ff.common.service.ITenantSecretKeyService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* *
@ -19,15 +34,57 @@ import java.util.List;
@Component("tenantQuotaTask") @Component("tenantQuotaTask")
public class TenantQuotaTask { public class TenantQuotaTask {
@Resource @Resource
private ITenantGameQuotaService tenantGameQuotaService; private ITenantGameQuotaService tenantGameQuotaService;
@Resource
private ITenantGameQuotaFlowService tenantGameQuotaFlowService;
@Resource
private ITenantSecretKeyService tenantSecretKeyService;
@Resource
private ITenantQuotaExchangeService tenantQuotaExchangeService;
/** /**
* *
*/ */
// public void updateTenantRealQuota() { public void updateTenantRealQuota() {
// List<TenantGameQuota> tenantGameQuotas = tenantGameQuotaService.selectTenantGameQuotaList(TenantGameQuota.builder() Long yesterdayStart = DateUtils.getYesterdayStart();
// .quotaType(TenantGameQuota.TenantQuotaType.TENANT_REAL_QUOTA.getCode()) Long yesterdayEnd = DateUtils.getYesterdayEnd();
// .build()); TenantGameQuotaFlow gameQuotaFlow = TenantGameQuotaFlow.builder()
// } .quotaType(QuotaType.BALANCE.getCode())
.operationType(OperationType.API_BALANCE.getCode())
.build();
Map<String, Object> params = gameQuotaFlow.getParams();
params.put("beginTime", yesterdayStart);
params.put("endTime", yesterdayEnd);
List<TenantGameQuotaFlow> balanceByTenantKey = tenantGameQuotaFlowService.getBalanceByTenantKey(gameQuotaFlow);
for (TenantGameQuotaFlow tenantGameQuotaFlow : balanceByTenantKey) {
BigDecimal balance = tenantGameQuotaFlow.getExchangeMoney();
Boolean isOut = Boolean.TRUE;
// 添加判断逻辑
if (balance.compareTo(BigDecimal.ZERO) < 0) {
balance = balance.abs();
isOut = Boolean.FALSE;
}
TenantQuotaExchange tenantQuotaExchange = tenantQuotaExchangeService.getTenantQuotaExchange(Constants.USDT, tenantGameQuotaFlow.getCurrencyCode());
//更新额度
BalanceRealChangesDTO realChangesDTO = BalanceRealChangesDTO.builder()
.isOut(isOut)
.tenantKey(tenantGameQuotaFlow.getTenantKey())
.balance(balance)
.remark(OperationType.REAL_BALANCE_SETTLEMENT.getDescription())
.operationType(OperationType.REAL_BALANCE_SETTLEMENT.getCode())
.currencyCode(tenantGameQuotaFlow.getCurrencyCode())
.actualBalance(tenantQuotaExchange.getActualBalance())
.build();
Boolean result = tenantGameQuotaService.balanceRealChanges(realChangesDTO);
//如果没成功重新跑
while (!result) {
result = tenantGameQuotaService.balanceRealChanges(realChangesDTO);
}
}
}
} }

View File

@ -145,4 +145,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
group by member_id group by member_id
</select> </select>
<select id="getBalanceByTenantKey" resultMap="TenantGameQuotaFlowResult">
select tenant_key, sum(if(is_out,exchange_money,0))-sum(if(!is_out,exchange_money,0)) as exchange_money,currency_code
from ff_tenant_game_quota_flow
where create_time between #{params.beginTime} and #{params.endTime}
and quota_type =#{quotaType} and operation_type = #{operationType}
group by tenant_key,currency_code
</select>
</mapper> </mapper>

View File

@ -10,7 +10,9 @@ import lombok.Getter;
*/ */
@Getter @Getter
public enum OperationType { public enum OperationType {
API_BALANCE(1, "租户游玩操作余额"); API_BALANCE(1, "租户游玩操作余额"),
REAL_BALANCE_SETTLEMENT(2, "日用额度结算")
;
private final Integer code; private final Integer code;
private final String description; private final String description;