Commit 7237bc07bb7ab656c8ce5ac1de07053cf8517b27
1 parent
c7f6f921
钱包退款的实现
Showing
15 changed files
with
202 additions
and
29 deletions
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClientFactory.java
| @@ -27,6 +27,12 @@ public interface PayClientFactory { | @@ -27,6 +27,12 @@ public interface PayClientFactory { | ||
| 27 | <Config extends PayClientConfig> void createOrUpdatePayClient(Long channelId, String channelCode, | 27 | <Config extends PayClientConfig> void createOrUpdatePayClient(Long channelId, String channelCode, |
| 28 | Config config); | 28 | Config config); |
| 29 | 29 | ||
| 30 | - <Config extends PayClientConfig> void createOrUpdateDelegatePayClient(Long channelId, DelegatePayClient<Config> delegatePayClient); | 30 | + /** |
| 31 | + * 新增或更新代理支付客户端 | ||
| 32 | + * @param channelId 渠道编号 | ||
| 33 | + * @param delegatePayClient 代理支付客户端 | ||
| 34 | + * @param <Config> 支付配置 | ||
| 35 | + */ | ||
| 36 | + <Config extends PayClientConfig> void addOrUpdateDelegatePayClient(Long channelId, DelegatePayClient<Config> delegatePayClient); | ||
| 31 | 37 | ||
| 32 | } | 38 | } |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/PayClientFactoryImpl.java
| @@ -53,7 +53,7 @@ public class PayClientFactoryImpl implements PayClientFactory { | @@ -53,7 +53,7 @@ public class PayClientFactoryImpl implements PayClientFactory { | ||
| 53 | } | 53 | } |
| 54 | 54 | ||
| 55 | @Override | 55 | @Override |
| 56 | - public <Config extends PayClientConfig> void createOrUpdateDelegatePayClient(Long channelId, DelegatePayClient<Config> delegatePayClient) { | 56 | + public <Config extends PayClientConfig> void addOrUpdateDelegatePayClient(Long channelId, DelegatePayClient<Config> delegatePayClient) { |
| 57 | clients.put(channelId, delegatePayClient); | 57 | clients.put(channelId, delegatePayClient); |
| 58 | } | 58 | } |
| 59 | 59 |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/delegate/DelegatePayClient.java
| @@ -10,6 +10,8 @@ import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient; | @@ -10,6 +10,8 @@ import cn.iocoder.yudao.framework.pay.core.client.impl.AbstractPayClient; | ||
| 10 | import java.util.Map; | 10 | import java.util.Map; |
| 11 | 11 | ||
| 12 | /** | 12 | /** |
| 13 | + * 代理支付 Client 的抽象类。用于支付 Client 由其它模块实现, 例如钱包支付 | ||
| 14 | + * | ||
| 13 | * @author jason | 15 | * @author jason |
| 14 | */ | 16 | */ |
| 15 | public abstract class DelegatePayClient<Config extends PayClientConfig> extends AbstractPayClient<PayClientConfig> { | 17 | public abstract class DelegatePayClient<Config extends PayClientConfig> extends AbstractPayClient<PayClientConfig> { |
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/ErrorCodeConstants.java
| @@ -44,6 +44,9 @@ public interface ErrorCodeConstants { | @@ -44,6 +44,9 @@ public interface ErrorCodeConstants { | ||
| 44 | // ========== 钱包模块(退款) 1007007000 ========== | 44 | // ========== 钱包模块(退款) 1007007000 ========== |
| 45 | ErrorCode WALLET_NOT_FOUND = new ErrorCode(1007007000, "用户钱包不存在"); | 45 | ErrorCode WALLET_NOT_FOUND = new ErrorCode(1007007000, "用户钱包不存在"); |
| 46 | ErrorCode WALLET_NOT_ENOUGH = new ErrorCode(1007007001, "钱包余额不足"); | 46 | ErrorCode WALLET_NOT_ENOUGH = new ErrorCode(1007007001, "钱包余额不足"); |
| 47 | + ErrorCode WALLET_TRANSACTION_NOT_FOUND = new ErrorCode(1007007002, "未找到对应的钱包交易"); | ||
| 48 | + ErrorCode WALLET_REFUND_AMOUNT_ERROR = new ErrorCode(1007007003, "钱包退款金额不对"); | ||
| 49 | + ErrorCode WALLET_REFUND_EXIST = new ErrorCode(1007007004, "已经存在钱包退款"); | ||
| 47 | 50 | ||
| 48 | // ========== 示例订单 1007900000 ========== | 51 | // ========== 示例订单 1007900000 ========== |
| 49 | ErrorCode DEMO_ORDER_NOT_FOUND = new ErrorCode(1007900000, "示例订单不存在"); | 52 | ErrorCode DEMO_ORDER_NOT_FOUND = new ErrorCode(1007900000, "示例订单不存在"); |
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/member/WalletBizTypeEnum.java
| @@ -13,7 +13,8 @@ import lombok.Getter; | @@ -13,7 +13,8 @@ import lombok.Getter; | ||
| 13 | public enum WalletBizTypeEnum { | 13 | public enum WalletBizTypeEnum { |
| 14 | RECHARGE(1, "充值"), | 14 | RECHARGE(1, "充值"), |
| 15 | RECHARGE_REFUND(2, "充值退款"), | 15 | RECHARGE_REFUND(2, "充值退款"), |
| 16 | - PAYMENT(3, "支付"); | 16 | + PAYMENT(3, "支付"), |
| 17 | + PAYMENT_REFUND(4, "支付退款"); | ||
| 17 | 18 | ||
| 18 | // TODO 后续增加 | 19 | // TODO 后续增加 |
| 19 | /** | 20 | /** |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/refund/PayRefundMapper.java
| @@ -37,6 +37,11 @@ public interface PayRefundMapper extends BaseMapperX<PayRefundDO> { | @@ -37,6 +37,11 @@ public interface PayRefundMapper extends BaseMapperX<PayRefundDO> { | ||
| 37 | .eq(PayRefundDO::getNo, no)); | 37 | .eq(PayRefundDO::getNo, no)); |
| 38 | } | 38 | } |
| 39 | 39 | ||
| 40 | + default PayRefundDO selectByNo(String no){ | ||
| 41 | + return selectOne(new LambdaQueryWrapperX<PayRefundDO>() | ||
| 42 | + .eq(PayRefundDO::getNo, no)); | ||
| 43 | + } | ||
| 44 | + | ||
| 40 | default int updateByIdAndStatus(Long id, Integer status, PayRefundDO update) { | 45 | default int updateByIdAndStatus(Long id, Integer status, PayRefundDO update) { |
| 41 | return update(update, new LambdaQueryWrapper<PayRefundDO>() | 46 | return update(update, new LambdaQueryWrapper<PayRefundDO>() |
| 42 | .eq(PayRefundDO::getId, id).eq(PayRefundDO::getStatus, status)); | 47 | .eq(PayRefundDO::getId, id).eq(PayRefundDO::getStatus, status)); |
| @@ -71,5 +76,4 @@ public interface PayRefundMapper extends BaseMapperX<PayRefundDO> { | @@ -71,5 +76,4 @@ public interface PayRefundMapper extends BaseMapperX<PayRefundDO> { | ||
| 71 | default List<PayRefundDO> selectListByStatus(Integer status) { | 76 | default List<PayRefundDO> selectListByStatus(Integer status) { |
| 72 | return selectList(PayRefundDO::getStatus, status); | 77 | return selectList(PayRefundDO::getStatus, status); |
| 73 | } | 78 | } |
| 74 | - | ||
| 75 | } | 79 | } |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/wallet/PayWalletTransactionMapper.java
| @@ -26,6 +26,15 @@ public interface PayWalletTransactionMapper extends BaseMapperX<PayWalletTransac | @@ -26,6 +26,15 @@ public interface PayWalletTransactionMapper extends BaseMapperX<PayWalletTransac | ||
| 26 | query.orderByDesc(PayWalletTransactionDO::getTransactionTime); | 26 | query.orderByDesc(PayWalletTransactionDO::getTransactionTime); |
| 27 | return selectPage(pageParam, query); | 27 | return selectPage(pageParam, query); |
| 28 | } | 28 | } |
| 29 | + | ||
| 30 | + default PayWalletTransactionDO selectByNo(String no) { | ||
| 31 | + return selectOne(PayWalletTransactionDO::getNo, no); | ||
| 32 | + } | ||
| 33 | + | ||
| 34 | + default PayWalletTransactionDO selectByWalletIdAndBiz(Long walletId, Long bizId, Integer bizType) { | ||
| 35 | + return selectOne(PayWalletTransactionDO::getWalletId, walletId, PayWalletTransactionDO::getBizId, | ||
| 36 | + bizId, PayWalletTransactionDO::getBizType, bizType); | ||
| 37 | + } | ||
| 29 | } | 38 | } |
| 30 | 39 | ||
| 31 | 40 |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/framework/pay/wallet/WalletPayClient.java
| 1 | package cn.iocoder.yudao.module.pay.framework.pay.wallet; | 1 | package cn.iocoder.yudao.module.pay.framework.pay.wallet; |
| 2 | 2 | ||
| 3 | -import cn.iocoder.yudao.framework.pay.core.client.impl.NonePayClientConfig; | 3 | +import cn.iocoder.yudao.framework.common.exception.ServiceException; |
| 4 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; | 4 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO; |
| 5 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; | 5 | import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO; |
| 6 | import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; | 6 | import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO; |
| 7 | import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO; | 7 | import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO; |
| 8 | +import cn.iocoder.yudao.framework.pay.core.client.impl.NonePayClientConfig; | ||
| 8 | import cn.iocoder.yudao.framework.pay.core.client.impl.delegate.DelegatePayClient; | 9 | import cn.iocoder.yudao.framework.pay.core.client.impl.delegate.DelegatePayClient; |
| 9 | import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO; | 10 | import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO; |
| 10 | import cn.iocoder.yudao.module.pay.service.wallet.PayWalletService; | 11 | import cn.iocoder.yudao.module.pay.service.wallet.PayWalletService; |
| @@ -12,6 +13,8 @@ import lombok.extern.slf4j.Slf4j; | @@ -12,6 +13,8 @@ import lombok.extern.slf4j.Slf4j; | ||
| 12 | 13 | ||
| 13 | import java.util.Map; | 14 | import java.util.Map; |
| 14 | 15 | ||
| 16 | +import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR; | ||
| 17 | + | ||
| 15 | /** | 18 | /** |
| 16 | * 钱包支付的 PayClient 实现类 | 19 | * 钱包支付的 PayClient 实现类 |
| 17 | * | 20 | * |
| @@ -19,7 +22,6 @@ import java.util.Map; | @@ -19,7 +22,6 @@ import java.util.Map; | ||
| 19 | */ | 22 | */ |
| 20 | @Slf4j | 23 | @Slf4j |
| 21 | public class WalletPayClient extends DelegatePayClient<NonePayClientConfig> { | 24 | public class WalletPayClient extends DelegatePayClient<NonePayClientConfig> { |
| 22 | - | ||
| 23 | private PayWalletService payWalletService; | 25 | private PayWalletService payWalletService; |
| 24 | 26 | ||
| 25 | public WalletPayClient(Long channelId, String channelCode, NonePayClientConfig config) { | 27 | public WalletPayClient(Long channelId, String channelCode, NonePayClientConfig config) { |
| @@ -38,13 +40,24 @@ public class WalletPayClient extends DelegatePayClient<NonePayClientConfig> { | @@ -38,13 +40,24 @@ public class WalletPayClient extends DelegatePayClient<NonePayClientConfig> { | ||
| 38 | 40 | ||
| 39 | @Override | 41 | @Override |
| 40 | protected PayOrderRespDTO doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) { | 42 | protected PayOrderRespDTO doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) { |
| 41 | - PayWalletTransactionDO payWalletTransaction = payWalletService.pay(reqDTO.getOutTradeNo(), reqDTO.getPrice()); | ||
| 42 | - return PayOrderRespDTO.successOf(payWalletTransaction.getNo(), payWalletTransaction.getCreator(), | ||
| 43 | - payWalletTransaction.getTransactionTime(), | ||
| 44 | - reqDTO.getOutTradeNo(), ""); | 43 | + try { |
| 44 | + PayWalletTransactionDO payWalletTransaction = payWalletService.pay(reqDTO.getOutTradeNo(), reqDTO.getPrice()); | ||
| 45 | + return PayOrderRespDTO.successOf(payWalletTransaction.getNo(), payWalletTransaction.getCreator(), | ||
| 46 | + payWalletTransaction.getTransactionTime(), | ||
| 47 | + reqDTO.getOutTradeNo(), "WALLET_PAY_SUCCESS"); | ||
| 48 | + } catch (Throwable ex) { | ||
| 49 | + log.error("[doUnifiedOrder] 失败", ex); | ||
| 50 | + String errorCode = String.valueOf(INTERNAL_SERVER_ERROR); | ||
| 51 | + String errorMsg = INTERNAL_SERVER_ERROR.getMsg(); | ||
| 52 | + if (ex instanceof ServiceException) { | ||
| 53 | + ServiceException serviceException = (ServiceException) ex; | ||
| 54 | + errorCode = String.valueOf(serviceException.getCode()); | ||
| 55 | + errorMsg = serviceException.getMessage(); | ||
| 56 | + } | ||
| 57 | + return PayOrderRespDTO.closedOf(errorCode, errorMsg, reqDTO.getOutTradeNo(), ex); | ||
| 58 | + } | ||
| 45 | } | 59 | } |
| 46 | 60 | ||
| 47 | - | ||
| 48 | @Override | 61 | @Override |
| 49 | protected PayOrderRespDTO doParseOrderNotify(Map<String, String> params, String body) { | 62 | protected PayOrderRespDTO doParseOrderNotify(Map<String, String> params, String body) { |
| 50 | throw new UnsupportedOperationException("钱包支付无支付回调"); | 63 | throw new UnsupportedOperationException("钱包支付无支付回调"); |
| @@ -52,12 +65,27 @@ public class WalletPayClient extends DelegatePayClient<NonePayClientConfig> { | @@ -52,12 +65,27 @@ public class WalletPayClient extends DelegatePayClient<NonePayClientConfig> { | ||
| 52 | 65 | ||
| 53 | @Override | 66 | @Override |
| 54 | protected PayOrderRespDTO doGetOrder(String outTradeNo) { | 67 | protected PayOrderRespDTO doGetOrder(String outTradeNo) { |
| 55 | - return null; | 68 | + throw new UnsupportedOperationException("待实现"); |
| 56 | } | 69 | } |
| 57 | 70 | ||
| 58 | @Override | 71 | @Override |
| 59 | protected PayRefundRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) { | 72 | protected PayRefundRespDTO doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) { |
| 60 | - return null; | 73 | + try { |
| 74 | + PayWalletTransactionDO payWalletTransaction = payWalletService.refund(reqDTO.getOutRefundNo(), | ||
| 75 | + reqDTO.getRefundPrice(), reqDTO.getReason()); | ||
| 76 | + return PayRefundRespDTO.successOf(payWalletTransaction.getNo(), payWalletTransaction.getTransactionTime(), | ||
| 77 | + reqDTO.getOutRefundNo(), "WALLET_REFUND_SUCCESS"); | ||
| 78 | + } catch (Throwable ex) { | ||
| 79 | + log.error("[doUnifiedRefund] 失败", ex); | ||
| 80 | + String errorCode = String.valueOf(INTERNAL_SERVER_ERROR); | ||
| 81 | + String errorMsg = INTERNAL_SERVER_ERROR.getMsg(); | ||
| 82 | + if (ex instanceof ServiceException) { | ||
| 83 | + ServiceException serviceException = (ServiceException) ex; | ||
| 84 | + errorCode = String.valueOf(serviceException.getCode()); | ||
| 85 | + errorMsg = serviceException.getMessage(); | ||
| 86 | + } | ||
| 87 | + return PayRefundRespDTO.failureOf(errorCode, errorMsg, reqDTO.getOutRefundNo(), ex); | ||
| 88 | + } | ||
| 61 | } | 89 | } |
| 62 | 90 | ||
| 63 | @Override | 91 | @Override |
| @@ -67,6 +95,6 @@ public class WalletPayClient extends DelegatePayClient<NonePayClientConfig> { | @@ -67,6 +95,6 @@ public class WalletPayClient extends DelegatePayClient<NonePayClientConfig> { | ||
| 67 | 95 | ||
| 68 | @Override | 96 | @Override |
| 69 | protected PayRefundRespDTO doGetRefund(String outTradeNo, String outRefundNo) { | 97 | protected PayRefundRespDTO doGetRefund(String outTradeNo, String outRefundNo) { |
| 70 | - return null; | 98 | + throw new UnsupportedOperationException("待实现"); |
| 71 | } | 99 | } |
| 72 | } | 100 | } |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/channel/PayChannelServiceImpl.java
| @@ -81,6 +81,7 @@ public class PayChannelServiceImpl implements PayChannelService { | @@ -81,6 +81,7 @@ public class PayChannelServiceImpl implements PayChannelService { | ||
| 81 | log.error("[支付模块 yudao-module-pay - 表结构未导入][参考 https://doc.iocoder.cn/pay/build/ 开启]"); | 81 | log.error("[支付模块 yudao-module-pay - 表结构未导入][参考 https://doc.iocoder.cn/pay/build/ 开启]"); |
| 82 | } | 82 | } |
| 83 | log.info("[initLocalCache][缓存支付渠道,数量为:{}]", channels.size()); | 83 | log.info("[initLocalCache][缓存支付渠道,数量为:{}]", channels.size()); |
| 84 | + // 钱包 client 需要和其它 client 分开了创建 | ||
| 84 | List<PayChannelDO> walletChannels = new ArrayList<>(); | 85 | List<PayChannelDO> walletChannels = new ArrayList<>(); |
| 85 | List<PayChannelDO> otherChannels = new ArrayList<>(); | 86 | List<PayChannelDO> otherChannels = new ArrayList<>(); |
| 86 | channels.forEach(t -> { | 87 | channels.forEach(t -> { |
| @@ -97,7 +98,7 @@ public class PayChannelServiceImpl implements PayChannelService { | @@ -97,7 +98,7 @@ public class PayChannelServiceImpl implements PayChannelService { | ||
| 97 | walletChannels.forEach(payChannel -> { | 98 | walletChannels.forEach(payChannel -> { |
| 98 | WalletPayClient walletPayClient = new WalletPayClient(payChannel.getId(), payChannel.getCode(), | 99 | WalletPayClient walletPayClient = new WalletPayClient(payChannel.getId(), payChannel.getCode(), |
| 99 | (NonePayClientConfig) payChannel.getConfig(), payWalletService); | 100 | (NonePayClientConfig) payChannel.getConfig(), payWalletService); |
| 100 | - payClientFactory.createOrUpdateDelegatePayClient(payChannel.getId(), walletPayClient); | 101 | + payClientFactory.addOrUpdateDelegatePayClient(payChannel.getId(), walletPayClient); |
| 101 | }); | 102 | }); |
| 102 | this.channelCache = channels; | 103 | this.channelCache = channels; |
| 103 | }); | 104 | }); |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/refund/PayRefundService.java
| @@ -25,6 +25,14 @@ public interface PayRefundService { | @@ -25,6 +25,14 @@ public interface PayRefundService { | ||
| 25 | PayRefundDO getRefund(Long id); | 25 | PayRefundDO getRefund(Long id); |
| 26 | 26 | ||
| 27 | /** | 27 | /** |
| 28 | + * 获得退款订单 | ||
| 29 | + * | ||
| 30 | + * @param no 外部退款单号 | ||
| 31 | + * @return 退款订单 | ||
| 32 | + */ | ||
| 33 | + PayRefundDO getRefundByNo(String no); | ||
| 34 | + | ||
| 35 | + /** | ||
| 28 | * 获得指定应用的退款数量 | 36 | * 获得指定应用的退款数量 |
| 29 | * | 37 | * |
| 30 | * @param appId 应用编号 | 38 | * @param appId 应用编号 |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/refund/PayRefundServiceImpl.java
| @@ -75,6 +75,11 @@ public class PayRefundServiceImpl implements PayRefundService { | @@ -75,6 +75,11 @@ public class PayRefundServiceImpl implements PayRefundService { | ||
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | @Override | 77 | @Override |
| 78 | + public PayRefundDO getRefundByNo(String no) { | ||
| 79 | + return refundMapper.selectByNo(no); | ||
| 80 | + } | ||
| 81 | + | ||
| 82 | + @Override | ||
| 78 | public Long getRefundCountByAppId(Long appId) { | 83 | public Long getRefundCountByAppId(Long appId) { |
| 79 | return refundMapper.selectCountByAppId(appId); | 84 | return refundMapper.selectCountByAppId(appId); |
| 80 | } | 85 | } |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletService.java
| @@ -17,5 +17,18 @@ public interface PayWalletService { | @@ -17,5 +17,18 @@ public interface PayWalletService { | ||
| 17 | */ | 17 | */ |
| 18 | PayWalletDO getPayWallet(Long userId, Integer userType); | 18 | PayWalletDO getPayWallet(Long userId, Integer userType); |
| 19 | 19 | ||
| 20 | + /** | ||
| 21 | + * 钱包支付 | ||
| 22 | + * @param outTradeNo 外部订单号 | ||
| 23 | + * @param price 金额 | ||
| 24 | + */ | ||
| 20 | PayWalletTransactionDO pay(String outTradeNo, Integer price); | 25 | PayWalletTransactionDO pay(String outTradeNo, Integer price); |
| 26 | + | ||
| 27 | + /** | ||
| 28 | + * 钱包支付退款 | ||
| 29 | + * @param outRefundNo 外部退款号 | ||
| 30 | + * @param refundPrice 退款金额 | ||
| 31 | + * @param reason 退款原因 | ||
| 32 | + */ | ||
| 33 | + PayWalletTransactionDO refund(String outRefundNo, Integer refundPrice, String reason); | ||
| 21 | } | 34 | } |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletServiceImpl.java
| 1 | package cn.iocoder.yudao.module.pay.service.wallet; | 1 | package cn.iocoder.yudao.module.pay.service.wallet; |
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO; | 3 | import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO; |
| 4 | +import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO; | ||
| 4 | import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletDO; | 5 | import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletDO; |
| 5 | import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO; | 6 | import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO; |
| 6 | import cn.iocoder.yudao.module.pay.dal.mysql.wallet.PayWalletMapper; | 7 | import cn.iocoder.yudao.module.pay.dal.mysql.wallet.PayWalletMapper; |
| 7 | import cn.iocoder.yudao.module.pay.dal.redis.no.PayNoRedisDAO; | 8 | import cn.iocoder.yudao.module.pay.dal.redis.no.PayNoRedisDAO; |
| 8 | import cn.iocoder.yudao.module.pay.service.order.PayOrderService; | 9 | import cn.iocoder.yudao.module.pay.service.order.PayOrderService; |
| 10 | +import cn.iocoder.yudao.module.pay.service.refund.PayRefundService; | ||
| 9 | import lombok.extern.slf4j.Slf4j; | 11 | import lombok.extern.slf4j.Slf4j; |
| 10 | import org.springframework.context.annotation.Lazy; | 12 | import org.springframework.context.annotation.Lazy; |
| 11 | import org.springframework.stereotype.Service; | 13 | import org.springframework.stereotype.Service; |
| 12 | import org.springframework.transaction.annotation.Transactional; | 14 | import org.springframework.transaction.annotation.Transactional; |
| 13 | 15 | ||
| 14 | import javax.annotation.Resource; | 16 | import javax.annotation.Resource; |
| 15 | - | ||
| 16 | import java.time.LocalDateTime; | 17 | import java.time.LocalDateTime; |
| 17 | 18 | ||
| 18 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | 19 | 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 | @@ -20,6 +21,7 @@ import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLogi | ||
| 20 | import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserType; | 21 | import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserType; |
| 21 | import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*; | 22 | import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*; |
| 22 | import static cn.iocoder.yudao.module.pay.enums.member.WalletBizTypeEnum.PAYMENT; | 23 | import static cn.iocoder.yudao.module.pay.enums.member.WalletBizTypeEnum.PAYMENT; |
| 24 | +import static cn.iocoder.yudao.module.pay.enums.member.WalletBizTypeEnum.PAYMENT_REFUND; | ||
| 23 | 25 | ||
| 24 | /** | 26 | /** |
| 25 | * 钱包 Service 实现类 | 27 | * 钱包 Service 实现类 |
| @@ -29,16 +31,20 @@ import static cn.iocoder.yudao.module.pay.enums.member.WalletBizTypeEnum.PAYMENT | @@ -29,16 +31,20 @@ import static cn.iocoder.yudao.module.pay.enums.member.WalletBizTypeEnum.PAYMENT | ||
| 29 | @Service | 31 | @Service |
| 30 | @Slf4j | 32 | @Slf4j |
| 31 | public class PayWalletServiceImpl implements PayWalletService { | 33 | public class PayWalletServiceImpl implements PayWalletService { |
| 32 | - private static final String WALLET_CHANNEL_NO_PREFIX = "W"; | ||
| 33 | - @Resource | ||
| 34 | - @Lazy | ||
| 35 | - private PayOrderService payOrderService; | 34 | + private static final String WALLET_PAY_NO_PREFIX = "WP"; |
| 35 | + private static final String WALLET_REFUND_NO_PREFIX = "WR"; | ||
| 36 | @Resource | 36 | @Resource |
| 37 | private PayWalletMapper payWalletMapper; | 37 | private PayWalletMapper payWalletMapper; |
| 38 | @Resource | 38 | @Resource |
| 39 | private PayWalletTransactionService payWalletTransactionService; | 39 | private PayWalletTransactionService payWalletTransactionService; |
| 40 | @Resource | 40 | @Resource |
| 41 | private PayNoRedisDAO noRedisDAO; | 41 | private PayNoRedisDAO noRedisDAO; |
| 42 | + @Resource | ||
| 43 | + @Lazy | ||
| 44 | + private PayOrderService payOrderService; | ||
| 45 | + @Resource | ||
| 46 | + @Lazy | ||
| 47 | + private PayRefundService payRefundService; | ||
| 42 | 48 | ||
| 43 | @Override | 49 | @Override |
| 44 | public PayWalletDO getPayWallet(Long userId, Integer userType) { | 50 | public PayWalletDO getPayWallet(Long userId, Integer userType) { |
| @@ -53,13 +59,7 @@ public class PayWalletServiceImpl implements PayWalletService { | @@ -53,13 +59,7 @@ public class PayWalletServiceImpl implements PayWalletService { | ||
| 53 | if (orderExtension == null) { | 59 | if (orderExtension == null) { |
| 54 | throw exception(ORDER_EXTENSION_NOT_FOUND); | 60 | throw exception(ORDER_EXTENSION_NOT_FOUND); |
| 55 | } | 61 | } |
| 56 | - Long userId = getLoginUserId(); | ||
| 57 | - Integer userType = getLoginUserType(); | ||
| 58 | - PayWalletDO payWallet = getPayWallet(userId, userType); | ||
| 59 | - if (payWallet == null) { | ||
| 60 | - log.error("[pay] 用户 {} 钱包不存在", userId); | ||
| 61 | - throw exception(WALLET_NOT_FOUND); | ||
| 62 | - } | 62 | + PayWalletDO payWallet = validatePayWallet(); |
| 63 | // 判断余额是否足够 | 63 | // 判断余额是否足够 |
| 64 | int afterBalance = payWallet.getBalance() - price; | 64 | int afterBalance = payWallet.getBalance() - price; |
| 65 | if(afterBalance < 0){ | 65 | if(afterBalance < 0){ |
| @@ -70,12 +70,73 @@ public class PayWalletServiceImpl implements PayWalletService { | @@ -70,12 +70,73 @@ public class PayWalletServiceImpl implements PayWalletService { | ||
| 70 | payWalletMapper.updateById(payWallet); | 70 | payWalletMapper.updateById(payWallet); |
| 71 | 71 | ||
| 72 | // 生成钱包渠道流水号 | 72 | // 生成钱包渠道流水号 |
| 73 | - String walletNo = noRedisDAO.generate(WALLET_CHANNEL_NO_PREFIX); | 73 | + String walletNo = noRedisDAO.generate(WALLET_PAY_NO_PREFIX); |
| 74 | PayWalletTransactionDO payWalletTransaction = new PayWalletTransactionDO().setWalletId(payWallet.getId()) | 74 | PayWalletTransactionDO payWalletTransaction = new PayWalletTransactionDO().setWalletId(payWallet.getId()) |
| 75 | - .setNo(walletNo).setAmount(price).setBalance(afterBalance).setTransactionTime(LocalDateTime.now()) | 75 | + .setNo(walletNo).setAmount(price * -1).setBalance(afterBalance).setTransactionTime(LocalDateTime.now()) |
| 76 | .setBizId(orderExtension.getOrderId()).setBizType(PAYMENT.getBizType()); | 76 | .setBizId(orderExtension.getOrderId()).setBizType(PAYMENT.getBizType()); |
| 77 | payWalletTransactionService.addPayWalletTransaction(payWalletTransaction); | 77 | payWalletTransactionService.addPayWalletTransaction(payWalletTransaction); |
| 78 | 78 | ||
| 79 | return payWalletTransaction; | 79 | return payWalletTransaction; |
| 80 | } | 80 | } |
| 81 | + | ||
| 82 | + private PayWalletDO validatePayWallet() { | ||
| 83 | + Long userId = getLoginUserId(); | ||
| 84 | + Integer userType = getLoginUserType(); | ||
| 85 | + PayWalletDO payWallet = getPayWallet(userId, userType); | ||
| 86 | + if (payWallet == null) { | ||
| 87 | + log.error("[validatePayWallet] 用户 {} 钱包不存在", userId); | ||
| 88 | + throw exception(WALLET_NOT_FOUND); | ||
| 89 | + } | ||
| 90 | + return payWallet; | ||
| 91 | + } | ||
| 92 | + | ||
| 93 | + @Override | ||
| 94 | + @Transactional(rollbackFor = Exception.class) | ||
| 95 | + public PayWalletTransactionDO refund(String outRefundNo, Integer refundPrice, String reason) { | ||
| 96 | + // 判断退款单是否存在 | ||
| 97 | + PayRefundDO payRefund = payRefundService.getRefundByNo(outRefundNo); | ||
| 98 | + if (payRefund == null) { | ||
| 99 | + throw exception(REFUND_NOT_FOUND); | ||
| 100 | + } | ||
| 101 | + PayWalletDO payWallet = validatePayWallet(); | ||
| 102 | + // 校验是否可以退款 | ||
| 103 | + validateWalletCanRefund(payRefund.getId(), payRefund.getChannelOrderNo(), payWallet.getId(), refundPrice); | ||
| 104 | + | ||
| 105 | + Integer afterBalance = payWallet.getBalance() + refundPrice; | ||
| 106 | + payWallet.setBalance(afterBalance); | ||
| 107 | + payWallet.setTotalExpense(payWallet.getTotalExpense() + refundPrice * -1L); | ||
| 108 | + payWalletMapper.updateById(payWallet); | ||
| 109 | + | ||
| 110 | + String walletNo = noRedisDAO.generate(WALLET_REFUND_NO_PREFIX); | ||
| 111 | + PayWalletTransactionDO newWalletTransaction = new PayWalletTransactionDO().setWalletId(payWallet.getId()) | ||
| 112 | + .setNo(walletNo).setAmount(refundPrice).setBalance(afterBalance).setTransactionTime(LocalDateTime.now()) | ||
| 113 | + .setBizId(payRefund.getId()).setBizType(PAYMENT_REFUND.getBizType()) | ||
| 114 | + .setDescription(reason); | ||
| 115 | + payWalletTransactionService.addPayWalletTransaction(newWalletTransaction); | ||
| 116 | + | ||
| 117 | + return newWalletTransaction; | ||
| 118 | + } | ||
| 119 | + | ||
| 120 | + /** | ||
| 121 | + * 校验是否能退款 | ||
| 122 | + * @param refundId 支付退款单 id | ||
| 123 | + * @param walletPayNo 钱包支付 no | ||
| 124 | + * @param walletId 钱包 id | ||
| 125 | + */ | ||
| 126 | + private void validateWalletCanRefund(long refundId, String walletPayNo, long walletId, int refundPrice) { | ||
| 127 | + // 查询钱包支付交易 | ||
| 128 | + PayWalletTransactionDO payWalletTransaction = payWalletTransactionService.getPayWalletTransactionByNo(walletPayNo); | ||
| 129 | + if (payWalletTransaction == null) { | ||
| 130 | + throw exception(WALLET_TRANSACTION_NOT_FOUND); | ||
| 131 | + } | ||
| 132 | + // 原来的支付金额 | ||
| 133 | + int amount = payWalletTransaction.getAmount() * -1; | ||
| 134 | + if (refundPrice != amount) { | ||
| 135 | + throw exception(WALLET_REFUND_AMOUNT_ERROR); | ||
| 136 | + } | ||
| 137 | + PayWalletTransactionDO refundTransaction = payWalletTransactionService.getPayWalletTransaction(walletId, refundId, PAYMENT_REFUND); | ||
| 138 | + if (refundTransaction != null) { | ||
| 139 | + throw exception(WALLET_REFUND_EXIST); | ||
| 140 | + } | ||
| 141 | + } | ||
| 81 | } | 142 | } |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletTransactionService.java
| @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.pay.service.wallet; | @@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.pay.service.wallet; | ||
| 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 4 | import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.AppPayWalletTransactionPageReqVO; | 4 | import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.AppPayWalletTransactionPageReqVO; |
| 5 | import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO; | 5 | import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO; |
| 6 | +import cn.iocoder.yudao.module.pay.enums.member.WalletBizTypeEnum; | ||
| 6 | 7 | ||
| 7 | /** | 8 | /** |
| 8 | * 钱包余额明细 Service 接口 | 9 | * 钱包余额明细 Service 接口 |
| @@ -21,5 +22,25 @@ public interface PayWalletTransactionService { | @@ -21,5 +22,25 @@ public interface PayWalletTransactionService { | ||
| 21 | PageResult<PayWalletTransactionDO> getWalletTransactionPage(Long userId, Integer userType, | 22 | PageResult<PayWalletTransactionDO> getWalletTransactionPage(Long userId, Integer userType, |
| 22 | AppPayWalletTransactionPageReqVO pageVO); | 23 | AppPayWalletTransactionPageReqVO pageVO); |
| 23 | 24 | ||
| 25 | + /** | ||
| 26 | + * 新增钱包余额明细 | ||
| 27 | + * @param payWalletTransaction 余额明细 | ||
| 28 | + * @return id | ||
| 29 | + */ | ||
| 24 | Long addPayWalletTransaction(PayWalletTransactionDO payWalletTransaction); | 30 | Long addPayWalletTransaction(PayWalletTransactionDO payWalletTransaction); |
| 31 | + | ||
| 32 | + /** | ||
| 33 | + * 获取钱包余额明细 根据 no | ||
| 34 | + * @param no 流水号 | ||
| 35 | + */ | ||
| 36 | + PayWalletTransactionDO getPayWalletTransactionByNo(String no); | ||
| 37 | + | ||
| 38 | + /** | ||
| 39 | + * 获取钱包 | ||
| 40 | + * @param walletId 钱包 id | ||
| 41 | + * @param bizId 业务编号 | ||
| 42 | + * @param typeEnum 业务类型 | ||
| 43 | + * @return 钱包余额明细 | ||
| 44 | + */ | ||
| 45 | + PayWalletTransactionDO getPayWalletTransaction(Long walletId, Long bizId, WalletBizTypeEnum typeEnum); | ||
| 25 | } | 46 | } |
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/wallet/PayWalletTransactionServiceImpl.java
| @@ -5,6 +5,7 @@ import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.AppPayWalletTransact | @@ -5,6 +5,7 @@ import cn.iocoder.yudao.module.pay.controller.app.wallet.vo.AppPayWalletTransact | ||
| 5 | import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletDO; | 5 | import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletDO; |
| 6 | import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO; | 6 | import cn.iocoder.yudao.module.pay.dal.dataobject.wallet.PayWalletTransactionDO; |
| 7 | import cn.iocoder.yudao.module.pay.dal.mysql.wallet.PayWalletTransactionMapper; | 7 | import cn.iocoder.yudao.module.pay.dal.mysql.wallet.PayWalletTransactionMapper; |
| 8 | +import cn.iocoder.yudao.module.pay.enums.member.WalletBizTypeEnum; | ||
| 8 | import cn.iocoder.yudao.module.pay.enums.member.WalletTransactionQueryTypeEnum; | 9 | import cn.iocoder.yudao.module.pay.enums.member.WalletTransactionQueryTypeEnum; |
| 9 | import lombok.extern.slf4j.Slf4j; | 10 | import lombok.extern.slf4j.Slf4j; |
| 10 | import org.springframework.stereotype.Service; | 11 | import org.springframework.stereotype.Service; |
| @@ -45,5 +46,15 @@ public class PayWalletTransactionServiceImpl implements PayWalletTransactionServ | @@ -45,5 +46,15 @@ public class PayWalletTransactionServiceImpl implements PayWalletTransactionServ | ||
| 45 | return payWalletTransaction.getId(); | 46 | return payWalletTransaction.getId(); |
| 46 | } | 47 | } |
| 47 | 48 | ||
| 49 | + @Override | ||
| 50 | + public PayWalletTransactionDO getPayWalletTransactionByNo(String no) { | ||
| 51 | + return payWalletTransactionMapper.selectByNo(no); | ||
| 52 | + } | ||
| 53 | + | ||
| 54 | + @Override | ||
| 55 | + public PayWalletTransactionDO getPayWalletTransaction(Long walletId, Long bizId, WalletBizTypeEnum typeEnum) { | ||
| 56 | + return payWalletTransactionMapper.selectByWalletIdAndBiz(walletId, bizId, typeEnum.getBizType()); | ||
| 57 | + } | ||
| 58 | + | ||
| 48 | 59 | ||
| 49 | } | 60 | } |