新增 transfer gold 接口

This commit is contained in:
tianfeng 2025-09-26 17:50:29 +08:00
parent 6b78840f5e
commit 324b8dc2d5
6 changed files with 230 additions and 0 deletions

View File

@ -619,6 +619,11 @@ public enum GoldOrigin {
*/
BANK_GOLD_COIN_EXCHANGE("[Bank]Gold coin exchange"),
/**
* 转账金币.
*/
BANK_GOLD_COIN_TRANSFER("[Bank]Gold coin transfer"),
/**
* 幸运礼物.
*/

View File

@ -15,6 +15,11 @@ public enum UserBankWaterEvent {
*/
TRANSFER("Transfer"),
/**
* 转账金币.
*/
TRANSFER_GOLD("Transfer"),
/**
* 接收转账.
*/

View File

@ -123,6 +123,20 @@ public class BankRestController extends BaseController {
return userBankService.transfer(cmd);
}
/**
* 转账到金币.
*
* @eo.name 转账到金币.
* @eo.url /transferGold
* @eo.method post
* @eo.request-type json
*/
@PostMapping("/transferGold")
public UserBankWithdrawResultCO transferGold(
@RequestBody @Validated UserBankWithdrawTransferCmd cmd) {
return userBankService.transferGold(cmd);
}
/**
* 钻石转账.
*

View File

@ -0,0 +1,195 @@
package com.red.circle.wallet.app.command.bank;
import com.red.circle.common.business.core.enums.OpUserType;
import com.red.circle.common.business.core.enums.ReceiptType;
import com.red.circle.common.business.core.enums.SysOriginPlatformEnum;
import com.red.circle.component.redis.service.RedisService;
import com.red.circle.framework.core.asserts.ResponseAssert;
import com.red.circle.framework.core.response.CommonErrorCode;
import com.red.circle.framework.core.response.ResponseErrorCode;
import com.red.circle.order.inner.endpoint.UserFreightRechargeRecordClient;
import com.red.circle.order.inner.endpoint.UserRechargeCountClient;
import com.red.circle.other.inner.endpoint.team.target.TeamMemberClient;
import com.red.circle.other.inner.endpoint.team.target.UserBillDiamondBalanceClient;
import com.red.circle.other.inner.endpoint.user.region.UserRegionClient;
import com.red.circle.other.inner.endpoint.user.user.UserSvipClient;
import com.red.circle.other.inner.model.dto.user.SysExchangeGoldTipDTO;
import com.red.circle.tool.core.date.TimestampUtils;
import com.red.circle.tool.core.num.ArithmeticUtils;
import com.red.circle.tool.core.sequence.IdWorkerUtils;
import com.red.circle.tool.core.tuple.PennyAmount;
import com.red.circle.wallet.app.dto.clientobject.UserBankWithdrawResultCO;
import com.red.circle.wallet.app.dto.cmd.UserBankExchangeGoldCmd;
import com.red.circle.wallet.app.dto.cmd.UserBankWithdrawTransferCmd;
import com.red.circle.wallet.domain.gateway.WalletGoldGateway;
import com.red.circle.wallet.domain.wallet.WalletReceipt;
import com.red.circle.wallet.infra.database.cache.service.UserPayAuthCacheService;
import com.red.circle.wallet.infra.database.mongo.entity.bank.UserBankRunningWater;
import com.red.circle.wallet.infra.database.mongo.service.bank.UserBankBalanceService;
import com.red.circle.wallet.infra.database.mongo.service.bank.UserBankRunningWaterService;
import com.red.circle.wallet.infra.database.mongo.service.bank.UserBankWithdrawGoldApplyService;
import com.red.circle.wallet.infra.database.rds.entity.freight.FreightBalanceRunningWater;
import com.red.circle.wallet.infra.database.rds.service.auth.PayAuthService;
import com.red.circle.wallet.infra.database.rds.service.diamond.SalaryDiamondBalanceService;
import com.red.circle.wallet.infra.database.rds.service.diamond.SalaryDiamondRunningWaterService;
import com.red.circle.wallet.infra.database.rds.service.freight.FreightBalanceRunningWaterService;
import com.red.circle.wallet.infra.database.rds.service.freight.FreightBalanceService;
import com.red.circle.wallet.inner.error.WalletErrorCode;
import com.red.circle.wallet.inner.model.dto.BankBalanceDTO;
import com.red.circle.wallet.inner.model.enums.FreightBalanceOrigin;
import com.red.circle.wallet.inner.model.enums.GoldOrigin;
import com.red.circle.wallet.inner.model.enums.UserBankWaterEvent;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
/**
* 用户银行转账到金币命令执行器
*
* @author system
*/
@Component
@RequiredArgsConstructor
public class UserBankTransferGoldCmdExe {
private final RedisService redisService;
private final UserBankBalanceService userBankBalanceService;
private final UserBankRunningWaterService userBankRunningWaterService;
private final WalletGoldGateway walletGoldGateway;
private final FreightBalanceService freightBalanceService;
private final UserRegionClient userRegionClient;
private final FreightBalanceRunningWaterService freightBalanceRunningWaterService;
/**
* 执行转账到金币操作
*
* @param cmd 转账命令
* @return 转账结果
*/
public UserBankWithdrawResultCO execute(UserBankWithdrawTransferCmd cmd) {
ResponseAssert.isTrue(ResponseErrorCode.REQUEST_PARAMETER_ERROR,
ArithmeticUtils.gtZero(cmd.getAmount()));
// 上锁
String key = "UBWTransferGold:" + cmd.requiredReqUserId();
ResponseAssert.isTrue(CommonErrorCode.REQUEST_LIMITING, redisService.lock(key, 60));
BigDecimal balance = userBankBalanceService.getBalance(cmd.requiredReqUserId())
.getAccurateBalance();
ResponseAssert.isTrue(WalletErrorCode.INSUFFICIENT_BALANCE,
ArithmeticUtils.gte(balance, cmd.getAmount()));
// 扣钱
BankBalanceDTO decrUserBankBalanceDTO = userBankBalanceService.decr(cmd.requiredReqUserId(),
PennyAmount.ofDollar(cmd.getAmount()));
ResponseAssert.notNull(WalletErrorCode.INSUFFICIENT_BALANCE, decrUserBankBalanceDTO);
Long bankRunWaterId = IdWorkerUtils.getId();
// 银行卡流水
userBankRunningWaterService.add(
new UserBankRunningWater()
.setId(bankRunWaterId)
.setUserId(cmd.requiredReqUserId())
.setSysOrigin(cmd.requireReqSysOrigin())
.setType(ReceiptType.EXPENDITURE.getType())
.setAmount(cmd.getAmount())
.setEvent(UserBankWaterEvent.TRANSFER_GOLD.name())
.setEventDescribe(UserBankWaterEvent.TRANSFER_GOLD.getDescribe())
.setRemark("Withdrawal transfer")
.setTrackId(Objects.toString(cmd.getAcceptUserId()))
.setBalance(decrUserBankBalanceDTO.getAccurateBalance())
.setCreateTime(TimestampUtils.now())
.setUpdateTime(TimestampUtils.now())
.setCreateUser(cmd.getReqUserId())
.setCreateUserOrigin(OpUserType.APP.getType())
);
boolean freight = freightBalanceService.existsBalance(cmd.getAcceptUserId());
// 获得区域兑换比例金币比例
Double goldRatio = getExchangeGoldRatio(cmd);
BigDecimal goldQuantity = BigDecimal.valueOf(goldRatio).multiply(cmd.getAmount()).setScale(0, RoundingMode.DOWN);
// 发送金额
sendGold(cmd, freight, goldQuantity, bankRunWaterId, "转账金币");
redisService.unlock(key);
return new UserBankWithdrawResultCO()
.setBankBalance(decrUserBankBalanceDTO.getAccurateBalance())
.setWithdrawAmount(Objects.toString(cmd.getAmount()));
}
private void sendGold(UserBankWithdrawTransferCmd cmd, boolean freight, BigDecimal goldQuantity,
Long bankRunWaterId, String remark) {
if (freight) {
// 货运代理入账
ResponseAssert.isTrue(CommonErrorCode.OPERATING_FAILURE,
freightBalanceService
.incrCandyBalance(SysOriginPlatformEnum.valueOf(cmd.getReqSysOrigin().getOrigin()),
cmd.getAcceptUserId(), goldQuantity));
// 插入流水
BigDecimal freightBalance = freightBalanceService.getAvailableBalance(cmd.getAcceptUserId());
freightBalanceRunningWaterService.save(new FreightBalanceRunningWater()
.setSysOrigin(cmd.getReqSysOrigin().getOrigin())
.setUserId(cmd.getReqUserId())
.setAcceptUserId(cmd.getAcceptUserId())
.setType(ReceiptType.INCOME.getType())
.setQuantity(goldQuantity)
.setUsdQuantity(cmd.getAmount())
.setBalance(freightBalance)
.setOrigin(FreightBalanceOrigin.PURCHASE.name())
.setRemark(remark)
.withCreateUser(cmd.getReqUserId()));
return;
}
// 金币入账
walletGoldGateway.changeBalance(new WalletReceipt()
.setReqTraceId(cmd.getReqTraceId())
.setReceiptType(ReceiptType.INCOME)
.setUserId(cmd.getAcceptUserId())
.setSysOrigin(cmd.getReqSysOrigin().getOrigin())
.setEventType(Objects.toString(GoldOrigin.BANK_GOLD_COIN_TRANSFER))
.setEventDesc(GoldOrigin.BANK_GOLD_COIN_TRANSFER.getDesc())
.setEventId(Objects.toString(bankRunWaterId))
.setAmount(PennyAmount.ofDollar(goldQuantity.longValue()))
.setOpUserType(OpUserType.APP)
.setCreateTime(cmd.getReqTime())
);
}
/**
* 获得1$兑换多少金币比例 基于区域+用户输入的美元.
*
* @return 1美元可获得的金币数量.
*/
private Double getExchangeGoldRatio(UserBankWithdrawTransferCmd cmd) {
boolean freight = freightBalanceService.existsBalance(cmd.getReqUserId());
List<SysExchangeGoldTipDTO> exchangeGolds = ResponseAssert.requiredSuccess(
userRegionClient.listRegionExchangeGoldTip(cmd.getReqUserId(), freight));
ResponseAssert.notEmpty(CommonErrorCode.CONFIGURATION_ERROR, exchangeGolds);
exchangeGolds = exchangeGolds.stream().filter(gold ->
cmd.getAmount().compareTo(BigDecimal.valueOf(gold.getStart())) >= 0 &&
cmd.getAmount().compareTo(BigDecimal.valueOf(gold.getEnd())) <= 0)
.collect(Collectors.toList());
ResponseAssert.notEmpty(CommonErrorCode.CONFIGURATION_ERROR, exchangeGolds);
SysExchangeGoldTipDTO exchangeGold = exchangeGolds.get(0);
ResponseAssert.notNull(CommonErrorCode.CONFIGURATION_ERROR, exchangeGold);
ResponseAssert.isFalse(CommonErrorCode.CONFIGURATION_ERROR,
Objects.isNull(exchangeGold.getValue()) || exchangeGold.getValue() <= 0);
return exchangeGold.getValue();
}
}

View File

@ -48,6 +48,7 @@ public class UserBankServiceImpl implements UserBankService {
private final UserBankCheckWithdrawQryExe userBankCheckWithdrawQueryExe;
private final UserBankExchangeGoldTipQryExe userBankExchangeGoldTipQryExe;
private final UserBankWithdrawTransferCmdExe userBankWithdrawTransferCmdExe;
private final UserBankTransferGoldCmdExe userBankTransferGoldCmdExe;
private final UserBankDiamondWithdrawTransferCmdExe userBankDiamondWithdrawTransferCmdExe;
private final UserBankSearchUserProfileQryExe userBankSearchUserProfileQryExe;
private final UserBankCheckExchangeGoldQryExe userBankCheckExchangeGoldQryExe;
@ -83,6 +84,11 @@ public class UserBankServiceImpl implements UserBankService {
return userBankWithdrawTransferCmdExe.execute(cmd);
}
@Override
public UserBankWithdrawResultCO transferGold(UserBankWithdrawTransferCmd cmd) {
return userBankTransferGoldCmdExe.execute(cmd);
}
@Override
public UserBankWithdrawResultCO diamondTransfer(UserBankWithdrawTransferCmd cmd) {
return userBankDiamondWithdrawTransferCmdExe.execute(cmd);

View File

@ -54,6 +54,11 @@ public interface UserBankService {
*/
UserBankWithdrawResultCO transfer(UserBankWithdrawTransferCmd cmd);
/**
* 转账到金币.
*/
UserBankWithdrawResultCO transferGold(UserBankWithdrawTransferCmd cmd);
/**
* 钻石转账.
*/