Commit 67aaf28832bd86a75e6fd9b54e286f7a94768428

Authored by YunaiV
1 parent d556eae5

code review 退款逻辑

yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/convert/order/PayRefundCoreConvert.java
@@ -12,8 +12,6 @@ public interface PayRefundCoreConvert { @@ -12,8 +12,6 @@ public interface PayRefundCoreConvert {
12 12
13 PayRefundCoreConvert INSTANCE = Mappers.getMapper(PayRefundCoreConvert.class); 13 PayRefundCoreConvert INSTANCE = Mappers.getMapper(PayRefundCoreConvert.class);
14 14
15 -  
16 -  
17 //TODO 太多需要处理了, 暂时不用 15 //TODO 太多需要处理了, 暂时不用
18 @Mappings(value = { 16 @Mappings(value = {
19 @Mapping(source = "amount", target = "payAmount"), 17 @Mapping(source = "amount", target = "payAmount"),
@@ -21,4 +19,5 @@ public interface PayRefundCoreConvert { @@ -21,4 +19,5 @@ public interface PayRefundCoreConvert {
21 @Mapping(target = "status",ignore = true) 19 @Mapping(target = "status",ignore = true)
22 }) 20 })
23 PayRefundDO convert(PayOrderDO orderDO); 21 PayRefundDO convert(PayOrderDO orderDO);
  22 +
24 } 23 }
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/dal/dataobject/order/PayRefundDO.java
@@ -3,6 +3,8 @@ package cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order; @@ -3,6 +3,8 @@ package cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.order;
3 import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayAppDO; 3 import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayAppDO;
4 import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayChannelDO; 4 import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayChannelDO;
5 import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayMerchantDO; 5 import cn.iocoder.yudao.coreservice.modules.pay.dal.dataobject.merchant.PayMerchantDO;
  6 +import cn.iocoder.yudao.coreservice.modules.pay.enums.order.PayRefundStatusEnum;
  7 +import cn.iocoder.yudao.coreservice.modules.pay.enums.order.PayRefundTypeEnum;
6 import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum; 8 import cn.iocoder.yudao.framework.pay.core.enums.PayChannelEnum;
7 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; 9 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
8 import com.baomidou.mybatisplus.annotation.TableId; 10 import com.baomidou.mybatisplus.annotation.TableId;
@@ -79,7 +81,6 @@ public class PayRefundDO extends BaseDO { @@ -79,7 +81,6 @@ public class PayRefundDO extends BaseDO {
79 */ 81 */
80 private Long orderId; 82 private Long orderId;
81 83
82 -  
83 /** 84 /**
84 * 交易订单号,根据规则生成 85 * 交易订单号,根据规则生成
85 * 调用支付渠道时,使用该字段作为对接的订单号。 86 * 调用支付渠道时,使用该字段作为对接的订单号。
@@ -110,7 +111,6 @@ public class PayRefundDO extends BaseDO { @@ -110,7 +111,6 @@ public class PayRefundDO extends BaseDO {
110 * 防止该笔交易重复退款。支付宝会保证同样的退款请求号多次请求只会退一次。 111 * 防止该笔交易重复退款。支付宝会保证同样的退款请求号多次请求只会退一次。
111 * 退款单请求号,根据规则生成 112 * 退款单请求号,根据规则生成
112 * 例如说,R202109181134287570000 113 * 例如说,R202109181134287570000
113 - *  
114 */ 114 */
115 private String merchantRefundNo; 115 private String merchantRefundNo;
116 116
@@ -129,19 +129,22 @@ public class PayRefundDO extends BaseDO { @@ -129,19 +129,22 @@ public class PayRefundDO extends BaseDO {
129 /** 129 /**
130 * 退款状态 130 * 退款状态
131 * 131 *
  132 + * 枚举 {@link PayRefundStatusEnum}
132 */ 133 */
133 private Integer status; 134 private Integer status;
134 135
135 /** 136 /**
136 * 退款类型(部分退款,全部退款) 137 * 退款类型(部分退款,全部退款)
  138 + *
  139 + * 枚举 {@link PayRefundTypeEnum}
137 */ 140 */
138 private Integer type; 141 private Integer type;
139 /** 142 /**
140 - * 支付金额,单位分 143 + * 支付金额,单位:分
141 */ 144 */
142 private Long payAmount; 145 private Long payAmount;
143 /** 146 /**
144 - * 退款金额,单位分 147 + * 退款金额,单位:分
145 */ 148 */
146 private Long refundAmount; 149 private Long refundAmount;
147 150
@@ -150,7 +153,6 @@ public class PayRefundDO extends BaseDO { @@ -150,7 +153,6 @@ public class PayRefundDO extends BaseDO {
150 */ 153 */
151 private String reason; 154 private String reason;
152 155
153 -  
154 /** 156 /**
155 * 用户 IP 157 * 用户 IP
156 */ 158 */
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/dal/mysql/order/PayRefundCoreMapper.java
@@ -17,6 +17,7 @@ public interface PayRefundCoreMapper extends BaseMapperX<PayRefundDO> { @@ -17,6 +17,7 @@ public interface PayRefundCoreMapper extends BaseMapperX<PayRefundDO> {
17 } 17 }
18 18
19 default PayRefundDO selectByTradeNoAndMerchantRefundNo(String tradeNo, String merchantRefundNo){ 19 default PayRefundDO selectByTradeNoAndMerchantRefundNo(String tradeNo, String merchantRefundNo){
20 - return selectOne("trade_no", tradeNo, "merchant_refund_no", merchantRefundNo); 20 + return selectOne("trade_no", tradeNo, "merchant_refund_no", merchantRefundNo);
21 } 21 }
  22 +
22 } 23 }
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/enums/order/PayRefundStatusEnum.java
@@ -6,6 +6,7 @@ import lombok.Getter; @@ -6,6 +6,7 @@ import lombok.Getter;
6 @Getter 6 @Getter
7 @AllArgsConstructor 7 @AllArgsConstructor
8 public enum PayRefundStatusEnum { 8 public enum PayRefundStatusEnum {
  9 +
9 CREATE(0, "退款订单生成"), 10 CREATE(0, "退款订单生成"),
10 SUCCESS(1, "退款成功"), 11 SUCCESS(1, "退款成功"),
11 FAILURE(2, "退款失败"), 12 FAILURE(2, "退款失败"),
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/dto/PayRefundReqDTO.java
@@ -16,8 +16,9 @@ import lombok.experimental.Accessors; @@ -16,8 +16,9 @@ import lombok.experimental.Accessors;
16 @AllArgsConstructor 16 @AllArgsConstructor
17 public class PayRefundReqDTO { 17 public class PayRefundReqDTO {
18 18
  19 + // TODO @jason:增加下 validation 注解哈
19 /** 20 /**
20 - * 支付订单编号自增 21 + * 支付订单编号
21 */ 22 */
22 private Long payOrderId; 23 private Long payOrderId;
23 24
@@ -31,10 +32,10 @@ public class PayRefundReqDTO { @@ -31,10 +32,10 @@ public class PayRefundReqDTO {
31 */ 32 */
32 private String reason; 33 private String reason;
33 34
34 -  
35 /** 35 /**
36 * 商户退款订单号 36 * 商户退款订单号
37 */ 37 */
  38 + // TODO @jason:merchantRefundNo=》merchantRefundId,保持和 PayOrder 的 merchantOrderId 一致哈
38 private String merchantRefundNo; 39 private String merchantRefundNo;
39 40
40 /** 41 /**
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/dto/PayRefundRespDTO.java
@@ -21,10 +21,11 @@ public class PayRefundRespDTO { @@ -21,10 +21,11 @@ public class PayRefundRespDTO {
21 * 退款处理中和退款成功 返回 1 21 * 退款处理中和退款成功 返回 1
22 * 失败和其他情况 返回 2 22 * 失败和其他情况 返回 2
23 */ 23 */
  24 + // TODO @jason:这个 result,可以使用 CommonResult 里呢
24 private Integer channelReturnResult; 25 private Integer channelReturnResult;
25 26
26 /** 27 /**
27 - * 渠道返回code 28 + * 渠道返回 code
28 */ 29 */
29 private String channelReturnCode; 30 private String channelReturnCode;
30 31
@@ -34,7 +35,8 @@ public class PayRefundRespDTO { @@ -34,7 +35,8 @@ public class PayRefundRespDTO {
34 private String channelReturnMsg; 35 private String channelReturnMsg;
35 36
36 /** 37 /**
37 - * 支付退款单编号, 自增 38 + * 支付退款单编号,自增
38 */ 39 */
39 private Long refundId; 40 private Long refundId;
  41 +
40 } 42 }
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/pay/service/order/impl/PayRefundCoreServiceImpl.java
@@ -11,20 +11,20 @@ import cn.iocoder.yudao.coreservice.modules.pay.dal.mysql.order.PayOrderExtensio @@ -11,20 +11,20 @@ import cn.iocoder.yudao.coreservice.modules.pay.dal.mysql.order.PayOrderExtensio
11 import cn.iocoder.yudao.coreservice.modules.pay.dal.mysql.order.PayRefundCoreMapper; 11 import cn.iocoder.yudao.coreservice.modules.pay.dal.mysql.order.PayRefundCoreMapper;
12 import cn.iocoder.yudao.coreservice.modules.pay.enums.notify.PayNotifyTypeEnum; 12 import cn.iocoder.yudao.coreservice.modules.pay.enums.notify.PayNotifyTypeEnum;
13 import cn.iocoder.yudao.coreservice.modules.pay.enums.order.PayOrderNotifyStatusEnum; 13 import cn.iocoder.yudao.coreservice.modules.pay.enums.order.PayOrderNotifyStatusEnum;
14 -import cn.iocoder.yudao.coreservice.modules.pay.service.notify.PayNotifyCoreService;  
15 -import cn.iocoder.yudao.coreservice.modules.pay.service.notify.dto.PayNotifyTaskCreateReqDTO;  
16 -import cn.iocoder.yudao.coreservice.modules.pay.service.order.dto.PayRefundReqDTO;  
17 -import cn.iocoder.yudao.framework.pay.core.client.dto.PayRefundNotifyDTO;  
18 -import cn.iocoder.yudao.coreservice.modules.pay.enums.order.PayRefundTypeEnum;  
19 import cn.iocoder.yudao.coreservice.modules.pay.enums.order.PayOrderStatusEnum; 14 import cn.iocoder.yudao.coreservice.modules.pay.enums.order.PayOrderStatusEnum;
20 import cn.iocoder.yudao.coreservice.modules.pay.enums.order.PayRefundStatusEnum; 15 import cn.iocoder.yudao.coreservice.modules.pay.enums.order.PayRefundStatusEnum;
  16 +import cn.iocoder.yudao.coreservice.modules.pay.enums.order.PayRefundTypeEnum;
21 import cn.iocoder.yudao.coreservice.modules.pay.service.merchant.PayAppCoreService; 17 import cn.iocoder.yudao.coreservice.modules.pay.service.merchant.PayAppCoreService;
22 import cn.iocoder.yudao.coreservice.modules.pay.service.merchant.PayChannelCoreService; 18 import cn.iocoder.yudao.coreservice.modules.pay.service.merchant.PayChannelCoreService;
  19 +import cn.iocoder.yudao.coreservice.modules.pay.service.notify.PayNotifyCoreService;
  20 +import cn.iocoder.yudao.coreservice.modules.pay.service.notify.dto.PayNotifyTaskCreateReqDTO;
23 import cn.iocoder.yudao.coreservice.modules.pay.service.order.PayRefundCoreService; 21 import cn.iocoder.yudao.coreservice.modules.pay.service.order.PayRefundCoreService;
  22 +import cn.iocoder.yudao.coreservice.modules.pay.service.order.dto.PayRefundReqDTO;
24 import cn.iocoder.yudao.coreservice.modules.pay.service.order.dto.PayRefundRespDTO; 23 import cn.iocoder.yudao.coreservice.modules.pay.service.order.dto.PayRefundRespDTO;
25 import cn.iocoder.yudao.framework.pay.core.client.PayClient; 24 import cn.iocoder.yudao.framework.pay.core.client.PayClient;
26 import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory; 25 import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory;
27 import cn.iocoder.yudao.framework.pay.core.client.dto.PayNotifyDataDTO; 26 import cn.iocoder.yudao.framework.pay.core.client.dto.PayNotifyDataDTO;
  27 +import cn.iocoder.yudao.framework.pay.core.client.dto.PayRefundNotifyDTO;
28 import cn.iocoder.yudao.framework.pay.core.client.dto.PayRefundUnifiedReqDTO; 28 import cn.iocoder.yudao.framework.pay.core.client.dto.PayRefundUnifiedReqDTO;
29 import cn.iocoder.yudao.framework.pay.core.client.dto.PayRefundUnifiedRespDTO; 29 import cn.iocoder.yudao.framework.pay.core.client.dto.PayRefundUnifiedRespDTO;
30 import cn.iocoder.yudao.framework.pay.core.enums.PayChannelRefundRespEnum; 30 import cn.iocoder.yudao.framework.pay.core.enums.PayChannelRefundRespEnum;
@@ -34,7 +34,8 @@ import org.springframework.stereotype.Service; @@ -34,7 +34,8 @@ import org.springframework.stereotype.Service;
34 import org.springframework.transaction.annotation.Transactional; 34 import org.springframework.transaction.annotation.Transactional;
35 35
36 import javax.annotation.Resource; 36 import javax.annotation.Resource;
37 -import java.util.*; 37 +import java.util.Date;
  38 +import java.util.Objects;
38 39
39 import static cn.iocoder.yudao.coreservice.modules.pay.enums.PayErrorCodeCoreConstants.*; 40 import static cn.iocoder.yudao.coreservice.modules.pay.enums.PayErrorCodeCoreConstants.*;
40 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 41 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
@@ -90,17 +91,19 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService { @@ -90,17 +91,19 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService {
90 91
91 PayOrderExtensionDO orderExtensionDO = payOrderExtensionCoreMapper.selectById(order.getSuccessExtensionId()); 92 PayOrderExtensionDO orderExtensionDO = payOrderExtensionCoreMapper.selectById(order.getSuccessExtensionId());
92 PayRefundDO payRefundDO = payRefundCoreMapper.selectByTradeNoAndMerchantRefundNo(orderExtensionDO.getNo(), req.getMerchantRefundNo()); 93 PayRefundDO payRefundDO = payRefundCoreMapper.selectByTradeNoAndMerchantRefundNo(orderExtensionDO.getNo(), req.getMerchantRefundNo());
93 - //构造渠道的统一的退款请求参数 94 + // 构造渠道的统一的退款请求参数
94 PayRefundUnifiedReqDTO unifiedReqDTO = new PayRefundUnifiedReqDTO(); 95 PayRefundUnifiedReqDTO unifiedReqDTO = new PayRefundUnifiedReqDTO();
95 if(Objects.nonNull(payRefundDO)){ 96 if(Objects.nonNull(payRefundDO)){
96 - //退款订单已经提交过。 97 + // 退款订单已经提交过。
97 //TODO 校验相同退款单的金额 98 //TODO 校验相同退款单的金额
98 - if(Objects.equals(PayRefundStatusEnum.SUCCESS.getStatus(), payRefundDO.getStatus())  
99 - || Objects.equals(PayRefundStatusEnum.CLOSE.getStatus(), payRefundDO.getStatus())){ 99 + // TODO @jason:咱要不封装一个 ObjectUtils.equalsAny
  100 + if (Objects.equals(PayRefundStatusEnum.SUCCESS.getStatus(), payRefundDO.getStatus())
  101 + || Objects.equals(PayRefundStatusEnum.CLOSE.getStatus(), payRefundDO.getStatus())) {
100 //已成功退款 102 //已成功退款
101 throw exception(PAY_REFUND_SUCCEED); 103 throw exception(PAY_REFUND_SUCCEED);
102 - }else{  
103 - //保证商户退款单不变,重复向渠道发起退款。渠道保持幂等 104 + } else{
  105 + // TODO @jason:这里不用 else,简洁一些
  106 + // 保证商户退款单不变,重复向渠道发起退款。渠道保持幂等
104 unifiedReqDTO.setUserIp(req.getUserIp()) 107 unifiedReqDTO.setUserIp(req.getUserIp())
105 .setAmount(payRefundDO.getRefundAmount()) 108 .setAmount(payRefundDO.getRefundAmount())
106 .setChannelOrderNo(payRefundDO.getChannelOrderNo()) 109 .setChannelOrderNo(payRefundDO.getChannelOrderNo())
@@ -109,7 +112,8 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService { @@ -109,7 +112,8 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService {
109 .setReason(payRefundDO.getReason()); 112 .setReason(payRefundDO.getReason());
110 } 113 }
111 }else{ 114 }else{
112 - //新生成退款单。 退款单入库 退款单状态:生成 115 + // 新生成退款单。 退款单入库 退款单状态:生成
  116 + // TODO @jason:封装一个小方法。插入退款单
113 payRefundDO = PayRefundDO.builder().channelOrderNo(order.getChannelOrderNo()) 117 payRefundDO = PayRefundDO.builder().channelOrderNo(order.getChannelOrderNo())
114 .appId(order.getAppId()) 118 .appId(order.getAppId())
115 .channelOrderNo(order.getChannelOrderNo()) 119 .channelOrderNo(order.getChannelOrderNo())
@@ -130,6 +134,7 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService { @@ -130,6 +134,7 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService {
130 .type(refundType.getStatus()) 134 .type(refundType.getStatus())
131 .build(); 135 .build();
132 payRefundCoreMapper.insert(payRefundDO); 136 payRefundCoreMapper.insert(payRefundDO);
  137 + // TODO @jason:这块的逻辑,和已存在的这块,貌似是统一的?
133 unifiedReqDTO.setUserIp(req.getUserIp()) 138 unifiedReqDTO.setUserIp(req.getUserIp())
134 .setAmount(payRefundDO.getRefundAmount()) 139 .setAmount(payRefundDO.getRefundAmount())
135 .setChannelOrderNo(payRefundDO.getChannelOrderNo()) 140 .setChannelOrderNo(payRefundDO.getChannelOrderNo())
@@ -137,19 +142,20 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService { @@ -137,19 +142,20 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService {
137 .setRefundReqNo(payRefundDO.getMerchantRefundNo()) 142 .setRefundReqNo(payRefundDO.getMerchantRefundNo())
138 .setReason(req.getReason()); 143 .setReason(req.getReason());
139 } 144 }
140 - //向渠道发起退款申请 145 + // 向渠道发起退款申请
141 PayRefundUnifiedRespDTO refundUnifiedRespDTO = client.unifiedRefund(unifiedReqDTO); 146 PayRefundUnifiedRespDTO refundUnifiedRespDTO = client.unifiedRefund(unifiedReqDTO);
142 - //构造退款申请返回对象 147 + // 构造退款申请返回对象
143 PayRefundRespDTO respDTO = new PayRefundRespDTO(); 148 PayRefundRespDTO respDTO = new PayRefundRespDTO();
144 - if(refundUnifiedRespDTO.getChannelResp() == PayChannelRefundRespEnum.SUCCESS  
145 - ||refundUnifiedRespDTO.getChannelResp() == PayChannelRefundRespEnum.PROCESSING ){  
146 - //成功处理, 在退款通知中处理, 这里不处理 149 + if (refundUnifiedRespDTO.getChannelResp() == PayChannelRefundRespEnum.SUCCESS
  150 + ||refundUnifiedRespDTO.getChannelResp() == PayChannelRefundRespEnum.PROCESSING) {
  151 + // 成功处理,在退款通知中处理, 这里不处理
147 respDTO.setChannelReturnResult(PayChannelRefundRespEnum.SUCCESS.getStatus()); 152 respDTO.setChannelReturnResult(PayChannelRefundRespEnum.SUCCESS.getStatus());
148 respDTO.setRefundId(payRefundDO.getId()); 153 respDTO.setRefundId(payRefundDO.getId());
149 }else { 154 }else {
150 - //失败返回错误给前端,可以重新发起退款,保证退款请求号(这里是商户退款单号), 避免重复退款。 155 + // 失败返回错误给前端,可以重新发起退款,保证退款请求号(这里是商户退款单号), 避免重复退款。
  156 + // TODO @jason:失败的话,是不是可以跑出 ServiceException 业务异常。这样就是成功返回 refundId,失败业务异常
151 respDTO.setChannelReturnResult(PayChannelRefundRespEnum.FAILURE.getStatus()); 157 respDTO.setChannelReturnResult(PayChannelRefundRespEnum.FAILURE.getStatus());
152 - //更新退款单状态 158 + // 更新退款单状态
153 PayRefundDO updatePayRefund = new PayRefundDO(); 159 PayRefundDO updatePayRefund = new PayRefundDO();
154 updatePayRefund.setId(payRefundDO.getId()) 160 updatePayRefund.setId(payRefundDO.getId())
155 .setChannelErrorMsg(refundUnifiedRespDTO.getChannelMsg()) 161 .setChannelErrorMsg(refundUnifiedRespDTO.getChannelMsg())
@@ -181,35 +187,37 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService { @@ -181,35 +187,37 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService {
181 payRefundSuccess(refundNotify); 187 payRefundSuccess(refundNotify);
182 } else { 188 } else {
183 //TODO 支付异常, 支付宝似乎没有支付异常的通知。 189 //TODO 支付异常, 支付宝似乎没有支付异常的通知。
  190 + // TODO @jason:那这里可以考虑打个 error logger
184 } 191 }
185 } 192 }
186 193
187 private void payRefundSuccess(PayRefundNotifyDTO refundNotify) { 194 private void payRefundSuccess(PayRefundNotifyDTO refundNotify) {
  195 + // 校验退款单存在
188 PayRefundDO refundDO = payRefundCoreMapper.selectByTradeNoAndMerchantRefundNo(refundNotify.getTradeNo(), refundNotify.getReqNo()); 196 PayRefundDO refundDO = payRefundCoreMapper.selectByTradeNoAndMerchantRefundNo(refundNotify.getTradeNo(), refundNotify.getReqNo());
189 if (refundDO == null) { 197 if (refundDO == null) {
190 - log.error("不存在 seqNo 为{} 的支付退款单",refundNotify.getReqNo()); 198 + log.error("[payRefundSuccess][不存在 seqNo 为{} 的支付退款单]", refundNotify.getReqNo());
191 throw exception(PAY_REFUND_NOT_FOUND); 199 throw exception(PAY_REFUND_NOT_FOUND);
192 } 200 }
193 - Long refundAmount = refundDO.getRefundAmount(); 201 +
  202 + // 计算订单的状态。如果全部退款,则订单处于关闭。TODO @jason:建议这里按照金额来判断,因为可能退款多次
194 Integer type = refundDO.getType(); 203 Integer type = refundDO.getType();
195 PayOrderStatusEnum orderStatus = PayOrderStatusEnum.SUCCESS; 204 PayOrderStatusEnum orderStatus = PayOrderStatusEnum.SUCCESS;
196 - if(PayRefundTypeEnum.ALL.getStatus().equals(type)){ 205 + if (PayRefundTypeEnum.ALL.getStatus().equals(type)){
197 orderStatus = PayOrderStatusEnum.CLOSED; 206 orderStatus = PayOrderStatusEnum.CLOSED;
198 } 207 }
199 - // 更新支付订单  
200 - PayOrderDO payOrderDO = payOrderCoreMapper.selectById(refundDO.getOrderId());  
201 // 需更新已退金额 208 // 需更新已退金额
  209 + PayOrderDO payOrderDO = payOrderCoreMapper.selectById(refundDO.getOrderId());
202 Long refundedAmount = payOrderDO.getRefundAmount(); 210 Long refundedAmount = payOrderDO.getRefundAmount();
  211 + // 更新支付订单
203 PayOrderDO updateOrderDO = new PayOrderDO(); 212 PayOrderDO updateOrderDO = new PayOrderDO();
204 updateOrderDO.setId(refundDO.getOrderId()) 213 updateOrderDO.setId(refundDO.getOrderId())
205 - .setRefundAmount(refundedAmount + refundAmount) 214 + .setRefundAmount(refundedAmount + refundDO.getRefundAmount())
206 .setStatus(orderStatus.getStatus()) 215 .setStatus(orderStatus.getStatus())
207 - .setRefundTimes(payOrderDO.getRefundTimes()+1) 216 + .setRefundTimes(payOrderDO.getRefundTimes() + 1)
208 .setRefundStatus(type); 217 .setRefundStatus(type);
209 -  
210 payOrderCoreMapper.updateById(updateOrderDO); 218 payOrderCoreMapper.updateById(updateOrderDO);
211 219
212 - // 跟新退款订单 220 + // 更新退款订单
213 PayRefundDO updateRefundDO = new PayRefundDO(); 221 PayRefundDO updateRefundDO = new PayRefundDO();
214 updateRefundDO.setId(refundDO.getId()) 222 updateRefundDO.setId(refundDO.getId())
215 .setSuccessTime(refundNotify.getRefundSuccessTime()) 223 .setSuccessTime(refundNotify.getRefundSuccessTime())
@@ -219,7 +227,7 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService { @@ -219,7 +227,7 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService {
219 .setStatus(PayRefundStatusEnum.SUCCESS.getStatus()); 227 .setStatus(PayRefundStatusEnum.SUCCESS.getStatus());
220 payRefundCoreMapper.updateById(updateRefundDO); 228 payRefundCoreMapper.updateById(updateRefundDO);
221 229
222 - //插入退款通知记录 230 + // 插入退款通知记录
223 // TODO 通知商户成功或者失败. 现在通知似乎没有实现, 只是回调 231 // TODO 通知商户成功或者失败. 现在通知似乎没有实现, 只是回调
224 payNotifyCoreService.createPayNotifyTask(PayNotifyTaskCreateReqDTO.builder() 232 payNotifyCoreService.createPayNotifyTask(PayNotifyTaskCreateReqDTO.builder()
225 .type(PayNotifyTypeEnum.REFUND.getType()).dataId(refundDO.getId()).build()); 233 .type(PayNotifyTypeEnum.REFUND.getType()).dataId(refundDO.getId()).build());
@@ -235,12 +243,12 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService { @@ -235,12 +243,12 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService {
235 if (!PayOrderStatusEnum.SUCCESS.getStatus().equals(order.getStatus())) { 243 if (!PayOrderStatusEnum.SUCCESS.getStatus().equals(order.getStatus())) {
236 throw exception(PAY_ORDER_STATUS_IS_NOT_SUCCESS); 244 throw exception(PAY_ORDER_STATUS_IS_NOT_SUCCESS);
237 } 245 }
238 - //是否已经全额退款 246 + // 是否已经全额退款
239 if (PayRefundTypeEnum.ALL.getStatus().equals(order.getRefundStatus())) { 247 if (PayRefundTypeEnum.ALL.getStatus().equals(order.getRefundStatus())) {
240 throw exception(PAY_REFUND_ALL_REFUNDED); 248 throw exception(PAY_REFUND_ALL_REFUNDED);
241 } 249 }
242 // 校验金额 退款金额不能大于 原定的金额 250 // 校验金额 退款金额不能大于 原定的金额
243 - if(req.getAmount() + order.getRefundAmount() > order.getAmount()){ 251 + if (req.getAmount() + order.getRefundAmount() > order.getAmount()){
244 throw exception(PAY_REFUND_AMOUNT_EXCEED); 252 throw exception(PAY_REFUND_AMOUNT_EXCEED);
245 } 253 }
246 // 校验渠道订单号 254 // 校验渠道订单号
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/PayRefundUnifiedReqDTO.java
@@ -28,6 +28,7 @@ public class PayRefundUnifiedReqDTO { @@ -28,6 +28,7 @@ public class PayRefundUnifiedReqDTO {
28 */ 28 */
29 private String userIp; 29 private String userIp;
30 30
  31 + // TODO @jason:这个是否为非必传字段呀,只需要传递 payTradeNo 字段即可。尽可能精简
31 /** 32 /**
32 * https://api.mch.weixin.qq.com/v3/refund/domestic/refunds 中的 transaction_id 33 * https://api.mch.weixin.qq.com/v3/refund/domestic/refunds 中的 transaction_id
33 * https://opendocs.alipay.com/apis alipay.trade.refund 中的 trade_no 34 * https://opendocs.alipay.com/apis alipay.trade.refund 中的 trade_no
@@ -35,7 +36,6 @@ public class PayRefundUnifiedReqDTO { @@ -35,7 +36,6 @@ public class PayRefundUnifiedReqDTO {
35 */ 36 */
36 private String channelOrderNo; 37 private String channelOrderNo;
37 38
38 -  
39 /** 39 /**
40 * https://api.mch.weixin.qq.com/v3/refund/domestic/refunds 中的 out_trade_no 40 * https://api.mch.weixin.qq.com/v3/refund/domestic/refunds 中的 out_trade_no
41 * https://opendocs.alipay.com/apis alipay.trade.refund 中的 out_trade_no 41 * https://opendocs.alipay.com/apis alipay.trade.refund 中的 out_trade_no
@@ -43,24 +43,22 @@ public class PayRefundUnifiedReqDTO { @@ -43,24 +43,22 @@ public class PayRefundUnifiedReqDTO {
43 */ 43 */
44 private String payTradeNo; 44 private String payTradeNo;
45 45
46 - 46 + // TODO @jason:这个字段,要不就使用 merchantRefundId,更直接
47 /** 47 /**
48 * https://api.mch.weixin.qq.com/v3/refund/domestic/refunds 中的 out_refund_no 48 * https://api.mch.weixin.qq.com/v3/refund/domestic/refunds 中的 out_refund_no
49 - * https://opendocs.alipay.com/apis alipay.trade.refund 中的 out_request_no 49 + * https://opendocs.alipay.com/apis alipay.trade.refund 中的 out_trade_no
50 * 退款请求单号 同一退款请求单号多次请求只退一笔。 50 * 退款请求单号 同一退款请求单号多次请求只退一笔。
51 * 使用 商户的退款单号。{PayRefundDO 字段 merchantRefundNo} 51 * 使用 商户的退款单号。{PayRefundDO 字段 merchantRefundNo}
52 */ 52 */
53 @NotEmpty(message = "退款请求单号") 53 @NotEmpty(message = "退款请求单号")
54 private String refundReqNo; 54 private String refundReqNo;
55 55
56 -  
57 /** 56 /**
58 * 退款原因 57 * 退款原因
59 */ 58 */
60 @NotEmpty(message = "退款原因不能为空") 59 @NotEmpty(message = "退款原因不能为空")
61 private String reason; 60 private String reason;
62 61
63 -  
64 /** 62 /**
65 * 退款金额,单位:分 63 * 退款金额,单位:分
66 */ 64 */
@@ -68,12 +66,10 @@ public class PayRefundUnifiedReqDTO { @@ -68,12 +66,10 @@ public class PayRefundUnifiedReqDTO {
68 @DecimalMin(value = "0", inclusive = false, message = "支付金额必须大于零") 66 @DecimalMin(value = "0", inclusive = false, message = "支付金额必须大于零")
69 private Long amount; 67 private Long amount;
70 68
71 -  
72 -  
73 -  
74 /** 69 /**
75 * 退款结果 notify 回调地址, 支付宝退款不需要回调地址, 微信需要 70 * 退款结果 notify 回调地址, 支付宝退款不需要回调地址, 微信需要
76 */ 71 */
77 @URL(message = "支付结果的 notify 回调地址必须是 URL 格式") 72 @URL(message = "支付结果的 notify 回调地址必须是 URL 格式")
78 private String notifyUrl; 73 private String notifyUrl;
  74 +
79 } 75 }
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/PayRefundUnifiedRespDTO.java
@@ -17,11 +17,14 @@ import lombok.experimental.Accessors; @@ -17,11 +17,14 @@ import lombok.experimental.Accessors;
17 @AllArgsConstructor 17 @AllArgsConstructor
18 @Data 18 @Data
19 public class PayRefundUnifiedRespDTO { 19 public class PayRefundUnifiedRespDTO {
  20 +
  21 + // TODO @jason:可以合并下。退款处理中、成功,都是成功;其它就业务失败。这样,可以复用 PayCommonResult;这个 RespDTO 可以返回渠道的退款编号
20 /** 22 /**
21 * 渠道的退款结果 23 * 渠道的退款结果
22 */ 24 */
23 private PayChannelRefundRespEnum channelResp; 25 private PayChannelRefundRespEnum channelResp;
24 26
  27 + // TODO @json:channelReturnCode 和 channelReturnMsg 放到 PayCommonResult 里噶
25 /** 28 /**
26 * 渠道返回码 29 * 渠道返回码
27 */ 30 */
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/enums/PayChannelRefundRespEnum.java
@@ -11,6 +11,7 @@ import lombok.Getter; @@ -11,6 +11,7 @@ import lombok.Getter;
11 @Getter 11 @Getter
12 @AllArgsConstructor 12 @AllArgsConstructor
13 public enum PayChannelRefundRespEnum { 13 public enum PayChannelRefundRespEnum {
  14 +
14 SUCCESS(1, "退款成功"), 15 SUCCESS(1, "退款成功"),
15 FAILURE(2, "退款失败"), 16 FAILURE(2, "退款失败"),
16 PROCESSING(3,"退款处理中"), 17 PROCESSING(3,"退款处理中"),
@@ -18,4 +19,5 @@ public enum PayChannelRefundRespEnum { @@ -18,4 +19,5 @@ public enum PayChannelRefundRespEnum {
18 19
19 private final Integer status; 20 private final Integer status;
20 private final String name; 21 private final String name;
  22 +
21 } 23 }