Commit bcc2ff0f5bee343442898dcc17306b197552c08a

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