Commit e27ec2fd50146abca9c5604e9f1c197e22d22341
1 parent
da529851
by gateway:
1. 完善部分 refund 单元测试
Showing
4 changed files
with
492 additions
and
116 deletions
yudao-module-pay/yudao-module-pay-biz/src/main/java/cn/iocoder/yudao/module/pay/service/refund/PayRefundServiceImpl.java
| 1 | package cn.iocoder.yudao.module.pay.service.refund; | 1 | package cn.iocoder.yudao.module.pay.service.refund; |
| 2 | 2 | ||
| 3 | -import cn.hutool.core.date.DateUtil; | ||
| 4 | -import cn.hutool.core.util.RandomUtil; | 3 | +import cn.hutool.extra.spring.SpringUtil; |
| 5 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 4 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 6 | import cn.iocoder.yudao.framework.pay.core.client.PayClient; | 5 | import cn.iocoder.yudao.framework.pay.core.client.PayClient; |
| 7 | import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory; | 6 | import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory; |
| @@ -16,9 +15,9 @@ import cn.iocoder.yudao.module.pay.convert.refund.PayRefundConvert; | @@ -16,9 +15,9 @@ import cn.iocoder.yudao.module.pay.convert.refund.PayRefundConvert; | ||
| 16 | import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO; | 15 | import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO; |
| 17 | import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO; | 16 | import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO; |
| 18 | import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; | 17 | import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; |
| 19 | -import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO; | ||
| 20 | import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO; | 18 | import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO; |
| 21 | import cn.iocoder.yudao.module.pay.dal.mysql.refund.PayRefundMapper; | 19 | import cn.iocoder.yudao.module.pay.dal.mysql.refund.PayRefundMapper; |
| 20 | +import cn.iocoder.yudao.module.pay.dal.redis.no.PayNoRedisDAO; | ||
| 22 | import cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants; | 21 | import cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants; |
| 23 | import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyTypeEnum; | 22 | import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyTypeEnum; |
| 24 | import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum; | 23 | import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum; |
| @@ -35,12 +34,11 @@ import org.springframework.transaction.annotation.Transactional; | @@ -35,12 +34,11 @@ import org.springframework.transaction.annotation.Transactional; | ||
| 35 | import org.springframework.validation.annotation.Validated; | 34 | import org.springframework.validation.annotation.Validated; |
| 36 | 35 | ||
| 37 | import javax.annotation.Resource; | 36 | import javax.annotation.Resource; |
| 38 | -import java.time.LocalDateTime; | ||
| 39 | import java.util.List; | 37 | import java.util.List; |
| 40 | 38 | ||
| 41 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | 39 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 42 | import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; | 40 | import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString; |
| 43 | -import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.CHANNEL_NOT_FOUND; | 41 | +import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*; |
| 44 | 42 | ||
| 45 | /** | 43 | /** |
| 46 | * 退款订单 Service 实现类 | 44 | * 退款订单 Service 实现类 |
| @@ -60,6 +58,8 @@ public class PayRefundServiceImpl implements PayRefundService { | @@ -60,6 +58,8 @@ public class PayRefundServiceImpl implements PayRefundService { | ||
| 60 | 58 | ||
| 61 | @Resource | 59 | @Resource |
| 62 | private PayRefundMapper refundMapper; | 60 | private PayRefundMapper refundMapper; |
| 61 | + @Resource | ||
| 62 | + private PayNoRedisDAO noRedisDAO; | ||
| 63 | 63 | ||
| 64 | @Resource | 64 | @Resource |
| 65 | private PayOrderService orderService; | 65 | private PayOrderService orderService; |
| @@ -112,8 +112,9 @@ public class PayRefundServiceImpl implements PayRefundService { | @@ -112,8 +112,9 @@ public class PayRefundServiceImpl implements PayRefundService { | ||
| 112 | } | 112 | } |
| 113 | 113 | ||
| 114 | // 2.1 插入退款单 | 114 | // 2.1 插入退款单 |
| 115 | + String no = noRedisDAO.generate(payProperties.getRefundNoPrefix()); | ||
| 115 | refund = PayRefundConvert.INSTANCE.convert(reqDTO) | 116 | refund = PayRefundConvert.INSTANCE.convert(reqDTO) |
| 116 | - .setNo(generateRefundNo()).setOrderId(order.getId()) | 117 | + .setNo(no).setOrderId(order.getId()) |
| 117 | .setChannelId(order.getChannelId()).setChannelCode(order.getChannelCode()) | 118 | .setChannelId(order.getChannelId()).setChannelCode(order.getChannelCode()) |
| 118 | // 商户相关的字段 | 119 | // 商户相关的字段 |
| 119 | .setNotifyUrl(app.getRefundNotifyUrl()) | 120 | .setNotifyUrl(app.getRefundNotifyUrl()) |
| @@ -123,20 +124,27 @@ public class PayRefundServiceImpl implements PayRefundService { | @@ -123,20 +124,27 @@ public class PayRefundServiceImpl implements PayRefundService { | ||
| 123 | .setStatus(PayRefundStatusEnum.WAITING.getStatus()) | 124 | .setStatus(PayRefundStatusEnum.WAITING.getStatus()) |
| 124 | .setPayPrice(order.getPrice()).setRefundPrice(reqDTO.getPrice()); | 125 | .setPayPrice(order.getPrice()).setRefundPrice(reqDTO.getPrice()); |
| 125 | refundMapper.insert(refund); | 126 | refundMapper.insert(refund); |
| 126 | - // 2.2 向渠道发起退款申请 | ||
| 127 | - PayOrderExtensionDO orderExtension = orderService.getOrderExtension(order.getExtensionId()); | ||
| 128 | - PayRefundUnifiedReqDTO unifiedReqDTO = new PayRefundUnifiedReqDTO() | ||
| 129 | - .setPayPrice(order.getPrice()) | ||
| 130 | - .setRefundPrice(reqDTO.getPrice()) | ||
| 131 | - .setOutTradeNo(orderExtension.getNo()) | ||
| 132 | - .setOutRefundNo(refund.getNo()) | ||
| 133 | - .setNotifyUrl(genChannelRefundNotifyUrl(channel)) | ||
| 134 | - .setReason(reqDTO.getReason()); | ||
| 135 | - PayRefundRespDTO refundRespDTO = client.unifiedRefund(unifiedReqDTO); | ||
| 136 | - // 2.3 处理退款返回 | ||
| 137 | - notifyRefund(channel, refundRespDTO); | 127 | + try { |
| 128 | + // 2.2 向渠道发起退款申请 | ||
| 129 | + PayRefundUnifiedReqDTO unifiedReqDTO = new PayRefundUnifiedReqDTO() | ||
| 130 | + .setPayPrice(order.getPrice()) | ||
| 131 | + .setRefundPrice(reqDTO.getPrice()) | ||
| 132 | + .setOutTradeNo(order.getNo()) | ||
| 133 | + .setOutRefundNo(refund.getNo()) | ||
| 134 | + .setNotifyUrl(genChannelRefundNotifyUrl(channel)) | ||
| 135 | + .setReason(reqDTO.getReason()); | ||
| 136 | + PayRefundRespDTO refundRespDTO = client.unifiedRefund(unifiedReqDTO); | ||
| 137 | + // 2.3 处理退款返回 | ||
| 138 | + getSelf().notifyRefund(channel, refundRespDTO); | ||
| 139 | + } catch (Throwable e) { | ||
| 140 | + // 注意:这里仅打印异常,不进行抛出。 | ||
| 141 | + // 原因是:虽然调用支付渠道进行退款发生异常(网络请求超时),实际退款成功。这个结果,后续通过退款回调、或者退款轮询补偿可以拿到。 | ||
| 142 | + // 最终,在异常的情况下,支付中心会异步回调业务的退款回调接口,提供退款结果 | ||
| 143 | + log.error("[createPayRefund][退款 id({}) requestDTO({}) 发生异常]", | ||
| 144 | + refund.getId(), reqDTO, e); | ||
| 145 | + } | ||
| 138 | 146 | ||
| 139 | - // 成功在 退款回调中处理 | 147 | + // 返回退款编号 |
| 140 | return refund.getId(); | 148 | return refund.getId(); |
| 141 | } | 149 | } |
| 142 | 150 | ||
| @@ -151,12 +159,12 @@ public class PayRefundServiceImpl implements PayRefundService { | @@ -151,12 +159,12 @@ public class PayRefundServiceImpl implements PayRefundService { | ||
| 151 | if (order == null) { | 159 | if (order == null) { |
| 152 | throw exception(ErrorCodeConstants.ORDER_NOT_FOUND); | 160 | throw exception(ErrorCodeConstants.ORDER_NOT_FOUND); |
| 153 | } | 161 | } |
| 154 | - // 校验状态,必须是支付状态 | ||
| 155 | - if (!PayOrderStatusEnum.SUCCESS.getStatus().equals(order.getStatus())) { | ||
| 156 | - throw exception(ErrorCodeConstants.ORDER_STATUS_IS_NOT_SUCCESS); | 162 | + // 校验状态,必须是已支付、或者已退款 |
| 163 | + if (!PayOrderStatusEnum.isSuccessOrRefund(order.getStatus())) { | ||
| 164 | + throw exception(ORDER_REFUND_FAIL_STATUS_ERROR); | ||
| 157 | } | 165 | } |
| 158 | 166 | ||
| 159 | - // 校验金额 退款金额不能大于原定的金额 | 167 | + // 校验金额,退款金额不能大于原定的金额 |
| 160 | if (reqDTO.getPrice() + order.getRefundPrice() > order.getPrice()){ | 168 | if (reqDTO.getPrice() + order.getRefundPrice() > order.getPrice()){ |
| 161 | throw exception(ErrorCodeConstants.REFUND_PRICE_EXCEED); | 169 | throw exception(ErrorCodeConstants.REFUND_PRICE_EXCEED); |
| 162 | } | 170 | } |
| @@ -178,38 +186,22 @@ public class PayRefundServiceImpl implements PayRefundService { | @@ -178,38 +186,22 @@ public class PayRefundServiceImpl implements PayRefundService { | ||
| 178 | return payProperties.getRefundNotifyUrl() + "/" + channel.getId(); | 186 | return payProperties.getRefundNotifyUrl() + "/" + channel.getId(); |
| 179 | } | 187 | } |
| 180 | 188 | ||
| 181 | - private String generateRefundNo() { | ||
| 182 | -// wx | ||
| 183 | -// 2014 | ||
| 184 | -// 10 | ||
| 185 | -// 27 | ||
| 186 | -// 20 | ||
| 187 | -// 09 | ||
| 188 | -// 39 | ||
| 189 | -// 5522657 | ||
| 190 | -// a690389285100 | ||
| 191 | - // 目前的算法 | ||
| 192 | - // 时间序列,年月日时分秒 14 位 | ||
| 193 | - // 纯随机,6 位 TODO 芋艿:此处估计是会有问题的,后续在调整 | ||
| 194 | - return DateUtil.format(LocalDateTime.now(), "yyyyMMddHHmmss") + // 时间序列 | ||
| 195 | - RandomUtil.randomInt(100000, 999999) // 随机。为什么是这个范围,因为偷懒 | ||
| 196 | - ; | ||
| 197 | - } | ||
| 198 | - | ||
| 199 | @Override | 189 | @Override |
| 200 | public void notifyRefund(Long channelId, PayRefundRespDTO notify) { | 190 | public void notifyRefund(Long channelId, PayRefundRespDTO notify) { |
| 201 | // 校验支付渠道是否有效 | 191 | // 校验支付渠道是否有效 |
| 202 | - channelService.validPayChannel(channelId); | ||
| 203 | - // 通知结果 | ||
| 204 | - | ||
| 205 | - // 校验支付渠道是否有效 | ||
| 206 | PayChannelDO channel = channelService.validPayChannel(channelId); | 192 | PayChannelDO channel = channelService.validPayChannel(channelId); |
| 207 | // 更新退款订单 | 193 | // 更新退款订单 |
| 208 | - TenantUtils.execute(channel.getTenantId(), () -> notifyRefund(channel, notify)); | 194 | + TenantUtils.execute(channel.getTenantId(), () -> getSelf().notifyRefund(channel, notify)); |
| 209 | } | 195 | } |
| 210 | 196 | ||
| 211 | - // TODO 芋艿:事务问题 | ||
| 212 | - private void notifyRefund(PayChannelDO channel, PayRefundRespDTO notify) { | 197 | + /** |
| 198 | + * 通知并更新订单的退款结果 | ||
| 199 | + * | ||
| 200 | + * @param channel 支付渠道 | ||
| 201 | + * @param notify 通知 | ||
| 202 | + */ | ||
| 203 | + @Transactional(rollbackFor = Exception.class) // 注意,如果是方法内调用该方法,需要通过 getSelf().notifyRefund(channel, notify) 调用,否则事务不生效 | ||
| 204 | + public void notifyRefund(PayChannelDO channel, PayRefundRespDTO notify) { | ||
| 213 | // 情况一:退款成功 | 205 | // 情况一:退款成功 |
| 214 | if (PayRefundStatusRespEnum.isSuccess(notify.getStatus())) { | 206 | if (PayRefundStatusRespEnum.isSuccess(notify.getStatus())) { |
| 215 | notifyRefundSuccess(channel, notify); | 207 | notifyRefundSuccess(channel, notify); |
| @@ -226,14 +218,14 @@ public class PayRefundServiceImpl implements PayRefundService { | @@ -226,14 +218,14 @@ public class PayRefundServiceImpl implements PayRefundService { | ||
| 226 | PayRefundDO refund = refundMapper.selectByAppIdAndNo( | 218 | PayRefundDO refund = refundMapper.selectByAppIdAndNo( |
| 227 | channel.getAppId(), notify.getOutRefundNo()); | 219 | channel.getAppId(), notify.getOutRefundNo()); |
| 228 | if (refund == null) { | 220 | if (refund == null) { |
| 229 | - throw exception(ErrorCodeConstants.REFUND_NOT_FOUND); | 221 | + throw exception(REFUND_NOT_FOUND); |
| 230 | } | 222 | } |
| 231 | if (PayRefundStatusEnum.isSuccess(refund.getStatus())) { // 如果已经是成功,直接返回,不用重复更新 | 223 | if (PayRefundStatusEnum.isSuccess(refund.getStatus())) { // 如果已经是成功,直接返回,不用重复更新 |
| 232 | log.info("[notifyRefundSuccess][退款订单({}) 已经是退款成功,无需更新]", refund.getId()); | 224 | log.info("[notifyRefundSuccess][退款订单({}) 已经是退款成功,无需更新]", refund.getId()); |
| 233 | return; | 225 | return; |
| 234 | } | 226 | } |
| 235 | if (!PayRefundStatusEnum.WAITING.getStatus().equals(refund.getStatus())) { | 227 | if (!PayRefundStatusEnum.WAITING.getStatus().equals(refund.getStatus())) { |
| 236 | - throw exception(ErrorCodeConstants.REFUND_STATUS_IS_NOT_WAITING); | 228 | + throw exception(REFUND_STATUS_IS_NOT_WAITING); |
| 237 | } | 229 | } |
| 238 | // 1.2 更新 PayRefundDO | 230 | // 1.2 更新 PayRefundDO |
| 239 | PayRefundDO updateRefundObj = new PayRefundDO() | 231 | PayRefundDO updateRefundObj = new PayRefundDO() |
| @@ -243,7 +235,7 @@ public class PayRefundServiceImpl implements PayRefundService { | @@ -243,7 +235,7 @@ public class PayRefundServiceImpl implements PayRefundService { | ||
| 243 | .setChannelNotifyData(toJsonString(notify)); | 235 | .setChannelNotifyData(toJsonString(notify)); |
| 244 | int updateCounts = refundMapper.updateByIdAndStatus(refund.getId(), refund.getStatus(), updateRefundObj); | 236 | int updateCounts = refundMapper.updateByIdAndStatus(refund.getId(), refund.getStatus(), updateRefundObj); |
| 245 | if (updateCounts == 0) { // 校验状态,必须是等待状态 | 237 | if (updateCounts == 0) { // 校验状态,必须是等待状态 |
| 246 | - throw exception(ErrorCodeConstants.REFUND_STATUS_IS_NOT_WAITING); | 238 | + throw exception(REFUND_STATUS_IS_NOT_WAITING); |
| 247 | } | 239 | } |
| 248 | log.info("[notifyRefundSuccess][退款订单({}) 更新为退款成功]", refund.getId()); | 240 | log.info("[notifyRefundSuccess][退款订单({}) 更新为退款成功]", refund.getId()); |
| 249 | 241 | ||
| @@ -261,14 +253,14 @@ public class PayRefundServiceImpl implements PayRefundService { | @@ -261,14 +253,14 @@ public class PayRefundServiceImpl implements PayRefundService { | ||
| 261 | PayRefundDO refund = refundMapper.selectByAppIdAndNo( | 253 | PayRefundDO refund = refundMapper.selectByAppIdAndNo( |
| 262 | channel.getAppId(), notify.getOutRefundNo()); | 254 | channel.getAppId(), notify.getOutRefundNo()); |
| 263 | if (refund == null) { | 255 | if (refund == null) { |
| 264 | - throw exception(ErrorCodeConstants.REFUND_NOT_FOUND); | 256 | + throw exception(REFUND_NOT_FOUND); |
| 265 | } | 257 | } |
| 266 | if (PayRefundStatusEnum.isFailure(refund.getStatus())) { // 如果已经是成功,直接返回,不用重复更新 | 258 | if (PayRefundStatusEnum.isFailure(refund.getStatus())) { // 如果已经是成功,直接返回,不用重复更新 |
| 267 | log.info("[notifyRefundSuccess][退款订单({}) 已经是退款关闭,无需更新]", refund.getId()); | 259 | log.info("[notifyRefundSuccess][退款订单({}) 已经是退款关闭,无需更新]", refund.getId()); |
| 268 | return; | 260 | return; |
| 269 | } | 261 | } |
| 270 | if (!PayRefundStatusEnum.WAITING.getStatus().equals(refund.getStatus())) { | 262 | if (!PayRefundStatusEnum.WAITING.getStatus().equals(refund.getStatus())) { |
| 271 | - throw exception(ErrorCodeConstants.REFUND_STATUS_IS_NOT_WAITING); | 263 | + throw exception(REFUND_STATUS_IS_NOT_WAITING); |
| 272 | } | 264 | } |
| 273 | // 1.2 更新 PayRefundDO | 265 | // 1.2 更新 PayRefundDO |
| 274 | PayRefundDO updateRefundObj = new PayRefundDO() | 266 | PayRefundDO updateRefundObj = new PayRefundDO() |
| @@ -278,7 +270,7 @@ public class PayRefundServiceImpl implements PayRefundService { | @@ -278,7 +270,7 @@ public class PayRefundServiceImpl implements PayRefundService { | ||
| 278 | .setChannelErrorCode(notify.getChannelErrorCode()).setChannelErrorMsg(notify.getChannelErrorMsg()); | 270 | .setChannelErrorCode(notify.getChannelErrorCode()).setChannelErrorMsg(notify.getChannelErrorMsg()); |
| 279 | int updateCounts = refundMapper.updateByIdAndStatus(refund.getId(), refund.getStatus(), updateRefundObj); | 271 | int updateCounts = refundMapper.updateByIdAndStatus(refund.getId(), refund.getStatus(), updateRefundObj); |
| 280 | if (updateCounts == 0) { // 校验状态,必须是等待状态 | 272 | if (updateCounts == 0) { // 校验状态,必须是等待状态 |
| 281 | - throw exception(ErrorCodeConstants.REFUND_STATUS_IS_NOT_WAITING); | 273 | + throw exception(REFUND_STATUS_IS_NOT_WAITING); |
| 282 | } | 274 | } |
| 283 | log.info("[notifyRefundFailure][退款订单({}) 更新为退款失败]", refund.getId()); | 275 | log.info("[notifyRefundFailure][退款订单({}) 更新为退款失败]", refund.getId()); |
| 284 | 276 | ||
| @@ -287,4 +279,13 @@ public class PayRefundServiceImpl implements PayRefundService { | @@ -287,4 +279,13 @@ public class PayRefundServiceImpl implements PayRefundService { | ||
| 287 | .type(PayNotifyTypeEnum.REFUND.getType()).dataId(refund.getId()).build()); | 279 | .type(PayNotifyTypeEnum.REFUND.getType()).dataId(refund.getId()).build()); |
| 288 | } | 280 | } |
| 289 | 281 | ||
| 282 | + /** | ||
| 283 | + * 获得自身的代理对象,解决 AOP 生效问题 | ||
| 284 | + * | ||
| 285 | + * @return 自己 | ||
| 286 | + */ | ||
| 287 | + private PayRefundServiceImpl getSelf() { | ||
| 288 | + return SpringUtil.getBean(getClass()); | ||
| 289 | + } | ||
| 290 | + | ||
| 290 | } | 291 | } |
yudao-module-pay/yudao-module-pay-biz/src/test/java/cn/iocoder/yudao/module/pay/service/order/PayOrderServiceTest.java
| @@ -30,7 +30,6 @@ import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService; | @@ -30,7 +30,6 @@ import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService; | ||
| 30 | import cn.iocoder.yudao.module.pay.service.notify.dto.PayNotifyTaskCreateReqDTO; | 30 | import cn.iocoder.yudao.module.pay.service.notify.dto.PayNotifyTaskCreateReqDTO; |
| 31 | import org.junit.jupiter.api.BeforeEach; | 31 | import org.junit.jupiter.api.BeforeEach; |
| 32 | import org.junit.jupiter.api.Test; | 32 | import org.junit.jupiter.api.Test; |
| 33 | -import org.mockito.ArgumentMatcher; | ||
| 34 | import org.mockito.MockedStatic; | 33 | import org.mockito.MockedStatic; |
| 35 | import org.springframework.boot.test.mock.mockito.MockBean; | 34 | import org.springframework.boot.test.mock.mockito.MockBean; |
| 36 | import org.springframework.context.annotation.Import; | 35 | import org.springframework.context.annotation.Import; |
| @@ -44,8 +43,7 @@ import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString | @@ -44,8 +43,7 @@ import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString | ||
| 44 | import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; | 43 | import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; |
| 45 | import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; | 44 | import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; |
| 46 | import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; | 45 | import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; |
| 47 | -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; | ||
| 48 | -import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString; | 46 | +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; |
| 49 | import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*; | 47 | import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*; |
| 50 | import static org.assertj.core.api.Assertions.assertThat; | 48 | import static org.assertj.core.api.Assertions.assertThat; |
| 51 | import static org.junit.jupiter.api.Assertions.assertEquals; | 49 | import static org.junit.jupiter.api.Assertions.assertEquals; |
| @@ -86,6 +84,51 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest { | @@ -86,6 +84,51 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest { | ||
| 86 | } | 84 | } |
| 87 | 85 | ||
| 88 | @Test | 86 | @Test |
| 87 | + public void testGetOrder_id() { | ||
| 88 | + // mock 数据(PayOrderDO) | ||
| 89 | + PayOrderDO order = randomPojo(PayOrderDO.class); | ||
| 90 | + orderMapper.insert(order); | ||
| 91 | + // 准备参数 | ||
| 92 | + Long id = order.getId(); | ||
| 93 | + | ||
| 94 | + // 调用 | ||
| 95 | + PayOrderDO dbOrder = orderService.getOrder(id); | ||
| 96 | + // 断言 | ||
| 97 | + assertPojoEquals(dbOrder, order); | ||
| 98 | + } | ||
| 99 | + | ||
| 100 | + @Test | ||
| 101 | + public void testGetOrder_appIdAndMerchantOrderId() { | ||
| 102 | + // mock 数据(PayOrderDO) | ||
| 103 | + PayOrderDO order = randomPojo(PayOrderDO.class); | ||
| 104 | + orderMapper.insert(order); | ||
| 105 | + // 准备参数 | ||
| 106 | + Long appId = order.getAppId(); | ||
| 107 | + String merchantOrderId = order.getMerchantOrderId(); | ||
| 108 | + | ||
| 109 | + // 调用 | ||
| 110 | + PayOrderDO dbOrder = orderService.getOrder(appId, merchantOrderId); | ||
| 111 | + // 断言 | ||
| 112 | + assertPojoEquals(dbOrder, order); | ||
| 113 | + } | ||
| 114 | + | ||
| 115 | + @Test | ||
| 116 | + public void testGetOrderCountByAppId() { | ||
| 117 | + // mock 数据(PayOrderDO) | ||
| 118 | + PayOrderDO order01 = randomPojo(PayOrderDO.class); | ||
| 119 | + orderMapper.insert(order01); | ||
| 120 | + PayOrderDO order02 = randomPojo(PayOrderDO.class); | ||
| 121 | + orderMapper.insert(order02); | ||
| 122 | + // 准备参数 | ||
| 123 | + Long appId = order01.getAppId(); | ||
| 124 | + | ||
| 125 | + // 调用 | ||
| 126 | + Long count = orderService.getOrderCountByAppId(appId); | ||
| 127 | + // 断言 | ||
| 128 | + assertEquals(count, 1L); | ||
| 129 | + } | ||
| 130 | + | ||
| 131 | + @Test | ||
| 89 | public void testGetOrderPage() { | 132 | public void testGetOrderPage() { |
| 90 | // mock 数据 | 133 | // mock 数据 |
| 91 | PayOrderDO dbOrder = randomPojo(PayOrderDO.class, o -> { // 等会查询到 | 134 | PayOrderDO dbOrder = randomPojo(PayOrderDO.class, o -> { // 等会查询到 |
| @@ -350,7 +393,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest { | @@ -350,7 +393,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest { | ||
| 350 | // mock 方法(client) | 393 | // mock 方法(client) |
| 351 | PayClient client = mock(PayClient.class); | 394 | PayClient client = mock(PayClient.class); |
| 352 | when(payClientFactory.getPayClient(eq(10L))).thenReturn(client); | 395 | when(payClientFactory.getPayClient(eq(10L))).thenReturn(client); |
| 353 | - // mock 方法() | 396 | + // mock 方法(支付渠道的调用) |
| 354 | PayOrderRespDTO unifiedOrderResp = randomPojo(PayOrderRespDTO.class, o -> o.setChannelErrorCode(null).setChannelErrorMsg(null) | 397 | PayOrderRespDTO unifiedOrderResp = randomPojo(PayOrderRespDTO.class, o -> o.setChannelErrorCode(null).setChannelErrorMsg(null) |
| 355 | .setDisplayMode(PayOrderDisplayModeEnum.URL.getMode()).setDisplayContent("tudou")); | 398 | .setDisplayMode(PayOrderDisplayModeEnum.URL.getMode()).setDisplayContent("tudou")); |
| 356 | when(client.unifiedOrder(argThat(payOrderUnifiedReqDTO -> { | 399 | when(client.unifiedOrder(argThat(payOrderUnifiedReqDTO -> { |
| @@ -553,14 +596,193 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest { | @@ -553,14 +596,193 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest { | ||
| 553 | assertPojoEquals(order, orderMapper.selectOne(null), | 596 | assertPojoEquals(order, orderMapper.selectOne(null), |
| 554 | "updateTime", "updater"); | 597 | "updateTime", "updater"); |
| 555 | // 断言,调用 | 598 | // 断言,调用 |
| 556 | - verify(notifyService).createPayNotifyTask(argThat(new ArgumentMatcher<PayNotifyTaskCreateReqDTO>() { | ||
| 557 | - @Override | ||
| 558 | - public boolean matches(PayNotifyTaskCreateReqDTO reqDTO) { | ||
| 559 | - assertEquals(reqDTO.getType(), PayNotifyTypeEnum.ORDER.getType()); | ||
| 560 | - assertEquals(reqDTO.getDataId(), orderExtension.getOrderId()); | ||
| 561 | - return true; | ||
| 562 | - } | 599 | + verify(notifyService).createPayNotifyTask(argThat(reqDTO -> { |
| 600 | + assertEquals(reqDTO.getType(), PayNotifyTypeEnum.ORDER.getType()); | ||
| 601 | + assertEquals(reqDTO.getDataId(), orderExtension.getOrderId()); | ||
| 602 | + return true; | ||
| 563 | })); | 603 | })); |
| 564 | } | 604 | } |
| 565 | 605 | ||
| 606 | + @Test | ||
| 607 | + public void testNotifyOrderClosed_orderExtension_notFound() { | ||
| 608 | + // 准备参数 | ||
| 609 | + PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L)); | ||
| 610 | + PayOrderRespDTO notify = randomPojo(PayOrderRespDTO.class, | ||
| 611 | + o -> o.setStatus(PayOrderStatusRespEnum.CLOSED.getStatus())); | ||
| 612 | + | ||
| 613 | + // 调用,并断言异常 | ||
| 614 | + assertServiceException(() -> orderService.notifyOrder(channel, notify), | ||
| 615 | + ORDER_EXTENSION_NOT_FOUND); | ||
| 616 | + } | ||
| 617 | + | ||
| 618 | + @Test | ||
| 619 | + public void testNotifyOrderClosed_orderExtension_closed() { | ||
| 620 | + // mock 数据(PayOrderExtensionDO) | ||
| 621 | + PayOrderExtensionDO orderExtension = randomPojo(PayOrderExtensionDO.class, | ||
| 622 | + o -> o.setStatus(PayOrderStatusEnum.CLOSED.getStatus()) | ||
| 623 | + .setNo("P110")); | ||
| 624 | + orderExtensionMapper.insert(orderExtension); | ||
| 625 | + // 准备参数 | ||
| 626 | + PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L)); | ||
| 627 | + PayOrderRespDTO notify = randomPojo(PayOrderRespDTO.class, | ||
| 628 | + o -> o.setStatus(PayOrderStatusRespEnum.CLOSED.getStatus()) | ||
| 629 | + .setOutTradeNo("P110")); | ||
| 630 | + | ||
| 631 | + // 调用,并断言 | ||
| 632 | + orderService.notifyOrder(channel, notify); | ||
| 633 | + // 断言 PayOrderExtensionDO :数据未更新,因为它是 CLOSED | ||
| 634 | + assertPojoEquals(orderExtension, orderExtensionMapper.selectOne(null)); | ||
| 635 | + } | ||
| 636 | + | ||
| 637 | + @Test | ||
| 638 | + public void testNotifyOrderClosed_orderExtension_paid() { | ||
| 639 | + // mock 数据(PayOrderExtensionDO) | ||
| 640 | + PayOrderExtensionDO orderExtension = randomPojo(PayOrderExtensionDO.class, | ||
| 641 | + o -> o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus()) | ||
| 642 | + .setNo("P110")); | ||
| 643 | + orderExtensionMapper.insert(orderExtension); | ||
| 644 | + // 准备参数 | ||
| 645 | + PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L)); | ||
| 646 | + PayOrderRespDTO notify = randomPojo(PayOrderRespDTO.class, | ||
| 647 | + o -> o.setStatus(PayOrderStatusRespEnum.CLOSED.getStatus()) | ||
| 648 | + .setOutTradeNo("P110")); | ||
| 649 | + | ||
| 650 | + // 调用,并断言 | ||
| 651 | + orderService.notifyOrder(channel, notify); | ||
| 652 | + // 断言 PayOrderExtensionDO :数据未更新,因为它是 SUCCESS | ||
| 653 | + assertPojoEquals(orderExtension, orderExtensionMapper.selectOne(null)); | ||
| 654 | + } | ||
| 655 | + | ||
| 656 | + @Test | ||
| 657 | + public void testNotifyOrderClosed_orderExtension_refund() { | ||
| 658 | + // mock 数据(PayOrderExtensionDO) | ||
| 659 | + PayOrderExtensionDO orderExtension = randomPojo(PayOrderExtensionDO.class, | ||
| 660 | + o -> o.setStatus(PayOrderStatusEnum.REFUND.getStatus()) | ||
| 661 | + .setNo("P110")); | ||
| 662 | + orderExtensionMapper.insert(orderExtension); | ||
| 663 | + // 准备参数 | ||
| 664 | + PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L)); | ||
| 665 | + PayOrderRespDTO notify = randomPojo(PayOrderRespDTO.class, | ||
| 666 | + o -> o.setStatus(PayOrderStatusRespEnum.CLOSED.getStatus()) | ||
| 667 | + .setOutTradeNo("P110")); | ||
| 668 | + | ||
| 669 | + // 调用,并断言异常 | ||
| 670 | + assertServiceException(() -> orderService.notifyOrder(channel, notify), | ||
| 671 | + ORDER_EXTENSION_STATUS_IS_NOT_WAITING); | ||
| 672 | + } | ||
| 673 | + | ||
| 674 | + @Test | ||
| 675 | + public void testNotifyOrderClosed_orderExtension_waiting() { | ||
| 676 | + // mock 数据(PayOrderExtensionDO) | ||
| 677 | + PayOrderExtensionDO orderExtension = randomPojo(PayOrderExtensionDO.class, | ||
| 678 | + o -> o.setStatus(PayOrderStatusEnum.WAITING.getStatus()) | ||
| 679 | + .setNo("P110")); | ||
| 680 | + orderExtensionMapper.insert(orderExtension); | ||
| 681 | + // 准备参数 | ||
| 682 | + PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L)); | ||
| 683 | + PayOrderRespDTO notify = randomPojo(PayOrderRespDTO.class, | ||
| 684 | + o -> o.setStatus(PayOrderStatusRespEnum.CLOSED.getStatus()) | ||
| 685 | + .setOutTradeNo("P110")); | ||
| 686 | + | ||
| 687 | + // 调用 | ||
| 688 | + orderService.notifyOrder(channel, notify); | ||
| 689 | + // 断言 PayOrderExtensionDO | ||
| 690 | + orderExtension.setStatus(PayOrderStatusEnum.CLOSED.getStatus()).setChannelNotifyData(toJsonString(notify)) | ||
| 691 | + .setChannelErrorCode(notify.getChannelErrorCode()).setChannelErrorMsg(notify.getChannelErrorMsg()); | ||
| 692 | + assertPojoEquals(orderExtension, orderExtensionMapper.selectOne(null), | ||
| 693 | + "updateTime", "updater"); | ||
| 694 | + } | ||
| 695 | + | ||
| 696 | + @Test | ||
| 697 | + public void testUpdateOrderRefundPrice_notFound() { | ||
| 698 | + // 准备参数 | ||
| 699 | + Long id = randomLongId(); | ||
| 700 | + Integer incrRefundPrice = randomInteger(); | ||
| 701 | + | ||
| 702 | + // 调用,并断言异常 | ||
| 703 | + assertServiceException(() -> orderService.updateOrderRefundPrice(id, incrRefundPrice), | ||
| 704 | + ORDER_NOT_FOUND); | ||
| 705 | + } | ||
| 706 | + | ||
| 707 | + @Test | ||
| 708 | + public void testUpdateOrderRefundPrice_waiting() { | ||
| 709 | + testUpdateOrderRefundPrice_waitingOrClosed(PayOrderStatusEnum.WAITING.getStatus()); | ||
| 710 | + } | ||
| 711 | + | ||
| 712 | + @Test | ||
| 713 | + public void testUpdateOrderRefundPrice_closed() { | ||
| 714 | + testUpdateOrderRefundPrice_waitingOrClosed(PayOrderStatusEnum.CLOSED.getStatus()); | ||
| 715 | + } | ||
| 716 | + | ||
| 717 | + private void testUpdateOrderRefundPrice_waitingOrClosed(Integer status) { | ||
| 718 | + // mock 数据(PayOrderDO) | ||
| 719 | + PayOrderDO order = randomPojo(PayOrderDO.class, | ||
| 720 | + o -> o.setStatus(status)); | ||
| 721 | + orderMapper.insert(order); | ||
| 722 | + // 准备参数 | ||
| 723 | + Long id = order.getId(); | ||
| 724 | + Integer incrRefundPrice = randomInteger(); | ||
| 725 | + | ||
| 726 | + // 调用,并断言异常 | ||
| 727 | + assertServiceException(() -> orderService.updateOrderRefundPrice(id, incrRefundPrice), | ||
| 728 | + ORDER_REFUND_FAIL_STATUS_ERROR); | ||
| 729 | + } | ||
| 730 | + | ||
| 731 | + @Test | ||
| 732 | + public void testUpdateOrderRefundPrice_priceExceed() { | ||
| 733 | + // mock 数据(PayOrderDO) | ||
| 734 | + PayOrderDO order = randomPojo(PayOrderDO.class, | ||
| 735 | + o -> o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus()) | ||
| 736 | + .setRefundPrice(1).setPrice(10)); | ||
| 737 | + orderMapper.insert(order); | ||
| 738 | + // 准备参数 | ||
| 739 | + Long id = order.getId(); | ||
| 740 | + Integer incrRefundPrice = 10; | ||
| 741 | + | ||
| 742 | + // 调用,并断言异常 | ||
| 743 | + assertServiceException(() -> orderService.updateOrderRefundPrice(id, incrRefundPrice), | ||
| 744 | + REFUND_PRICE_EXCEED); | ||
| 745 | + } | ||
| 746 | + | ||
| 747 | + @Test | ||
| 748 | + public void testUpdateOrderRefundPrice_refund() { | ||
| 749 | + testUpdateOrderRefundPrice_refundOrSuccess(PayOrderStatusEnum.REFUND.getStatus()); | ||
| 750 | + } | ||
| 751 | + | ||
| 752 | + @Test | ||
| 753 | + public void testUpdateOrderRefundPrice_success() { | ||
| 754 | + testUpdateOrderRefundPrice_refundOrSuccess(PayOrderStatusEnum.SUCCESS.getStatus()); | ||
| 755 | + } | ||
| 756 | + | ||
| 757 | + private void testUpdateOrderRefundPrice_refundOrSuccess(Integer status) { | ||
| 758 | + // mock 数据(PayOrderDO) | ||
| 759 | + PayOrderDO order = randomPojo(PayOrderDO.class, | ||
| 760 | + o -> o.setStatus(status).setRefundPrice(1).setPrice(10)); | ||
| 761 | + orderMapper.insert(order); | ||
| 762 | + // 准备参数 | ||
| 763 | + Long id = order.getId(); | ||
| 764 | + Integer incrRefundPrice = 8; | ||
| 765 | + | ||
| 766 | + // 调用 | ||
| 767 | + orderService.updateOrderRefundPrice(id, incrRefundPrice); | ||
| 768 | + // 断言 | ||
| 769 | + order.setRefundPrice(9).setStatus(PayOrderStatusEnum.REFUND.getStatus()); | ||
| 770 | + assertPojoEquals(order, orderMapper.selectOne(null), | ||
| 771 | + "updateTime", "updater"); | ||
| 772 | + } | ||
| 773 | + | ||
| 774 | + @Test | ||
| 775 | + public void testGetOrderExtension() { | ||
| 776 | + // mock 数据(PayOrderExtensionDO) | ||
| 777 | + PayOrderExtensionDO orderExtension = randomPojo(PayOrderExtensionDO.class); | ||
| 778 | + orderExtensionMapper.insert(orderExtension); | ||
| 779 | + // 准备参数 | ||
| 780 | + Long id = orderExtension.getId(); | ||
| 781 | + | ||
| 782 | + // 调用 | ||
| 783 | + PayOrderExtensionDO dbOrderExtension = orderService.getOrderExtension(id); | ||
| 784 | + // 断言 | ||
| 785 | + assertPojoEquals(dbOrderExtension, orderExtension); | ||
| 786 | + } | ||
| 787 | + | ||
| 566 | } | 788 | } |
yudao-module-pay/yudao-module-pay-biz/src/test/java/cn/iocoder/yudao/module/pay/service/refund/PayRefundServiceTest.java
| 1 | package cn.iocoder.yudao.module.pay.service.refund; | 1 | package cn.iocoder.yudao.module.pay.service.refund; |
| 2 | 2 | ||
| 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; | 3 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 4 | +import cn.iocoder.yudao.framework.pay.core.client.PayClient; | ||
| 4 | import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory; | 5 | import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory; |
| 5 | import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; | 6 | import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum; |
| 6 | import cn.iocoder.yudao.framework.test.core.ut.BaseDbAndRedisUnitTest; | 7 | import cn.iocoder.yudao.framework.test.core.ut.BaseDbAndRedisUnitTest; |
| 7 | import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; | 8 | import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; |
| 8 | -import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundExportReqVO; | 9 | +import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO;import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundExportReqVO; |
| 9 | import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundPageReqVO; | 10 | import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundPageReqVO; |
| 11 | +import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO; | ||
| 12 | +import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO; | ||
| 13 | +import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO; | ||
| 10 | import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO; | 14 | import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO; |
| 11 | import cn.iocoder.yudao.module.pay.dal.mysql.refund.PayRefundMapper; | 15 | import cn.iocoder.yudao.module.pay.dal.mysql.refund.PayRefundMapper; |
| 16 | +import cn.iocoder.yudao.module.pay.dal.redis.no.PayNoRedisDAO; | ||
| 12 | import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum; | 17 | import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum; |
| 13 | import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum; | 18 | import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum; |
| 14 | import cn.iocoder.yudao.module.pay.framework.pay.config.PayProperties; | 19 | import cn.iocoder.yudao.module.pay.framework.pay.config.PayProperties; |
| @@ -24,12 +29,25 @@ import javax.annotation.Resource; | @@ -24,12 +29,25 @@ import javax.annotation.Resource; | ||
| 24 | import java.time.LocalDateTime; | 29 | import java.time.LocalDateTime; |
| 25 | import java.util.List; | 30 | import java.util.List; |
| 26 | 31 | ||
| 32 | +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime; | ||
| 33 | +import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime; | ||
| 27 | import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; | 34 | import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId; |
| 28 | import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; | 35 | import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; |
| 36 | +import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; | ||
| 29 | import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; | 37 | import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; |
| 38 | +import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString; | ||
| 39 | +import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*; | ||
| 30 | import static org.junit.jupiter.api.Assertions.assertEquals; | 40 | import static org.junit.jupiter.api.Assertions.assertEquals; |
| 41 | +import static org.mockito.ArgumentMatchers.eq; | ||
| 42 | +import static org.mockito.Mockito.mock; | ||
| 43 | +import static org.mockito.Mockito.when; | ||
| 31 | 44 | ||
| 32 | -@Import(PayRefundServiceImpl.class) | 45 | +/** |
| 46 | + * {@link PayRefundServiceImpl} 的单元测试类 | ||
| 47 | + * | ||
| 48 | + * @author 芋艿 | ||
| 49 | + */ | ||
| 50 | +@Import({PayRefundServiceImpl.class, PayNoRedisDAO.class}) | ||
| 33 | public class PayRefundServiceTest extends BaseDbAndRedisUnitTest { | 51 | public class PayRefundServiceTest extends BaseDbAndRedisUnitTest { |
| 34 | 52 | ||
| 35 | @Resource | 53 | @Resource |
| @@ -56,45 +74,41 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest { | @@ -56,45 +74,41 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest { | ||
| 56 | // mock 数据 | 74 | // mock 数据 |
| 57 | PayRefundDO dbRefund = randomPojo(PayRefundDO.class, o -> { // 等会查询到 | 75 | PayRefundDO dbRefund = randomPojo(PayRefundDO.class, o -> { // 等会查询到 |
| 58 | o.setAppId(1L); | 76 | o.setAppId(1L); |
| 59 | - o.setChannelId(1L); | ||
| 60 | o.setChannelCode(PayChannelEnum.WX_PUB.getCode()); | 77 | o.setChannelCode(PayChannelEnum.WX_PUB.getCode()); |
| 61 | - o.setOrderId(1L); | ||
| 62 | - o.setNo("OT0000001"); | ||
| 63 | o.setMerchantOrderId("MOT0000001"); | 78 | o.setMerchantOrderId("MOT0000001"); |
| 64 | o.setMerchantRefundId("MRF0000001"); | 79 | o.setMerchantRefundId("MRF0000001"); |
| 65 | - o.setNotifyUrl("https://www.cancanzi.com"); | ||
| 66 | o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus()); | 80 | o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus()); |
| 67 | - o.setPayPrice(100); | ||
| 68 | - o.setRefundPrice(500); | ||
| 69 | - o.setReason("就是想退款了,你有意见吗"); | ||
| 70 | - o.setUserIp("127.0.0.1"); | ||
| 71 | o.setChannelOrderNo("CH0000001"); | 81 | o.setChannelOrderNo("CH0000001"); |
| 72 | o.setChannelRefundNo("CHR0000001"); | 82 | o.setChannelRefundNo("CHR0000001"); |
| 73 | - o.setChannelErrorCode(""); | ||
| 74 | - o.setChannelErrorMsg(""); | ||
| 75 | - o.setSuccessTime(LocalDateTime.of(2021, 1, 1, 10, 10, 15)); | ||
| 76 | - o.setCreateTime(LocalDateTime.of(2021, 1, 1, 10, 10, 10)); | ||
| 77 | - o.setUpdateTime(LocalDateTime.of(2021, 1, 1, 10, 10, 35)); | 83 | + o.setCreateTime(buildTime(2021, 1, 10)); |
| 78 | }); | 84 | }); |
| 79 | refundMapper.insert(dbRefund); | 85 | refundMapper.insert(dbRefund); |
| 80 | // 测试 appId 不匹配 | 86 | // 测试 appId 不匹配 |
| 81 | refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setAppId(2L))); | 87 | refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setAppId(2L))); |
| 82 | // 测试 channelCode 不匹配 | 88 | // 测试 channelCode 不匹配 |
| 83 | refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setChannelCode(PayChannelEnum.ALIPAY_APP.getCode()))); | 89 | refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setChannelCode(PayChannelEnum.ALIPAY_APP.getCode()))); |
| 84 | - // 测试 merchantRefundNo 不匹配 | ||
| 85 | - refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setMerchantRefundId("MRF1111112"))); | 90 | + // 测试 merchantOrderId 不匹配 |
| 91 | + refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setMerchantOrderId(randomString()))); | ||
| 92 | + // 测试 merchantRefundId 不匹配 | ||
| 93 | + refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setMerchantRefundId(randomString()))); | ||
| 94 | + // 测试 channelOrderNo 不匹配 | ||
| 95 | + refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setChannelOrderNo(randomString()))); | ||
| 96 | + // 测试 channelRefundNo 不匹配 | ||
| 97 | + refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setChannelRefundNo(randomString()))); | ||
| 86 | // 测试 status 不匹配 | 98 | // 测试 status 不匹配 |
| 87 | refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setStatus(PayOrderStatusEnum.WAITING.getStatus()))); | 99 | refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setStatus(PayOrderStatusEnum.WAITING.getStatus()))); |
| 88 | // 测试 createTime 不匹配 | 100 | // 测试 createTime 不匹配 |
| 89 | - refundMapper.insert(cloneIgnoreId(dbRefund, o -> | ||
| 90 | - o.setCreateTime(LocalDateTime.of(2022, 1, 1, 10, 10, 10)))); | 101 | + refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setCreateTime(buildTime(2021, 1, 1)))); |
| 91 | // 准备参数 | 102 | // 准备参数 |
| 92 | PayRefundPageReqVO reqVO = new PayRefundPageReqVO(); | 103 | PayRefundPageReqVO reqVO = new PayRefundPageReqVO(); |
| 93 | reqVO.setAppId(1L); | 104 | reqVO.setAppId(1L); |
| 94 | reqVO.setChannelCode(PayChannelEnum.WX_PUB.getCode()); | 105 | reqVO.setChannelCode(PayChannelEnum.WX_PUB.getCode()); |
| 106 | + reqVO.setMerchantOrderId("MOT0000001"); | ||
| 95 | reqVO.setMerchantRefundId("MRF0000001"); | 107 | reqVO.setMerchantRefundId("MRF0000001"); |
| 96 | - reqVO.setStatus(PayRefundStatusEnum.SUCCESS.getStatus()); | ||
| 97 | - reqVO.setCreateTime((new LocalDateTime[]{LocalDateTime.of(2021, 1, 1, 10, 10, 10), LocalDateTime.of(2021, 1, 1, 10, 10, 12)})); | 108 | + reqVO.setStatus(PayOrderStatusEnum.SUCCESS.getStatus()); |
| 109 | + reqVO.setChannelOrderNo("CH0000001"); | ||
| 110 | + reqVO.setChannelRefundNo("CHR0000001"); | ||
| 111 | + reqVO.setCreateTime(buildBetweenTime(2021, 1, 9, 2021, 1, 11)); | ||
| 98 | 112 | ||
| 99 | // 调用 | 113 | // 调用 |
| 100 | PageResult<PayRefundDO> pageResult = refundService.getRefundPage(reqVO); | 114 | PageResult<PayRefundDO> pageResult = refundService.getRefundPage(reqVO); |
| @@ -109,45 +123,41 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest { | @@ -109,45 +123,41 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest { | ||
| 109 | // mock 数据 | 123 | // mock 数据 |
| 110 | PayRefundDO dbRefund = randomPojo(PayRefundDO.class, o -> { // 等会查询到 | 124 | PayRefundDO dbRefund = randomPojo(PayRefundDO.class, o -> { // 等会查询到 |
| 111 | o.setAppId(1L); | 125 | o.setAppId(1L); |
| 112 | - o.setChannelId(1L); | ||
| 113 | o.setChannelCode(PayChannelEnum.WX_PUB.getCode()); | 126 | o.setChannelCode(PayChannelEnum.WX_PUB.getCode()); |
| 114 | - o.setOrderId(1L); | ||
| 115 | - o.setNo("OT0000001"); | ||
| 116 | o.setMerchantOrderId("MOT0000001"); | 127 | o.setMerchantOrderId("MOT0000001"); |
| 117 | o.setMerchantRefundId("MRF0000001"); | 128 | o.setMerchantRefundId("MRF0000001"); |
| 118 | - o.setNotifyUrl("https://www.cancanzi.com"); | ||
| 119 | o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus()); | 129 | o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus()); |
| 120 | - o.setPayPrice(100); | ||
| 121 | - o.setRefundPrice(500); | ||
| 122 | - o.setReason("就是想退款了,你有意见吗"); | ||
| 123 | - o.setUserIp("127.0.0.1"); | ||
| 124 | o.setChannelOrderNo("CH0000001"); | 130 | o.setChannelOrderNo("CH0000001"); |
| 125 | o.setChannelRefundNo("CHR0000001"); | 131 | o.setChannelRefundNo("CHR0000001"); |
| 126 | - o.setChannelErrorCode(""); | ||
| 127 | - o.setChannelErrorMsg(""); | ||
| 128 | - o.setSuccessTime(LocalDateTime.of(2021, 1, 1, 10, 10, 15)); | ||
| 129 | - o.setCreateTime(LocalDateTime.of(2021, 1, 1, 10, 10, 10)); | ||
| 130 | - o.setUpdateTime(LocalDateTime.of(2021, 1, 1, 10, 10, 35)); | 132 | + o.setCreateTime(buildTime(2021, 1, 10)); |
| 131 | }); | 133 | }); |
| 132 | refundMapper.insert(dbRefund); | 134 | refundMapper.insert(dbRefund); |
| 133 | // 测试 appId 不匹配 | 135 | // 测试 appId 不匹配 |
| 134 | refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setAppId(2L))); | 136 | refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setAppId(2L))); |
| 135 | // 测试 channelCode 不匹配 | 137 | // 测试 channelCode 不匹配 |
| 136 | refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setChannelCode(PayChannelEnum.ALIPAY_APP.getCode()))); | 138 | refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setChannelCode(PayChannelEnum.ALIPAY_APP.getCode()))); |
| 137 | - // 测试 merchantRefundNo 不匹配 | ||
| 138 | - refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setMerchantRefundId("MRF1111112"))); | 139 | + // 测试 merchantOrderId 不匹配 |
| 140 | + refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setMerchantOrderId(randomString()))); | ||
| 141 | + // 测试 merchantRefundId 不匹配 | ||
| 142 | + refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setMerchantRefundId(randomString()))); | ||
| 143 | + // 测试 channelOrderNo 不匹配 | ||
| 144 | + refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setChannelOrderNo(randomString()))); | ||
| 145 | + // 测试 channelRefundNo 不匹配 | ||
| 146 | + refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setChannelRefundNo(randomString()))); | ||
| 139 | // 测试 status 不匹配 | 147 | // 测试 status 不匹配 |
| 140 | refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setStatus(PayOrderStatusEnum.WAITING.getStatus()))); | 148 | refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setStatus(PayOrderStatusEnum.WAITING.getStatus()))); |
| 141 | // 测试 createTime 不匹配 | 149 | // 测试 createTime 不匹配 |
| 142 | - refundMapper.insert(cloneIgnoreId(dbRefund, o -> | ||
| 143 | - o.setCreateTime(LocalDateTime.of(2022, 1, 1, 10, 10, 10)))); | ||
| 144 | - | 150 | + refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setCreateTime(buildTime(2021, 1, 1)))); |
| 145 | // 准备参数 | 151 | // 准备参数 |
| 146 | PayRefundExportReqVO reqVO = new PayRefundExportReqVO(); | 152 | PayRefundExportReqVO reqVO = new PayRefundExportReqVO(); |
| 147 | reqVO.setAppId(1L); | 153 | reqVO.setAppId(1L); |
| 148 | reqVO.setChannelCode(PayChannelEnum.WX_PUB.getCode()); | 154 | reqVO.setChannelCode(PayChannelEnum.WX_PUB.getCode()); |
| 149 | - reqVO.setStatus(PayRefundStatusEnum.SUCCESS.getStatus()); | ||
| 150 | - reqVO.setCreateTime((new LocalDateTime[]{LocalDateTime.of(2021, 1, 1, 10, 10, 10), LocalDateTime.of(2021, 1, 1, 10, 10, 12)})); | 155 | + reqVO.setMerchantOrderId("MOT0000001"); |
| 156 | + reqVO.setMerchantRefundId("MRF0000001"); | ||
| 157 | + reqVO.setStatus(PayOrderStatusEnum.SUCCESS.getStatus()); | ||
| 158 | + reqVO.setChannelOrderNo("CH0000001"); | ||
| 159 | + reqVO.setChannelRefundNo("CHR0000001"); | ||
| 160 | + reqVO.setCreateTime(buildBetweenTime(2021, 1, 9, 2021, 1, 11)); | ||
| 151 | 161 | ||
| 152 | // 调用 | 162 | // 调用 |
| 153 | List<PayRefundDO> list = refundService.getRefundList(reqVO); | 163 | List<PayRefundDO> list = refundService.getRefundList(reqVO); |
| @@ -156,4 +166,151 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest { | @@ -156,4 +166,151 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest { | ||
| 156 | assertPojoEquals(dbRefund, list.get(0)); | 166 | assertPojoEquals(dbRefund, list.get(0)); |
| 157 | } | 167 | } |
| 158 | 168 | ||
| 169 | + @Test | ||
| 170 | + public void testCreateRefund_orderNotFound() { | ||
| 171 | + PayRefundCreateReqDTO reqDTO = randomPojo(PayRefundCreateReqDTO.class, | ||
| 172 | + o -> o.setAppId(1L)); | ||
| 173 | + // mock 方法(app) | ||
| 174 | + PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L)); | ||
| 175 | + when(appService.validPayApp(eq(1L))).thenReturn(app); | ||
| 176 | + | ||
| 177 | + // 调用,并断言异常 | ||
| 178 | + assertServiceException(() -> refundService.createPayRefund(reqDTO), | ||
| 179 | + ORDER_NOT_FOUND); | ||
| 180 | + } | ||
| 181 | + | ||
| 182 | + @Test | ||
| 183 | + public void testCreateRefund_orderWaiting() { | ||
| 184 | + testCreateRefund_orderWaitingOrClosed(PayOrderStatusEnum.WAITING.getStatus()); | ||
| 185 | + } | ||
| 186 | + | ||
| 187 | + @Test | ||
| 188 | + public void testCreateRefund_orderClosed() { | ||
| 189 | + testCreateRefund_orderWaitingOrClosed(PayOrderStatusEnum.CLOSED.getStatus()); | ||
| 190 | + } | ||
| 191 | + | ||
| 192 | + private void testCreateRefund_orderWaitingOrClosed(Integer status) { | ||
| 193 | + // 准备参数 | ||
| 194 | + PayRefundCreateReqDTO reqDTO = randomPojo(PayRefundCreateReqDTO.class, | ||
| 195 | + o -> o.setAppId(1L).setMerchantOrderId("100")); | ||
| 196 | + // mock 方法(app) | ||
| 197 | + PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L)); | ||
| 198 | + when(appService.validPayApp(eq(1L))).thenReturn(app); | ||
| 199 | + // mock 数据(order) | ||
| 200 | + PayOrderDO order = randomPojo(PayOrderDO.class, o -> o.setStatus(status)); | ||
| 201 | + when(orderService.getOrder(eq(1L), eq("100"))).thenReturn(order); | ||
| 202 | + | ||
| 203 | + // 调用,并断言异常 | ||
| 204 | + assertServiceException(() -> refundService.createPayRefund(reqDTO), | ||
| 205 | + ORDER_REFUND_FAIL_STATUS_ERROR); | ||
| 206 | + } | ||
| 207 | + | ||
| 208 | + @Test | ||
| 209 | + public void testCreateRefund_refundPriceExceed() { | ||
| 210 | + // 准备参数 | ||
| 211 | + PayRefundCreateReqDTO reqDTO = randomPojo(PayRefundCreateReqDTO.class, | ||
| 212 | + o -> o.setAppId(1L).setMerchantOrderId("100").setPrice(10)); | ||
| 213 | + // mock 方法(app) | ||
| 214 | + PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L)); | ||
| 215 | + when(appService.validPayApp(eq(1L))).thenReturn(app); | ||
| 216 | + // mock 数据(order) | ||
| 217 | + PayOrderDO order = randomPojo(PayOrderDO.class, o -> | ||
| 218 | + o.setStatus(PayOrderStatusEnum.REFUND.getStatus()) | ||
| 219 | + .setPrice(10).setRefundPrice(1)); | ||
| 220 | + when(orderService.getOrder(eq(1L), eq("100"))).thenReturn(order); | ||
| 221 | + | ||
| 222 | + // 调用,并断言异常 | ||
| 223 | + assertServiceException(() -> refundService.createPayRefund(reqDTO), | ||
| 224 | + REFUND_PRICE_EXCEED); | ||
| 225 | + } | ||
| 226 | + | ||
| 227 | + @Test | ||
| 228 | + public void testCreateRefund_orderHasRefunding() { | ||
| 229 | + // 准备参数 | ||
| 230 | + PayRefundCreateReqDTO reqDTO = randomPojo(PayRefundCreateReqDTO.class, | ||
| 231 | + o -> o.setAppId(1L).setMerchantOrderId("100").setPrice(10)); | ||
| 232 | + // mock 方法(app) | ||
| 233 | + PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L)); | ||
| 234 | + when(appService.validPayApp(eq(1L))).thenReturn(app); | ||
| 235 | + // mock 数据(order) | ||
| 236 | + PayOrderDO order = randomPojo(PayOrderDO.class, o -> | ||
| 237 | + o.setStatus(PayOrderStatusEnum.REFUND.getStatus()) | ||
| 238 | + .setPrice(10).setRefundPrice(1)); | ||
| 239 | + when(orderService.getOrder(eq(1L), eq("100"))).thenReturn(order); | ||
| 240 | + // mock 数据(refund 在退款中) | ||
| 241 | + PayRefundDO refund = randomPojo(PayRefundDO.class, o -> | ||
| 242 | + o.setOrderId(order.getId()).setStatus(PayOrderStatusEnum.WAITING.getStatus())); | ||
| 243 | + refundMapper.insert(refund); | ||
| 244 | + | ||
| 245 | + // 调用,并断言异常 | ||
| 246 | + assertServiceException(() -> refundService.createPayRefund(reqDTO), | ||
| 247 | + REFUND_PRICE_EXCEED); | ||
| 248 | + } | ||
| 249 | + | ||
| 250 | + @Test | ||
| 251 | + public void testCreateRefund_channelNotFound() { | ||
| 252 | + // 准备参数 | ||
| 253 | + PayRefundCreateReqDTO reqDTO = randomPojo(PayRefundCreateReqDTO.class, | ||
| 254 | + o -> o.setAppId(1L).setMerchantOrderId("100").setPrice(9)); | ||
| 255 | + // mock 方法(app) | ||
| 256 | + PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L)); | ||
| 257 | + when(appService.validPayApp(eq(1L))).thenReturn(app); | ||
| 258 | + // mock 数据(order) | ||
| 259 | + PayOrderDO order = randomPojo(PayOrderDO.class, o -> | ||
| 260 | + o.setStatus(PayOrderStatusEnum.REFUND.getStatus()) | ||
| 261 | + .setPrice(10).setRefundPrice(1) | ||
| 262 | + .setChannelId(1L).setChannelCode(PayChannelEnum.ALIPAY_APP.getCode())); | ||
| 263 | + when(orderService.getOrder(eq(1L), eq("100"))).thenReturn(order); | ||
| 264 | + // mock 方法(channel) | ||
| 265 | + PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L) | ||
| 266 | + .setCode(PayChannelEnum.ALIPAY_APP.getCode())); | ||
| 267 | + when(channelService.validPayChannel(eq(1L))).thenReturn(channel); | ||
| 268 | + | ||
| 269 | + // 调用,并断言异常 | ||
| 270 | + assertServiceException(() -> refundService.createPayRefund(reqDTO), | ||
| 271 | + CHANNEL_NOT_FOUND); | ||
| 272 | + } | ||
| 273 | + | ||
| 274 | + @Test | ||
| 275 | + public void testCreateRefund_refundExists() { | ||
| 276 | + // 准备参数 | ||
| 277 | + PayRefundCreateReqDTO reqDTO = randomPojo(PayRefundCreateReqDTO.class, | ||
| 278 | + o -> o.setAppId(1L).setMerchantOrderId("100").setPrice(9) | ||
| 279 | + .setReason("测试退款")); | ||
| 280 | + // mock 方法(app) | ||
| 281 | + PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L)); | ||
| 282 | + when(appService.validPayApp(eq(1L))).thenReturn(app); | ||
| 283 | + // mock 数据(order) | ||
| 284 | + PayOrderDO order = randomPojo(PayOrderDO.class, o -> | ||
| 285 | + o.setStatus(PayOrderStatusEnum.REFUND.getStatus()) | ||
| 286 | + .setPrice(10).setRefundPrice(1) | ||
| 287 | + .setChannelId(1L).setChannelCode(PayChannelEnum.ALIPAY_APP.getCode())); | ||
| 288 | + when(orderService.getOrder(eq(1L), eq("100"))).thenReturn(order); | ||
| 289 | + // mock 方法(channel) | ||
| 290 | + PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L) | ||
| 291 | + .setCode(PayChannelEnum.ALIPAY_APP.getCode())); | ||
| 292 | + when(channelService.validPayChannel(eq(1L))).thenReturn(channel); | ||
| 293 | + // mock 方法(client) | ||
| 294 | + PayClient client = mock(PayClient.class); | ||
| 295 | + when(payClientFactory.getPayClient(eq(10L))).thenReturn(client); | ||
| 296 | + // mock 数据(refund 已存在) | ||
| 297 | + PayRefundDO refund = randomPojo(PayRefundDO.class, o -> | ||
| 298 | + o.setOrderId(order.getId()).setStatus(PayOrderStatusEnum.WAITING.getStatus())); | ||
| 299 | + refundMapper.insert(refund); | ||
| 300 | + | ||
| 301 | + // 调用,并断言异常 | ||
| 302 | + assertServiceException(() -> refundService.createPayRefund(reqDTO), | ||
| 303 | + REFUND_EXISTS); | ||
| 304 | + } | ||
| 305 | + | ||
| 306 | + @Test | ||
| 307 | + public void testCreateRefund_invokeException() { | ||
| 308 | + | ||
| 309 | + } | ||
| 310 | + | ||
| 311 | + @Test | ||
| 312 | + public void testCreateRefund_invokeSuccess() { | ||
| 313 | + | ||
| 314 | + } | ||
| 315 | + | ||
| 159 | } | 316 | } |
yudao-module-pay/yudao-module-pay-biz/src/test/resources/sql/create_tables.sql
| @@ -82,29 +82,25 @@ CREATE TABLE IF NOT EXISTS `pay_order_extension` ( | @@ -82,29 +82,25 @@ CREATE TABLE IF NOT EXISTS `pay_order_extension` ( | ||
| 82 | 82 | ||
| 83 | CREATE TABLE IF NOT EXISTS `pay_refund` ( | 83 | CREATE TABLE IF NOT EXISTS `pay_refund` ( |
| 84 | "id" number NOT NULL GENERATED BY DEFAULT AS IDENTITY, | 84 | "id" number NOT NULL GENERATED BY DEFAULT AS IDENTITY, |
| 85 | + `no` varchar(64) NOT NULL, | ||
| 85 | `app_id` bigint(20) NOT NULL, | 86 | `app_id` bigint(20) NOT NULL, |
| 86 | `channel_id` bigint(20) NOT NULL, | 87 | `channel_id` bigint(20) NOT NULL, |
| 87 | `channel_code` varchar(32) NOT NULL, | 88 | `channel_code` varchar(32) NOT NULL, |
| 88 | `order_id` bigint(20) NOT NULL, | 89 | `order_id` bigint(20) NOT NULL, |
| 89 | - `trade_no` varchar(64) NOT NULL, | ||
| 90 | `merchant_order_id` varchar(64) NOT NULL, | 90 | `merchant_order_id` varchar(64) NOT NULL, |
| 91 | - `merchant_refund_no` varchar(64) NOT NULL, | 91 | + `merchant_refund_id` varchar(64) NOT NULL, |
| 92 | `notify_url` varchar(1024) NOT NULL, | 92 | `notify_url` varchar(1024) NOT NULL, |
| 93 | - `notify_status` tinyint(4) NOT NULL, | ||
| 94 | `status` tinyint(4) NOT NULL, | 93 | `status` tinyint(4) NOT NULL, |
| 95 | - `type` tinyint(4) NOT NULL, | ||
| 96 | - `pay_amount` bigint(20) NOT NULL, | ||
| 97 | - `refund_amount` bigint(20) NOT NULL, | 94 | + `pay_price` bigint(20) NOT NULL, |
| 95 | + `refund_price` bigint(20) NOT NULL, | ||
| 98 | `reason` varchar(256) NOT NULL, | 96 | `reason` varchar(256) NOT NULL, |
| 99 | `user_ip` varchar(50) NULL DEFAULT NULL, | 97 | `user_ip` varchar(50) NULL DEFAULT NULL, |
| 100 | `channel_order_no` varchar(64) NOT NULL, | 98 | `channel_order_no` varchar(64) NOT NULL, |
| 101 | `channel_refund_no` varchar(64) NULL DEFAULT NULL, | 99 | `channel_refund_no` varchar(64) NULL DEFAULT NULL, |
| 100 | + `success_time` datetime(0) NULL DEFAULT NULL, | ||
| 102 | `channel_error_code` varchar(128) NULL DEFAULT NULL, | 101 | `channel_error_code` varchar(128) NULL DEFAULT NULL, |
| 103 | `channel_error_msg` varchar(256) NULL DEFAULT NULL, | 102 | `channel_error_msg` varchar(256) NULL DEFAULT NULL, |
| 104 | - `channel_extras` varchar(1024) NULL DEFAULT NULL, | ||
| 105 | - `expire_time` datetime(0) NULL DEFAULT NULL, | ||
| 106 | - `success_time` datetime(0) NULL DEFAULT NULL, | ||
| 107 | - `notify_time` datetime(0) NULL DEFAULT NULL, | 103 | + `channel_notify_data` varchar(1024) NULL, |
| 108 | `creator` varchar(64) NULL DEFAULT '', | 104 | `creator` varchar(64) NULL DEFAULT '', |
| 109 | `create_time` datetime(0) NOT NULL DEFAULT CURRENT_TIMESTAMP, | 105 | `create_time` datetime(0) NOT NULL DEFAULT CURRENT_TIMESTAMP, |
| 110 | `updater` varchar(64) NULL DEFAULT '', | 106 | `updater` varchar(64) NULL DEFAULT '', |