feat:送礼物

This commit is contained in:
dzc committed 2025-11-10 16:34:19 +08:00
1 parent d0c9628bea
commit c59d1a241f
7 files changed
+81 -12

No files matched your search

@@ -7,6 +7,8 @@ import java.time.LocalDateTime;
@Data
public class ProductGiftRespDTO {
private Long id;
/**
* 礼物标题
*/
@@ -0,0 +1,19 @@
package cn.iocoder.yudao.module.pay.enums.transfer;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 用户转账类型枚举
*/
@AllArgsConstructor
@Getter
public enum PayUserTransferTypeEnum {
GIFT_TRANSFER("1", "礼物转账"),
;
private final String type;
private final String name;
}
@@ -30,6 +30,17 @@
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-module-member-api</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-spring-boot-starter-protection</artifactId>
</dependency>
<!-- 业务组件 -->
<dependency>
<groupId>cn.iocoder.boot</groupId>
@@ -5,6 +5,8 @@ import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.idempotent.core.annotation.Idempotent;
import cn.iocoder.yudao.framework.idempotent.core.keyresolver.impl.UserIdempotentKeyResolver;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.recharge.AppPayWalletGiftSendReqVo;
import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.recharge.AppPayWalletRechargeCreateReqVO;
@@ -29,6 +31,7 @@ import javax.validation.Valid;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
@@ -59,9 +62,10 @@ public class AppPayWalletRechargeController {
@PostMapping("/send-gift")
@Operation(summary = "钱包送出礼物")
public CommonResult<Boolean> sendGift(@Valid @RequestBody AppPayWalletGiftSendReqVo dto) {
dto.setOperationMemberId(getLoginUserId());
dto.setOperationUserType(getLoginUserType());
@Idempotent(timeout = 3, timeUnit = TimeUnit.SECONDS, keyResolver = UserIdempotentKeyResolver.class, message = "正在送出礼物中,请稍后重试")
public CommonResult<Long> sendGift(@Valid @RequestBody AppPayWalletGiftSendReqVo dto) {
dto.setOperationMemberId(getLoginUserId());
dto.setOperationUserType(getLoginUserType());
return success(walletRechargeService.sendGift(dto));
}
@@ -31,7 +31,7 @@ public interface PayWalletRechargeService {
/**
* 钱包送出礼物
*/
Boolean sendGift(@Valid AppPayWalletGiftSendReqVo dto);
Long sendGift(@Valid AppPayWalletGiftSendReqVo dto);
/**
* 获得钱包充值记录分页
@@ -7,6 +7,8 @@ import cn.hutool.extra.spring.SpringUtil;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.pay.core.enums.refund.PayRefundStatusRespEnum;
import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
import cn.iocoder.yudao.module.pay.api.order.dto.PayOrderCreateReqDTO;
import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO;
import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.recharge.AppPayWalletGiftSendReqVo;
@@ -16,9 +18,12 @@ import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO;
import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletDO;
import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletRechargeDO;
import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletRechargePackageDO;
import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.WalletUserTransitionDO;
import cn.iocoder.yudao.module.pay.dal.mysql.wallet.PayWalletRechargeMapper;
import cn.iocoder.yudao.module.pay.dal.mysql.wallet.WalletUserTransitionMapper;
import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum;
import cn.iocoder.yudao.module.pay.enums.transfer.PayUserTransferTypeEnum;
import cn.iocoder.yudao.module.pay.enums.wallet.PayWalletBizTypeEnum;
import cn.iocoder.yudao.module.pay.framework.pay.config.PayProperties;
import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
@@ -62,6 +67,8 @@ public class PayWalletRechargeServiceImpl implements PayWalletRechargeService {
@Resource
private PayWalletRechargeMapper walletRechargeMapper;
@Resource
private WalletUserTransitionMapper walletUserTransitionMapper;
@Resource
private PayWalletService payWalletService;
@Resource
private PayOrderService payOrderService;
@@ -74,6 +81,8 @@ public class PayWalletRechargeServiceImpl implements PayWalletRechargeService {
public SocialClientApi socialClientApi;
@Resource
private ProductGiftApi productGiftApi;
@Resource
private MemberUserApi memberUserApi;
@Resource
private PayProperties payProperties;
@@ -115,29 +124,51 @@ public class PayWalletRechargeServiceImpl implements PayWalletRechargeService {
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean sendGift(AppPayWalletGiftSendReqVo dto) {
public Long sendGift(AppPayWalletGiftSendReqVo dto) {
// 自己不能给自己送出礼物
if (ObjectUtil.equals(dto.getTargetMemberId(), dto.getOperationMemberId())) {
throw new RuntimeException("自己不能给自己送出礼物");
}
// 查询目标用户钱包
PayWalletDO targetWallet = payWalletService.getOrCreateWallet(dto.getTargetMemberId(), dto.getOperationUserType());
if (ObjectUtil.isEmpty(targetWallet)) throw exception(WALLET_TARGET_NOT_FOUND);
MemberUserRespDTO targetUser = memberUserApi.getUser(dto.getTargetMemberId());
// 查询当前用户钱包
PayWalletDO wallet = payWalletService.getOrCreateWallet(dto.getOperationMemberId(), dto.getOperationUserType());
if (ObjectUtil.isEmpty(wallet)) throw exception(WALLET_NOT_FOUND);
PayWalletDO currentWallet = payWalletService.getOrCreateWallet(dto.getOperationMemberId(), dto.getOperationUserType());
if (ObjectUtil.isEmpty(currentWallet)) throw exception(WALLET_NOT_FOUND);
MemberUserRespDTO currentUser = memberUserApi.getUser(dto.getOperationMemberId());
// 查询礼物
ProductGiftRespDTO gift = productGiftApi.getGift(dto.getGiftId());
if (ObjectUtil.isEmpty(gift)) throw exception(GIFT_NOT_EXISTS);
// 判断当前用于余额是否够
if (wallet.getBalance() < gift.getPrice()) throw exception(WALLET_RECHARGE_GIFT_BALANCE_NOT_ENOUGH);
if (currentWallet.getBalance() < gift.getPrice()) throw exception(WALLET_RECHARGE_GIFT_BALANCE_NOT_ENOUGH);
String title = String.format("用户[%s]赠送给用户[%s]价值[%s]元的礼物", currentUser.getNickname(), targetUser.getNickname(), fenToYuanStr(gift.getPrice()));
// 添加转账记录
WalletUserTransitionDO userTransitionObj = new WalletUserTransitionDO();
userTransitionObj.setBizType(PayUserTransferTypeEnum.GIFT_TRANSFER.getType());
userTransitionObj.setBizId(gift.getId());
userTransitionObj.setSendUserId(dto.getTargetMemberId());
userTransitionObj.setSendBeforeBalance(currentWallet.getBalance());
userTransitionObj.setSendAfterBalance(currentWallet.getBalance() - gift.getPrice());
userTransitionObj.setTargetUserId(dto.getTargetMemberId());
userTransitionObj.setTargetBeforeBalance(targetWallet.getBalance());
userTransitionObj.setTargetAfterBalance(targetWallet.getBalance() + gift.getPrice());
userTransitionObj.setPrice(gift.getPrice());
userTransitionObj.setTitle(title);
walletUserTransitionMapper.insert(userTransitionObj);
// 扣除用户余额
payWalletService.reduceWalletBalance(wallet.getId(), 1L, PayWalletBizTypeEnum.GIFT, gift.getPrice());
payWalletService.reduceWalletBalance(currentWallet.getId(), userTransitionObj.getBizId(), PayWalletBizTypeEnum.GIFT, gift.getPrice());
// 添加目标用户余额
payWalletService.addWalletBalance(targetWallet.getId(), String.valueOf(1L), PayWalletBizTypeEnum.GIFT, gift.getPrice());
payWalletService.addWalletBalance(targetWallet.getId(), String.valueOf(userTransitionObj.getId()), PayWalletBizTypeEnum.GIFT, gift.getPrice());
return true;
return userTransitionObj.getId();
}
@Override
@@ -112,7 +112,7 @@ public class PayWalletServiceImpl implements PayWalletService {
/**
* 校验是否能退款
*
* @param refundId 支付退款单 id
* @param refundId 支付退款单 id
* @param walletPayNo 钱包支付 no
*/
private Long validateWalletCanRefund(Long refundId, String walletPayNo) {
@@ -147,6 +147,7 @@ public class PayWalletServiceImpl implements PayWalletService {
// 2. 扣除余额
int updateCounts;
switch (bizType) {
case GIFT: // 送礼物
case PAYMENT: {
updateCounts = walletMapper.updateWhenConsumption(payWallet.getId(), price);
break;
@@ -197,6 +198,7 @@ public class PayWalletServiceImpl implements PayWalletService {
walletMapper.updateWhenRecharge(payWallet.getId(), price);
break;
}
case GIFT: // 赠送
case UPDATE_BALANCE: // 更新余额
case BROKERAGE_WITHDRAW: // 分佣提现
walletMapper.updateWhenAdd(payWallet.getId(), price);