Commit bcc2ff0f5bee343442898dcc17306b197552c08a
1 parent
d49ce4c8
code review 退款逻辑
Showing
17 changed files
with
77 additions
and
156 deletions
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/PayCommonCoreService.java deleted
| 1 | -package cn.iocoder.yudao.coreservice.modules.pay.service.order; | |
| 2 | - | |
| 3 | -import cn.iocoder.yudao.framework.pay.core.client.dto.PayNotifyDataDTO; | |
| 4 | - | |
| 5 | -/** | |
| 6 | - * 支付通用 Core Service | |
| 7 | - * | |
| 8 | - * @author jason | |
| 9 | - */ | |
| 10 | -public interface PayCommonCoreService { | |
| 11 | - | |
| 12 | - /** | |
| 13 | - * 验证是否是渠道通知 | |
| 14 | - * @param notifyData 通知数据 | |
| 15 | - */ | |
| 16 | - void verifyNotifyData(Long channelId, PayNotifyDataDTO notifyData); | |
| 17 | - | |
| 18 | - /** | |
| 19 | - * 支付宝的支付回调通知,和退款回调通知 地址是同一个 | |
| 20 | - * 是否是退款回调通知 | |
| 21 | - * @param notifyData 通知数据 | |
| 22 | - * @return | |
| 23 | - */ | |
| 24 | - boolean isRefundNotify(Long channelId, PayNotifyDataDTO notifyData); | |
| 25 | -} |
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/PayOrderCoreService.java
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/PayRefundChannelPostHandler.java
| ... | ... | @@ -5,19 +5,21 @@ import cn.iocoder.yudao.framework.pay.core.enums.PayChannelRespEnum; |
| 5 | 5 | |
| 6 | 6 | /** |
| 7 | 7 | * 支付退款订单 ,渠道返回后 后置处理 |
| 8 | + * | |
| 8 | 9 | * @author jason |
| 9 | 10 | */ |
| 10 | 11 | public interface PayRefundChannelPostHandler { |
| 11 | 12 | |
| 12 | 13 | /** |
| 13 | 14 | * 支持的渠道返回值 |
| 15 | + * | |
| 14 | 16 | * @return 支持的渠道返回值数组 |
| 15 | 17 | */ |
| 16 | 18 | PayChannelRespEnum[] supportHandleResp(); |
| 17 | 19 | |
| 18 | - | |
| 19 | 20 | /** |
| 20 | - * 根据渠道返回, 处理支付退款单 | |
| 21 | + * 根据渠道返回,处理支付退款单 | |
| 22 | + * | |
| 21 | 23 | * @param respBO |
| 22 | 24 | */ |
| 23 | 25 | void handleRefundChannelResp(PayRefundPostReqBO respBO); | ... | ... |
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/PayRefundCoreService.java
| ... | ... | @@ -11,23 +11,22 @@ import cn.iocoder.yudao.framework.pay.core.client.dto.PayNotifyDataDTO; |
| 11 | 11 | */ |
| 12 | 12 | public interface PayRefundCoreService { |
| 13 | 13 | |
| 14 | - | |
| 14 | + // TODO @jason:方法名改成,submitRefundOrder,发起退款订单。这样和发起支付单,保持一致 | |
| 15 | 15 | /** |
| 16 | 16 | * 提交退款申请 |
| 17 | + * | |
| 17 | 18 | * @param reqDTO 退款申请信息 |
| 18 | 19 | * @return 退款申请返回信息 |
| 19 | 20 | */ |
| 20 | 21 | PayRefundRespBO refund(PayRefundReqBO reqDTO); |
| 21 | 22 | |
| 22 | - | |
| 23 | 23 | /** |
| 24 | 24 | * 渠道的退款通知 |
| 25 | + * | |
| 25 | 26 | * @param channelId 渠道编号 |
| 26 | 27 | * @param notifyData 通知数据 |
| 27 | 28 | * @throws Exception 退款通知异常 |
| 28 | 29 | */ |
| 29 | 30 | void notifyPayRefund(Long channelId, PayNotifyDataDTO notifyData) throws Exception; |
| 30 | 31 | |
| 31 | - | |
| 32 | - | |
| 33 | 32 | } | ... | ... |
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/bo/PayRefundPostReqBO.java
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/bo/PayRefundReqBO.java
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/bo/PayRefundRespBO.java
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/impl/PayCommonCoreServiceImpl.java deleted
| 1 | -package cn.iocoder.yudao.coreservice.modules.pay.service.order.impl; | |
| 2 | - | |
| 3 | -import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayChannelDO; | |
| 4 | -import cn.iocoder.yudao.coreservice.modules.pay.service.merchant.PayChannelCoreService; | |
| 5 | -import cn.iocoder.yudao.coreservice.modules.pay.service.order.PayCommonCoreService; | |
| 6 | -import cn.iocoder.yudao.framework.pay.core.client.PayClient; | |
| 7 | -import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory; | |
| 8 | -import cn.iocoder.yudao.framework.pay.core.client.dto.PayNotifyDataDTO; | |
| 9 | -import lombok.extern.slf4j.Slf4j; | |
| 10 | -import org.springframework.stereotype.Service; | |
| 11 | - | |
| 12 | -import javax.annotation.Resource; | |
| 13 | - | |
| 14 | -import static cn.iocoder.yudao.coreservice.modules.pay.enums.PayErrorCodeCoreConstants.PAY_CHANNEL_CLIENT_NOT_FOUND; | |
| 15 | -import static cn.iocoder.yudao.coreservice.modules.pay.enums.PayErrorCodeCoreConstants.PAY_CHANNEL_NOTIFY_VERIFY_FAILED; | |
| 16 | -import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | |
| 17 | - | |
| 18 | -/** | |
| 19 | - * 支付通用 Core Service 实现类 | |
| 20 | - * | |
| 21 | - * @author jason | |
| 22 | - */ | |
| 23 | -@Service | |
| 24 | -@Slf4j | |
| 25 | -public class PayCommonCoreServiceImpl implements PayCommonCoreService { | |
| 26 | - | |
| 27 | - @Resource | |
| 28 | - private PayChannelCoreService payChannelCoreService; | |
| 29 | - | |
| 30 | - @Resource | |
| 31 | - private PayClientFactory payClientFactory; | |
| 32 | - | |
| 33 | - @Override | |
| 34 | - public void verifyNotifyData(Long channelId, PayNotifyDataDTO notifyData) { | |
| 35 | - // 校验支付渠道是否有效 | |
| 36 | - PayChannelDO channel = payChannelCoreService.validPayChannel(channelId); | |
| 37 | - // 校验支付客户端是否正确初始化 | |
| 38 | - PayClient client = payClientFactory.getPayClient(channel.getId()); | |
| 39 | - if (client == null) { | |
| 40 | - log.error("[notifyPayOrder][渠道编号({}) 找不到对应的支付客户端]", channel.getId()); | |
| 41 | - throw exception(PAY_CHANNEL_CLIENT_NOT_FOUND); | |
| 42 | - } | |
| 43 | - boolean verifyResult = client.verifyNotifyData(notifyData); | |
| 44 | - if(!verifyResult){ | |
| 45 | - //渠道通知验证失败 | |
| 46 | - throw exception(PAY_CHANNEL_NOTIFY_VERIFY_FAILED); | |
| 47 | - } | |
| 48 | - } | |
| 49 | - | |
| 50 | - @Override | |
| 51 | - public boolean isRefundNotify(Long channelId, PayNotifyDataDTO notifyData) { | |
| 52 | - // 校验支付渠道是否有效 | |
| 53 | - PayChannelDO channel = payChannelCoreService.validPayChannel(channelId); | |
| 54 | - // 校验支付客户端是否正确初始化 | |
| 55 | - PayClient client = payClientFactory.getPayClient(channel.getId()); | |
| 56 | - if (client == null) { | |
| 57 | - log.error("[notifyPayOrder][渠道编号({}) 找不到对应的支付客户端]", channel.getId()); | |
| 58 | - throw exception(PAY_CHANNEL_CLIENT_NOT_FOUND); | |
| 59 | - } | |
| 60 | - return client.isRefundNotify(notifyData); | |
| 61 | - } | |
| 62 | -} |
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/impl/PayRefundCoreServiceImpl.java
| ... | ... | @@ -50,18 +50,17 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService { |
| 50 | 50 | |
| 51 | 51 | @Resource |
| 52 | 52 | private PayOrderCoreMapper payOrderCoreMapper; |
| 53 | - | |
| 54 | 53 | @Resource |
| 55 | 54 | private PayRefundCoreMapper payRefundCoreMapper; |
| 56 | - | |
| 57 | 55 | @Resource |
| 58 | 56 | private PayOrderExtensionCoreMapper payOrderExtensionCoreMapper; |
| 59 | 57 | |
| 60 | 58 | @Resource |
| 61 | 59 | private PayAppCoreService payAppCoreService; |
| 62 | - | |
| 63 | 60 | @Resource |
| 64 | 61 | private PayChannelCoreService payChannelCoreService; |
| 62 | + @Resource | |
| 63 | + private PayNotifyCoreService payNotifyCoreService; | |
| 65 | 64 | |
| 66 | 65 | @Resource |
| 67 | 66 | private PayClientFactory payClientFactory; |
| ... | ... | @@ -72,25 +71,18 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService { |
| 72 | 71 | @Resource |
| 73 | 72 | private List<PayRefundChannelPostHandler> handlerList; |
| 74 | 73 | |
| 75 | - @Resource | |
| 76 | - private PayNotifyCoreService payNotifyCoreService; | |
| 77 | - | |
| 78 | - | |
| 74 | + // TODO @json:mapHandlers | |
| 79 | 75 | private final EnumMap<PayChannelRespEnum, PayRefundChannelPostHandler> mapHandler = new EnumMap<>(PayChannelRespEnum.class); |
| 80 | 76 | |
| 81 | - | |
| 82 | - | |
| 83 | 77 | @PostConstruct |
| 84 | 78 | public void init(){ |
| 85 | - | |
| 86 | 79 | if (Objects.nonNull(handlerList)) { |
| 87 | - handlerList.forEach(t->{ | |
| 88 | - for (PayChannelRespEnum item : t.supportHandleResp()) { | |
| 89 | - mapHandler.put(item, t); | |
| 80 | + handlerList.forEach(handler -> { | |
| 81 | + for (PayChannelRespEnum item : handler.supportHandleResp()) { | |
| 82 | + mapHandler.put(item, handler); | |
| 90 | 83 | } |
| 91 | 84 | }); |
| 92 | 85 | } |
| 93 | - | |
| 94 | 86 | } |
| 95 | 87 | |
| 96 | 88 | @Override |
| ... | ... | @@ -113,16 +105,16 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService { |
| 113 | 105 | throw exception(PAY_CHANNEL_CLIENT_NOT_FOUND); |
| 114 | 106 | } |
| 115 | 107 | |
| 116 | - //校验退款的条件 | |
| 108 | + // 校验退款的条件 | |
| 117 | 109 | validatePayRefund(reqBO, order); |
| 118 | 110 | |
| 119 | - //退款类型 | |
| 111 | + // 退款类型 | |
| 120 | 112 | PayRefundTypeEnum refundType = PayRefundTypeEnum.SOME; |
| 121 | 113 | if (Objects.equals(reqBO.getAmount(), order.getAmount())) { |
| 122 | 114 | refundType = PayRefundTypeEnum.ALL; |
| 123 | 115 | } |
| 124 | 116 | |
| 125 | - //退款单入库 退款单状态:生成, 没有和渠道产生交互 | |
| 117 | + // 退款单入库 退款单状态:生成, 没有和渠道产生交互 | |
| 126 | 118 | PayOrderExtensionDO orderExtensionDO = payOrderExtensionCoreMapper.selectById(order.getSuccessExtensionId()); |
| 127 | 119 | PayRefundDO refundDO = PayRefundDO.builder().channelOrderNo(order.getChannelOrderNo()) |
| 128 | 120 | .appId(order.getAppId()) |
| ... | ... | @@ -144,9 +136,9 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService { |
| 144 | 136 | .reqNo(PaySeqUtils.genRefundReqNo()) |
| 145 | 137 | .type(refundType.getStatus()) |
| 146 | 138 | .build(); |
| 147 | - | |
| 148 | 139 | payRefundCoreMapper.insert(refundDO); |
| 149 | 140 | |
| 141 | + // TODO @jason:可以把“调用渠道进行退款"写到这里,这样分块更明确 | |
| 150 | 142 | PayRefundUnifiedReqDTO unifiedReqDTO = PayRefundUnifiedReqDTO.builder() |
| 151 | 143 | .userIp(reqBO.getUserIp()) |
| 152 | 144 | .channelOrderNo(refundDO.getChannelOrderNo()) |
| ... | ... | @@ -156,13 +148,14 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService { |
| 156 | 148 | .reason(refundDO.getReason()) |
| 157 | 149 | .build(); |
| 158 | 150 | |
| 159 | - //调用渠道进行退款 | |
| 151 | + // 调用渠道进行退款 | |
| 160 | 152 | PayRefundUnifiedRespDTO refundUnifiedRespDTO = client.unifiedRefund(unifiedReqDTO); |
| 161 | 153 | |
| 162 | - //根据渠道返回,获取退款后置处理,由postHandler 进行处理 | |
| 154 | + // TODO @jason:下面这块,是一整块逻辑,不要空开。不然阅读的时候,会以为不是一块逻辑 | |
| 155 | + // 根据渠道返回,获取退款后置处理,由postHandler 进行处理 | |
| 163 | 156 | PayRefundChannelPostHandler payRefundChannelPostHandler = mapHandler.get(refundUnifiedRespDTO.getRespEnum()); |
| 164 | 157 | |
| 165 | - if(Objects.isNull(payRefundChannelPostHandler)){ | |
| 158 | + if (Objects.isNull(payRefundChannelPostHandler)) { | |
| 166 | 159 | throw exception(PAY_REFUND_POST_HANDLER_NOT_FOUND); |
| 167 | 160 | } |
| 168 | 161 | |
| ... | ... | @@ -192,11 +185,12 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService { |
| 192 | 185 | log.error("[notifyPayOrder][渠道编号({}) 找不到对应的支付客户端]", channel.getId()); |
| 193 | 186 | throw exception(PAY_CHANNEL_CLIENT_NOT_FOUND); |
| 194 | 187 | } |
| 195 | - //解析渠道退款通知数据, 统一处理 | |
| 188 | + // 解析渠道退款通知数据, 统一处理 | |
| 196 | 189 | PayRefundNotifyDTO refundNotify = client.parseRefundNotify(notifyData); |
| 197 | 190 | |
| 198 | - if(Objects.equals(PayNotifyRefundStatusEnum.SUCCESS,refundNotify.getStatus())){ | |
| 199 | - //退款成功。 支付宝只有退款成功才会发通知 | |
| 191 | + // TODO @jason:抽一个 notifyPayRefundSuccess 方法 | |
| 192 | + if (Objects.equals(PayNotifyRefundStatusEnum.SUCCESS,refundNotify.getStatus())){ | |
| 193 | + // 退款成功。 支付宝只有退款成功才会发通知 | |
| 200 | 194 | PayRefundDO refundDO = payRefundCoreMapper.selectByReqNo(refundNotify.getReqNo()); |
| 201 | 195 | if (refundDO == null) { |
| 202 | 196 | log.error("不存在 seqNo 为{} 的支付退款单",refundNotify.getReqNo()); |
| ... | ... | @@ -208,9 +202,9 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService { |
| 208 | 202 | if(PayRefundTypeEnum.ALL.getStatus().equals(type)){ |
| 209 | 203 | orderStatus = PayOrderStatusEnum.CLOSED; |
| 210 | 204 | } |
| 211 | - //更新支付订单 | |
| 205 | + // 更新支付订单 | |
| 212 | 206 | PayOrderDO payOrderDO = payOrderCoreMapper.selectById(refundDO.getOrderId()); |
| 213 | - //需更新已退金额 | |
| 207 | + // 需更新已退金额 | |
| 214 | 208 | Long refundedAmount = payOrderDO.getRefundAmount(); |
| 215 | 209 | PayOrderDO updateOrderDO = new PayOrderDO(); |
| 216 | 210 | updateOrderDO.setId(refundDO.getOrderId()) |
| ... | ... | @@ -219,7 +213,7 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService { |
| 219 | 213 | .setRefundStatus(type); |
| 220 | 214 | payOrderCoreMapper.updateById(updateOrderDO); |
| 221 | 215 | |
| 222 | - //跟新退款订单 | |
| 216 | + // 跟新退款订单 | |
| 223 | 217 | PayRefundDO updateRefundDO = new PayRefundDO(); |
| 224 | 218 | updateRefundDO.setId(refundDO.getId()) |
| 225 | 219 | .setSuccessTime(refundNotify.getRefundSuccessTime()) |
| ... | ... | @@ -233,10 +227,9 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService { |
| 233 | 227 | // TODO 通知商户成功或者失败. 现在通知似乎没有实现, 只是回调 |
| 234 | 228 | payNotifyCoreService.createPayNotifyTask(PayNotifyTaskCreateReqDTO.builder() |
| 235 | 229 | .type(PayNotifyTypeEnum.REFUND.getType()).dataId(refundDO.getId()).build()); |
| 236 | - }else{ | |
| 230 | + } else { | |
| 237 | 231 | //TODO 退款失败 |
| 238 | 232 | } |
| 239 | - | |
| 240 | 233 | } |
| 241 | 234 | |
| 242 | 235 | /** |
| ... | ... | @@ -245,7 +238,6 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService { |
| 245 | 238 | * @param order 原始支付订单信息 |
| 246 | 239 | */ |
| 247 | 240 | private void validatePayRefund(PayRefundReqBO reqBO, PayOrderDO order) { |
| 248 | - | |
| 249 | 241 | // 校验状态,必须是支付状态 |
| 250 | 242 | if (!PayOrderStatusEnum.SUCCESS.getStatus().equals(order.getStatus())) { |
| 251 | 243 | throw exception(PAY_ORDER_STATUS_IS_NOT_SUCCESS); |
| ... | ... | @@ -258,10 +250,11 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService { |
| 258 | 250 | if(reqBO.getAmount() + order.getRefundAmount() > order.getAmount()){ |
| 259 | 251 | throw exception(PAY_REFUND_AMOUNT_EXCEED); |
| 260 | 252 | } |
| 261 | - //校验渠道订单号 | |
| 253 | + // 校验渠道订单号 | |
| 262 | 254 | if (StrUtil.isEmpty(order.getChannelOrderNo())) { |
| 263 | 255 | throw exception(PAY_REFUND_CHN_ORDER_NO_IS_NULL); |
| 264 | 256 | } |
| 265 | 257 | //TODO 退款的期限 退款次数的控制 |
| 266 | 258 | } |
| 259 | + | |
| 267 | 260 | } | ... | ... |
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/impl/PayRefundChannelFailedHandler.java renamed to yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/impl/handler/PayRefundChannelFailedHandler.java
| 1 | -package cn.iocoder.yudao.coreservice.modules.pay.service.order.impl; | |
| 1 | +package cn.iocoder.yudao.coreservice.modules.pay.service.order.impl.handler; | |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayOrderDO; |
| 4 | 4 | import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayRefundDO; | ... | ... |
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/impl/PayRefundChannelNotifyHandler.java renamed to yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/impl/handler/PayRefundChannelNotifyHandler.java
| 1 | -package cn.iocoder.yudao.coreservice.modules.pay.service.order.impl; | |
| 1 | +package cn.iocoder.yudao.coreservice.modules.pay.service.order.impl.handler; | |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayOrderDO; |
| 4 | 4 | import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayRefundDO; | ... | ... |
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/impl/PayRefundChannelQueryHandler.java renamed to yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/impl/handler/PayRefundChannelQueryHandler.java
| 1 | -package cn.iocoder.yudao.coreservice.modules.pay.service.order.impl; | |
| 1 | +package cn.iocoder.yudao.coreservice.modules.pay.service.order.impl.handler; | |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayOrderDO; |
| 4 | 4 | import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayRefundDO; | ... | ... |
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/impl/PayRefundChannelRetryHandler.java renamed to yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/impl/handler/PayRefundChannelRetryHandler.java
| 1 | -package cn.iocoder.yudao.coreservice.modules.pay.service.order.impl; | |
| 1 | +package cn.iocoder.yudao.coreservice.modules.pay.service.order.impl.handler; | |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayOrderDO; |
| 4 | 4 | import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayRefundDO; | ... | ... |
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/impl/PayRefundChannelSuccessHandler.java renamed to yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/impl/handler/PayRefundChannelSuccessHandler.java
| 1 | -package cn.iocoder.yudao.coreservice.modules.pay.service.order.impl; | |
| 1 | +package cn.iocoder.yudao.coreservice.modules.pay.service.order.impl.handler; | |
| 2 | 2 | |
| 3 | 3 | import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayOrderDO; |
| 4 | 4 | import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayRefundDO; | ... | ... |
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/PayClient.java
| ... | ... | @@ -34,7 +34,6 @@ public interface PayClient { |
| 34 | 34 | */ |
| 35 | 35 | PayOrderNotifyRespDTO parseOrderNotify(PayNotifyDataDTO data) throws Exception; |
| 36 | 36 | |
| 37 | - | |
| 38 | 37 | /** |
| 39 | 38 | * 调用支付渠道,进行退款 |
| 40 | 39 | * @param reqDTO 统一退款请求信息 |
| ... | ... | @@ -49,22 +48,26 @@ public interface PayClient { |
| 49 | 48 | */ |
| 50 | 49 | PayRefundNotifyDTO parseRefundNotify(PayNotifyDataDTO notifyData); |
| 51 | 50 | |
| 52 | - | |
| 51 | + // TODO @芋艿:后续改成非 default,避免不知道去实现 | |
| 53 | 52 | /** |
| 54 | 53 | * 验证是否渠道通知 |
| 54 | + * | |
| 55 | 55 | * @param notifyData 通知数据 |
| 56 | 56 | * @return 默认是 true |
| 57 | 57 | */ |
| 58 | - default boolean verifyNotifyData(PayNotifyDataDTO notifyData){ | |
| 58 | + default boolean verifyNotifyData(PayNotifyDataDTO notifyData) { | |
| 59 | 59 | return true; |
| 60 | 60 | } |
| 61 | 61 | |
| 62 | + // TODO @芋艿:后续改成非 default,避免不知道去实现 | |
| 62 | 63 | /** |
| 63 | - * 是否退款通知 | |
| 64 | + * 判断是否为退款通知 | |
| 65 | + * | |
| 64 | 66 | * @param notifyData 通知数据 |
| 65 | 67 | * @return 默认是 false |
| 66 | 68 | */ |
| 67 | 69 | default boolean isRefundNotify(PayNotifyDataDTO notifyData){ |
| 68 | 70 | return false; |
| 69 | 71 | } |
| 72 | + | |
| 70 | 73 | } | ... | ... |
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/pay/controller/order/PayOrderController.java
| ... | ... | @@ -2,27 +2,27 @@ package cn.iocoder.yudao.userserver.modules.pay.controller.order; |
| 2 | 2 | |
| 3 | 3 | import cn.hutool.core.bean.BeanUtil; |
| 4 | 4 | import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order.PayOrderDO; |
| 5 | -import cn.iocoder.yudao.coreservice.modules.pay.service.order.PayCommonCoreService; | |
| 6 | 5 | import cn.iocoder.yudao.coreservice.modules.pay.service.order.PayOrderCoreService; |
| 7 | 6 | import cn.iocoder.yudao.coreservice.modules.pay.service.order.PayRefundCoreService; |
| 8 | 7 | import cn.iocoder.yudao.coreservice.modules.pay.service.order.dto.PayOrderSubmitReqDTO; |
| 9 | 8 | import cn.iocoder.yudao.coreservice.modules.pay.service.order.dto.PayOrderSubmitRespDTO; |
| 10 | 9 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 10 | +import cn.iocoder.yudao.framework.pay.core.client.PayClient; | |
| 11 | +import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory; | |
| 11 | 12 | import cn.iocoder.yudao.framework.pay.core.client.dto.PayNotifyDataDTO; |
| 12 | -import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum; | |
| 13 | 13 | import cn.iocoder.yudao.userserver.modules.pay.controller.order.vo.PayOrderSubmitReqVO; |
| 14 | 14 | import cn.iocoder.yudao.userserver.modules.pay.controller.order.vo.PayOrderSubmitRespVO; |
| 15 | 15 | import io.swagger.annotations.Api; |
| 16 | 16 | import io.swagger.annotations.ApiOperation; |
| 17 | 17 | import lombok.extern.slf4j.Slf4j; |
| 18 | -import org.springframework.http.MediaType; | |
| 19 | 18 | import org.springframework.validation.annotation.Validated; |
| 20 | 19 | import org.springframework.web.bind.annotation.*; |
| 21 | 20 | |
| 22 | 21 | import javax.annotation.Resource; |
| 23 | - | |
| 24 | 22 | import java.util.Map; |
| 25 | 23 | |
| 24 | +import static cn.iocoder.yudao.coreservice.modules.pay.enums.PayErrorCodeCoreConstants.PAY_CHANNEL_CLIENT_NOT_FOUND; | |
| 25 | +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | |
| 26 | 26 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| 27 | 27 | import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP; |
| 28 | 28 | |
| ... | ... | @@ -35,11 +35,11 @@ public class PayOrderController { |
| 35 | 35 | |
| 36 | 36 | @Resource |
| 37 | 37 | private PayOrderCoreService payOrderCoreService; |
| 38 | - | |
| 39 | 38 | @Resource |
| 40 | 39 | private PayRefundCoreService payRefundCoreService; |
| 41 | 40 | |
| 42 | - @Resource PayCommonCoreService commonCoreService; | |
| 41 | + @Resource | |
| 42 | + private PayClientFactory payClientFactory; | |
| 43 | 43 | |
| 44 | 44 | |
| 45 | 45 | @PostMapping("/submit") |
| ... | ... | @@ -81,11 +81,12 @@ public class PayOrderController { |
| 81 | 81 | public String returnAliPayOrder(@PathVariable("channelId") Long channelId, @RequestParam Map<String, String> params){ |
| 82 | 82 | //TODO 可以根据渠道和 app_id 返回不同的页面 |
| 83 | 83 | log.info("app_id is {}", params.get("app_id")); |
| 84 | - return String.format("渠道[%s]支付成功", String.valueOf(channelId)); | |
| 84 | + return String.format("渠道[%s]支付成功", channelId); | |
| 85 | 85 | } |
| 86 | 86 | |
| 87 | 87 | /** |
| 88 | 88 | * 统一的渠道支付回调,支付宝的退款回调 |
| 89 | + * | |
| 89 | 90 | * @param channelId 渠道编号 |
| 90 | 91 | * @param params form 参数 |
| 91 | 92 | * @param originData http request body |
| ... | ... | @@ -94,20 +95,27 @@ public class PayOrderController { |
| 94 | 95 | @PostMapping(value = "/notify/{channelId}") |
| 95 | 96 | @ApiOperation("渠道统一的支付成功,或退款成功 通知url") |
| 96 | 97 | public String notifyChannelPay(@PathVariable("channelId") Long channelId, |
| 97 | - @RequestParam Map<String, String> params, | |
| 98 | - @RequestBody String originData) throws Exception { | |
| 99 | - //校验是否是渠道回调 | |
| 100 | - commonCoreService.verifyNotifyData(channelId, PayNotifyDataDTO.builder().params(params).body(originData).build()); | |
| 101 | - //支付宝退款交易也会触发支付回调接口 | |
| 102 | - //参考 https://opensupport.alipay.com/support/helpcenter/193/201602484851 | |
| 103 | - //判断是否为退款通知 | |
| 104 | - if(commonCoreService.isRefundNotify(channelId, PayNotifyDataDTO.builder().params(params).body(originData).build())) { | |
| 105 | - //退款通知 | |
| 106 | - payRefundCoreService.notifyPayRefund(channelId,PayNotifyDataDTO.builder().params(params).body(originData).build()); | |
| 107 | - }else{ | |
| 108 | - //支付通知 | |
| 109 | - payOrderCoreService.notifyPayOrder(channelId,PayNotifyDataDTO.builder().params(params).body(originData).build()); | |
| 98 | + @RequestParam Map<String, String> params, | |
| 99 | + @RequestBody String originData) throws Exception { | |
| 100 | + // 校验支付渠道是否存在 | |
| 101 | + PayClient payClient = payClientFactory.getPayClient(channelId); | |
| 102 | + if (payClient == null) { | |
| 103 | + log.error("[notifyPayOrder][渠道编号({}) 找不到对应的支付客户端]", channelId); | |
| 104 | + throw exception(PAY_CHANNEL_CLIENT_NOT_FOUND); | |
| 110 | 105 | } |
| 106 | + | |
| 107 | + // 校验通知数据是否合法 | |
| 108 | + PayNotifyDataDTO notifyData = PayNotifyDataDTO.builder().params(params).body(originData).build(); | |
| 109 | + payClient.verifyNotifyData(notifyData); | |
| 110 | + | |
| 111 | + // 如果是退款,则发起退款通知 | |
| 112 | + if (payClient.isRefundNotify(notifyData)) { | |
| 113 | + payRefundCoreService.notifyPayRefund(channelId, PayNotifyDataDTO.builder().params(params).body(originData).build()); | |
| 114 | + return "success"; | |
| 115 | + } | |
| 116 | + | |
| 117 | + // 如果非退款,则发起支付通知 | |
| 118 | + payOrderCoreService.notifyPayOrder(channelId, PayNotifyDataDTO.builder().params(params).body(originData).build()); | |
| 111 | 119 | return "success"; |
| 112 | 120 | } |
| 113 | 121 | ... | ... |
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/pay/controller/order/PayRefundController.java
| ... | ... | @@ -32,7 +32,7 @@ public class PayRefundController { |
| 32 | 32 | |
| 33 | 33 | @PostMapping("/refund") |
| 34 | 34 | @ApiOperation("提交退款订单") |
| 35 | - public CommonResult<PayRefundRespVO> refund(@RequestBody PayRefundReqVO reqVO){ | |
| 35 | + public CommonResult<PayRefundRespVO> refund(@RequestBody PayRefundReqVO reqVO){ | |
| 36 | 36 | PayRefundReqBO reqBO = PayRefundConvert.INSTANCE.convert(reqVO); |
| 37 | 37 | reqBO.setUserIp(getClientIP()); |
| 38 | 38 | //TODO 测试暂时模拟生成商户退款订单 |
| ... | ... | @@ -40,4 +40,5 @@ public class PayRefundController { |
| 40 | 40 | //reqBO.setMerchantRefundNo("MO202111210814084370000"); |
| 41 | 41 | return CommonResult.success( PayRefundConvert.INSTANCE.convert(payRefundCoreService.refund(reqBO))); |
| 42 | 42 | } |
| 43 | + | |
| 43 | 44 | } | ... | ... |