mirror of
				https://gitee.com/hhyykk/ipms-sjy.git
				synced 2025-11-04 12:18:42 +08:00 
			
		
		
		
	钱包退款的实现
This commit is contained in:
		@@ -27,6 +27,12 @@ public interface PayClientFactory {
 | 
				
			|||||||
    <Config extends PayClientConfig> void createOrUpdatePayClient(Long channelId, String channelCode,
 | 
					    <Config extends PayClientConfig> void createOrUpdatePayClient(Long channelId, String channelCode,
 | 
				
			||||||
                                                                  Config config);
 | 
					                                                                  Config config);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <Config extends PayClientConfig> void createOrUpdateDelegatePayClient(Long channelId, DelegatePayClient<Config> delegatePayClient);
 | 
					    /**
 | 
				
			||||||
 | 
					     * 新增或更新代理支付客户端
 | 
				
			||||||
 | 
					     * @param channelId 渠道编号
 | 
				
			||||||
 | 
					     * @param delegatePayClient 代理支付客户端
 | 
				
			||||||
 | 
					     * @param <Config> 支付配置
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    <Config extends PayClientConfig> void addOrUpdateDelegatePayClient(Long channelId, DelegatePayClient<Config> delegatePayClient);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -53,7 +53,7 @@ public class PayClientFactoryImpl implements PayClientFactory {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public <Config extends PayClientConfig> void createOrUpdateDelegatePayClient(Long channelId, DelegatePayClient<Config> delegatePayClient) {
 | 
					    public <Config extends PayClientConfig> void addOrUpdateDelegatePayClient(Long channelId, DelegatePayClient<Config> delegatePayClient) {
 | 
				
			||||||
        clients.put(channelId, delegatePayClient);
 | 
					        clients.put(channelId, delegatePayClient);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,6 +10,8 @@ import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient;
 | 
				
			|||||||
import java.util.Map;
 | 
					import java.util.Map;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 | 
					 * 代理支付 Client 的抽象类。用于支付 Client 由其它模块实现, 例如钱包支付
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 * @author jason
 | 
					 * @author jason
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
public abstract  class DelegatePayClient<Config extends PayClientConfig> extends AbstractPayClient<PayClientConfig> {
 | 
					public abstract  class DelegatePayClient<Config extends PayClientConfig> extends AbstractPayClient<PayClientConfig> {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -44,6 +44,9 @@ public interface ErrorCodeConstants {
 | 
				
			|||||||
    // ========== 钱包模块(退款) 1007007000 ==========
 | 
					    // ========== 钱包模块(退款) 1007007000 ==========
 | 
				
			||||||
    ErrorCode WALLET_NOT_FOUND = new ErrorCode(1007007000, "用户钱包不存在");
 | 
					    ErrorCode WALLET_NOT_FOUND = new ErrorCode(1007007000, "用户钱包不存在");
 | 
				
			||||||
    ErrorCode WALLET_NOT_ENOUGH = new ErrorCode(1007007001, "钱包余额不足");
 | 
					    ErrorCode WALLET_NOT_ENOUGH = new ErrorCode(1007007001, "钱包余额不足");
 | 
				
			||||||
 | 
					    ErrorCode WALLET_TRANSACTION_NOT_FOUND = new ErrorCode(1007007002, "未找到对应的钱包交易");
 | 
				
			||||||
 | 
					    ErrorCode WALLET_REFUND_AMOUNT_ERROR = new ErrorCode(1007007003, "钱包退款金额不对");
 | 
				
			||||||
 | 
					    ErrorCode WALLET_REFUND_EXIST = new ErrorCode(1007007004, "已经存在钱包退款");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // ========== 示例订单 1007900000 ==========
 | 
					    // ========== 示例订单 1007900000 ==========
 | 
				
			||||||
    ErrorCode DEMO_ORDER_NOT_FOUND = new ErrorCode(1007900000, "示例订单不存在");
 | 
					    ErrorCode DEMO_ORDER_NOT_FOUND = new ErrorCode(1007900000, "示例订单不存在");
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,7 +13,8 @@ import lombok.Getter;
 | 
				
			|||||||
public enum WalletBizTypeEnum {
 | 
					public enum WalletBizTypeEnum {
 | 
				
			||||||
    RECHARGE(1, "充值"),
 | 
					    RECHARGE(1, "充值"),
 | 
				
			||||||
    RECHARGE_REFUND(2, "充值退款"),
 | 
					    RECHARGE_REFUND(2, "充值退款"),
 | 
				
			||||||
    PAYMENT(3, "支付");
 | 
					    PAYMENT(3, "支付"),
 | 
				
			||||||
 | 
					    PAYMENT_REFUND(4, "支付退款");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // TODO 后续增加
 | 
					    // TODO 后续增加
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -37,6 +37,11 @@ public interface PayRefundMapper extends BaseMapperX<PayRefundDO> {
 | 
				
			|||||||
                .eq(PayRefundDO::getNo, no));
 | 
					                .eq(PayRefundDO::getNo, no));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    default PayRefundDO selectByNo(String no){
 | 
				
			||||||
 | 
					        return selectOne(new LambdaQueryWrapperX<PayRefundDO>()
 | 
				
			||||||
 | 
					                .eq(PayRefundDO::getNo, no));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    default int updateByIdAndStatus(Long id, Integer status, PayRefundDO update) {
 | 
					    default int updateByIdAndStatus(Long id, Integer status, PayRefundDO update) {
 | 
				
			||||||
        return update(update, new LambdaQueryWrapper<PayRefundDO>()
 | 
					        return update(update, new LambdaQueryWrapper<PayRefundDO>()
 | 
				
			||||||
                .eq(PayRefundDO::getId, id).eq(PayRefundDO::getStatus, status));
 | 
					                .eq(PayRefundDO::getId, id).eq(PayRefundDO::getStatus, status));
 | 
				
			||||||
@@ -71,5 +76,4 @@ public interface PayRefundMapper extends BaseMapperX<PayRefundDO> {
 | 
				
			|||||||
    default List<PayRefundDO> selectListByStatus(Integer status) {
 | 
					    default List<PayRefundDO> selectListByStatus(Integer status) {
 | 
				
			||||||
        return selectList(PayRefundDO::getStatus, status);
 | 
					        return selectList(PayRefundDO::getStatus, status);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -26,6 +26,15 @@ public interface PayWalletTransactionMapper extends BaseMapperX<PayWalletTransac
 | 
				
			|||||||
        query.orderByDesc(PayWalletTransactionDO::getTransactionTime);
 | 
					        query.orderByDesc(PayWalletTransactionDO::getTransactionTime);
 | 
				
			||||||
        return selectPage(pageParam, query);
 | 
					        return selectPage(pageParam, query);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    default PayWalletTransactionDO selectByNo(String no) {
 | 
				
			||||||
 | 
					        return selectOne(PayWalletTransactionDO::getNo, no);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    default PayWalletTransactionDO selectByWalletIdAndBiz(Long walletId, Long bizId, Integer bizType) {
 | 
				
			||||||
 | 
					        return selectOne(PayWalletTransactionDO::getWalletId, walletId, PayWalletTransactionDO::getBizId,
 | 
				
			||||||
 | 
					                bizId, PayWalletTransactionDO::getBizType, bizType);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,10 +1,11 @@
 | 
				
			|||||||
package cn.iocoder.yudao.module.pay.framework.pay.wallet;
 | 
					package cn.iocoder.yudao.module.pay.framework.pay.wallet;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import cn.iocoder.yudao.framework.pay.core.client.impl.NonePayClientConfig;
 | 
					import cn.iocoder.yudao.framework.common.exception.ServiceException;
 | 
				
			||||||
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
 | 
					import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
 | 
				
			||||||
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
 | 
					import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
 | 
				
			||||||
import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO;
 | 
					import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO;
 | 
				
			||||||
import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO;
 | 
					import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO;
 | 
				
			||||||
 | 
					import cn.iocoder.yudao.framework.pay.core.client.impl.NonePayClientConfig;
 | 
				
			||||||
import cn.iocoder.yudao.framework.pay.core.client.impl.delegate.DelegatePayClient;
 | 
					import cn.iocoder.yudao.framework.pay.core.client.impl.delegate.DelegatePayClient;
 | 
				
			||||||
import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO;
 | 
					import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO;
 | 
				
			||||||
import cn.iocoder.yudao.module.pay.service.wallet.PayWalletService;
 | 
					import cn.iocoder.yudao.module.pay.service.wallet.PayWalletService;
 | 
				
			||||||
@@ -12,6 +13,8 @@ import lombok.extern.slf4j.Slf4j;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import java.util.Map;
 | 
					import java.util.Map;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * 钱包支付的 PayClient 实现类
 | 
					 * 钱包支付的 PayClient 实现类
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
@@ -19,7 +22,6 @@ import java.util.Map;
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
@Slf4j
 | 
					@Slf4j
 | 
				
			||||||
public class WalletPayClient extends DelegatePayClient<NonePayClientConfig> {
 | 
					public class WalletPayClient extends DelegatePayClient<NonePayClientConfig> {
 | 
				
			||||||
 | 
					 | 
				
			||||||
    private PayWalletService payWalletService;
 | 
					    private PayWalletService payWalletService;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public WalletPayClient(Long channelId, String channelCode, NonePayClientConfig config) {
 | 
					    public WalletPayClient(Long channelId, String channelCode, NonePayClientConfig config) {
 | 
				
			||||||
@@ -38,13 +40,24 @@ public class WalletPayClient extends DelegatePayClient<NonePayClientConfig> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    protected PayOrderRespDTO doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) {
 | 
					    protected PayOrderRespDTO doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) {
 | 
				
			||||||
        PayWalletTransactionDO payWalletTransaction = payWalletService.pay(reqDTO.getOutTradeNo(), reqDTO.getPrice());
 | 
					        try {
 | 
				
			||||||
        return PayOrderRespDTO.successOf(payWalletTransaction.getNo(), payWalletTransaction.getCreator(),
 | 
					            PayWalletTransactionDO payWalletTransaction = payWalletService.pay(reqDTO.getOutTradeNo(), reqDTO.getPrice());
 | 
				
			||||||
                payWalletTransaction.getTransactionTime(),
 | 
					            return PayOrderRespDTO.successOf(payWalletTransaction.getNo(), payWalletTransaction.getCreator(),
 | 
				
			||||||
                reqDTO.getOutTradeNo(), "");
 | 
					                    payWalletTransaction.getTransactionTime(),
 | 
				
			||||||
 | 
					                    reqDTO.getOutTradeNo(), "WALLET_PAY_SUCCESS");
 | 
				
			||||||
 | 
					        } catch (Throwable ex) {
 | 
				
			||||||
 | 
					            log.error("[doUnifiedOrder] 失败", ex);
 | 
				
			||||||
 | 
					            String errorCode = String.valueOf(INTERNAL_SERVER_ERROR);
 | 
				
			||||||
 | 
					            String errorMsg = INTERNAL_SERVER_ERROR.getMsg();
 | 
				
			||||||
 | 
					            if (ex instanceof ServiceException) {
 | 
				
			||||||
 | 
					                ServiceException serviceException = (ServiceException) ex;
 | 
				
			||||||
 | 
					                errorCode = String.valueOf(serviceException.getCode());
 | 
				
			||||||
 | 
					                errorMsg = serviceException.getMessage();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return PayOrderRespDTO.closedOf(errorCode, errorMsg, reqDTO.getOutTradeNo(), ex);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    protected PayOrderRespDTO doParseOrderNotify(Map<String, String> params, String body) {
 | 
					    protected PayOrderRespDTO doParseOrderNotify(Map<String, String> params, String body) {
 | 
				
			||||||
        throw new UnsupportedOperationException("钱包支付无支付回调");
 | 
					        throw new UnsupportedOperationException("钱包支付无支付回调");
 | 
				
			||||||
@@ -52,12 +65,27 @@ public class WalletPayClient extends DelegatePayClient<NonePayClientConfig> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    protected PayOrderRespDTO doGetOrder(String outTradeNo) {
 | 
					    protected PayOrderRespDTO doGetOrder(String outTradeNo) {
 | 
				
			||||||
        return null;
 | 
					        throw new UnsupportedOperationException("待实现");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    protected PayRefundRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) {
 | 
					    protected PayRefundRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) {
 | 
				
			||||||
        return null;
 | 
					        try {
 | 
				
			||||||
 | 
					            PayWalletTransactionDO payWalletTransaction = payWalletService.refund(reqDTO.getOutRefundNo(),
 | 
				
			||||||
 | 
					                    reqDTO.getRefundPrice(), reqDTO.getReason());
 | 
				
			||||||
 | 
					            return PayRefundRespDTO.successOf(payWalletTransaction.getNo(), payWalletTransaction.getTransactionTime(),
 | 
				
			||||||
 | 
					                    reqDTO.getOutRefundNo(), "WALLET_REFUND_SUCCESS");
 | 
				
			||||||
 | 
					        } catch (Throwable ex) {
 | 
				
			||||||
 | 
					            log.error("[doUnifiedRefund] 失败", ex);
 | 
				
			||||||
 | 
					            String errorCode = String.valueOf(INTERNAL_SERVER_ERROR);
 | 
				
			||||||
 | 
					            String errorMsg = INTERNAL_SERVER_ERROR.getMsg();
 | 
				
			||||||
 | 
					            if (ex instanceof ServiceException) {
 | 
				
			||||||
 | 
					                ServiceException serviceException = (ServiceException) ex;
 | 
				
			||||||
 | 
					                errorCode = String.valueOf(serviceException.getCode());
 | 
				
			||||||
 | 
					                errorMsg = serviceException.getMessage();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return PayRefundRespDTO.failureOf(errorCode, errorMsg, reqDTO.getOutRefundNo(), ex);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
@@ -67,6 +95,6 @@ public class WalletPayClient extends DelegatePayClient<NonePayClientConfig> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    protected PayRefundRespDTO doGetRefund(String outTradeNo, String outRefundNo) {
 | 
					    protected PayRefundRespDTO doGetRefund(String outTradeNo, String outRefundNo) {
 | 
				
			||||||
        return null;
 | 
					        throw new UnsupportedOperationException("待实现");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -81,6 +81,7 @@ public class PayChannelServiceImpl implements PayChannelService {
 | 
				
			|||||||
                log.error("[支付模块 yudao-module-pay - 表结构未导入][参考 https://doc.iocoder.cn/pay/build/ 开启]");
 | 
					                log.error("[支付模块 yudao-module-pay - 表结构未导入][参考 https://doc.iocoder.cn/pay/build/ 开启]");
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            log.info("[initLocalCache][缓存支付渠道,数量为:{}]", channels.size());
 | 
					            log.info("[initLocalCache][缓存支付渠道,数量为:{}]", channels.size());
 | 
				
			||||||
 | 
					            // 钱包 client 需要和其它 client 分开了创建
 | 
				
			||||||
            List<PayChannelDO> walletChannels = new ArrayList<>();
 | 
					            List<PayChannelDO> walletChannels = new ArrayList<>();
 | 
				
			||||||
            List<PayChannelDO> otherChannels = new ArrayList<>();
 | 
					            List<PayChannelDO> otherChannels = new ArrayList<>();
 | 
				
			||||||
            channels.forEach(t -> {
 | 
					            channels.forEach(t -> {
 | 
				
			||||||
@@ -97,7 +98,7 @@ public class PayChannelServiceImpl implements PayChannelService {
 | 
				
			|||||||
            walletChannels.forEach(payChannel -> {
 | 
					            walletChannels.forEach(payChannel -> {
 | 
				
			||||||
                WalletPayClient walletPayClient = new WalletPayClient(payChannel.getId(), payChannel.getCode(),
 | 
					                WalletPayClient walletPayClient = new WalletPayClient(payChannel.getId(), payChannel.getCode(),
 | 
				
			||||||
                        (NonePayClientConfig) payChannel.getConfig(), payWalletService);
 | 
					                        (NonePayClientConfig) payChannel.getConfig(), payWalletService);
 | 
				
			||||||
                payClientFactory.createOrUpdateDelegatePayClient(payChannel.getId(), walletPayClient);
 | 
					                payClientFactory.addOrUpdateDelegatePayClient(payChannel.getId(), walletPayClient);
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
            this.channelCache = channels;
 | 
					            this.channelCache = channels;
 | 
				
			||||||
        });
 | 
					        });
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -24,6 +24,14 @@ public interface PayRefundService {
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    PayRefundDO getRefund(Long id);
 | 
					    PayRefundDO getRefund(Long id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 获得退款订单
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param no 外部退款单号
 | 
				
			||||||
 | 
					     * @return 退款订单
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    PayRefundDO getRefundByNo(String no);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * 获得指定应用的退款数量
 | 
					     * 获得指定应用的退款数量
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -74,6 +74,11 @@ public class PayRefundServiceImpl implements PayRefundService {
 | 
				
			|||||||
        return refundMapper.selectById(id);
 | 
					        return refundMapper.selectById(id);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public PayRefundDO getRefundByNo(String no) {
 | 
				
			||||||
 | 
					        return refundMapper.selectByNo(no);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public Long getRefundCountByAppId(Long appId) {
 | 
					    public Long getRefundCountByAppId(Long appId) {
 | 
				
			||||||
        return refundMapper.selectCountByAppId(appId);
 | 
					        return refundMapper.selectCountByAppId(appId);
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,5 +17,18 @@ public interface PayWalletService {
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    PayWalletDO getPayWallet(Long userId, Integer userType);
 | 
					    PayWalletDO getPayWallet(Long userId, Integer userType);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 钱包支付
 | 
				
			||||||
 | 
					     * @param outTradeNo 外部订单号
 | 
				
			||||||
 | 
					     * @param price 金额
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
    PayWalletTransactionDO pay(String outTradeNo, Integer price);
 | 
					    PayWalletTransactionDO pay(String outTradeNo, Integer price);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 钱包支付退款
 | 
				
			||||||
 | 
					     * @param outRefundNo 外部退款号
 | 
				
			||||||
 | 
					     * @param refundPrice 退款金额
 | 
				
			||||||
 | 
					     * @param reason  退款原因
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    PayWalletTransactionDO refund(String outRefundNo, Integer refundPrice, String reason);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,18 +1,19 @@
 | 
				
			|||||||
package cn.iocoder.yudao.module.pay.service.wallet;
 | 
					package cn.iocoder.yudao.module.pay.service.wallet;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO;
 | 
					import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO;
 | 
				
			||||||
 | 
					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.PayWalletDO;
 | 
				
			||||||
import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO;
 | 
					import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO;
 | 
				
			||||||
import cn.iocoder.yudao.module.pay.dal.mysql.wallet.PayWalletMapper;
 | 
					import cn.iocoder.yudao.module.pay.dal.mysql.wallet.PayWalletMapper;
 | 
				
			||||||
import cn.iocoder.yudao.module.pay.dal.redis.no.PayNoRedisDAO;
 | 
					import cn.iocoder.yudao.module.pay.dal.redis.no.PayNoRedisDAO;
 | 
				
			||||||
import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
 | 
					import cn.iocoder.yudao.module.pay.service.order.PayOrderService;
 | 
				
			||||||
 | 
					import cn.iocoder.yudao.module.pay.service.refund.PayRefundService;
 | 
				
			||||||
import lombok.extern.slf4j.Slf4j;
 | 
					import lombok.extern.slf4j.Slf4j;
 | 
				
			||||||
import org.springframework.context.annotation.Lazy;
 | 
					import org.springframework.context.annotation.Lazy;
 | 
				
			||||||
import org.springframework.stereotype.Service;
 | 
					import org.springframework.stereotype.Service;
 | 
				
			||||||
import org.springframework.transaction.annotation.Transactional;
 | 
					import org.springframework.transaction.annotation.Transactional;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import javax.annotation.Resource;
 | 
					import javax.annotation.Resource;
 | 
				
			||||||
 | 
					 | 
				
			||||||
import java.time.LocalDateTime;
 | 
					import java.time.LocalDateTime;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 | 
					import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
 | 
				
			||||||
@@ -20,6 +21,7 @@ import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLogi
 | 
				
			|||||||
import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserType;
 | 
					import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserType;
 | 
				
			||||||
import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*;
 | 
					import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*;
 | 
				
			||||||
import static cn.iocoder.yudao.module.pay.enums.member.WalletBizTypeEnum.PAYMENT;
 | 
					import static cn.iocoder.yudao.module.pay.enums.member.WalletBizTypeEnum.PAYMENT;
 | 
				
			||||||
 | 
					import static cn.iocoder.yudao.module.pay.enums.member.WalletBizTypeEnum.PAYMENT_REFUND;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * 钱包 Service 实现类
 | 
					 * 钱包 Service 实现类
 | 
				
			||||||
@@ -29,16 +31,20 @@ import static cn.iocoder.yudao.module.pay.enums.member.WalletBizTypeEnum.PAYMENT
 | 
				
			|||||||
@Service
 | 
					@Service
 | 
				
			||||||
@Slf4j
 | 
					@Slf4j
 | 
				
			||||||
public class PayWalletServiceImpl implements  PayWalletService {
 | 
					public class PayWalletServiceImpl implements  PayWalletService {
 | 
				
			||||||
    private static final String WALLET_CHANNEL_NO_PREFIX = "W";
 | 
					    private static final String WALLET_PAY_NO_PREFIX = "WP";
 | 
				
			||||||
    @Resource
 | 
					    private static final String WALLET_REFUND_NO_PREFIX = "WR";
 | 
				
			||||||
    @Lazy
 | 
					 | 
				
			||||||
    private PayOrderService payOrderService;
 | 
					 | 
				
			||||||
    @Resource
 | 
					    @Resource
 | 
				
			||||||
    private PayWalletMapper payWalletMapper;
 | 
					    private PayWalletMapper payWalletMapper;
 | 
				
			||||||
    @Resource
 | 
					    @Resource
 | 
				
			||||||
    private PayWalletTransactionService payWalletTransactionService;
 | 
					    private PayWalletTransactionService payWalletTransactionService;
 | 
				
			||||||
    @Resource
 | 
					    @Resource
 | 
				
			||||||
    private PayNoRedisDAO noRedisDAO;
 | 
					    private PayNoRedisDAO noRedisDAO;
 | 
				
			||||||
 | 
					    @Resource
 | 
				
			||||||
 | 
					    @Lazy
 | 
				
			||||||
 | 
					    private PayOrderService payOrderService;
 | 
				
			||||||
 | 
					    @Resource
 | 
				
			||||||
 | 
					    @Lazy
 | 
				
			||||||
 | 
					    private PayRefundService payRefundService;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @Override
 | 
					    @Override
 | 
				
			||||||
    public PayWalletDO getPayWallet(Long userId, Integer userType) {
 | 
					    public PayWalletDO getPayWallet(Long userId, Integer userType) {
 | 
				
			||||||
@@ -53,13 +59,7 @@ public class PayWalletServiceImpl implements  PayWalletService {
 | 
				
			|||||||
        if (orderExtension == null) {
 | 
					        if (orderExtension == null) {
 | 
				
			||||||
            throw exception(ORDER_EXTENSION_NOT_FOUND);
 | 
					            throw exception(ORDER_EXTENSION_NOT_FOUND);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        Long userId = getLoginUserId();
 | 
					        PayWalletDO payWallet = validatePayWallet();
 | 
				
			||||||
        Integer userType = getLoginUserType();
 | 
					 | 
				
			||||||
        PayWalletDO payWallet = getPayWallet(userId, userType);
 | 
					 | 
				
			||||||
        if (payWallet == null) {
 | 
					 | 
				
			||||||
            log.error("[pay] 用户 {} 钱包不存在", userId);
 | 
					 | 
				
			||||||
            throw exception(WALLET_NOT_FOUND);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        // 判断余额是否足够
 | 
					        // 判断余额是否足够
 | 
				
			||||||
        int afterBalance = payWallet.getBalance() - price;
 | 
					        int afterBalance = payWallet.getBalance() - price;
 | 
				
			||||||
        if(afterBalance < 0){
 | 
					        if(afterBalance < 0){
 | 
				
			||||||
@@ -70,12 +70,73 @@ public class PayWalletServiceImpl implements  PayWalletService {
 | 
				
			|||||||
        payWalletMapper.updateById(payWallet);
 | 
					        payWalletMapper.updateById(payWallet);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // 生成钱包渠道流水号
 | 
					        // 生成钱包渠道流水号
 | 
				
			||||||
        String walletNo = noRedisDAO.generate(WALLET_CHANNEL_NO_PREFIX);
 | 
					        String walletNo = noRedisDAO.generate(WALLET_PAY_NO_PREFIX);
 | 
				
			||||||
        PayWalletTransactionDO payWalletTransaction = new PayWalletTransactionDO().setWalletId(payWallet.getId())
 | 
					        PayWalletTransactionDO payWalletTransaction = new PayWalletTransactionDO().setWalletId(payWallet.getId())
 | 
				
			||||||
                .setNo(walletNo).setAmount(price).setBalance(afterBalance).setTransactionTime(LocalDateTime.now())
 | 
					                .setNo(walletNo).setAmount(price * -1).setBalance(afterBalance).setTransactionTime(LocalDateTime.now())
 | 
				
			||||||
                .setBizId(orderExtension.getOrderId()).setBizType(PAYMENT.getBizType());
 | 
					                .setBizId(orderExtension.getOrderId()).setBizType(PAYMENT.getBizType());
 | 
				
			||||||
        payWalletTransactionService.addPayWalletTransaction(payWalletTransaction);
 | 
					        payWalletTransactionService.addPayWalletTransaction(payWalletTransaction);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return payWalletTransaction;
 | 
					        return payWalletTransaction;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private PayWalletDO validatePayWallet() {
 | 
				
			||||||
 | 
					        Long userId = getLoginUserId();
 | 
				
			||||||
 | 
					        Integer userType = getLoginUserType();
 | 
				
			||||||
 | 
					        PayWalletDO payWallet = getPayWallet(userId, userType);
 | 
				
			||||||
 | 
					        if (payWallet == null) {
 | 
				
			||||||
 | 
					            log.error("[validatePayWallet] 用户 {} 钱包不存在", userId);
 | 
				
			||||||
 | 
					            throw exception(WALLET_NOT_FOUND);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return payWallet;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    @Transactional(rollbackFor = Exception.class)
 | 
				
			||||||
 | 
					    public PayWalletTransactionDO refund(String outRefundNo, Integer refundPrice, String reason) {
 | 
				
			||||||
 | 
					        // 判断退款单是否存在
 | 
				
			||||||
 | 
					        PayRefundDO payRefund = payRefundService.getRefundByNo(outRefundNo);
 | 
				
			||||||
 | 
					        if (payRefund == null) {
 | 
				
			||||||
 | 
					            throw exception(REFUND_NOT_FOUND);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        PayWalletDO payWallet = validatePayWallet();
 | 
				
			||||||
 | 
					        // 校验是否可以退款
 | 
				
			||||||
 | 
					        validateWalletCanRefund(payRefund.getId(), payRefund.getChannelOrderNo(), payWallet.getId(), refundPrice);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Integer afterBalance = payWallet.getBalance() + refundPrice;
 | 
				
			||||||
 | 
					        payWallet.setBalance(afterBalance);
 | 
				
			||||||
 | 
					        payWallet.setTotalExpense(payWallet.getTotalExpense() + refundPrice * -1L);
 | 
				
			||||||
 | 
					        payWalletMapper.updateById(payWallet);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        String walletNo = noRedisDAO.generate(WALLET_REFUND_NO_PREFIX);
 | 
				
			||||||
 | 
					        PayWalletTransactionDO newWalletTransaction = new PayWalletTransactionDO().setWalletId(payWallet.getId())
 | 
				
			||||||
 | 
					                .setNo(walletNo).setAmount(refundPrice).setBalance(afterBalance).setTransactionTime(LocalDateTime.now())
 | 
				
			||||||
 | 
					                .setBizId(payRefund.getId()).setBizType(PAYMENT_REFUND.getBizType())
 | 
				
			||||||
 | 
					                .setDescription(reason);
 | 
				
			||||||
 | 
					        payWalletTransactionService.addPayWalletTransaction(newWalletTransaction);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return newWalletTransaction;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 校验是否能退款
 | 
				
			||||||
 | 
					     * @param refundId 支付退款单 id
 | 
				
			||||||
 | 
					     * @param walletPayNo 钱包支付 no
 | 
				
			||||||
 | 
					     * @param walletId 钱包 id
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private void validateWalletCanRefund(long refundId, String walletPayNo, long walletId, int refundPrice) {
 | 
				
			||||||
 | 
					        // 查询钱包支付交易
 | 
				
			||||||
 | 
					        PayWalletTransactionDO payWalletTransaction = payWalletTransactionService.getPayWalletTransactionByNo(walletPayNo);
 | 
				
			||||||
 | 
					        if (payWalletTransaction == null) {
 | 
				
			||||||
 | 
					            throw exception(WALLET_TRANSACTION_NOT_FOUND);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // 原来的支付金额
 | 
				
			||||||
 | 
					        int amount = payWalletTransaction.getAmount() * -1;
 | 
				
			||||||
 | 
					        if (refundPrice != amount) {
 | 
				
			||||||
 | 
					            throw exception(WALLET_REFUND_AMOUNT_ERROR);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        PayWalletTransactionDO refundTransaction = payWalletTransactionService.getPayWalletTransaction(walletId, refundId, PAYMENT_REFUND);
 | 
				
			||||||
 | 
					        if (refundTransaction != null) {
 | 
				
			||||||
 | 
					            throw exception(WALLET_REFUND_EXIST);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.pay.service.wallet;
 | 
				
			|||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
 | 
					import cn.iocoder.yudao.framework.common.pojo.PageResult;
 | 
				
			||||||
import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.AppPayWalletTransactionPageReqVO;
 | 
					import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.AppPayWalletTransactionPageReqVO;
 | 
				
			||||||
import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO;
 | 
					import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO;
 | 
				
			||||||
 | 
					import cn.iocoder.yudao.module.pay.enums.member.WalletBizTypeEnum;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * 钱包余额明细 Service 接口
 | 
					 * 钱包余额明细 Service 接口
 | 
				
			||||||
@@ -21,5 +22,25 @@ public interface PayWalletTransactionService {
 | 
				
			|||||||
    PageResult<PayWalletTransactionDO> getWalletTransactionPage(Long userId, Integer userType,
 | 
					    PageResult<PayWalletTransactionDO> getWalletTransactionPage(Long userId, Integer userType,
 | 
				
			||||||
                                                                AppPayWalletTransactionPageReqVO pageVO);
 | 
					                                                                AppPayWalletTransactionPageReqVO pageVO);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 新增钱包余额明细
 | 
				
			||||||
 | 
					     * @param payWalletTransaction 余额明细
 | 
				
			||||||
 | 
					     * @return id
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
    Long addPayWalletTransaction(PayWalletTransactionDO payWalletTransaction);
 | 
					    Long addPayWalletTransaction(PayWalletTransactionDO payWalletTransaction);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 获取钱包余额明细 根据 no
 | 
				
			||||||
 | 
					     * @param no 流水号
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    PayWalletTransactionDO getPayWalletTransactionByNo(String no);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 获取钱包
 | 
				
			||||||
 | 
					     * @param walletId 钱包 id
 | 
				
			||||||
 | 
					     * @param bizId  业务编号
 | 
				
			||||||
 | 
					     * @param typeEnum  业务类型
 | 
				
			||||||
 | 
					     * @return 钱包余额明细
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    PayWalletTransactionDO getPayWalletTransaction(Long walletId, Long bizId, WalletBizTypeEnum typeEnum);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,6 +5,7 @@ import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.AppPayWalletTransact
 | 
				
			|||||||
import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletDO;
 | 
					import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletDO;
 | 
				
			||||||
import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO;
 | 
					import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO;
 | 
				
			||||||
import cn.iocoder.yudao.module.pay.dal.mysql.wallet.PayWalletTransactionMapper;
 | 
					import cn.iocoder.yudao.module.pay.dal.mysql.wallet.PayWalletTransactionMapper;
 | 
				
			||||||
 | 
					import cn.iocoder.yudao.module.pay.enums.member.WalletBizTypeEnum;
 | 
				
			||||||
import cn.iocoder.yudao.module.pay.enums.member.WalletTransactionQueryTypeEnum;
 | 
					import cn.iocoder.yudao.module.pay.enums.member.WalletTransactionQueryTypeEnum;
 | 
				
			||||||
import lombok.extern.slf4j.Slf4j;
 | 
					import lombok.extern.slf4j.Slf4j;
 | 
				
			||||||
import org.springframework.stereotype.Service;
 | 
					import org.springframework.stereotype.Service;
 | 
				
			||||||
@@ -45,5 +46,15 @@ public class PayWalletTransactionServiceImpl implements PayWalletTransactionServ
 | 
				
			|||||||
         return payWalletTransaction.getId();
 | 
					         return payWalletTransaction.getId();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public PayWalletTransactionDO getPayWalletTransactionByNo(String no) {
 | 
				
			||||||
 | 
					        return payWalletTransactionMapper.selectByNo(no);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public PayWalletTransactionDO getPayWalletTransaction(Long walletId, Long bizId, WalletBizTypeEnum typeEnum) {
 | 
				
			||||||
 | 
					        return payWalletTransactionMapper.selectByWalletIdAndBiz(walletId, bizId, typeEnum.getBizType());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user