From 324b8dc2d59ae73672ac1a3915eec6752cba53b1 Mon Sep 17 00:00:00 2001 From: tianfeng <769204422@qq.com> Date: Fri, 26 Sep 2025 17:50:29 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=20transfer=20gold=20?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../wallet/inner/model/enums/GoldOrigin.java | 5 + .../inner/model/enums/UserBankWaterEvent.java | 5 + .../adapter/app/BankRestController.java | 14 ++ .../bank/UserBankTransferGoldCmdExe.java | 195 ++++++++++++++++++ .../app/service/UserBankServiceImpl.java | 6 + .../wallet/app/service/UserBankService.java | 5 + 6 files changed, 230 insertions(+) create mode 100644 rc-service/rc-service-wallet/wallet-application/src/main/java/com/red/circle/wallet/app/command/bank/UserBankTransferGoldCmdExe.java diff --git a/rc-service/rc-inner-api/wallet-inner/wallet-inner-model/src/main/java/com/red/circle/wallet/inner/model/enums/GoldOrigin.java b/rc-service/rc-inner-api/wallet-inner/wallet-inner-model/src/main/java/com/red/circle/wallet/inner/model/enums/GoldOrigin.java index 705fcf95..22f566bb 100644 --- a/rc-service/rc-inner-api/wallet-inner/wallet-inner-model/src/main/java/com/red/circle/wallet/inner/model/enums/GoldOrigin.java +++ b/rc-service/rc-inner-api/wallet-inner/wallet-inner-model/src/main/java/com/red/circle/wallet/inner/model/enums/GoldOrigin.java @@ -619,6 +619,11 @@ public enum GoldOrigin { */ BANK_GOLD_COIN_EXCHANGE("[Bank]Gold coin exchange"), + /** + * 转账金币. + */ + BANK_GOLD_COIN_TRANSFER("[Bank]Gold coin transfer"), + /** * 幸运礼物. */ diff --git a/rc-service/rc-inner-api/wallet-inner/wallet-inner-model/src/main/java/com/red/circle/wallet/inner/model/enums/UserBankWaterEvent.java b/rc-service/rc-inner-api/wallet-inner/wallet-inner-model/src/main/java/com/red/circle/wallet/inner/model/enums/UserBankWaterEvent.java index 177435ec..e4ae0681 100644 --- a/rc-service/rc-inner-api/wallet-inner/wallet-inner-model/src/main/java/com/red/circle/wallet/inner/model/enums/UserBankWaterEvent.java +++ b/rc-service/rc-inner-api/wallet-inner/wallet-inner-model/src/main/java/com/red/circle/wallet/inner/model/enums/UserBankWaterEvent.java @@ -15,6 +15,11 @@ public enum UserBankWaterEvent { */ TRANSFER("Transfer"), + /** + * 转账金币. + */ + TRANSFER_GOLD("Transfer"), + /** * 接收转账. */ diff --git a/rc-service/rc-service-wallet/wallet-adapter/src/main/java/com/red/circle/wallet/adapter/app/BankRestController.java b/rc-service/rc-service-wallet/wallet-adapter/src/main/java/com/red/circle/wallet/adapter/app/BankRestController.java index 42ccddca..f2914a91 100644 --- a/rc-service/rc-service-wallet/wallet-adapter/src/main/java/com/red/circle/wallet/adapter/app/BankRestController.java +++ b/rc-service/rc-service-wallet/wallet-adapter/src/main/java/com/red/circle/wallet/adapter/app/BankRestController.java @@ -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); + } + /** * 钻石转账. * diff --git a/rc-service/rc-service-wallet/wallet-application/src/main/java/com/red/circle/wallet/app/command/bank/UserBankTransferGoldCmdExe.java b/rc-service/rc-service-wallet/wallet-application/src/main/java/com/red/circle/wallet/app/command/bank/UserBankTransferGoldCmdExe.java new file mode 100644 index 00000000..f545b00f --- /dev/null +++ b/rc-service/rc-service-wallet/wallet-application/src/main/java/com/red/circle/wallet/app/command/bank/UserBankTransferGoldCmdExe.java @@ -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 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(); + } + +} diff --git a/rc-service/rc-service-wallet/wallet-application/src/main/java/com/red/circle/wallet/app/service/UserBankServiceImpl.java b/rc-service/rc-service-wallet/wallet-application/src/main/java/com/red/circle/wallet/app/service/UserBankServiceImpl.java index e412ab8f..57425859 100644 --- a/rc-service/rc-service-wallet/wallet-application/src/main/java/com/red/circle/wallet/app/service/UserBankServiceImpl.java +++ b/rc-service/rc-service-wallet/wallet-application/src/main/java/com/red/circle/wallet/app/service/UserBankServiceImpl.java @@ -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); diff --git a/rc-service/rc-service-wallet/wallet-client/src/main/java/com/red/circle/wallet/app/service/UserBankService.java b/rc-service/rc-service-wallet/wallet-client/src/main/java/com/red/circle/wallet/app/service/UserBankService.java index d92b4621..421cc8be 100644 --- a/rc-service/rc-service-wallet/wallet-client/src/main/java/com/red/circle/wallet/app/service/UserBankService.java +++ b/rc-service/rc-service-wallet/wallet-client/src/main/java/com/red/circle/wallet/app/service/UserBankService.java @@ -54,6 +54,11 @@ public interface UserBankService { */ UserBankWithdrawResultCO transfer(UserBankWithdrawTransferCmd cmd); + /** + * 转账到金币. + */ + UserBankWithdrawResultCO transferGold(UserBankWithdrawTransferCmd cmd); + /** * 钻石转账. */