新增活动exchange transfer 功能

This commit is contained in:
tianfeng 2025-10-24 11:24:40 +08:00
parent 79f0c8f15a
commit ba7a024e03
11 changed files with 493 additions and 25 deletions

View File

@ -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;

View File

@ -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.*;
/**
* <p>
@ -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);
}
}

View File

@ -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<SysExchangeGoldTipDTO> 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();
}
}

View File

@ -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<SysExchangeGoldTipDTO> 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();
}
}

View File

@ -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()

View File

@ -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()

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -21,9 +21,10 @@ import lombok.experimental.Accessors;
public class LotteryWithdrawCmd extends AppExtCommand {
/**
* 活动ID可选.
* 活动ID
*/
private Long activityId;
@NotBlank
private String activityId;
/**
* 提现金额.

View File

@ -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);
}