Commit c44ace601160ae562e85e38240c318591257f93b

Authored by YunaiV
1 parent 518e89dc

mall + pay:

1. 完成支付宝的退款重构
2. 完成 demo 模块的退款接入
Showing 23 changed files with 333 additions and 274 deletions
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/dto/refund/PayRefundRespDTO.java
... ... @@ -21,6 +21,13 @@ public class PayRefundRespDTO {
21 21 private Integer status;
22 22  
23 23 /**
  24 + * 外部退款号
  25 + *
  26 + * 对应 PayRefundDO 的 no 字段
  27 + */
  28 + private String outRefundNo;
  29 +
  30 + /**
24 31 * 渠道退款单号
25 32 *
26 33 * 对应 PayRefundDO.channelRefundNo 字段
... ...
yudao-framework/yudao-spring-boot-starter-biz-pay/src/main/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayPayClient.java
... ... @@ -68,7 +68,6 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient<AlipayPa
68 68 model.setOutTradeNo(reqDTO.getOutTradeNo());
69 69 model.setOutRequestNo(reqDTO.getOutRefundNo());
70 70 model.setRefundAmount(formatAmount(reqDTO.getPrice()));
71   -// model.setRefundAmount(formatAmount(reqDTO.getPrice() / 2));
72 71 model.setRefundReason(reqDTO.getReason());
73 72 // 1.2 构建 AlipayTradePayRequest 请求
74 73 AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
... ... @@ -77,6 +76,7 @@ public abstract class AbstractAlipayPayClient extends AbstractPayClient<AlipayPa
77 76 // 2.1 执行请求
78 77 AlipayTradeRefundResponse response = client.execute(request);
79 78 PayRefundRespDTO refund = new PayRefundRespDTO()
  79 + .setOutRefundNo(reqDTO.getOutRefundNo())
80 80 .setRawData(response);
81 81 // 支付宝只要退款调用返回 success,就认为退款成功,不需要回调。具体可见 parseNotify 方法的说明。
82 82 // 另外,支付宝没有退款单号,所以不用设置
... ...
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/api/refund/dto/PayRefundCreateReqDTO.java
... ... @@ -27,26 +27,32 @@ public class PayRefundCreateReqDTO {
27 27 private String userIp;
28 28  
29 29 // ========== 商户相关字段 ==========
  30 + /**
  31 + * 商户订单编号
  32 + */
  33 + @NotEmpty(message = "商户订单编号不能为空")
  34 + private String merchantOrderId;
  35 +
  36 + /**
  37 + * 商户退款编号
  38 + */
  39 + @NotEmpty(message = "商户退款编号不能为空")
  40 + private String merchantRefundId;
30 41  
31 42 /**
32 43 * 退款描述
33 44 */
34 45 @NotEmpty(message = "退款描述不能为空")
35   - @Length(max = 128, message = "退款描述长度不能超过128")
  46 + @Length(max = 128, message = "退款描述长度不能超过 128")
36 47 private String reason;
37 48  
38 49 // ========== 订单相关字段 ==========
39 50  
40 51 /**
41   - * 支付单号
42   - */
43   - @NotNull(message = "支付单号不能为空")
44   - private Long payOrderId;
45   -
46   - /**
47 52 * 退款金额,单位:分
48 53 */
49 54 @NotNull(message = "退款金额不能为空")
50 55 @Min(value = 1, message = "退款金额必须大于零")
51 56 private Integer price;
  57 +
52 58 }
... ...
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/ErrorCodeConstants.java
... ... @@ -33,11 +33,12 @@ public interface ErrorCodeConstants {
33 33 ErrorCode PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING = new ErrorCode(1007003001, "支付交易拓展单不处于待支付");
34 34  
35 35 // ========== 支付模块(退款) 1007006000 ==========
36   - ErrorCode PAY_PRICE_PRICE_EXCEED = new ErrorCode(1007006000, "退款金额超过订单可退款金额");
  36 + ErrorCode PAY_REFUND_PRICE_EXCEED = new ErrorCode(1007006000, "退款金额超过订单可退款金额");
37 37 ErrorCode PAY_REFUND_ALL_REFUNDED = new ErrorCode(1007006001, "订单已经全额退款");
38   - ErrorCode PAY_REFUND_CHN_ORDER_NO_IS_NULL = new ErrorCode(1007006002, "该订单的渠道订单为空");
39   - ErrorCode PAY_REFUND_SUCCEED = new ErrorCode(1007006003, "已经退款成功");
  38 + ErrorCode PAY_REFUND_HAS_REFUNDING = new ErrorCode(1007006002, "已经有退款在处理中");
  39 + ErrorCode PAY_REFUND_EXISTS = new ErrorCode(1007006003, "已经存在退款单");
40 40 ErrorCode PAY_REFUND_NOT_FOUND = new ErrorCode(1007006004, "支付退款单不存在");
  41 + ErrorCode PAY_REFUND_STATUS_IS_NOT_WAITING = new ErrorCode(1007006005, "支付退款单不处于待退款");
41 42  
42 43 // ========== 示例订单 1007900000 ==========
43 44 ErrorCode PAY_DEMO_ORDER_NOT_FOUND = new ErrorCode(1007900000, "示例订单不存在");
... ...
yudao-module-pay/yudao-module-pay-api/src/main/java/cn/iocoder/yudao/module/pay/enums/order/PayOrderStatusEnum.java
... ... @@ -38,4 +38,14 @@ public enum PayOrderStatusEnum implements IntArrayValuable {
38 38 return Objects.equals(status, SUCCESS.getStatus());
39 39 }
40 40  
  41 + /**
  42 + * 判断是否支付关闭
  43 + *
  44 + * @param status 状态
  45 + * @return 是否支付关闭
  46 + */
  47 + public static boolean isClosed(Integer status) {
  48 + return Objects.equals(status, CLOSED.getStatus());
  49 + }
  50 +
41 51 }
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/order/PayOrderApiImpl.java
... ... @@ -22,7 +22,7 @@ public class PayOrderApiImpl implements PayOrderApi {
22 22  
23 23 @Override
24 24 public Long createOrder(PayOrderCreateReqDTO reqDTO) {
25   - return payOrderService.createPayOrder(reqDTO);
  25 + return payOrderService.createOrder(reqDTO);
26 26 }
27 27  
28 28 @Override
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/api/refund/PayRefundApiImpl.java
... ... @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.pay.api.refund;
2 2  
3 3 import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO;
4 4 import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundRespDTO;
  5 +import cn.iocoder.yudao.module.pay.convert.refund.PayRefundConvert;
5 6 import cn.iocoder.yudao.module.pay.service.refund.PayRefundService;
6 7 import org.springframework.stereotype.Service;
7 8 import org.springframework.validation.annotation.Validated;
... ... @@ -27,8 +28,7 @@ public class PayRefundApiImpl implements PayRefundApi {
27 28  
28 29 @Override
29 30 public PayRefundRespDTO getPayRefund(Long id) {
30   - // TODO 芋艿:暂未实现
31   - return null;
  31 + return PayRefundConvert.INSTANCE.convert02(payRefundService.getRefund(id));
32 32 }
33 33  
34 34 }
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/notify/PayNotifyController.java
... ... @@ -65,12 +65,12 @@ public class PayNotifyController {
65 65 // 3. 处理通知
66 66 // 3.1:退款通知
67 67 if (notify instanceof PayRefundRespDTO) {
68   - refundService.notifyPayRefund(channelId, (PayRefundRespDTO) notify);
  68 + refundService.notifyRefund(channelId, (PayRefundRespDTO) notify);
69 69 return "success";
70 70 }
71 71 // 3.2:支付通知
72 72 if (notify instanceof PayOrderRespDTO) {
73   - orderService.notifyPayOrder(channelId, (PayOrderRespDTO) notify);
  73 + orderService.notifyOrder(channelId, (PayOrderRespDTO) notify);
74 74 return "success";
75 75 }
76 76 throw new UnsupportedOperationException("未知通知:" + toJsonString(notify));
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/admin/order/PayOrderController.java
... ... @@ -86,7 +86,7 @@ public class PayOrderController {
86 86 @PostMapping("/submit")
87 87 @Operation(summary = "提交支付订单")
88 88 public CommonResult<PayOrderSubmitRespVO> submitPayOrder(@RequestBody PayOrderSubmitReqVO reqVO) {
89   - PayOrderSubmitRespVO respVO = payOrderService.submitPayOrder(reqVO, getClientIP());
  89 + PayOrderSubmitRespVO respVO = payOrderService.submitOrder(reqVO, getClientIP());
90 90 return success(respVO);
91 91 }
92 92  
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/controller/app/order/AppPayOrderController.java
... ... @@ -40,7 +40,7 @@ public class AppPayOrderController {
40 40 @PostMapping("/submit")
41 41 @Operation(summary = "提交支付订单")
42 42 public CommonResult<AppPayOrderSubmitRespVO> submitPayOrder(@RequestBody AppPayOrderSubmitReqVO reqVO) {
43   - PayOrderSubmitRespVO respVO = payOrderService.submitPayOrder(reqVO, getClientIP());
  43 + PayOrderSubmitRespVO respVO = payOrderService.submitOrder(reqVO, getClientIP());
44 44 return success(PayOrderConvert.INSTANCE.convert3(respVO));
45 45 }
46 46  
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/convert/refund/PayRefundConvert.java
1 1 package cn.iocoder.yudao.module.pay.convert.refund;
2 2  
3 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  4 +import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO;
  5 +import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundRespDTO;
4 6 import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.*;
5   -import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
6 7 import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO;
7 8 import org.mapstruct.Mapper;
8   -import org.mapstruct.Mapping;
9   -import org.mapstruct.Mappings;
10 9 import org.mapstruct.factory.Mappers;
11 10  
12 11 import java.math.BigDecimal;
... ... @@ -44,8 +43,6 @@ public interface PayRefundConvert {
44 43  
45 44 PageResult<PayRefundRespVO> convertPage(PageResult<PayRefundDO> page);
46 45  
47   - List<PayRefundExcelVO> convertList02(List<PayRefundDO> list);
48   -
49 46 /**
50 47 * 退款订单DO 转 导出excel VO
51 48 *
... ... @@ -67,7 +64,6 @@ public interface PayRefundConvert {
67 64 payRefundExcelVO.setNotifyUrl(bean.getNotifyUrl());
68 65 payRefundExcelVO.setNotifyStatus(bean.getNotifyStatus());
69 66 payRefundExcelVO.setStatus(bean.getStatus());
70   - payRefundExcelVO.setType(bean.getType());
71 67 payRefundExcelVO.setReason(bean.getReason());
72 68 payRefundExcelVO.setUserIp(bean.getUserIp());
73 69 payRefundExcelVO.setChannelOrderNo(bean.getChannelOrderNo());
... ... @@ -84,12 +80,8 @@ public interface PayRefundConvert {
84 80 return payRefundExcelVO;
85 81 }
86 82  
87   - //TODO 太多需要处理了, 暂时不用
88   - @Mappings(value = {
89   - @Mapping(source = "price", target = "payPrice"),
90   - @Mapping(source = "id", target = "orderId"),
91   - @Mapping(target = "status",ignore = true)
92   - })
93   - PayRefundDO convert(PayOrderDO orderDO);
  83 + PayRefundDO convert(PayRefundCreateReqDTO bean);
  84 +
  85 + PayRefundRespDTO convert02(PayRefundDO bean);
94 86  
95 87 }
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/order/PayOrderDO.java
... ... @@ -6,7 +6,7 @@ import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO;
6 6 import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO;
7 7 import cn.iocoder.yudao.module.pay.enums.order.PayOrderNotifyStatusEnum;
8 8 import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
9   -import cn.iocoder.yudao.module.pay.enums.refund.PayRefundTypeEnum;
  9 +import cn.iocoder.yudao.module.pay.enums.order.PayOrderRefundStatusEnum;
10 10 import com.baomidou.mybatisplus.annotation.KeySequence;
11 11 import com.baomidou.mybatisplus.annotation.TableName;
12 12 import lombok.*;
... ... @@ -127,7 +127,7 @@ public class PayOrderDO extends BaseDO {
127 127 /**
128 128 * 退款状态
129 129 *
130   - * 枚举 {@link PayRefundTypeEnum}
  130 + * 枚举 {@link PayOrderRefundStatusEnum}
131 131 */
132 132 private Integer refundStatus;
133 133 /**
... ... @@ -137,7 +137,7 @@ public class PayOrderDO extends BaseDO {
137 137 /**
138 138 * 退款总金额,单位:分
139 139 */
140   - private Long refundPrice;
  140 + private Integer refundPrice;
141 141  
142 142 // ========== 渠道相关字段 ==========
143 143 /**
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/dataobject/refund/PayRefundDO.java
... ... @@ -7,7 +7,6 @@ import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO;
7 7 import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
8 8 import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyStatusEnum;
9 9 import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum;
10   -import cn.iocoder.yudao.module.pay.enums.refund.PayRefundTypeEnum;
11 10 import com.baomidou.mybatisplus.annotation.KeySequence;
12 11 import com.baomidou.mybatisplus.annotation.TableId;
13 12 import com.baomidou.mybatisplus.annotation.TableName;
... ... @@ -105,12 +104,6 @@ public class PayRefundDO extends BaseDO {
105 104 private Integer status;
106 105  
107 106 /**
108   - * 退款类型(部分退款,全部退款)
109   - *
110   - * 枚举 {@link PayRefundTypeEnum}
111   - */
112   - private Integer type;
113   - /**
114 107 * 支付金额,单位:分
115 108 */
116 109 private Integer payPrice;
... ... @@ -158,12 +151,6 @@ public class PayRefundDO extends BaseDO {
158 151 private String channelErrorMsg;
159 152  
160 153 /**
161   - * 支付渠道的额外参数
162   - *
163   - * 参见 <a href="https://www.pingxx.com/api/支付渠道%20extra%20参数说明.html">参数说明</>
164   - */
165   - private String channelExtras;
166   - /**
167 154 * 支付渠道异步通知的内容
168 155 *
169 156 * 在退款成功后,会记录回调的数据
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/dal/mysql/refund/PayRefundMapper.java
1 1 package cn.iocoder.yudao.module.pay.dal.mysql.refund;
2 2  
3   -import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundExportReqVO;
4   -import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundPageReqVO;
5 3 import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 4 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
  5 +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
7 6 import cn.iocoder.yudao.framework.mybatis.core.query.QueryWrapperX;
  7 +import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundExportReqVO;
  8 +import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundPageReqVO;
8 9 import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO;
  10 +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
9 11 import org.apache.ibatis.annotations.Mapper;
10 12  
11 13 import java.util.List;
... ... @@ -13,6 +15,34 @@ import java.util.List;
13 15 @Mapper
14 16 public interface PayRefundMapper extends BaseMapperX<PayRefundDO> {
15 17  
  18 + default Long selectCountByAppId(Long appId) {
  19 + return selectCount(PayRefundDO::getAppId, appId);
  20 + }
  21 +
  22 + default PayRefundDO selectByAppIdAndMerchantRefundId(Long appId, String merchantRefundId) {
  23 + return selectOne(new LambdaQueryWrapperX<PayRefundDO>()
  24 + .eq(PayRefundDO::getAppId, appId)
  25 + .eq(PayRefundDO::getMerchantRefundId, merchantRefundId));
  26 + }
  27 +
  28 + default Long selectCountByAppIdAndOrderId(Long appId, Long orderId, Integer status) {
  29 + return selectCount(new LambdaQueryWrapperX<PayRefundDO>()
  30 + .eq(PayRefundDO::getAppId, appId)
  31 + .eq(PayRefundDO::getOrderId, orderId)
  32 + .eq(PayRefundDO::getStatus, status));
  33 + }
  34 +
  35 + default PayRefundDO selectByAppIdAndNo(Long appId, String no) {
  36 + return selectOne(new LambdaQueryWrapperX<PayRefundDO>()
  37 + .eq(PayRefundDO::getAppId, appId)
  38 + .eq(PayRefundDO::getNo, no));
  39 + }
  40 +
  41 + default int updateByIdAndStatus(Long id, Integer status, PayRefundDO update) {
  42 + return update(update, new LambdaQueryWrapper<PayRefundDO>()
  43 + .eq(PayRefundDO::getId, id).eq(PayRefundDO::getStatus, status));
  44 + }
  45 +
16 46 default PageResult<PayRefundDO> selectPage(PayRefundPageReqVO reqVO) {
17 47 return selectPage(reqVO, new QueryWrapperX<PayRefundDO>()
18 48 .eqIfPresent("app_id", reqVO.getAppId())
... ... @@ -37,18 +67,4 @@ public interface PayRefundMapper extends BaseMapperX&lt;PayRefundDO&gt; {
37 67 .orderByDesc("id"));
38 68 }
39 69  
40   - default Long selectCountByApp(Long appId) {
41   - return selectCount(PayRefundDO::getAppId, appId);
42   - }
43   -
44   - default PayRefundDO selectByReqNo(String reqNo) {
45   - return selectOne("req_no", reqNo);
46   - }
47   -
48   - // TODO 芋艿:要重构
49   - default PayRefundDO selectByTradeNoAndMerchantRefundNo(String tradeNo, String merchantRefundNo){
50   -// return selectOne("trade_no", tradeNo, "merchant_refund_no", merchantRefundNo);
51   - return null;
52   - }
53   -
54 70 }
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/enums/refund/PayRefundTypeEnum.java renamed to yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/enums/order/PayOrderRefundStatusEnum.java
1   -package cn.iocoder.yudao.module.pay.enums.refund;
  1 +package cn.iocoder.yudao.module.pay.enums.order;
2 2  
3 3 import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
4 4 import lombok.AllArgsConstructor;
... ... @@ -11,10 +11,10 @@ import lombok.Getter;
11 11 */
12 12 @Getter
13 13 @AllArgsConstructor
14   -public enum PayRefundTypeEnum implements IntArrayValuable {
  14 +public enum PayOrderRefundStatusEnum implements IntArrayValuable {
15 15  
16 16 NO(0, "未退款"),
17   - SOME(10, "部分退款"),
  17 + PART(10, "部分退款"),
18 18 ALL(20, "全部退款")
19 19 ;
20 20  
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/demo/PayDemoOrderServiceImpl.java
... ... @@ -184,12 +184,17 @@ public class PayDemoOrderServiceImpl implements PayDemoOrderService {
184 184 // 1. 校验订单是否可以退款
185 185 PayDemoOrderDO order = validateDemoOrderCanRefund(id);
186 186  
187   - // 2.1 创建退款单
  187 + // 2.1 生成退款单号
  188 + // 一般来说,用户发起退款的时候,都会单独插入一个售后维权表,然后使用该表的 id 作为 refundId
  189 + // 这里我们是个简单的 demo,所以没有售后维权表,直接使用订单 id + "-refund" 来演示
  190 + String refundId = order.getId() + "-refund";
  191 + // 2.2 创建退款单
188 192 Long payRefundId = payRefundApi.createPayRefund(new PayRefundCreateReqDTO()
189 193 .setAppId(PAY_APP_ID).setUserIp(getClientIP()) // 支付应用
190   - .setPayOrderId(order.getPayOrderId()) // 支付单号
  194 + .setMerchantOrderId(String.valueOf(order.getId())) // 支付单号
  195 + .setMerchantRefundId(refundId)
191 196 .setReason("想退钱").setPrice(order.getPrice()));// 价格信息
192   - // 2.2 更新退款单到 demo 订单
  197 + // 2.3 更新退款单到 demo 订单
193 198 payDemoOrderMapper.updateById(new PayDemoOrderDO().setId(id)
194 199 .setPayRefundId(payRefundId).setRefundPrice(order.getPrice()));
195 200 }
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderExtensionService.java
... ... @@ -7,6 +7,7 @@ import java.util.Collection;
7 7 import java.util.List;
8 8 import java.util.Map;
9 9  
  10 +// TODO 芋艿:合并到 PayOrder 里;
10 11 /**
11 12 * 支付订单 Service 接口
12 13 *
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderService.java
... ... @@ -32,6 +32,15 @@ public interface PayOrderService {
32 32 PayOrderDO getOrder(Long id);
33 33  
34 34 /**
  35 + * 获得支付订单
  36 + *
  37 + * @param appId 应用编号
  38 + * @param merchantOrderId 商户订单编号
  39 + * @return 支付订单
  40 + */
  41 + PayOrderDO getOrder(Long appId, String merchantOrderId);
  42 +
  43 + /**
35 44 * 获得指定应用的订单数量
36 45 *
37 46 * @param appId 应用编号
... ... @@ -70,11 +79,11 @@ public interface PayOrderService {
70 79 /**
71 80 * 根据订单 ID 集合获取订单商品名称Map集合
72 81 *
73   - * @param idList 订单 ID 集合
  82 + * @param ids 订单 ID 集合
74 83 * @return 订单商品 map 集合
75 84 */
76   - default Map<Long, PayOrderDO> getOrderSubjectMap(Collection<Long> idList) {
77   - List<PayOrderDO> list = getOrderSubjectList(idList);
  85 + default Map<Long, PayOrderDO> getOrderSubjectMap(Collection<Long> ids) {
  86 + List<PayOrderDO> list = getOrderSubjectList(ids);
78 87 return CollectionUtils.convertMap(list, PayOrderDO::getId);
79 88 }
80 89  
... ... @@ -84,7 +93,7 @@ public interface PayOrderService {
84 93 * @param reqDTO 创建请求
85 94 * @return 支付单编号
86 95 */
87   - Long createPayOrder(@Valid PayOrderCreateReqDTO reqDTO);
  96 + Long createOrder(@Valid PayOrderCreateReqDTO reqDTO);
88 97  
89 98 /**
90 99 * 提交支付
... ... @@ -94,8 +103,8 @@ public interface PayOrderService {
94 103 * @param userIp 提交 IP
95 104 * @return 提交结果
96 105 */
97   - PayOrderSubmitRespVO submitPayOrder(@Valid PayOrderSubmitReqVO reqVO,
98   - @NotEmpty(message = "提交 IP 不能为空") String userIp);
  106 + PayOrderSubmitRespVO submitOrder(@Valid PayOrderSubmitReqVO reqVO,
  107 + @NotEmpty(message = "提交 IP 不能为空") String userIp);
99 108  
100 109 /**
101 110 * 通知支付单成功
... ... @@ -103,6 +112,14 @@ public interface PayOrderService {
103 112 * @param channelId 渠道编号
104 113 * @param notify 通知
105 114 */
106   - void notifyPayOrder(Long channelId, PayOrderRespDTO notify);
  115 + void notifyOrder(Long channelId, PayOrderRespDTO notify);
  116 +
  117 + /**
  118 + * 更新支付订单的退款金额
  119 + *
  120 + * @param id 编号
  121 + * @param incrRefundPrice 增加的退款金额
  122 + */
  123 + void updateOrderRefundPrice(Long id, Integer incrRefundPrice);
107 124  
108 125 }
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceImpl.java
... ... @@ -26,11 +26,10 @@ import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
26 26 import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO;
27 27 import cn.iocoder.yudao.module.pay.dal.mysql.order.PayOrderExtensionMapper;
28 28 import cn.iocoder.yudao.module.pay.dal.mysql.order.PayOrderMapper;
29   -import cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants;
30 29 import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyTypeEnum;
31 30 import cn.iocoder.yudao.module.pay.enums.order.PayOrderNotifyStatusEnum;
  31 +import cn.iocoder.yudao.module.pay.enums.order.PayOrderRefundStatusEnum;
32 32 import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
33   -import cn.iocoder.yudao.module.pay.enums.refund.PayRefundTypeEnum;
34 33 import cn.iocoder.yudao.module.pay.service.app.PayAppService;
35 34 import cn.iocoder.yudao.module.pay.service.channel.PayChannelService;
36 35 import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService;
... ... @@ -48,6 +47,7 @@ import java.util.Objects;
48 47  
49 48 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
50 49 import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
  50 +import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*;
51 51  
52 52 /**
53 53 * 支付订单 Service 实现类
... ... @@ -83,6 +83,11 @@ public class PayOrderServiceImpl implements PayOrderService {
83 83 }
84 84  
85 85 @Override
  86 + public PayOrderDO getOrder(Long appId, String merchantOrderId) {
  87 + return orderMapper.selectByAppIdAndMerchantOrderId(appId, merchantOrderId);
  88 + }
  89 +
  90 + @Override
86 91 public Long getOrderCountByAppId(Long appId) {
87 92 return orderMapper.selectCountByAppId(appId);
88 93 }
... ... @@ -104,7 +109,7 @@ public class PayOrderServiceImpl implements PayOrderService {
104 109 }
105 110  
106 111 @Override
107   - public Long createPayOrder(PayOrderCreateReqDTO reqDTO) {
  112 + public Long createOrder(PayOrderCreateReqDTO reqDTO) {
108 113 // 校验 App
109 114 PayAppDO app = appService.validPayApp(reqDTO.getAppId());
110 115  
... ... @@ -112,7 +117,7 @@ public class PayOrderServiceImpl implements PayOrderService {
112 117 PayOrderDO order = orderMapper.selectByAppIdAndMerchantOrderId(
113 118 reqDTO.getAppId(), reqDTO.getMerchantOrderId());
114 119 if (order != null) {
115   - log.warn("[createPayOrder][appId({}) merchantOrderId({}) 已经存在对应的支付单({})]", order.getAppId(),
  120 + log.warn("[createOrder][appId({}) merchantOrderId({}) 已经存在对应的支付单({})]", order.getAppId(),
116 121 order.getMerchantOrderId(), toJsonString(order)); // 理论来说,不会出现这个情况
117 122 return order.getId();
118 123 }
... ... @@ -124,16 +129,16 @@ public class PayOrderServiceImpl implements PayOrderService {
124 129 // 订单相关字段
125 130 .setStatus(PayOrderStatusEnum.WAITING.getStatus())
126 131 // 退款相关字段
127   - .setRefundStatus(PayRefundTypeEnum.NO.getStatus()).setRefundTimes(0).setRefundPrice(0L);
  132 + .setRefundStatus(PayOrderRefundStatusEnum.NO.getStatus()).setRefundTimes(0).setRefundPrice(0);
128 133 orderMapper.insert(order);
129 134 return order.getId();
130 135 }
131 136  
132 137 @Override
133 138 @Transactional(rollbackFor = Exception.class)
134   - public PayOrderSubmitRespVO submitPayOrder(PayOrderSubmitReqVO reqVO, String userIp) {
  139 + public PayOrderSubmitRespVO submitOrder(PayOrderSubmitReqVO reqVO, String userIp) {
135 140 // 1. 获得 PayOrderDO ,并校验其是否存在
136   - PayOrderDO order = validatePayOrderCanSubmit(reqVO.getId());
  141 + PayOrderDO order = validateOrderCanSubmit(reqVO.getId());
137 142 // 1.2 校验支付渠道是否有效
138 143 PayChannelDO channel = validatePayChannelCanSubmit(order.getAppId(), reqVO.getChannelCode());
139 144 PayClient client = payClientFactory.getPayClient(channel.getId());
... ... @@ -167,16 +172,16 @@ public class PayOrderServiceImpl implements PayOrderService {
167 172 return PayOrderConvert.INSTANCE.convert(order, unifiedOrderRespDTO);
168 173 }
169 174  
170   - private PayOrderDO validatePayOrderCanSubmit(Long id) {
  175 + private PayOrderDO validateOrderCanSubmit(Long id) {
171 176 PayOrderDO order = orderMapper.selectById(id);
172 177 if (order == null) { // 是否存在
173   - throw exception(ErrorCodeConstants.PAY_ORDER_NOT_FOUND);
  178 + throw exception(PAY_ORDER_NOT_FOUND);
174 179 }
175 180 if (!PayOrderStatusEnum.WAITING.getStatus().equals(order.getStatus())) { // 校验状态,必须是待支付
176   - throw exception(ErrorCodeConstants.PAY_ORDER_STATUS_IS_NOT_WAITING);
  181 + throw exception(PAY_ORDER_STATUS_IS_NOT_WAITING);
177 182 }
178 183 if (LocalDateTimeUtils.beforeNow(order.getExpireTime())) { // 校验是否过期
179   - throw exception(ErrorCodeConstants.PAY_ORDER_IS_EXPIRED);
  184 + throw exception(PAY_ORDER_IS_EXPIRED);
180 185 }
181 186 return order;
182 187 }
... ... @@ -184,14 +189,12 @@ public class PayOrderServiceImpl implements PayOrderService {
184 189 private PayChannelDO validatePayChannelCanSubmit(Long appId, String channelCode) {
185 190 // 校验 App
186 191 appService.validPayApp(appId);
187   -
188 192 // 校验支付渠道是否有效
189 193 PayChannelDO channel = channelService.validPayChannel(appId, channelCode);
190   - // 校验支付客户端是否正确初始化
191 194 PayClient client = payClientFactory.getPayClient(channel.getId());
192 195 if (client == null) {
193 196 log.error("[validatePayChannelCanSubmit][渠道编号({}) 找不到对应的支付客户端]", channel.getId());
194   - throw exception(ErrorCodeConstants.PAY_CHANNEL_CLIENT_NOT_FOUND);
  197 + throw exception(PAY_CHANNEL_CLIENT_NOT_FOUND);
195 198 }
196 199 return channel;
197 200 }
... ... @@ -226,28 +229,55 @@ public class PayOrderServiceImpl implements PayOrderService {
226 229  
227 230 @Override
228 231 @Transactional(rollbackFor = Exception.class)
229   - public void notifyPayOrder(Long channelId, PayOrderRespDTO notify) {
  232 + public void notifyOrder(Long channelId, PayOrderRespDTO notify) {
230 233 // 校验支付渠道是否有效
231 234 PayChannelDO channel = channelService.validPayChannel(channelId);
232 235 // 更新支付订单为已支付
233 236 TenantUtils.execute(channel.getTenantId(), () -> notifyPayOrder(channel, notify));
234 237 }
235 238  
  239 + @Override
  240 + public void updateOrderRefundPrice(Long id, Integer incrRefundPrice) {
  241 + PayOrderDO order = orderMapper.selectById(id);
  242 + if (order == null) {
  243 + throw exception(PAY_ORDER_NOT_FOUND);
  244 + }
  245 + if (!PayOrderStatusEnum.isSuccess(order.getStatus())) {
  246 + throw exception(PAY_REFUND_PRICE_EXCEED);
  247 + }
  248 + if (order.getRefundPrice() + incrRefundPrice > order.getPrice()) {
  249 + throw exception(PAY_REFUND_PRICE_EXCEED);
  250 + }
  251 +
  252 + // 更新订单
  253 + PayOrderDO updateObj = new PayOrderDO()
  254 + .setRefundPrice(order.getRefundPrice() + incrRefundPrice)
  255 + .setRefundTimes(order.getRefundTimes() + 1);
  256 + if (Objects.equals(updateObj.getRefundPrice(), order.getPrice())) {
  257 + updateObj.setStatus(PayOrderStatusEnum.CLOSED.getStatus())
  258 + .setRefundStatus(PayOrderRefundStatusEnum.ALL.getStatus());
  259 + } else {
  260 + updateObj.setStatus(PayOrderStatusEnum.CLOSED.getStatus())
  261 + .setRefundStatus(PayOrderRefundStatusEnum.PART.getStatus());
  262 + }
  263 + orderMapper.updateByIdAndStatus(id, PayOrderStatusEnum.SUCCESS.getStatus(), updateObj);
  264 + }
  265 +
236 266 private void notifyPayOrder(PayChannelDO channel, PayOrderRespDTO notify) {
237 267 // 情况一:支付成功的回调
238 268 if (PayOrderStatusRespEnum.isSuccess(notify.getStatus())) {
239   - notifyPayOrderSuccess(channel, notify);
  269 + notifyOrderSuccess(channel, notify);
240 270 return;
241 271 }
242 272 // 情况二:非支付成功的回调,进行忽略
243 273 log.info("[notifyPayOrder][非支付成功的回调({}),直接忽略]", toJsonString(notify));
244 274 }
245 275  
246   - private void notifyPayOrderSuccess(PayChannelDO channel, PayOrderRespDTO notify) {
  276 + private void notifyOrderSuccess(PayChannelDO channel, PayOrderRespDTO notify) {
247 277 // 1. 更新 PayOrderExtensionDO 支付成功
248   - PayOrderExtensionDO orderExtension = updatePayOrderExtensionSuccess(notify);
  278 + PayOrderExtensionDO orderExtension = updateOrderExtensionSuccess(notify);
249 279 // 2. 更新 PayOrderDO 支付成功
250   - Pair<Boolean, PayOrderDO> order = updatePayOrderSuccess(channel, orderExtension, notify);
  280 + Pair<Boolean, PayOrderDO> order = updateOrderExtensionSuccess(channel, orderExtension, notify);
251 281 if (order.getKey()) { // 如果之前已经成功回调,则直接返回,不用重复记录支付通知记录;例如说:支付平台重复回调
252 282 return;
253 283 }
... ... @@ -263,27 +293,27 @@ public class PayOrderServiceImpl implements PayOrderService {
263 293 * @param notify 通知
264 294 * @return PayOrderExtensionDO 对象
265 295 */
266   - private PayOrderExtensionDO updatePayOrderExtensionSuccess(PayOrderRespDTO notify) {
  296 + private PayOrderExtensionDO updateOrderExtensionSuccess(PayOrderRespDTO notify) {
267 297 // 1. 查询 PayOrderExtensionDO
268 298 PayOrderExtensionDO orderExtension = orderExtensionMapper.selectByNo(notify.getOutTradeNo());
269 299 if (orderExtension == null) {
270   - throw exception(ErrorCodeConstants.PAY_ORDER_EXTENSION_NOT_FOUND);
  300 + throw exception(PAY_ORDER_EXTENSION_NOT_FOUND);
271 301 }
272 302 if (PayOrderStatusEnum.isSuccess(orderExtension.getStatus())) { // 如果已经是成功,直接返回,不用重复更新
273   - log.info("[updatePayOrderSuccess][支付拓展单({}) 已经是已支付,无需更新为已支付]", orderExtension.getId());
  303 + log.info("[updateOrderExtensionSuccess][支付拓展单({}) 已经是已支付,无需更新为已支付]", orderExtension.getId());
274 304 return orderExtension;
275 305 }
276 306 if (ObjectUtil.notEqual(orderExtension.getStatus(), PayOrderStatusEnum.WAITING.getStatus())) { // 校验状态,必须是待支付
277   - throw exception(ErrorCodeConstants.PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
  307 + throw exception(PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
278 308 }
279 309  
280 310 // 2. 更新 PayOrderExtensionDO
281   - int updateCounts = orderExtensionMapper.updateByIdAndStatus(orderExtension.getId(), PayOrderStatusEnum.WAITING.getStatus(),
  311 + int updateCounts = orderExtensionMapper.updateByIdAndStatus(orderExtension.getId(), orderExtension.getStatus(),
282 312 PayOrderExtensionDO.builder().status(PayOrderStatusEnum.SUCCESS.getStatus()).channelNotifyData(toJsonString(notify)).build());
283 313 if (updateCounts == 0) { // 校验状态,必须是待支付
284   - throw exception(ErrorCodeConstants.PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
  314 + throw exception(PAY_ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
285 315 }
286   - log.info("[updatePayOrderSuccess][支付拓展单({}) 更新为已支付]", orderExtension.getId());
  316 + log.info("[updateOrderExtensionSuccess][支付拓展单({}) 更新为已支付]", orderExtension.getId());
287 317 return orderExtension;
288 318 }
289 319  
... ... @@ -296,20 +326,20 @@ public class PayOrderServiceImpl implements PayOrderService {
296 326 * @return key:是否之前已经成功回调
297 327 * value:PayOrderDO 对象
298 328 */
299   - private Pair<Boolean, PayOrderDO> updatePayOrderSuccess(PayChannelDO channel, PayOrderExtensionDO orderExtension,
  329 + private Pair<Boolean, PayOrderDO> updateOrderExtensionSuccess(PayChannelDO channel, PayOrderExtensionDO orderExtension,
300 330 PayOrderRespDTO notify) {
301 331 // 1. 判断 PayOrderDO 是否处于待支付
302 332 PayOrderDO order = orderMapper.selectById(orderExtension.getOrderId());
303 333 if (order == null) {
304   - throw exception(ErrorCodeConstants.PAY_ORDER_NOT_FOUND);
  334 + throw exception(PAY_ORDER_NOT_FOUND);
305 335 }
306 336 if (PayOrderStatusEnum.isSuccess(order.getStatus()) // 如果已经是成功,直接返回,不用重复更新
307 337 && Objects.equals(order.getSuccessExtensionId(), orderExtension.getId())) {
308   - log.info("[updatePayOrderSuccess][支付订单({}) 已经是已支付,无需更新为已支付]", order.getId());
  338 + log.info("[updateOrderExtensionSuccess][支付订单({}) 已经是已支付,无需更新为已支付]", order.getId());
309 339 return Pair.of(true, order);
310 340 }
311 341 if (!PayOrderStatusEnum.WAITING.getStatus().equals(order.getStatus())) { // 校验状态,必须是待支付
312   - throw exception(ErrorCodeConstants.PAY_ORDER_STATUS_IS_NOT_WAITING);
  342 + throw exception(PAY_ORDER_STATUS_IS_NOT_WAITING);
313 343 }
314 344  
315 345 // 2. 更新 PayOrderDO
... ... @@ -320,9 +350,9 @@ public class PayOrderServiceImpl implements PayOrderService {
320 350 .channelOrderNo(notify.getChannelOrderNo()).channelUserId(notify.getChannelUserId())
321 351 .notifyTime(LocalDateTime.now()).build());
322 352 if (updateCounts == 0) { // 校验状态,必须是待支付
323   - throw exception(ErrorCodeConstants.PAY_ORDER_STATUS_IS_NOT_WAITING);
  353 + throw exception(PAY_ORDER_STATUS_IS_NOT_WAITING);
324 354 }
325   - log.info("[updatePayOrderSuccess][支付订单({}) 更新为已支付]", order.getId());
  355 + log.info("[updateOrderExtensionSuccess][支付订单({}) 更新为已支付]", order.getId());
326 356 return Pair.of(false, order);
327 357 }
328 358  
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/refund/PayRefundService.java
... ... @@ -62,6 +62,6 @@ public interface PayRefundService {
62 62 * @param channelId 渠道编号
63 63 * @param notify 通知
64 64 */
65   - void notifyPayRefund(Long channelId, PayRefundRespDTO notify);
  65 + void notifyRefund(Long channelId, PayRefundRespDTO notify);
66 66  
67 67 }
... ...
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/refund/PayRefundServiceImpl.java
1 1 package cn.iocoder.yudao.module.pay.service.refund;
2 2  
  3 +import cn.hutool.core.date.DateUtil;
3 4 import cn.hutool.core.util.RandomUtil;
4   -import cn.hutool.core.util.StrUtil;
5   -import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
6 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
7 6 import cn.iocoder.yudao.framework.pay.config.PayProperties;
8 7 import cn.iocoder.yudao.framework.pay.core.client.PayClient;
... ... @@ -10,22 +9,23 @@ import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory;
10 9 import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO;
11 10 import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO;
12 11 import cn.iocoder.yudao.framework.pay.core.enums.refund.PayRefundStatusRespEnum;
  12 +import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
13 13 import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO;
14 14 import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundExportReqVO;
15 15 import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundPageReqVO;
  16 +import cn.iocoder.yudao.module.pay.convert.refund.PayRefundConvert;
16 17 import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO;
17 18 import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO;
18 19 import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
19 20 import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO;
20 21 import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO;
21   -import cn.iocoder.yudao.module.pay.dal.mysql.order.PayOrderMapper;
22 22 import cn.iocoder.yudao.module.pay.dal.mysql.refund.PayRefundMapper;
23 23 import cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants;
  24 +import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyStatusEnum;
24 25 import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyTypeEnum;
25   -import cn.iocoder.yudao.module.pay.enums.order.PayOrderNotifyStatusEnum;
  26 +import cn.iocoder.yudao.module.pay.enums.order.PayOrderRefundStatusEnum;
26 27 import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
27 28 import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum;
28   -import cn.iocoder.yudao.module.pay.enums.refund.PayRefundTypeEnum;
29 29 import cn.iocoder.yudao.module.pay.service.app.PayAppService;
30 30 import cn.iocoder.yudao.module.pay.service.channel.PayChannelService;
31 31 import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService;
... ... @@ -38,8 +38,11 @@ import org.springframework.transaction.annotation.Transactional;
38 38 import org.springframework.validation.annotation.Validated;
39 39  
40 40 import javax.annotation.Resource;
  41 +import java.time.LocalDateTime;
41 42 import java.util.List;
42   -import java.util.Objects;
  43 +
  44 +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
  45 +import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
43 46  
44 47 /**
45 48 * 退款订单 Service 实现类
... ... @@ -59,8 +62,6 @@ public class PayRefundServiceImpl implements PayRefundService {
59 62  
60 63 @Resource
61 64 private PayRefundMapper refundMapper;
62   - @Resource
63   - private PayOrderMapper orderMapper; // TODO @jason:需要改成不直接操作 db;
64 65  
65 66 @Resource
66 67 private PayOrderService orderService;
... ... @@ -80,7 +81,7 @@ public class PayRefundServiceImpl implements PayRefundService {
80 81  
81 82 @Override
82 83 public Long getRefundCountByAppId(Long appId) {
83   - return refundMapper.selectCountByApp(appId);
  84 + return refundMapper.selectCountByAppId(appId);
84 85 }
85 86  
86 87 @Override
... ... @@ -96,82 +97,82 @@ public class PayRefundServiceImpl implements PayRefundService {
96 97 @Override
97 98 @Transactional(rollbackFor = Exception.class)
98 99 public Long createPayRefund(PayRefundCreateReqDTO reqDTO) {
99   - // 获得 PayOrderDO
100   - PayOrderDO order = orderService.getOrder(reqDTO.getPayOrderId());
101   - // 校验订单是否存在
102   - if (Objects.isNull(order) ) {
103   - throw ServiceExceptionUtil.exception(ErrorCodeConstants.PAY_ORDER_NOT_FOUND);
104   - }
105   - // 校验 App
106   - PayAppDO app = appService.validPayApp(order.getAppId());
107   - // 校验支付渠道是否有效
  100 + // 1.1 校验 App
  101 + PayAppDO app = appService.validPayApp(reqDTO.getAppId());
  102 + // 1.2 校验支付订单
  103 + PayOrderDO order = validatePayOrderCanRefund(reqDTO);
  104 + // 1.3 校验支付渠道是否有效
108 105 PayChannelDO channel = channelService.validPayChannel(order.getChannelId());
109   - // 校验支付客户端是否正确初始化
110 106 PayClient client = payClientFactory.getPayClient(channel.getId());
111 107 if (client == null) {
112 108 log.error("[refund][渠道编号({}) 找不到对应的支付客户端]", channel.getId());
113   - throw ServiceExceptionUtil.exception(ErrorCodeConstants.PAY_CHANNEL_CLIENT_NOT_FOUND);
  109 + throw exception(ErrorCodeConstants.PAY_CHANNEL_CLIENT_NOT_FOUND);
114 110 }
115   -
116   - // TODO 芋艿:待实现
117   - String merchantRefundId = "rrr" + RandomUtil.randomNumbers(16);
118   -
119   - // 校验退款的条件
120   - validatePayRefund(reqDTO, order);
121   - // 退款类型
122   - PayRefundTypeEnum refundType = PayRefundTypeEnum.SOME;
123   - if (Objects.equals(reqDTO.getPrice(), order.getPrice())) {
124   - refundType = PayRefundTypeEnum.ALL;
  111 + // 1.4 校验退款订单是否已经存在
  112 + PayRefundDO refund = refundMapper.selectByAppIdAndMerchantRefundId(
  113 + app.getId(), reqDTO.getMerchantRefundId());
  114 + if (refund != null) {
  115 + throw exception(ErrorCodeConstants.PAY_REFUND_EXISTS);
125 116 }
126   - PayOrderExtensionDO orderExtensionDO = orderExtensionService.getOrderExtension(order.getSuccessExtensionId());
127   - PayRefundDO payRefundDO = refundMapper.selectByTradeNoAndMerchantRefundNo(orderExtensionDO.getNo(),
128   - merchantRefundId); // TODO 芋艿:需要优化
129   - if (Objects.nonNull(payRefundDO)) {
130   - // 退款订单已经提交过。
131   - //TODO 校验相同退款单的金额
132   - // TODO @jason:咱要不封装一个 ObjectUtils.equalsAny
133   - if (Objects.equals(PayRefundStatusEnum.SUCCESS.getStatus(), payRefundDO.getStatus())) {
134   - //已成功退款
135   - throw ServiceExceptionUtil.exception(ErrorCodeConstants.PAY_REFUND_SUCCEED);
136   - }
137   - //可以重复提交,保证 退款请求号 一致,由渠道保证幂等
138   - } else {
139   - // 成功,插入退款单 状态为生成.没有和渠道交互
140   - // TODO @jason:搞到 convert 里。一些额外的自动,手动 set 下;
141   - payRefundDO = PayRefundDO.builder()
142   - .appId(order.getAppId())
143   - .channelOrderNo(order.getChannelOrderNo())
144   - .channelCode(order.getChannelCode())
145   - .channelId(order.getChannelId())
146   - .orderId(order.getId())
147   - .merchantRefundId(merchantRefundId)
148   - .notifyUrl(app.getRefundNotifyUrl())
149   - .payPrice(order.getPrice())
150   - .refundPrice(reqDTO.getPrice())
151   - .userIp(reqDTO.getUserIp())
152   - .merchantOrderId(order.getMerchantOrderId())
153   - .no(orderExtensionDO.getNo())
154   - .status(PayRefundStatusEnum.WAITING.getStatus())
155   - .reason(reqDTO.getReason())
156   - .notifyStatus(PayOrderNotifyStatusEnum.NO.getStatus())
157   - .type(refundType.getStatus())
158   - .build();
159   - refundMapper.insert(payRefundDO);
160   - }
161   - // TODO @jason:搞到 convert 里。一些额外的自动,手动 set 下;
  117 +
  118 + // 2.1 插入退款单
  119 + refund = PayRefundConvert.INSTANCE.convert(reqDTO)
  120 + .setNo(generateRefundNo()).setOrderId(order.getId())
  121 + .setChannelId(order.getChannelId()).setChannelCode(order.getChannelCode())
  122 + // 商户相关的字段
  123 + .setNotifyUrl(app.getRefundNotifyUrl()).setNotifyStatus(PayNotifyStatusEnum.WAITING.getStatus())
  124 + // 渠道相关字段
  125 + .setChannelOrderNo(order.getChannelOrderNo())
  126 + // 退款相关字段
  127 + .setStatus(PayRefundStatusEnum.WAITING.getStatus())
  128 + .setPayPrice(order.getPrice()).setRefundPrice(reqDTO.getPrice());
  129 + refundMapper.insert(refund);
  130 + // 2.2 向渠道发起退款申请
  131 + PayOrderExtensionDO orderExtension = orderExtensionService.getOrderExtension(order.getSuccessExtensionId());
162 132 PayRefundUnifiedReqDTO unifiedReqDTO = new PayRefundUnifiedReqDTO();
163 133 unifiedReqDTO.setPrice(reqDTO.getPrice())
164   - .setOutTradeNo(orderExtensionDO.getNo())
165   - .setOutRefundNo(merchantRefundId) // TODO 芋艿:需要优化
  134 + .setOutTradeNo(orderExtension.getNo())
  135 + .setOutRefundNo(refund.getNo())
166 136 .setNotifyUrl(genChannelPayNotifyUrl(channel)) // TODO 芋艿:优化下 notifyUrl
167 137 .setReason(reqDTO.getReason());
168   - // 向渠道发起退款申请
169   - client.unifiedRefund(unifiedReqDTO);
170   - // 检查是否失败,失败抛出业务异常。
171   - // TODO 渠道的异常记录。
172   - // TODO @jason:可以先打个 warn log 哈;
  138 + PayRefundRespDTO refundRespDTO = client.unifiedRefund(unifiedReqDTO); // TODO 增加一个 channelErrorCode、channelErrorMsg 字段
  139 + // 2.3 处理退款返回
  140 + notifyRefund(channel, refundRespDTO);
  141 +
173 142 // 成功在 退款回调中处理
174   - return payRefundDO.getId();
  143 + return refund.getId();
  144 + }
  145 +
  146 + /**
  147 + * 校验支付订单是否可以退款
  148 + *
  149 + * @param reqDTO 退款申请信息
  150 + * @return 支付订单
  151 + */
  152 + private PayOrderDO validatePayOrderCanRefund(PayRefundCreateReqDTO reqDTO) {
  153 + PayOrderDO order = orderService.getOrder(reqDTO.getAppId(), reqDTO.getMerchantOrderId());
  154 + if (order == null) {
  155 + throw exception(ErrorCodeConstants.PAY_ORDER_NOT_FOUND);
  156 + }
  157 + // 校验状态,必须是支付状态
  158 + if (!PayOrderStatusEnum.SUCCESS.getStatus().equals(order.getStatus())) {
  159 + throw exception(ErrorCodeConstants.PAY_ORDER_STATUS_IS_NOT_SUCCESS);
  160 + }
  161 +
  162 + // 是否已经全额退款
  163 + if (PayOrderRefundStatusEnum.ALL.getStatus().equals(order.getRefundStatus())) {
  164 + throw exception(ErrorCodeConstants.PAY_REFUND_ALL_REFUNDED);
  165 + }
  166 + // 校验金额 退款金额不能大于原定的金额
  167 + if (reqDTO.getPrice() + order.getRefundPrice() > order.getPrice()){
  168 + throw exception(ErrorCodeConstants.PAY_REFUND_PRICE_EXCEED);
  169 + }
  170 + // 是否有退款中的订单
  171 + if (refundMapper.selectCountByAppIdAndOrderId(reqDTO.getAppId(), order.getId(),
  172 + PayRefundStatusEnum.WAITING.getStatus()) > 0) {
  173 + throw exception(ErrorCodeConstants.PAY_REFUND_HAS_REFUNDING);
  174 + }
  175 + return order;
175 176 }
176 177  
177 178 /**
... ... @@ -184,88 +185,80 @@ public class PayRefundServiceImpl implements PayRefundService {
184 185 return payProperties.getCallbackUrl() + "/" + channel.getId();
185 186 }
186 187  
  188 + private String generateRefundNo() {
  189 +// wx
  190 +// 2014
  191 +// 10
  192 +// 27
  193 +// 20
  194 +// 09
  195 +// 39
  196 +// 5522657
  197 +// a690389285100
  198 + // 目前的算法
  199 + // 时间序列,年月日时分秒 14 位
  200 + // 纯随机,6 位 TODO 芋艿:此处估计是会有问题的,后续在调整
  201 + return DateUtil.format(LocalDateTime.now(), "yyyyMMddHHmmss") + // 时间序列
  202 + RandomUtil.randomInt(100000, 999999) // 随机。为什么是这个范围,因为偷懒
  203 + ;
  204 + }
  205 +
187 206 @Override
188 207 @Transactional(rollbackFor = Exception.class)
189   - public void notifyPayRefund(Long channelId, PayRefundRespDTO notify) {
  208 + public void notifyRefund(Long channelId, PayRefundRespDTO notify) {
  209 + // 校验支付渠道是否有效
  210 + channelService.validPayChannel(channelId);
  211 + // 通知结果
  212 +
190 213 // 校验支付渠道是否有效
191   - // TODO 芋艿:需要重构下这块的逻辑
192 214 PayChannelDO channel = channelService.validPayChannel(channelId);
  215 + // 更新退款订单
  216 + TenantUtils.execute(channel.getTenantId(), () -> notifyRefund(channel, notify));
  217 + }
  218 +
  219 + private void notifyRefund(PayChannelDO channel, PayRefundRespDTO notify) {
193 220 if (PayRefundStatusRespEnum.isSuccess(notify.getStatus())) {
194   - payRefundSuccess(notify);
  221 + notifyRefundSuccess(channel, notify);
195 222 } else {
196   - // TODO @jason:那这里可以考虑打个 error logger @芋艿 微信是否存在支付异常通知
  223 + notifyRefundFailure(channel, notify);
197 224 }
198 225 }
199 226  
200   - private void payRefundSuccess(PayRefundRespDTO refundNotify) {
201   - // 校验退款单存在
202   - PayRefundDO refundDO = null; // TODO 芋艿:临时注释
203   -// PayRefundDO refundDO = refundMapper.selectByTradeNoAndMerchantRefundNo(refundNotify.getTradeNo(),
204   -// refundNotify.getReqNo());
205   - if (refundDO == null) {
206   - // TODO 芋艿:临时注释
207   -// log.error("[payRefundSuccess][不存在 seqNo 为{} 的支付退款单]", refundNotify.getReqNo());
208   - throw ServiceExceptionUtil.exception(ErrorCodeConstants.PAY_REFUND_NOT_FOUND);
  227 + private void notifyRefundSuccess(PayChannelDO channel, PayRefundRespDTO notify) {
  228 + // 1.1 查询 PayRefundDO
  229 + PayRefundDO refund = refundMapper.selectByAppIdAndNo(
  230 + channel.getAppId(), notify.getOutRefundNo());
  231 + if (refund == null) {
  232 + throw exception(ErrorCodeConstants.PAY_REFUND_NOT_FOUND);
  233 + }
  234 + if (PayRefundStatusEnum.isSuccess(refund.getStatus())) { // 如果已经是成功,直接返回,不用重复更新
  235 + return;
  236 + }
  237 + if (!PayRefundStatusEnum.WAITING.getStatus().equals(refund.getStatus())) {
  238 + throw exception(ErrorCodeConstants.PAY_REFUND_STATUS_IS_NOT_WAITING);
209 239 }
210 240  
211   - // 得到已退金额
212   - PayOrderDO payOrderDO = orderService.getOrder(refundDO.getOrderId());
213   - Long refundedAmount = payOrderDO.getRefundPrice();
214   -
215   - PayOrderStatusEnum orderStatus = PayOrderStatusEnum.SUCCESS;
216   - if(Objects.equals(payOrderDO.getPrice(), refundedAmount+ refundDO.getRefundPrice())){
217   - //支付金额 = 已退金额 + 本次退款金额。
218   - orderStatus = PayOrderStatusEnum.CLOSED;
  241 + // 1.2 更新 PayRefundDO
  242 + PayRefundDO updateRefundObj = new PayRefundDO()
  243 + .setSuccessTime(notify.getSuccessTime())
  244 + .setChannelRefundNo(notify.getChannelRefundNo())
  245 + .setStatus(PayRefundStatusEnum.SUCCESS.getStatus())
  246 + .setChannelNotifyData(toJsonString(notify));
  247 + int updateCounts = refundMapper.updateByIdAndStatus(refund.getId(), refund.getStatus(), updateRefundObj);
  248 + if (updateCounts == 0) { // 校验状态,必须是等待状态
  249 + throw exception(ErrorCodeConstants.PAY_REFUND_STATUS_IS_NOT_WAITING);
219 250 }
220   - // 更新支付订单
221   - PayOrderDO updateOrderDO = new PayOrderDO();
222   - updateOrderDO.setId(refundDO.getOrderId())
223   - .setRefundPrice(refundedAmount + refundDO.getRefundPrice())
224   - .setStatus(orderStatus.getStatus())
225   - .setRefundTimes(payOrderDO.getRefundTimes() + 1)
226   - .setRefundStatus(refundDO.getType());
227   - orderMapper.updateById(updateOrderDO);
228 251  
229   - // 更新退款订单
230   - PayRefundDO updateRefundDO = new PayRefundDO();
231   - updateRefundDO.setId(refundDO.getId())
232   - .setSuccessTime(refundNotify.getSuccessTime())
233   - // TODO 芋艿:如下两行,临时注释
234   -// .setChannelRefundNo(refundNotify.getChannelOrderNo())
235   -// .setNo(refundNotify.getTradeNo())
236   - .setStatus(PayRefundStatusEnum.SUCCESS.getStatus());
237   - refundMapper.updateById(updateRefundDO);
  252 + // 2. 更新订单
  253 + orderService.updateOrderRefundPrice(refund.getOrderId(), refund.getRefundPrice());
238 254  
239   - // 插入退款通知记录
240   - // TODO 通知商户成功或者失败. 现在通知似乎没有实现, 只是回调
  255 + // 3. 插入退款通知记录
241 256 notifyService.createPayNotifyTask(PayNotifyTaskCreateReqDTO.builder()
242   - .type(PayNotifyTypeEnum.REFUND.getType()).dataId(refundDO.getId()).build());
  257 + .type(PayNotifyTypeEnum.REFUND.getType()).dataId(refund.getId()).build());
243 258 }
244 259  
245   - /**
246   - * 校验是否进行退款
247   - *
248   - * @param reqDTO 退款申请信息
249   - * @param order 原始支付订单信息
250   - */
251   - private void validatePayRefund(PayRefundCreateReqDTO reqDTO, PayOrderDO order) {
252   - // 校验状态,必须是支付状态
253   - if (!PayOrderStatusEnum.SUCCESS.getStatus().equals(order.getStatus())) {
254   - throw ServiceExceptionUtil.exception(ErrorCodeConstants.PAY_ORDER_STATUS_IS_NOT_SUCCESS);
255   - }
256   - // 是否已经全额退款
257   - if (PayRefundTypeEnum.ALL.getStatus().equals(order.getRefundStatus())) {
258   - throw ServiceExceptionUtil.exception(ErrorCodeConstants.PAY_REFUND_ALL_REFUNDED);
259   - }
260   - // 校验金额 退款金额不能大于 原定的金额
261   - if (reqDTO.getPrice() + order.getRefundPrice() > order.getPrice()){
262   - throw ServiceExceptionUtil.exception(ErrorCodeConstants.PAY_PRICE_PRICE_EXCEED);
263   - }
264   - // 校验渠道订单号
265   - if (StrUtil.isEmpty(order.getChannelOrderNo())) {
266   - throw ServiceExceptionUtil.exception(ErrorCodeConstants.PAY_REFUND_CHN_ORDER_NO_IS_NULL);
267   - }
268   - //TODO 退款的期限 退款次数的控制
  260 + private void notifyRefundFailure(PayChannelDO channel, PayRefundRespDTO notify) {
  261 + // TODO 芋艿:未实现
269 262 }
270 263  
271 264 }
... ...
yudao-module-pay/yudao-module-pay-biz/src/test/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceTest.java
... ... @@ -13,7 +13,7 @@ import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
13 13 import cn.iocoder.yudao.module.pay.dal.mysql.order.PayOrderMapper;
14 14 import cn.iocoder.yudao.module.pay.enums.order.PayOrderNotifyStatusEnum;
15 15 import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
16   -import cn.iocoder.yudao.module.pay.enums.refund.PayRefundTypeEnum;
  16 +import cn.iocoder.yudao.module.pay.enums.order.PayOrderRefundStatusEnum;
17 17 import cn.iocoder.yudao.module.pay.service.app.PayAppService;
18 18 import cn.iocoder.yudao.module.pay.service.channel.PayChannelService;
19 19 import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService;
... ... @@ -85,7 +85,7 @@ public class PayOrderServiceTest extends BaseDbUnitTest {
85 85 o.setSuccessTime(LocalDateTime.of(2018, 1, 1, 10, 10, 2));
86 86 o.setNotifyTime(LocalDateTime.of(2018, 1, 1, 10, 10, 15));
87 87 o.setSuccessExtensionId(1L);
88   - o.setRefundStatus(PayRefundTypeEnum.NO.getStatus());
  88 + o.setRefundStatus(PayOrderRefundStatusEnum.NO.getStatus());
89 89 o.setRefundTimes(0);
90 90 o.setRefundPrice(0L);
91 91 o.setChannelUserId("1008611");
... ... @@ -106,7 +106,7 @@ public class PayOrderServiceTest extends BaseDbUnitTest {
106 106 // 测试 status 不匹配
107 107 orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setStatus(PayOrderStatusEnum.CLOSED.getStatus())));
108 108 // 测试 refundStatus 不匹配
109   - orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setRefundStatus(PayRefundTypeEnum.ALL.getStatus())));
  109 + orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setRefundStatus(PayOrderRefundStatusEnum.ALL.getStatus())));
110 110 // 测试 createTime 不匹配
111 111 orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setCreateTime(LocalDateTime.of(2019, 1, 1, 10, 10,
112 112 1))));
... ... @@ -118,7 +118,7 @@ public class PayOrderServiceTest extends BaseDbUnitTest {
118 118 reqVO.setMerchantOrderId(merchantOrderId);
119 119 reqVO.setNotifyStatus(PayOrderNotifyStatusEnum.SUCCESS.getStatus());
120 120 reqVO.setStatus(PayOrderStatusEnum.SUCCESS.getStatus());
121   - reqVO.setRefundStatus(PayRefundTypeEnum.NO.getStatus());
  121 + reqVO.setRefundStatus(PayOrderRefundStatusEnum.NO.getStatus());
122 122 reqVO.setCreateTime((new LocalDateTime[]{LocalDateTime.of(2018, 1, 1, 10, 1, 0), LocalDateTime.of(2018, 1, 1, 10, 1, 0)}));
123 123 // 调用
124 124 PageResult<PayOrderDO> pageResult = orderService.getOrderPage(reqVO);
... ... @@ -153,7 +153,7 @@ public class PayOrderServiceTest extends BaseDbUnitTest {
153 153 o.setSuccessTime(LocalDateTime.of(2018, 1, 1, 10, 10, 2));
154 154 o.setNotifyTime(LocalDateTime.of(2018, 1, 1, 10, 10, 15));
155 155 o.setSuccessExtensionId(1L);
156   - o.setRefundStatus(PayRefundTypeEnum.NO.getStatus());
  156 + o.setRefundStatus(PayOrderRefundStatusEnum.NO.getStatus());
157 157 o.setRefundTimes(0);
158 158 o.setRefundPrice(0L);
159 159 o.setChannelUserId("1008611");
... ... @@ -175,7 +175,7 @@ public class PayOrderServiceTest extends BaseDbUnitTest {
175 175 // 测试 status 不匹配
176 176 orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setStatus(PayOrderStatusEnum.CLOSED.getStatus())));
177 177 // 测试 refundStatus 不匹配
178   - orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setRefundStatus(PayRefundTypeEnum.ALL.getStatus())));
  178 + orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setRefundStatus(PayOrderRefundStatusEnum.ALL.getStatus())));
179 179 // 测试 createTime 不匹配
180 180 orderMapper.insert(cloneIgnoreId(dbOrder, o -> o.setCreateTime(LocalDateTime.of(2019, 1, 1, 10, 10,
181 181 1))));
... ... @@ -187,7 +187,7 @@ public class PayOrderServiceTest extends BaseDbUnitTest {
187 187 reqVO.setMerchantOrderId(merchantOrderId);
188 188 reqVO.setNotifyStatus(PayOrderNotifyStatusEnum.SUCCESS.getStatus());
189 189 reqVO.setStatus(PayOrderStatusEnum.SUCCESS.getStatus());
190   - reqVO.setRefundStatus(PayRefundTypeEnum.NO.getStatus());
  190 + reqVO.setRefundStatus(PayOrderRefundStatusEnum.NO.getStatus());
191 191 reqVO.setCreateTime((new LocalDateTime[]{LocalDateTime.of(2018, 1, 1, 10, 1, 0), LocalDateTime.of(2018, 1, 1, 10, 1, 0)}));
192 192  
193 193 // 调用
... ...
yudao-module-pay/yudao-module-pay-biz/src/test/java/cn/iocoder/yudao/module/pay/service/refund/PayRefundServiceTest.java
... ... @@ -11,7 +11,7 @@ import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO;
11 11 import cn.iocoder.yudao.module.pay.dal.mysql.refund.PayRefundMapper;
12 12 import cn.iocoder.yudao.module.pay.enums.order.PayOrderNotifyStatusEnum;
13 13 import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum;
14   -import cn.iocoder.yudao.module.pay.enums.refund.PayRefundTypeEnum;
  14 +import cn.iocoder.yudao.module.pay.enums.order.PayOrderRefundStatusEnum;
15 15 import cn.iocoder.yudao.module.pay.service.app.PayAppService;
16 16 import cn.iocoder.yudao.module.pay.service.channel.PayChannelService;
17 17 import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService;
... ... @@ -64,11 +64,11 @@ public class PayRefundServiceTest extends BaseDbUnitTest {
64 64 o.setOrderId(1L);
65 65 o.setNo("OT0000001");
66 66 o.setMerchantOrderId("MOT0000001");
67   - o.setMerchantRefundNo("MRF0000001");
  67 + o.setMerchantRefundId("MRF0000001");
68 68 o.setNotifyUrl("https://www.cancanzi.com");
69 69 o.setNotifyStatus(PayOrderNotifyStatusEnum.SUCCESS.getStatus());
70 70 o.setStatus(PayRefundStatusEnum.SUCCESS.getStatus());
71   - o.setType(PayRefundTypeEnum.SOME.getStatus());
  71 + o.setType(PayOrderRefundStatusEnum.PART.getStatus());
72 72 o.setPayPrice(100);
73 73 o.setRefundPrice(500);
74 74 o.setReason("就是想退款了,你有意见吗");
... ... @@ -77,10 +77,7 @@ public class PayRefundServiceTest extends BaseDbUnitTest {
77 77 o.setChannelRefundNo("CHR0000001");
78 78 o.setChannelErrorCode("");
79 79 o.setChannelErrorMsg("");
80   - o.setChannelExtras("");
81   - o.setExpireTime(LocalDateTime.of(2021, 1, 1, 10, 10, 30));
82 80 o.setSuccessTime(LocalDateTime.of(2021, 1, 1, 10, 10, 15));
83   - o.setNotifyTime(LocalDateTime.of(2021, 1, 1, 10, 10, 20));
84 81 o.setCreateTime(LocalDateTime.of(2021, 1, 1, 10, 10, 10));
85 82 o.setUpdateTime(LocalDateTime.of(2021, 1, 1, 10, 10, 35));
86 83 });
... ... @@ -90,14 +87,14 @@ public class PayRefundServiceTest extends BaseDbUnitTest {
90 87 // 测试 channelCode 不匹配
91 88 refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setChannelCode(PayChannelEnum.ALIPAY_APP.getCode())));
92 89 // 测试 merchantRefundNo 不匹配
93   - refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setMerchantRefundNo("MRF1111112")));
  90 + refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setMerchantRefundId("MRF1111112")));
94 91 // 测试 notifyStatus 不匹配
95 92 refundMapper.insert(
96 93 cloneIgnoreId(dbRefund, o -> o.setNotifyStatus(PayOrderNotifyStatusEnum.FAILURE.getStatus())));
97 94 // 测试 status 不匹配
98   - refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setStatus(PayRefundStatusEnum.CLOSE.getStatus())));
  95 + refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setStatus(PayRefundStatusEnum.FAILURE.getStatus())));
99 96 // 测试 type 不匹配
100   - refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setType(PayRefundTypeEnum.ALL.getStatus())));
  97 + refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setType(PayOrderRefundStatusEnum.ALL.getStatus())));
101 98 // 测试 createTime 不匹配
102 99 refundMapper.insert(cloneIgnoreId(dbRefund, o ->
103 100 o.setCreateTime(LocalDateTime.of(2022, 1, 1, 10, 10, 10))));
... ... @@ -108,7 +105,7 @@ public class PayRefundServiceTest extends BaseDbUnitTest {
108 105 reqVO.setMerchantRefundNo("MRF0000001");
109 106 reqVO.setNotifyStatus(PayOrderNotifyStatusEnum.SUCCESS.getStatus());
110 107 reqVO.setStatus(PayRefundStatusEnum.SUCCESS.getStatus());
111   - reqVO.setType(PayRefundTypeEnum.SOME.getStatus());
  108 + reqVO.setType(PayOrderRefundStatusEnum.PART.getStatus());
112 109 reqVO.setCreateTime((new LocalDateTime[]{LocalDateTime.of(2021, 1, 1, 10, 10, 10), LocalDateTime.of(2021, 1, 1, 10, 10, 12)}));
113 110  
114 111 // 调用
... ... @@ -129,11 +126,11 @@ public class PayRefundServiceTest extends BaseDbUnitTest {
129 126 o.setOrderId(1L);
130 127 o.setNo("OT0000001");
131 128 o.setMerchantOrderId("MOT0000001");
132   - o.setMerchantRefundNo("MRF0000001");
  129 + o.setMerchantRefundId("MRF0000001");
133 130 o.setNotifyUrl("https://www.cancanzi.com");
134 131 o.setNotifyStatus(PayOrderNotifyStatusEnum.SUCCESS.getStatus());
135 132 o.setStatus(PayRefundStatusEnum.SUCCESS.getStatus());
136   - o.setType(PayRefundTypeEnum.SOME.getStatus());
  133 + o.setType(PayOrderRefundStatusEnum.PART.getStatus());
137 134 o.setPayPrice(100);
138 135 o.setRefundPrice(500);
139 136 o.setReason("就是想退款了,你有意见吗");
... ... @@ -142,10 +139,7 @@ public class PayRefundServiceTest extends BaseDbUnitTest {
142 139 o.setChannelRefundNo("CHR0000001");
143 140 o.setChannelErrorCode("");
144 141 o.setChannelErrorMsg("");
145   - o.setChannelExtras("");
146   - o.setExpireTime(LocalDateTime.of(2021, 1, 1, 10, 10, 30));
147 142 o.setSuccessTime(LocalDateTime.of(2021, 1, 1, 10, 10, 15));
148   - o.setNotifyTime(LocalDateTime.of(2021, 1, 1, 10, 10, 20));
149 143 o.setCreateTime(LocalDateTime.of(2021, 1, 1, 10, 10, 10));
150 144 o.setUpdateTime(LocalDateTime.of(2021, 1, 1, 10, 10, 35));
151 145 });
... ... @@ -155,14 +149,14 @@ public class PayRefundServiceTest extends BaseDbUnitTest {
155 149 // 测试 channelCode 不匹配
156 150 refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setChannelCode(PayChannelEnum.ALIPAY_APP.getCode())));
157 151 // 测试 merchantRefundNo 不匹配
158   - refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setMerchantRefundNo("MRF1111112")));
  152 + refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setMerchantRefundId("MRF1111112")));
159 153 // 测试 notifyStatus 不匹配
160 154 refundMapper.insert(
161 155 cloneIgnoreId(dbRefund, o -> o.setNotifyStatus(PayOrderNotifyStatusEnum.FAILURE.getStatus())));
162 156 // 测试 status 不匹配
163   - refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setStatus(PayRefundStatusEnum.CLOSE.getStatus())));
  157 + refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setStatus(PayRefundStatusEnum.FAILURE.getStatus())));
164 158 // 测试 type 不匹配
165   - refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setType(PayRefundTypeEnum.ALL.getStatus())));
  159 + refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setType(PayOrderRefundStatusEnum.ALL.getStatus())));
166 160 // 测试 createTime 不匹配
167 161 refundMapper.insert(cloneIgnoreId(dbRefund, o ->
168 162 o.setCreateTime(LocalDateTime.of(2022, 1, 1, 10, 10, 10))));
... ... @@ -174,7 +168,7 @@ public class PayRefundServiceTest extends BaseDbUnitTest {
174 168 reqVO.setMerchantRefundNo("MRF0000001");
175 169 reqVO.setNotifyStatus(PayOrderNotifyStatusEnum.SUCCESS.getStatus());
176 170 reqVO.setStatus(PayRefundStatusEnum.SUCCESS.getStatus());
177   - reqVO.setType(PayRefundTypeEnum.SOME.getStatus());
  171 + reqVO.setType(PayOrderRefundStatusEnum.PART.getStatus());
178 172 reqVO.setCreateTime((new LocalDateTime[]{LocalDateTime.of(2021, 1, 1, 10, 10, 10), LocalDateTime.of(2021, 1, 1, 10, 10, 12)}));
179 173  
180 174 // 调用
... ...