diff --git a/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/gift/dto/ProductGiftRespDTO.java b/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/gift/dto/ProductGiftRespDTO.java
index e6bfade..1e5c347 100644
--- a/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/gift/dto/ProductGiftRespDTO.java
+++ b/yudao-module-mall/yudao-module-product-api/src/main/java/cn/iocoder/yudao/module/product/api/gift/dto/ProductGiftRespDTO.java
@@ -7,6 +7,8 @@ import java.time.LocalDateTime;
@Data
public class ProductGiftRespDTO {
+ private Long id;
+
/**
* 礼物标题
*/
diff --git a/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/transfer/PayUserTransferTypeEnum.java b/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/transfer/PayUserTransferTypeEnum.java
new file mode 100644
index 0000000..fd5df99
--- /dev/null
+++ b/yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/transfer/PayUserTransferTypeEnum.java
@@ -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;
+
+}
diff --git a/yudao-module-pay/yudao-module-pay-biz/pom.xml b/yudao-module-pay/yudao-module-pay-biz/pom.xml
index f36dea6..e5b3495 100644
--- a/yudao-module-pay/yudao-module-pay-biz/pom.xml
+++ b/yudao-module-pay/yudao-module-pay-biz/pom.xml
@@ -30,6 +30,17 @@
${revision}
+
+ cn.iocoder.boot
+ yudao-module-member-api
+ ${revision}
+
+
+
+ cn.iocoder.boot
+ yudao-spring-boot-starter-protection
+
+
cn.iocoder.boot
diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/AppPayWalletRechargeController.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/AppPayWalletRechargeController.java
index a9555f0..50316e1 100644
--- a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/AppPayWalletRechargeController.java
+++ b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/AppPayWalletRechargeController.java
@@ -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 sendGift(@Valid @RequestBody AppPayWalletGiftSendReqVo dto) {
- dto.setOperationMemberId(getLoginUserId());
- dto.setOperationUserType(getLoginUserType());
+ @Idempotent(timeout = 3, timeUnit = TimeUnit.SECONDS, keyResolver = UserIdempotentKeyResolver.class, message = "正在送出礼物中,请稍后重试")
+ public CommonResult sendGift(@Valid @RequestBody AppPayWalletGiftSendReqVo dto) {
+ dto.setOperationMemberId(getLoginUserId());
+ dto.setOperationUserType(getLoginUserType());
return success(walletRechargeService.sendGift(dto));
}
diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletRechargeService.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletRechargeService.java
index 11ec0aa..3c2cc54 100644
--- a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletRechargeService.java
+++ b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletRechargeService.java
@@ -31,7 +31,7 @@ public interface PayWalletRechargeService {
/**
* 钱包送出礼物
*/
- Boolean sendGift(@Valid AppPayWalletGiftSendReqVo dto);
+ Long sendGift(@Valid AppPayWalletGiftSendReqVo dto);
/**
* 获得钱包充值记录分页
diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletRechargeServiceImpl.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletRechargeServiceImpl.java
index f1c4e02..5fec2f2 100644
--- a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletRechargeServiceImpl.java
+++ b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletRechargeServiceImpl.java
@@ -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
diff --git a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletServiceImpl.java b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletServiceImpl.java
index be8af43..eb41710 100644
--- a/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletServiceImpl.java
+++ b/yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletServiceImpl.java
@@ -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);