Переглянути джерело

code review:支付钱包

YunaiV 1 рік тому
батько
коміт
3e09da0128

+ 15 - 6
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/order/PayOrderController.java

@@ -6,14 +6,15 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
 import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
 import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
-import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
 import cn.iocoder.yudao.module.pay.controller.admin.order.vo.*;
 import cn.iocoder.yudao.module.pay.convert.order.PayOrderConvert;
 import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO;
 import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
 import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO;
+import cn.iocoder.yudao.module.pay.framework.pay.wallet.WalletPayClient;
 import cn.iocoder.yudao.module.pay.service.app.PayAppService;
 import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
+import com.google.common.collect.Maps;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.Parameter;
 import io.swagger.v3.oas.annotations.tags.Tag;
@@ -25,12 +26,17 @@ import javax.annotation.Resource;
 import javax.servlet.http.HttpServletResponse;
 import javax.validation.Valid;
 import java.io.IOException;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
 
 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
 import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
 import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
+import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId;
+import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserType;
 
 @Tag(name = "管理后台 - 支付订单")
 @RestController
@@ -70,13 +76,16 @@ public class PayOrderController {
     @PostMapping("/submit")
     @Operation(summary = "提交支付订单")
     public CommonResult<PayOrderSubmitRespVO> submitPayOrder(@RequestBody PayOrderSubmitReqVO reqVO) {
-        // 钱包支付需要 额外传 user_id 和 user_type
+        // 1. 钱包支付事,需要额外传 user_id 和 user_type
         if (Objects.equals(reqVO.getChannelCode(), PayChannelEnum.WALLET.getCode())) {
-            Map<String, String> channelExtras = reqVO.getChannelExtras() == null ? new HashMap<>(8) : reqVO.getChannelExtras();
-            channelExtras.put("user_id", String.valueOf(WebFrameworkUtils.getLoginUserId()));
-            channelExtras.put("user_type", String.valueOf(WebFrameworkUtils.getLoginUserType()));
+            Map<String, String> channelExtras = reqVO.getChannelExtras() == null ?
+                    Maps.newHashMapWithExpectedSize(2) : reqVO.getChannelExtras();
+            channelExtras.put(WalletPayClient.USER_ID_KEY, String.valueOf(getLoginUserId()));
+            channelExtras.put(WalletPayClient.USER_TYPE_KEY, String.valueOf(getLoginUserType()));
             reqVO.setChannelExtras(channelExtras);
         }
+
+        // 2. 提交支付
         PayOrderSubmitRespVO respVO = orderService.submitOrder(reqVO, getClientIP());
         return success(respVO);
     }

+ 1 - 1
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/wallet/AppPayWalletController.java

@@ -37,7 +37,7 @@ public class AppPayWalletController {
     @Operation(summary = "获取钱包")
     @PreAuthenticated
     public CommonResult<AppPayWalletRespVO> getPayWallet() {
-        PayWalletDO wallet = payWalletService.getOrCreatePayWallet(getLoginUserId(), UserTypeEnum.MEMBER.getValue());
+        PayWalletDO wallet = payWalletService.getOrCreateWallet(getLoginUserId(), UserTypeEnum.MEMBER.getValue());
         return success(PayWalletConvert.INSTANCE.convert(wallet));
     }
 

+ 2 - 0
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/wallet/PayWalletDO.java

@@ -37,6 +37,8 @@ public class PayWalletDO extends BaseDO {
      */
     private Integer userType;
 
+    // TODO @jason:三个都搞 integer?应该要统一哈
+
     /**
      * 余额,单位分
      */

+ 3 - 0
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/wallet/PayWalletMapper.java

@@ -15,6 +15,7 @@ public interface PayWalletMapper extends BaseMapperX<PayWalletDO> {
                 PayWalletDO::getUserType, userType);
     }
 
+    // TODO @jason:减少时,需要 update price -= ? where price >= ?,避免并发问题。现在基于 price 来过滤,虽然也能解决并发问题,但是冲突概率会高一点;可以看到 TradeBrokerageUserMapper 的做法;
     /**
      * 当余额减少时候更新
      *
@@ -27,6 +28,7 @@ public interface PayWalletMapper extends BaseMapperX<PayWalletDO> {
      */
     default int updateWhenDecBalance(PayWalletBizTypeEnum bizType, Integer balance, Long totalRecharge,
                                      Long totalExpense, Integer price, Long id) {
+        // TODO @jason:这种偏判断的,最红放在 service 层;mapper 可以写多个方法;
         PayWalletDO updateDO = new PayWalletDO().setBalance(balance - price);
         if(bizType == PayWalletBizTypeEnum.PAYMENT){
             updateDO.setTotalExpense(totalExpense + price);
@@ -40,6 +42,7 @@ public interface PayWalletMapper extends BaseMapperX<PayWalletDO> {
                         .ge(PayWalletDO::getBalance, price));
     }
 
+    // TODO @jason:类似上面的修改建议哈;
     /**
      * 当余额增加时候更新
      *

+ 14 - 13
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/framework/pay/wallet/WalletPayClient.java

@@ -37,13 +37,13 @@ import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.REFUND_NOT_FO
 @Slf4j
 public class WalletPayClient extends AbstractPayClient<NonePayClientConfig> {
 
-    private PayWalletService wallService;
+    public static final String USER_ID_KEY = "user_id";
+    public static final String USER_TYPE_KEY = "user_type";
 
+    private PayWalletService wallService;
     private PayWalletTransactionService walletTransactionService;
-
-    private PayOrderService payOrderService;
-
-    private PayRefundService payRefundService;
+    private PayOrderService orderService;
+    private PayRefundService refundService;
 
     public WalletPayClient(Long channelId,  NonePayClientConfig config) {
         super(channelId, PayChannelEnum.WALLET.getCode(), config);
@@ -62,8 +62,9 @@ public class WalletPayClient extends AbstractPayClient<NonePayClientConfig> {
     @Override
     protected PayOrderRespDTO doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) {
         try {
-            String userId = MapUtil.getStr(reqDTO.getChannelExtras(), "user_id");
-            String userType = MapUtil.getStr(reqDTO.getChannelExtras(), "user_type");
+            // TODO @jason:直接 getLong 和 getInt 会不会更简洁哈
+            String userId = MapUtil.getStr(reqDTO.getChannelExtras(), USER_ID_KEY);
+            String userType = MapUtil.getStr(reqDTO.getChannelExtras(), USER_TYPE_KEY);
             Assert.notEmpty(userId, "用户 id 不能为空");
             Assert.notEmpty(userType, "用户类型不能为空");
             PayWalletTransactionDO transaction = wallService.orderPay(Long.valueOf(userId), Integer.valueOf(userType),
@@ -92,10 +93,10 @@ public class WalletPayClient extends AbstractPayClient<NonePayClientConfig> {
 
     @Override
     protected PayOrderRespDTO doGetOrder(String outTradeNo) {
-        if (payOrderService == null) {
-            payOrderService = SpringUtil.getBean(PayOrderService.class);
+        if (orderService == null) {
+            orderService = SpringUtil.getBean(PayOrderService.class);
         }
-        PayOrderExtensionDO orderExtension = payOrderService.getOrderExtensionByNo(outTradeNo);
+        PayOrderExtensionDO orderExtension = orderService.getOrderExtensionByNo(outTradeNo);
         // 支付交易拓展单不存在, 返回关闭状态
         if (orderExtension == null) {
             return PayOrderRespDTO.closedOf(String.valueOf(ORDER_EXTENSION_NOT_FOUND.getCode()),
@@ -147,10 +148,10 @@ public class WalletPayClient extends AbstractPayClient<NonePayClientConfig> {
 
     @Override
     protected PayRefundRespDTO doGetRefund(String outTradeNo, String outRefundNo) {
-        if (payRefundService == null) {
-            payRefundService = SpringUtil.getBean(PayRefundService.class);
+        if (refundService == null) {
+            refundService = SpringUtil.getBean(PayRefundService.class);
         }
-        PayRefundDO payRefund = payRefundService.getRefundByNo(outRefundNo);
+        PayRefundDO payRefund = refundService.getRefundByNo(outRefundNo);
         // 支付退款单不存在, 返回退款失败状态
         if (payRefund == null) {
             return PayRefundRespDTO.failureOf(String.valueOf(REFUND_NOT_FOUND), REFUND_NOT_FOUND.getMsg(),

+ 12 - 12
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletService.java

@@ -12,12 +12,14 @@ import cn.iocoder.yudao.module.pay.enums.member.PayWalletBizTypeEnum;
 public interface PayWalletService {
 
     /**
-     * 获取钱包信息,如果不存在创建钱包。由于用户注册时候不会创建钱包
+     * 获取钱包信息
+     *
+     * 如果不存在,则创建钱包。由于用户注册时候不会创建钱包
      *
      * @param userId 用户编号
      * @param userType 用户类型
      */
-    PayWalletDO getOrCreatePayWallet(Long userId, Integer userType);
+    PayWalletDO getOrCreateWallet(Long userId, Integer userType);
 
     /**
      * 钱包订单支付
@@ -29,6 +31,14 @@ public interface PayWalletService {
      */
     PayWalletTransactionDO orderPay(Long userId, Integer userType, String outTradeNo, Integer price);
 
+    /**
+     * 钱包订单支付退款
+     *
+     * @param outRefundNo 外部退款号
+     * @param refundPrice 退款金额
+     * @param reason  退款原因
+     */
+    PayWalletTransactionDO orderRefund(String outRefundNo, Integer refundPrice, String reason);
 
     /**
      * 扣减钱包余额
@@ -43,7 +53,6 @@ public interface PayWalletService {
     PayWalletTransactionDO reduceWalletBalance(Long userId, Integer userType,
                                                Long bizId, PayWalletBizTypeEnum bizType, Integer price);
 
-
     /**
      * 增加钱包余额
      *
@@ -57,13 +66,4 @@ public interface PayWalletService {
     PayWalletTransactionDO addWalletBalance(Long userId, Integer userType,
                                             Long bizId, PayWalletBizTypeEnum bizType, Integer price);
 
-    /**
-     * 钱包订单支付退款
-     *
-     * @param outRefundNo 外部退款号
-     * @param refundPrice 退款金额
-     * @param reason  退款原因
-     */
-    PayWalletTransactionDO orderRefund(String outRefundNo, Integer refundPrice, String reason);
-
 }

+ 74 - 71
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletServiceImpl.java

@@ -43,81 +43,124 @@ public class PayWalletServiceImpl implements  PayWalletService {
     private static final String WALLET_REFUND_NO_PREFIX = "WR";
 
     @Resource
-    private PayWalletMapper payWalletMapper;
+    private PayWalletMapper walletMapper;
     @Resource
     private PayNoRedisDAO noRedisDAO;
 
     @Resource
-    private PayWalletTransactionService payWalletTransactionService;
+    private PayWalletTransactionService walletTransactionService;
     @Resource
     @Lazy
-    private PayOrderService payOrderService;
+    private PayOrderService orderService;
     @Resource
     @Lazy
-    private PayRefundService payRefundService;
+    private PayRefundService refundService;
 
     @Override
-    public PayWalletDO getOrCreatePayWallet(Long userId, Integer userType) {
-        PayWalletDO payWalletDO = payWalletMapper.selectByUserIdAndType(userId, userType);
-        if (payWalletDO == null) {
-            payWalletDO = new PayWalletDO();
-            payWalletDO.setUserId(userId);
-            payWalletDO.setUserType(userType);
-            payWalletDO.setBalance(0);
-            payWalletDO.setTotalExpense(0L);
-            payWalletDO.setTotalRecharge(0L);
-            payWalletDO.setCreateTime(LocalDateTime.now());
-            payWalletMapper.insert(payWalletDO);
+    public PayWalletDO getOrCreateWallet(Long userId, Integer userType) {
+        PayWalletDO wallet = walletMapper.selectByUserIdAndType(userId, userType);
+        if (wallet == null) {
+            wallet = new PayWalletDO().setUserId(userId).setUserType(userType)
+                    .setBalance(0).setTotalExpense(0L).setTotalRecharge(0L);
+            wallet.setCreateTime(LocalDateTime.now());
+            walletMapper.insert(wallet);
         }
-        return payWalletDO;
+        return wallet;
     }
 
-
     @Override
     @Transactional(rollbackFor = Exception.class)
     public PayWalletTransactionDO orderPay(Long userId, Integer userType, String outTradeNo, Integer price) {
-        // 判断支付交易拓展单是否存
-        PayOrderExtensionDO orderExtension = payOrderService.getOrderExtensionByNo(outTradeNo);
+        // 1. 判断支付交易拓展单是否存
+        PayOrderExtensionDO orderExtension = orderService.getOrderExtensionByNo(outTradeNo);
         if (orderExtension == null) {
             throw exception(ORDER_EXTENSION_NOT_FOUND);
         }
+        // 2. 扣减余额
         return reduceWalletBalance(userId, userType, orderExtension.getOrderId(), PAYMENT, price);
     }
 
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public PayWalletTransactionDO orderRefund(String outRefundNo, Integer refundPrice, String reason) {
+        // 1.1 判断退款单是否存在
+        PayRefundDO payRefund = refundService.getRefundByNo(outRefundNo);
+        if (payRefund == null) {
+            throw exception(REFUND_NOT_FOUND);
+        }
+        // 1.2 校验是否可以退款
+        Long walletId = validateWalletCanRefund(payRefund.getId(), payRefund.getChannelOrderNo(),  refundPrice);
+        PayWalletDO wallet = walletMapper.selectById(walletId);
+        Assert.notNull(wallet, "钱包 {} 不存在", walletId);
+        // 2. 增加余额
+        return addWalletBalance(wallet.getUserId(), wallet.getUserType(), payRefund.getId(), PAYMENT_REFUND, refundPrice);
+    }
+
+    /**
+     * 校验是否能退款
+     *
+     * @param refundId 支付退款单 id
+     * @param walletPayNo 钱包支付 no
+     */
+    private Long validateWalletCanRefund(Long refundId, String walletPayNo, Integer refundPrice) {
+        // 1. 校验钱包支付交易存在
+        PayWalletTransactionDO walletTransaction = walletTransactionService.getWalletTransactionByNo(walletPayNo);
+        if (walletTransaction == null) {
+            throw exception(WALLET_TRANSACTION_NOT_FOUND);
+        }
+        // 原来的支付金额
+        // TODO @jason:应该允许多次退款哈;
+        int amount = - walletTransaction.getPrice();
+        if (refundPrice != amount) {
+            throw exception(WALLET_REFUND_AMOUNT_ERROR);
+        }
+        PayWalletTransactionDO refundTransaction = walletTransactionService.getWalletTransaction(
+                String.valueOf(refundId), PAYMENT_REFUND);
+        if (refundTransaction != null) {
+            throw exception(WALLET_REFUND_EXIST);
+        }
+        return walletTransaction.getWalletId();
+    }
+
     @Override
     public PayWalletTransactionDO reduceWalletBalance(Long userId, Integer userType,
                                                       Long bizId, PayWalletBizTypeEnum bizType, Integer price) {
         // 1.1 获取钱包
-        PayWalletDO payWallet = getOrCreatePayWallet(userId, userType);
+        PayWalletDO payWallet = getOrCreateWallet(userId, userType);
         // 1.2 判断余额是否足够
         int afterBalance = payWallet.getBalance() - price;
         if (afterBalance < 0) {
             throw exception(WALLET_BALANCE_NOT_ENOUGH);
         }
 
+        // TODO jason:建议基于 where price >= 来做哈;然后抛出 WALLET_BALANCE_NOT_ENOUGH
         // 2.1 扣除余额
-        int number = payWalletMapper.updateWhenDecBalance(bizType,payWallet.getBalance(), payWallet.getTotalRecharge(),
-                payWallet.getTotalExpense(), price, payWallet.getId());
+        int number = walletMapper.updateWhenDecBalance(bizType, payWallet.getBalance(),
+                payWallet.getTotalRecharge(), payWallet.getTotalExpense(), price, payWallet.getId());
         if (number == 0) {
             throw exception(TOO_MANY_REQUESTS);
         }
+
         // 2.2 生成钱包流水
+        // TODO @jason:walletNo 交给 payWalletTransactionService 自己生成哈;
         String walletNo = generateWalletNo(bizType);
         PayWalletTransactionDO walletTransaction = new PayWalletTransactionDO().setWalletId(payWallet.getId())
                 .setNo(walletNo).setPrice(-price).setBalance(afterBalance)
                 .setBizId(String.valueOf(bizId)).setBizType(bizType.getType()).setTitle(bizType.getDescription());
-        payWalletTransactionService.createWalletTransaction(walletTransaction);
+        // TODO @jason:是不是可以 createWalletTransaction 搞个 bo 参数,然后 PayWalletTransactionDO 交回给 walletTransactionService 更好;然后把参数简化下
+        walletTransactionService.createWalletTransaction(walletTransaction);
         return walletTransaction;
     }
 
     @Override
-    public PayWalletTransactionDO addWalletBalance(Long userId, Integer userType, Long bizId,
-                                                   PayWalletBizTypeEnum bizType, Integer price) {
+    public PayWalletTransactionDO addWalletBalance(Long userId, Integer userType,
+                                                   Long bizId, PayWalletBizTypeEnum bizType, Integer price) {
         // 1.1 获取钱包
-        PayWalletDO payWallet = getOrCreatePayWallet(userId, userType);
+        PayWalletDO payWallet = getOrCreateWallet(userId, userType);
 
         // 2.1 增加余额
-        int number = payWalletMapper.updateWhenIncBalance(bizType, payWallet.getBalance(), payWallet.getTotalRecharge(),
+        // TODO @jason:类似上面的思路哈;
+        int number = walletMapper.updateWhenIncBalance(bizType, payWallet.getBalance(), payWallet.getTotalRecharge(),
                 payWallet.getTotalExpense(), price, payWallet.getId());
         if (number == 0) {
             throw exception(TOO_MANY_REQUESTS);
@@ -129,63 +172,23 @@ public class PayWalletServiceImpl implements  PayWalletService {
                 .setNo(walletNo).setPrice(price).setBalance(payWallet.getBalance()+price)
                 .setBizId(String.valueOf(bizId)).setBizType(bizType.getType())
                 .setTitle(bizType.getDescription());
-        payWalletTransactionService.createWalletTransaction(newWalletTransaction);
+        walletTransactionService.createWalletTransaction(newWalletTransaction);
         return newWalletTransaction;
     }
 
     private String generateWalletNo(PayWalletBizTypeEnum bizType) {
+        // TODO @jason:对于余额来说,是不是直接 W+序号就行了,它其实不关注业务;;;不然就耦合啦
         String no = "";
         switch(bizType){
-            case PAYMENT :
+            case PAYMENT:
                 no = noRedisDAO.generate(WALLET_PAY_NO_PREFIX);
                 break;
-            case PAYMENT_REFUND :
+            case PAYMENT_REFUND:
                 no = noRedisDAO.generate(WALLET_REFUND_NO_PREFIX);
                 break;
             default :
-                // TODO 待增加
         }
         return no;
     }
 
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public PayWalletTransactionDO orderRefund(String outRefundNo, Integer refundPrice, String reason) {
-        // 1.1 判断退款单是否存在
-        PayRefundDO payRefund = payRefundService.getRefundByNo(outRefundNo);
-        if (payRefund == null) {
-            throw exception(REFUND_NOT_FOUND);
-        }
-        // 1.2 校验是否可以退款
-        Long walletId =  validateWalletCanRefund(payRefund.getId(), payRefund.getChannelOrderNo(),  refundPrice);
-
-        PayWalletDO payWallet = payWalletMapper.selectById(walletId);
-        Assert.notNull(payWallet, "钱包 {} 不存在", walletId);
-        return addWalletBalance(payWallet.getUserId(), payWallet.getUserType(),payRefund.getId(), PAYMENT_REFUND, refundPrice);
-    }
-
-    /**
-     * 校验是否能退款
-     *
-     * @param refundId 支付退款单 id
-     * @param walletPayNo 钱包支付 no
-     */
-    private Long validateWalletCanRefund(Long refundId, String walletPayNo, Integer refundPrice) {
-        // 查询钱包支付交易
-        PayWalletTransactionDO payWalletTransaction = payWalletTransactionService.getWalletTransactionByNo(walletPayNo);
-        if (payWalletTransaction == null) {
-            throw exception(WALLET_TRANSACTION_NOT_FOUND);
-        }
-        // 原来的支付金额
-        int amount = - payWalletTransaction.getPrice();
-        if (refundPrice != amount) {
-            throw exception(WALLET_REFUND_AMOUNT_ERROR);
-        }
-        PayWalletTransactionDO refundTransaction = payWalletTransactionService.getWalletTransaction(
-                String.valueOf(refundId), PAYMENT_REFUND);
-        if (refundTransaction != null) {
-            throw exception(WALLET_REFUND_EXIST);
-        }
-        return payWalletTransaction.getWalletId();
-    }
 }

+ 1 - 1
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletTransactionServiceImpl.java

@@ -28,7 +28,7 @@ public class PayWalletTransactionServiceImpl implements PayWalletTransactionServ
     @Override
     public PageResult<PayWalletTransactionDO> getWalletTransactionPage(Long userId, Integer userType,
                                                                        AppPayWalletTransactionPageReqVO pageVO) {
-        PayWalletDO wallet = payWalletService.getOrCreatePayWallet(userId, userType);
+        PayWalletDO wallet = payWalletService.getOrCreateWallet(userId, userType);
         return payWalletTransactionMapper.selectPage(wallet.getId(), pageVO);
     }