|
@@ -11,20 +11,20 @@ import cn.iocoder.yudao.coreservice.modules.pay.dal.mysql.order.PayOrderExtensio
|
|
|
import cn.iocoder.yudao.coreservice.modules.pay.dal.mysql.order.PayRefundCoreMapper;
|
|
|
import cn.iocoder.yudao.coreservice.modules.pay.enums.notify.PayNotifyTypeEnum;
|
|
|
import cn.iocoder.yudao.coreservice.modules.pay.enums.order.PayOrderNotifyStatusEnum;
|
|
|
-import cn.iocoder.yudao.coreservice.modules.pay.service.notify.PayNotifyCoreService;
|
|
|
-import cn.iocoder.yudao.coreservice.modules.pay.service.notify.dto.PayNotifyTaskCreateReqDTO;
|
|
|
-import cn.iocoder.yudao.coreservice.modules.pay.service.order.dto.PayRefundReqDTO;
|
|
|
-import cn.iocoder.yudao.framework.pay.core.client.dto.PayRefundNotifyDTO;
|
|
|
-import cn.iocoder.yudao.coreservice.modules.pay.enums.order.PayRefundTypeEnum;
|
|
|
import cn.iocoder.yudao.coreservice.modules.pay.enums.order.PayOrderStatusEnum;
|
|
|
import cn.iocoder.yudao.coreservice.modules.pay.enums.order.PayRefundStatusEnum;
|
|
|
+import cn.iocoder.yudao.coreservice.modules.pay.enums.order.PayRefundTypeEnum;
|
|
|
import cn.iocoder.yudao.coreservice.modules.pay.service.merchant.PayAppCoreService;
|
|
|
import cn.iocoder.yudao.coreservice.modules.pay.service.merchant.PayChannelCoreService;
|
|
|
+import cn.iocoder.yudao.coreservice.modules.pay.service.notify.PayNotifyCoreService;
|
|
|
+import cn.iocoder.yudao.coreservice.modules.pay.service.notify.dto.PayNotifyTaskCreateReqDTO;
|
|
|
import cn.iocoder.yudao.coreservice.modules.pay.service.order.PayRefundCoreService;
|
|
|
+import cn.iocoder.yudao.coreservice.modules.pay.service.order.dto.PayRefundReqDTO;
|
|
|
import cn.iocoder.yudao.coreservice.modules.pay.service.order.dto.PayRefundRespDTO;
|
|
|
import cn.iocoder.yudao.framework.pay.core.client.PayClient;
|
|
|
import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory;
|
|
|
import cn.iocoder.yudao.framework.pay.core.client.dto.PayNotifyDataDTO;
|
|
|
+import cn.iocoder.yudao.framework.pay.core.client.dto.PayRefundNotifyDTO;
|
|
|
import cn.iocoder.yudao.framework.pay.core.client.dto.PayRefundUnifiedReqDTO;
|
|
|
import cn.iocoder.yudao.framework.pay.core.client.dto.PayRefundUnifiedRespDTO;
|
|
|
import cn.iocoder.yudao.framework.pay.core.enums.PayChannelRefundRespEnum;
|
|
@@ -34,7 +34,8 @@ import org.springframework.stereotype.Service;
|
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
|
|
|
|
import javax.annotation.Resource;
|
|
|
-import java.util.*;
|
|
|
+import java.util.Date;
|
|
|
+import java.util.Objects;
|
|
|
|
|
|
import static cn.iocoder.yudao.coreservice.modules.pay.enums.PayErrorCodeCoreConstants.*;
|
|
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
|
@@ -90,17 +91,19 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService {
|
|
|
|
|
|
PayOrderExtensionDO orderExtensionDO = payOrderExtensionCoreMapper.selectById(order.getSuccessExtensionId());
|
|
|
PayRefundDO payRefundDO = payRefundCoreMapper.selectByTradeNoAndMerchantRefundNo(orderExtensionDO.getNo(), req.getMerchantRefundNo());
|
|
|
- //构造渠道的统一的退款请求参数
|
|
|
+ // 构造渠道的统一的退款请求参数
|
|
|
PayRefundUnifiedReqDTO unifiedReqDTO = new PayRefundUnifiedReqDTO();
|
|
|
if(Objects.nonNull(payRefundDO)){
|
|
|
- //退款订单已经提交过。
|
|
|
+ // 退款订单已经提交过。
|
|
|
//TODO 校验相同退款单的金额
|
|
|
- if(Objects.equals(PayRefundStatusEnum.SUCCESS.getStatus(), payRefundDO.getStatus())
|
|
|
- || Objects.equals(PayRefundStatusEnum.CLOSE.getStatus(), payRefundDO.getStatus())){
|
|
|
+ // TODO @jason:咱要不封装一个 ObjectUtils.equalsAny
|
|
|
+ if (Objects.equals(PayRefundStatusEnum.SUCCESS.getStatus(), payRefundDO.getStatus())
|
|
|
+ || Objects.equals(PayRefundStatusEnum.CLOSE.getStatus(), payRefundDO.getStatus())) {
|
|
|
//已成功退款
|
|
|
throw exception(PAY_REFUND_SUCCEED);
|
|
|
- }else{
|
|
|
- //保证商户退款单不变,重复向渠道发起退款。渠道保持幂等
|
|
|
+ } else{
|
|
|
+ // TODO @jason:这里不用 else,简洁一些
|
|
|
+ // 保证商户退款单不变,重复向渠道发起退款。渠道保持幂等
|
|
|
unifiedReqDTO.setUserIp(req.getUserIp())
|
|
|
.setAmount(payRefundDO.getRefundAmount())
|
|
|
.setChannelOrderNo(payRefundDO.getChannelOrderNo())
|
|
@@ -109,7 +112,8 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService {
|
|
|
.setReason(payRefundDO.getReason());
|
|
|
}
|
|
|
}else{
|
|
|
- //新生成退款单。 退款单入库 退款单状态:生成
|
|
|
+ // 新生成退款单。 退款单入库 退款单状态:生成
|
|
|
+ // TODO @jason:封装一个小方法。插入退款单
|
|
|
payRefundDO = PayRefundDO.builder().channelOrderNo(order.getChannelOrderNo())
|
|
|
.appId(order.getAppId())
|
|
|
.channelOrderNo(order.getChannelOrderNo())
|
|
@@ -130,6 +134,7 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService {
|
|
|
.type(refundType.getStatus())
|
|
|
.build();
|
|
|
payRefundCoreMapper.insert(payRefundDO);
|
|
|
+ // TODO @jason:这块的逻辑,和已存在的这块,貌似是统一的?
|
|
|
unifiedReqDTO.setUserIp(req.getUserIp())
|
|
|
.setAmount(payRefundDO.getRefundAmount())
|
|
|
.setChannelOrderNo(payRefundDO.getChannelOrderNo())
|
|
@@ -137,19 +142,20 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService {
|
|
|
.setRefundReqNo(payRefundDO.getMerchantRefundNo())
|
|
|
.setReason(req.getReason());
|
|
|
}
|
|
|
- //向渠道发起退款申请
|
|
|
+ // 向渠道发起退款申请
|
|
|
PayRefundUnifiedRespDTO refundUnifiedRespDTO = client.unifiedRefund(unifiedReqDTO);
|
|
|
- //构造退款申请返回对象
|
|
|
+ // 构造退款申请返回对象
|
|
|
PayRefundRespDTO respDTO = new PayRefundRespDTO();
|
|
|
- if(refundUnifiedRespDTO.getChannelResp() == PayChannelRefundRespEnum.SUCCESS
|
|
|
- ||refundUnifiedRespDTO.getChannelResp() == PayChannelRefundRespEnum.PROCESSING ){
|
|
|
- //成功处理, 在退款通知中处理, 这里不处理
|
|
|
+ if (refundUnifiedRespDTO.getChannelResp() == PayChannelRefundRespEnum.SUCCESS
|
|
|
+ ||refundUnifiedRespDTO.getChannelResp() == PayChannelRefundRespEnum.PROCESSING) {
|
|
|
+ // 成功处理,在退款通知中处理, 这里不处理
|
|
|
respDTO.setChannelReturnResult(PayChannelRefundRespEnum.SUCCESS.getStatus());
|
|
|
respDTO.setRefundId(payRefundDO.getId());
|
|
|
}else {
|
|
|
- //失败返回错误给前端,可以重新发起退款,保证退款请求号(这里是商户退款单号), 避免重复退款。
|
|
|
+ // 失败返回错误给前端,可以重新发起退款,保证退款请求号(这里是商户退款单号), 避免重复退款。
|
|
|
+ // TODO @jason:失败的话,是不是可以跑出 ServiceException 业务异常。这样就是成功返回 refundId,失败业务异常
|
|
|
respDTO.setChannelReturnResult(PayChannelRefundRespEnum.FAILURE.getStatus());
|
|
|
- //更新退款单状态
|
|
|
+ // 更新退款单状态
|
|
|
PayRefundDO updatePayRefund = new PayRefundDO();
|
|
|
updatePayRefund.setId(payRefundDO.getId())
|
|
|
.setChannelErrorMsg(refundUnifiedRespDTO.getChannelMsg())
|
|
@@ -181,35 +187,37 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService {
|
|
|
payRefundSuccess(refundNotify);
|
|
|
} else {
|
|
|
//TODO 支付异常, 支付宝似乎没有支付异常的通知。
|
|
|
+ // TODO @jason:那这里可以考虑打个 error logger
|
|
|
}
|
|
|
}
|
|
|
|
|
|
private void payRefundSuccess(PayRefundNotifyDTO refundNotify) {
|
|
|
+ // 校验退款单存在
|
|
|
PayRefundDO refundDO = payRefundCoreMapper.selectByTradeNoAndMerchantRefundNo(refundNotify.getTradeNo(), refundNotify.getReqNo());
|
|
|
if (refundDO == null) {
|
|
|
- log.error("不存在 seqNo 为{} 的支付退款单",refundNotify.getReqNo());
|
|
|
+ log.error("[payRefundSuccess][不存在 seqNo 为{} 的支付退款单]", refundNotify.getReqNo());
|
|
|
throw exception(PAY_REFUND_NOT_FOUND);
|
|
|
}
|
|
|
- Long refundAmount = refundDO.getRefundAmount();
|
|
|
+
|
|
|
+ // 计算订单的状态。如果全部退款,则订单处于关闭。TODO @jason:建议这里按照金额来判断,因为可能退款多次
|
|
|
Integer type = refundDO.getType();
|
|
|
PayOrderStatusEnum orderStatus = PayOrderStatusEnum.SUCCESS;
|
|
|
- if(PayRefundTypeEnum.ALL.getStatus().equals(type)){
|
|
|
+ if (PayRefundTypeEnum.ALL.getStatus().equals(type)){
|
|
|
orderStatus = PayOrderStatusEnum.CLOSED;
|
|
|
}
|
|
|
- // 更新支付订单
|
|
|
- PayOrderDO payOrderDO = payOrderCoreMapper.selectById(refundDO.getOrderId());
|
|
|
// 需更新已退金额
|
|
|
+ PayOrderDO payOrderDO = payOrderCoreMapper.selectById(refundDO.getOrderId());
|
|
|
Long refundedAmount = payOrderDO.getRefundAmount();
|
|
|
+ // 更新支付订单
|
|
|
PayOrderDO updateOrderDO = new PayOrderDO();
|
|
|
updateOrderDO.setId(refundDO.getOrderId())
|
|
|
- .setRefundAmount(refundedAmount + refundAmount)
|
|
|
+ .setRefundAmount(refundedAmount + refundDO.getRefundAmount())
|
|
|
.setStatus(orderStatus.getStatus())
|
|
|
- .setRefundTimes(payOrderDO.getRefundTimes()+1)
|
|
|
+ .setRefundTimes(payOrderDO.getRefundTimes() + 1)
|
|
|
.setRefundStatus(type);
|
|
|
-
|
|
|
payOrderCoreMapper.updateById(updateOrderDO);
|
|
|
|
|
|
- // 跟新退款订单
|
|
|
+ // 更新退款订单
|
|
|
PayRefundDO updateRefundDO = new PayRefundDO();
|
|
|
updateRefundDO.setId(refundDO.getId())
|
|
|
.setSuccessTime(refundNotify.getRefundSuccessTime())
|
|
@@ -219,7 +227,7 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService {
|
|
|
.setStatus(PayRefundStatusEnum.SUCCESS.getStatus());
|
|
|
payRefundCoreMapper.updateById(updateRefundDO);
|
|
|
|
|
|
- //插入退款通知记录
|
|
|
+ // 插入退款通知记录
|
|
|
// TODO 通知商户成功或者失败. 现在通知似乎没有实现, 只是回调
|
|
|
payNotifyCoreService.createPayNotifyTask(PayNotifyTaskCreateReqDTO.builder()
|
|
|
.type(PayNotifyTypeEnum.REFUND.getType()).dataId(refundDO.getId()).build());
|
|
@@ -235,12 +243,12 @@ public class PayRefundCoreServiceImpl implements PayRefundCoreService {
|
|
|
if (!PayOrderStatusEnum.SUCCESS.getStatus().equals(order.getStatus())) {
|
|
|
throw exception(PAY_ORDER_STATUS_IS_NOT_SUCCESS);
|
|
|
}
|
|
|
- //是否已经全额退款
|
|
|
+ // 是否已经全额退款
|
|
|
if (PayRefundTypeEnum.ALL.getStatus().equals(order.getRefundStatus())) {
|
|
|
throw exception(PAY_REFUND_ALL_REFUNDED);
|
|
|
}
|
|
|
// 校验金额 退款金额不能大于 原定的金额
|
|
|
- if(req.getAmount() + order.getRefundAmount() > order.getAmount()){
|
|
|
+ if (req.getAmount() + order.getRefundAmount() > order.getAmount()){
|
|
|
throw exception(PAY_REFUND_AMOUNT_EXCEED);
|
|
|
}
|
|
|
// 校验渠道订单号
|