From ba7a024e039a039ab239c1c597f63ad38d1c2a90 Mon Sep 17 00:00:00 2001
From: tianfeng <769204422@qq.com>
Date: Fri, 24 Oct 2025 11:24:40 +0800
Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=B4=BB=E5=8A=A8exchange=20?=
=?UTF-8?q?transfer=20=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../wallet/inner/model/enums/GoldOrigin.java | 10 +
.../LotteryActivityRestController.java | 39 +++-
.../activity/LotteryExchangeGoldExe.java | 142 +++++++++++++
.../command/activity/LotteryTransferExe.java | 193 ++++++++++++++++++
.../activity/LotteryWithdrawAmountQryExe.java | 10 +-
.../activity/LotteryWithdrawApplyExe.java | 13 +-
.../LotteryActivityRestServiceImpl.java | 18 +-
.../cmd/activity/LotteryExchangeGoldCmd.java | 34 +++
.../dto/cmd/activity/LotteryTransferCmd.java | 40 ++++
.../dto/cmd/activity/LotteryWithdrawCmd.java | 5 +-
.../activity/LotteryActivityRestService.java | 14 +-
11 files changed, 493 insertions(+), 25 deletions(-)
create mode 100644 rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/LotteryExchangeGoldExe.java
create mode 100644 rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/LotteryTransferExe.java
create mode 100644 rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/activity/LotteryExchangeGoldCmd.java
create mode 100644 rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/activity/LotteryTransferCmd.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 1d4027cc..c1d544c3 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
@@ -702,6 +702,16 @@ public enum GoldOrigin {
* 抽奖奖励
*/
LOTTERY_REWARD("Lottery reward"),
+
+ /**
+ * 抽奖兑换金币
+ */
+ LOTTERY_EXCHANGE_GOLD("Lottery exchange gold"),
+
+ /**
+ * 抽奖转账金币
+ */
+ LOTTERY_TRANSFER_GOLD("Lottery transfer gold"),
;
private final String desc;
diff --git a/rc-service/rc-service-other/other-adapter/src/main/java/com/red/circle/other/adapter/app/activity/LotteryActivityRestController.java b/rc-service/rc-service-other/other-adapter/src/main/java/com/red/circle/other/adapter/app/activity/LotteryActivityRestController.java
index b2bb6ce9..3756db7c 100644
--- a/rc-service/rc-service-other/other-adapter/src/main/java/com/red/circle/other/adapter/app/activity/LotteryActivityRestController.java
+++ b/rc-service/rc-service-other/other-adapter/src/main/java/com/red/circle/other/adapter/app/activity/LotteryActivityRestController.java
@@ -20,6 +20,8 @@ import com.red.circle.other.app.dto.cmd.activity.LotteryRecordQryCmd;
import com.red.circle.other.app.dto.cmd.activity.LotteryWinnerHistoryQryCmd;
import com.red.circle.other.app.dto.cmd.activity.LotteryWithdrawCmd;
import com.red.circle.other.app.dto.cmd.activity.LotteryWithdrawQryCmd;
+import com.red.circle.other.app.dto.cmd.activity.LotteryExchangeGoldCmd;
+import com.red.circle.other.app.dto.cmd.activity.LotteryTransferCmd;
import com.red.circle.other.app.service.activity.LotteryActivityRestService;
import java.util.List;
@@ -27,12 +29,7 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.MediaType;
import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
/**
*
@@ -219,8 +216,34 @@ public class LotteryActivityRestController extends BaseController {
* @eo.request-type formdata
*/
@GetMapping("/withdraw/amount")
- public LotteryWithdrawAmountCO getWithdrawAmount(AppExtCommand cmd, Long activityId) {
- return lotteryActivityRestService.getWithdrawAmount(cmd, activityId);
+ public LotteryWithdrawAmountCO getWithdrawAmount(AppExtCommand cmd, @RequestParam Long activityId) {
+ return lotteryActivityRestService.getWithdrawAmount(cmd.getReqUserId(), activityId);
+ }
+
+ /**
+ * 可提现金额兑换金币.
+ *
+ * @eo.name 可提现金额兑换金币.
+ * @eo.url /exchange
+ * @eo.method post
+ * @eo.request-type json
+ */
+ @PostMapping("/exchange")
+ public void exchange(@RequestBody @Validated LotteryExchangeGoldCmd cmd) {
+ lotteryActivityRestService.exchangeGold(cmd);
+ }
+
+ /**
+ * 可提现金额转账给指定用户.
+ *
+ * @eo.name 可提现金额转账给指定用户.
+ * @eo.url /transfer
+ * @eo.method post
+ * @eo.request-type json
+ */
+ @PostMapping("/transfer")
+ public void transfer(@RequestBody @Validated LotteryTransferCmd cmd) {
+ lotteryActivityRestService.transfer(cmd);
}
}
diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/LotteryExchangeGoldExe.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/LotteryExchangeGoldExe.java
new file mode 100644
index 00000000..e5812940
--- /dev/null
+++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/LotteryExchangeGoldExe.java
@@ -0,0 +1,142 @@
+package com.red.circle.other.app.command.activity;
+
+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.other.app.dto.clientobject.activity.LotteryWithdrawAmountCO;
+import com.red.circle.other.app.dto.cmd.activity.LotteryExchangeGoldCmd;
+import com.red.circle.other.app.service.activity.LotteryActivityRestService;
+import com.red.circle.other.infra.database.rds.entity.activity.LotteryUserProgress;
+import com.red.circle.other.infra.database.rds.entity.activity.LotteryWithdraw;
+import com.red.circle.other.infra.database.rds.service.activity.LotteryUserProgressService;
+import com.red.circle.other.infra.database.rds.service.activity.LotteryWithdrawService;
+import com.red.circle.other.inner.endpoint.user.region.UserRegionClient;
+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.wallet.inner.endpoint.wallet.WalletGoldClient;
+import com.red.circle.wallet.inner.error.WalletErrorCode;
+import com.red.circle.wallet.inner.model.cmd.GoldReceiptCmd;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.time.LocalDate;
+import java.time.temporal.WeekFields;
+import java.util.List;
+import java.util.Locale;
+import java.util.Objects;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.stream.Collectors;
+
+import com.red.circle.wallet.inner.model.enums.GoldOrigin;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+/**
+ * 可提现金额兑换金币执行器.
+ *
+ * @author system
+ * @since 2025-10-24
+ */
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class LotteryExchangeGoldExe {
+
+ private final RedisService redisService;
+ private final LotteryWithdrawService lotteryWithdrawService;
+ private final UserRegionClient userRegionClient;
+ private final WalletGoldClient walletGoldClient;
+ private final LotteryWithdrawAmountQryExe lotteryWithdrawAmountQryExe;
+
+ public void execute(LotteryExchangeGoldCmd cmd) {
+ ResponseAssert.isTrue(ResponseErrorCode.REQUEST_PARAMETER_ERROR,
+ ArithmeticUtils.gtZero(cmd.getAmount()));
+
+ // 上锁
+ String key = "LotteryExchangeGold:" + cmd.requiredReqUserId();
+ ResponseAssert.isTrue(CommonErrorCode.REQUEST_LIMITING, redisService.lock(key, 60));
+
+ try {
+ Long userId = cmd.requiredReqUserId();
+
+ // 1. 获取可提现金额
+ LotteryWithdrawAmountCO withdrawAmount = lotteryWithdrawAmountQryExe.execute(userId, cmd.getActivityId());
+ BigDecimal availableAmount = withdrawAmount.getAvailableAmount();
+
+ // 2. 验证金额是否足够
+ ResponseAssert.isTrue(WalletErrorCode.INSUFFICIENT_BALANCE, ArithmeticUtils.gte(availableAmount, cmd.getAmount()));
+
+ // 3. 获取区域兑换金币比例
+ Double goldRatio = getExchangeGoldRatio(cmd);
+
+ // 4. 计算金币数量
+ BigDecimal goldQuantity = BigDecimal.valueOf(goldRatio)
+ .multiply(cmd.getAmount())
+ .setScale(0, RoundingMode.DOWN);
+
+ // 5. 记录兑换(作为提现记录)
+ LotteryWithdraw withdraw = new LotteryWithdraw();
+ withdraw.setUserId(userId);
+ withdraw.setWithdrawNo(generateExchangeWithdrawNo());
+ withdraw.setActivityId(cmd.getActivityId());
+ withdraw.setAmount(cmd.getAmount());
+ withdraw.setStatus(3); // 已完成
+ withdraw.setDescription("兑换金币: " + goldQuantity + "金币");
+ withdraw.setCreateTime(TimestampUtils.now());
+ withdraw.setUpdateTime(TimestampUtils.now());
+ lotteryWithdrawService.save(withdraw);
+
+ // 6. 充值金币给用户自己
+ GoldReceiptCmd build = GoldReceiptCmd.builder()
+ .appIncome()
+ .userId(userId)
+ .amount(goldQuantity)
+ .eventId(withdraw.getId().toString())
+ .remark("抽奖活动兑换金币")
+ .sysOrigin(cmd.getReqSysOrigin().getOrigin())
+ .origin(GoldOrigin.LOTTERY_EXCHANGE_GOLD)
+ .build();
+ ResponseAssert.requiredSuccess(walletGoldClient.changeBalance(build));
+
+ log.info("用户{}兑换金币成功,金额{},金币{}", userId, cmd.getAmount(), goldQuantity);
+ } finally {
+ redisService.unlock(key);
+ }
+ }
+
+ /**
+ * 生成提现单号.
+ */
+ private String generateExchangeWithdrawNo() {
+ return "EX" + System.currentTimeMillis() +
+ String.format("%06d", ThreadLocalRandom.current().nextInt(1000000));
+ }
+
+
+ /**
+ * 获得1$兑换多少金币比例,基于区域+用户输入的美元.
+ *
+ * @return 1美元可获得的金币数量.
+ */
+ private Double getExchangeGoldRatio(LotteryExchangeGoldCmd cmd) {
+ List exchangeGolds = ResponseAssert.requiredSuccess(
+ userRegionClient.listRegionExchangeGoldTip(cmd.requiredReqUserId(), false));
+ 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.notNull(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();
+ }
+
+}
\ No newline at end of file
diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/LotteryTransferExe.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/LotteryTransferExe.java
new file mode 100644
index 00000000..1be1759f
--- /dev/null
+++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/LotteryTransferExe.java
@@ -0,0 +1,193 @@
+package com.red.circle.other.app.command.activity;
+
+import com.red.circle.common.business.core.enums.OpUserType;
+import com.red.circle.common.business.core.enums.ReceiptType;
+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.other.app.dto.clientobject.activity.LotteryWithdrawAmountCO;
+import com.red.circle.other.app.dto.cmd.activity.LotteryTransferCmd;
+import com.red.circle.other.app.service.activity.LotteryActivityRestService;
+import com.red.circle.other.infra.database.rds.entity.activity.LotteryUserProgress;
+import com.red.circle.other.infra.database.rds.entity.activity.LotteryWithdraw;
+import com.red.circle.other.infra.database.rds.service.activity.LotteryUserProgressService;
+import com.red.circle.other.infra.database.rds.service.activity.LotteryWithdrawService;
+import com.red.circle.other.inner.endpoint.user.region.UserRegionClient;
+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.tuple.PennyAmount;
+import com.red.circle.wallet.inner.endpoint.freight.FreightBalanceClient;
+import com.red.circle.wallet.inner.endpoint.freight.FreightBalanceRunningWaterClient;
+import com.red.circle.wallet.inner.endpoint.wallet.WalletGoldClient;
+import com.red.circle.wallet.inner.error.WalletErrorCode;
+import com.red.circle.wallet.inner.model.cmd.GoldReceiptCmd;
+import com.red.circle.wallet.inner.model.dto.FreightBalanceRunningWaterDTO;
+import com.red.circle.wallet.inner.model.enums.FreightBalanceOrigin;
+import com.red.circle.wallet.inner.model.enums.GoldOrigin;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.time.LocalDate;
+import java.time.temporal.WeekFields;
+import java.util.List;
+import java.util.Locale;
+import java.util.Objects;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.stream.Collectors;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+/**
+ * 可提现金额转账给指定用户执行器.
+ *
+ * @author system
+ * @since 2025-10-24
+ */
+@Slf4j
+@Component
+@RequiredArgsConstructor
+public class LotteryTransferExe {
+
+ private final RedisService redisService;
+ private final LotteryWithdrawService lotteryWithdrawService;
+ private final UserRegionClient userRegionClient;
+ private final WalletGoldClient walletGoldClient;
+ private final FreightBalanceClient freightBalanceClient;
+ private final FreightBalanceRunningWaterClient freightBalanceRunningWaterClient;
+ private final LotteryWithdrawAmountQryExe lotteryWithdrawAmountQryExe;
+
+ public void execute(LotteryTransferCmd cmd) {
+ ResponseAssert.isTrue(ResponseErrorCode.REQUEST_PARAMETER_ERROR,
+ ArithmeticUtils.gtZero(cmd.getAmount()));
+ ResponseAssert.notNull(ResponseErrorCode.REQUEST_PARAMETER_ERROR,
+ cmd.getAcceptUserId());
+
+ // 上锁
+ String key = "LotteryTransfer:" + cmd.requiredReqUserId();
+ ResponseAssert.isTrue(CommonErrorCode.REQUEST_LIMITING, redisService.lock(key, 60));
+
+ try {
+ Long userId = cmd.requiredReqUserId();
+
+ // 1. 获取可提现金额
+ LotteryWithdrawAmountCO withdrawAmount = lotteryWithdrawAmountQryExe.execute(userId, cmd.getActivityId());;
+ BigDecimal availableAmount = withdrawAmount.getAvailableAmount();
+
+ // 2. 验证金额是否足够
+ ResponseAssert.isTrue(WalletErrorCode.INSUFFICIENT_BALANCE,
+ ArithmeticUtils.gte(availableAmount, cmd.getAmount()));
+
+ // 3. 获取区域兑换金币比例
+ Double goldRatio = getExchangeGoldRatio(cmd);
+
+ // 4. 计算金币数量
+ BigDecimal goldQuantity = BigDecimal.valueOf(goldRatio)
+ .multiply(cmd.getAmount())
+ .setScale(0, RoundingMode.DOWN);
+
+ // 5. 记录转账(作为提现记录)
+ LotteryWithdraw withdraw = new LotteryWithdraw();
+ withdraw.setUserId(userId);
+ withdraw.setWithdrawNo(generateTransferWithdrawNo());
+ withdraw.setActivityId(cmd.getActivityId());
+ withdraw.setAmount(cmd.getAmount());
+ withdraw.setStatus(3); // 已完成
+ withdraw.setDescription("转账给用户" + cmd.getAcceptUserId() + ": " + goldQuantity + "金币");
+ withdraw.setCreateTime(TimestampUtils.now());
+ withdraw.setUpdateTime(TimestampUtils.now());
+ lotteryWithdrawService.save(withdraw);
+
+ Long withdrawId = withdraw.getId();
+
+ // 6. 判断接收用户是否是货运代理
+ boolean isFreight = freightBalanceClient.existsBalance(cmd.getAcceptUserId()).getBody();
+
+ // 7. 发送金币给接收用户
+ sendGold(cmd, isFreight, goldQuantity, withdrawId, "抽奖活动转账金币");
+
+ log.info("用户{}转账给用户{}成功,金额{},金币{}",
+ userId, cmd.getAcceptUserId(), cmd.getAmount(), goldQuantity);
+ } finally {
+ redisService.unlock(key);
+ }
+ }
+
+ /**
+ * 生成提现单号.
+ */
+ private String generateTransferWithdrawNo() {
+ return "TS" + System.currentTimeMillis() +
+ String.format("%06d", ThreadLocalRandom.current().nextInt(1000000));
+ }
+
+ /**
+ * 发送金币给接收用户.
+ */
+ private void sendGold(LotteryTransferCmd cmd, boolean isFreight, BigDecimal goldQuantity,
+ Long withdrawId, String remark) {
+ if (isFreight) {
+ // 货运代理入账
+ ResponseAssert.isTrue(CommonErrorCode.OPERATING_FAILURE,
+ freightBalanceClient.incrCandyBalance(
+ com.red.circle.common.business.core.enums.SysOriginPlatformEnum.valueOf(
+ cmd.getReqSysOrigin().getOrigin()),
+ cmd.getAcceptUserId(), goldQuantity).getBody());
+
+ // 插入流水
+ BigDecimal freightBalance = freightBalanceClient.getAvailableBalance(cmd.getAcceptUserId()).getBody();
+ freightBalanceRunningWaterClient.save(new FreightBalanceRunningWaterDTO()
+ .setSysOrigin(cmd.getReqSysOrigin().getOrigin())
+ .setUserId(cmd.requiredReqUserId())
+ .setAcceptUserId(cmd.getAcceptUserId())
+ .setType(ReceiptType.INCOME.getType())
+ .setQuantity(goldQuantity)
+ .setUsdQuantity(cmd.getAmount())
+ .setBalance(freightBalance)
+ .setOrigin(FreightBalanceOrigin.PURCHASE.name())
+ .setRemark(remark)
+ .setCreateUser(cmd.requiredReqUserId()));
+ return;
+ }
+
+ // 6. 充值金币给用户自己
+ GoldReceiptCmd build = GoldReceiptCmd.builder()
+ .appIncome()
+ .userId(cmd.requiredReqUserId())
+ .amount(goldQuantity)
+ .eventId(Objects.toString(withdrawId))
+ .sysOrigin(cmd.getReqSysOrigin().getOrigin())
+ .origin(GoldOrigin.LOTTERY_TRANSFER_GOLD)
+ .remark(remark)
+ .build();
+ // 金币入账
+ walletGoldClient.changeBalance(build);
+ }
+
+
+ /**
+ * 获得1$兑换多少金币比例,基于区域+用户输入的美元.
+ *
+ * @return 1美元可获得的金币数量.
+ */
+ private Double getExchangeGoldRatio(LotteryTransferCmd cmd) {
+ List exchangeGolds = ResponseAssert.requiredSuccess(
+ userRegionClient.listRegionExchangeGoldTip(cmd.requiredReqUserId(), false));
+ 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();
+ }
+
+}
\ No newline at end of file
diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/LotteryWithdrawAmountQryExe.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/LotteryWithdrawAmountQryExe.java
index dd0ed0da..c1024d53 100644
--- a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/LotteryWithdrawAmountQryExe.java
+++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/LotteryWithdrawAmountQryExe.java
@@ -28,14 +28,12 @@ public class LotteryWithdrawAmountQryExe {
private final LotteryUserProgressService lotteryUserProgressService;
private final LotteryWithdrawService lotteryWithdrawService;
- public LotteryWithdrawAmountCO execute(AppExtCommand cmd, Long activityId) {
- Long userId = cmd.requiredReqUserId();
-
+ public LotteryWithdrawAmountCO execute(Long userId, Long activityId) {
// 1. 获取用户本周累计金额
String weekKey = getCurrentWeekKey();
LotteryUserProgress progress = lotteryUserProgressService.query()
.eq(LotteryUserProgress::getUserId, userId)
- .eq(activityId != null, LotteryUserProgress::getActivityId, activityId)
+ .eq(LotteryUserProgress::getActivityId, activityId)
.eq(LotteryUserProgress::getWeekKey, weekKey)
.getOne();
@@ -46,7 +44,7 @@ public class LotteryWithdrawAmountQryExe {
// 2. 计算已提现金额
BigDecimal withdrawnAmount = lotteryWithdrawService.query()
.eq(LotteryWithdraw::getUserId, userId)
- .eq(activityId != null, LotteryWithdraw::getActivityId, activityId)
+ .eq(LotteryWithdraw::getActivityId, activityId)
.in(LotteryWithdraw::getStatus, 1, 3) // 已通过、已完成
.list()
.stream()
@@ -56,7 +54,7 @@ public class LotteryWithdrawAmountQryExe {
// 3. 计算待审核金额
BigDecimal pendingAmount = lotteryWithdrawService.query()
.eq(LotteryWithdraw::getUserId, userId)
- .eq(activityId != null, LotteryWithdraw::getActivityId, activityId)
+ .eq(LotteryWithdraw::getActivityId, activityId)
.eq(LotteryWithdraw::getStatus, 0) // 待审核
.list()
.stream()
diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/LotteryWithdrawApplyExe.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/LotteryWithdrawApplyExe.java
index 2d94b8d6..2c7e2728 100644
--- a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/LotteryWithdrawApplyExe.java
+++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/activity/LotteryWithdrawApplyExe.java
@@ -36,12 +36,13 @@ public class LotteryWithdrawApplyExe {
public void execute(LotteryWithdrawCmd cmd) {
Long userId = cmd.requiredReqUserId();
BigDecimal amount = cmd.getAmount();
+ Long activityId = Long.valueOf(cmd.getActivityId());
// 1. 获取用户本周累计金额
String weekKey = getCurrentWeekKey();
LotteryUserProgress progress = lotteryUserProgressService.query()
.eq(LotteryUserProgress::getUserId, userId)
- .eq(cmd.getActivityId() != null, LotteryUserProgress::getActivityId, cmd.getActivityId())
+ .eq(LotteryUserProgress::getActivityId, activityId)
.eq(LotteryUserProgress::getWeekKey, weekKey)
.getOne();
@@ -50,8 +51,8 @@ public class LotteryWithdrawApplyExe {
progress.getTotalAmount() != null && progress.getTotalAmount().compareTo(BigDecimal.ZERO) > 0);
// 2. 计算可提现金额(总金额 - 已提现金额 - 待审核金额)
- BigDecimal withdrawnAmount = getWithdrawnAmount(userId, cmd.getActivityId());
- BigDecimal pendingAmount = getPendingAmount(userId, cmd.getActivityId());
+ BigDecimal withdrawnAmount = getWithdrawnAmount(userId, activityId);
+ BigDecimal pendingAmount = getPendingAmount(userId, activityId);
BigDecimal availableAmount = progress.getTotalAmount().subtract(withdrawnAmount).subtract(pendingAmount);
// 3. 校验提现金额
@@ -62,7 +63,7 @@ public class LotteryWithdrawApplyExe {
LotteryWithdraw withdraw = new LotteryWithdraw();
withdraw.setWithdrawNo(generateWithdrawNo());
withdraw.setUserId(userId);
- withdraw.setActivityId(cmd.getActivityId());
+ withdraw.setActivityId(activityId);
withdraw.setAmount(amount);
withdraw.setContactNumber(cmd.getContactNumber());
withdraw.setDescription(cmd.getDescription());
@@ -83,7 +84,7 @@ public class LotteryWithdrawApplyExe {
private BigDecimal getWithdrawnAmount(Long userId, Long activityId) {
return lotteryWithdrawService.query()
.eq(LotteryWithdraw::getUserId, userId)
- .eq(activityId != null, LotteryWithdraw::getActivityId, activityId)
+ .eq(LotteryWithdraw::getActivityId, activityId)
.in(LotteryWithdraw::getStatus, 1, 3) // 已通过、已完成
.list()
.stream()
@@ -97,7 +98,7 @@ public class LotteryWithdrawApplyExe {
private BigDecimal getPendingAmount(Long userId, Long activityId) {
return lotteryWithdrawService.query()
.eq(LotteryWithdraw::getUserId, userId)
- .eq(activityId != null, LotteryWithdraw::getActivityId, activityId)
+ .eq(LotteryWithdraw::getActivityId, activityId)
.eq(LotteryWithdraw::getStatus, 0) // 待审核
.list()
.stream()
diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/activity/LotteryActivityRestServiceImpl.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/activity/LotteryActivityRestServiceImpl.java
index cda2f8a3..501f0b3d 100644
--- a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/activity/LotteryActivityRestServiceImpl.java
+++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/service/activity/LotteryActivityRestServiceImpl.java
@@ -14,6 +14,8 @@ import com.red.circle.other.app.command.activity.LotteryWinnerHistoryQryExe;
import com.red.circle.other.app.command.activity.LotteryWithdrawAmountQryExe;
import com.red.circle.other.app.command.activity.LotteryWithdrawApplyExe;
import com.red.circle.other.app.command.activity.LotteryWithdrawQryExe;
+import com.red.circle.other.app.command.activity.LotteryExchangeGoldExe;
+import com.red.circle.other.app.command.activity.LotteryTransferExe;
import com.red.circle.other.app.dto.clientobject.activity.*;
import com.red.circle.other.app.dto.cmd.activity.*;
@@ -45,6 +47,8 @@ public class LotteryActivityRestServiceImpl implements LotteryActivityRestServic
private final LotteryWithdrawApplyExe lotteryWithdrawApplyExe;
private final LotteryWithdrawQryExe lotteryWithdrawQryExe;
private final LotteryWithdrawAmountQryExe lotteryWithdrawAmountQryExe;
+ private final LotteryExchangeGoldExe lotteryExchangeGoldExe;
+ private final LotteryTransferExe lotteryTransferExe;
private final DistributedLockUtil distributedLockUtil;
private static final String LOCK_KEY_PREFIX = "activity:lottery:draw:lock";
@@ -108,8 +112,18 @@ public class LotteryActivityRestServiceImpl implements LotteryActivityRestServic
}
@Override
- public LotteryWithdrawAmountCO getWithdrawAmount(AppExtCommand cmd, Long activityId) {
- return lotteryWithdrawAmountQryExe.execute(cmd, activityId);
+ public LotteryWithdrawAmountCO getWithdrawAmount(Long userId, Long activityId) {
+ return lotteryWithdrawAmountQryExe.execute(userId, activityId);
+ }
+
+ @Override
+ public void exchangeGold(LotteryExchangeGoldCmd cmd) {
+ lotteryExchangeGoldExe.execute(cmd);
+ }
+
+ @Override
+ public void transfer(LotteryTransferCmd cmd) {
+ lotteryTransferExe.execute(cmd);
}
}
diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/activity/LotteryExchangeGoldCmd.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/activity/LotteryExchangeGoldCmd.java
new file mode 100644
index 00000000..2df0c17d
--- /dev/null
+++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/activity/LotteryExchangeGoldCmd.java
@@ -0,0 +1,34 @@
+package com.red.circle.other.app.dto.cmd.activity;
+
+import com.red.circle.common.business.dto.cmd.AppExtCommand;
+import jakarta.validation.constraints.DecimalMin;
+import jakarta.validation.constraints.NotNull;
+import java.math.BigDecimal;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * 可提现金额兑换金币CMD.
+ *
+ * @author system
+ * @since 2025-10-24
+ */
+@Data
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = true)
+public class LotteryExchangeGoldCmd extends AppExtCommand {
+
+ /**
+ * 活动ID(可选).
+ */
+ private Long activityId;
+
+ /**
+ * 兑换金额.
+ */
+ @NotNull(message = "兑换金额不能为空")
+ @DecimalMin(value = "0.01", message = "兑换金额必须大于0")
+ private BigDecimal amount;
+
+}
\ No newline at end of file
diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/activity/LotteryTransferCmd.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/activity/LotteryTransferCmd.java
new file mode 100644
index 00000000..c3cb1f9c
--- /dev/null
+++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/activity/LotteryTransferCmd.java
@@ -0,0 +1,40 @@
+package com.red.circle.other.app.dto.cmd.activity;
+
+import com.red.circle.common.business.dto.cmd.AppExtCommand;
+import jakarta.validation.constraints.DecimalMin;
+import jakarta.validation.constraints.NotNull;
+import java.math.BigDecimal;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+
+/**
+ * 可提现金额转账给指定用户CMD.
+ *
+ * @author system
+ * @since 2025-10-24
+ */
+@Data
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = true)
+public class LotteryTransferCmd extends AppExtCommand {
+
+ /**
+ * 活动ID(可选).
+ */
+ private Long activityId;
+
+ /**
+ * 接收用户ID.
+ */
+ @NotNull(message = "接收用户ID不能为空")
+ private Long acceptUserId;
+
+ /**
+ * 转账金额.
+ */
+ @NotNull(message = "转账金额不能为空")
+ @DecimalMin(value = "0.01", message = "转账金额必须大于0")
+ private BigDecimal amount;
+
+}
\ No newline at end of file
diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/activity/LotteryWithdrawCmd.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/activity/LotteryWithdrawCmd.java
index 60f08a6c..e9ddd27d 100644
--- a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/activity/LotteryWithdrawCmd.java
+++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/cmd/activity/LotteryWithdrawCmd.java
@@ -21,9 +21,10 @@ import lombok.experimental.Accessors;
public class LotteryWithdrawCmd extends AppExtCommand {
/**
- * 活动ID(可选).
+ * 活动ID
*/
- private Long activityId;
+ @NotBlank
+ private String activityId;
/**
* 提现金额.
diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/service/activity/LotteryActivityRestService.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/service/activity/LotteryActivityRestService.java
index bc1a630c..f80c24ed 100644
--- a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/service/activity/LotteryActivityRestService.java
+++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/service/activity/LotteryActivityRestService.java
@@ -19,6 +19,8 @@ import com.red.circle.other.app.dto.cmd.activity.LotteryRecordQryCmd;
import com.red.circle.other.app.dto.cmd.activity.LotteryWinnerHistoryQryCmd;
import com.red.circle.other.app.dto.cmd.activity.LotteryWithdrawCmd;
import com.red.circle.other.app.dto.cmd.activity.LotteryWithdrawQryCmd;
+import com.red.circle.other.app.dto.cmd.activity.LotteryExchangeGoldCmd;
+import com.red.circle.other.app.dto.cmd.activity.LotteryTransferCmd;
import java.util.List;
/**
@@ -87,6 +89,16 @@ public interface LotteryActivityRestService {
/**
* 查询可提现金额.
*/
- LotteryWithdrawAmountCO getWithdrawAmount(AppExtCommand cmd, Long activityId);
+ LotteryWithdrawAmountCO getWithdrawAmount(Long userId, Long activityId);
+
+ /**
+ * 可提现金额兑换金币.
+ */
+ void exchangeGold(LotteryExchangeGoldCmd cmd);
+
+ /**
+ * 可提现金额转账给指定用户.
+ */
+ void transfer(LotteryTransferCmd cmd);
}