新增活动exchange transfer 功能
This commit is contained in:
parent
79f0c8f15a
commit
ba7a024e03
@ -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;
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@ -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()
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
}
|
||||
@ -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;
|
||||
|
||||
}
|
||||
@ -21,9 +21,10 @@ import lombok.experimental.Accessors;
|
||||
public class LotteryWithdrawCmd extends AppExtCommand {
|
||||
|
||||
/**
|
||||
* 活动ID(可选).
|
||||
* 活动ID
|
||||
*/
|
||||
private Long activityId;
|
||||
@NotBlank
|
||||
private String activityId;
|
||||
|
||||
/**
|
||||
* 提现金额.
|
||||
|
||||
@ -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);
|
||||
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user