mirror of
https://gitee.com/huangge1199_admin/vue-pro.git
synced 2024-11-23 07:41:53 +08:00
by gateway:
1. 完善部分 refund 单元测试
This commit is contained in:
parent
da529851bd
commit
e27ec2fd50
@ -1,7 +1,6 @@
|
|||||||
package cn.iocoder.yudao.module.pay.service.refund;
|
package cn.iocoder.yudao.module.pay.service.refund;
|
||||||
|
|
||||||
import cn.hutool.core.date.DateUtil;
|
import cn.hutool.extra.spring.SpringUtil;
|
||||||
import cn.hutool.core.util.RandomUtil;
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
import cn.iocoder.yudao.framework.pay.core.client.PayClient;
|
import cn.iocoder.yudao.framework.pay.core.client.PayClient;
|
||||||
import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory;
|
import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory;
|
||||||
@ -16,9 +15,9 @@ import cn.iocoder.yudao.module.pay.convert.refund.PayRefundConvert;
|
|||||||
import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO;
|
import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO;
|
||||||
import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO;
|
import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO;
|
||||||
import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
|
import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
|
||||||
import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderExtensionDO;
|
|
||||||
import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO;
|
import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO;
|
||||||
import cn.iocoder.yudao.module.pay.dal.mysql.refund.PayRefundMapper;
|
import cn.iocoder.yudao.module.pay.dal.mysql.refund.PayRefundMapper;
|
||||||
|
import cn.iocoder.yudao.module.pay.dal.redis.no.PayNoRedisDAO;
|
||||||
import cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants;
|
import cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants;
|
||||||
import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyTypeEnum;
|
import cn.iocoder.yudao.module.pay.enums.notify.PayNotifyTypeEnum;
|
||||||
import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
|
import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
|
||||||
@ -35,12 +34,11 @@ import org.springframework.transaction.annotation.Transactional;
|
|||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||||
import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
|
import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
|
||||||
import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.CHANNEL_NOT_FOUND;
|
import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 退款订单 Service 实现类
|
* 退款订单 Service 实现类
|
||||||
@ -60,6 +58,8 @@ public class PayRefundServiceImpl implements PayRefundService {
|
|||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private PayRefundMapper refundMapper;
|
private PayRefundMapper refundMapper;
|
||||||
|
@Resource
|
||||||
|
private PayNoRedisDAO noRedisDAO;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private PayOrderService orderService;
|
private PayOrderService orderService;
|
||||||
@ -112,8 +112,9 @@ public class PayRefundServiceImpl implements PayRefundService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 2.1 插入退款单
|
// 2.1 插入退款单
|
||||||
|
String no = noRedisDAO.generate(payProperties.getRefundNoPrefix());
|
||||||
refund = PayRefundConvert.INSTANCE.convert(reqDTO)
|
refund = PayRefundConvert.INSTANCE.convert(reqDTO)
|
||||||
.setNo(generateRefundNo()).setOrderId(order.getId())
|
.setNo(no).setOrderId(order.getId())
|
||||||
.setChannelId(order.getChannelId()).setChannelCode(order.getChannelCode())
|
.setChannelId(order.getChannelId()).setChannelCode(order.getChannelCode())
|
||||||
// 商户相关的字段
|
// 商户相关的字段
|
||||||
.setNotifyUrl(app.getRefundNotifyUrl())
|
.setNotifyUrl(app.getRefundNotifyUrl())
|
||||||
@ -123,20 +124,27 @@ public class PayRefundServiceImpl implements PayRefundService {
|
|||||||
.setStatus(PayRefundStatusEnum.WAITING.getStatus())
|
.setStatus(PayRefundStatusEnum.WAITING.getStatus())
|
||||||
.setPayPrice(order.getPrice()).setRefundPrice(reqDTO.getPrice());
|
.setPayPrice(order.getPrice()).setRefundPrice(reqDTO.getPrice());
|
||||||
refundMapper.insert(refund);
|
refundMapper.insert(refund);
|
||||||
|
try {
|
||||||
// 2.2 向渠道发起退款申请
|
// 2.2 向渠道发起退款申请
|
||||||
PayOrderExtensionDO orderExtension = orderService.getOrderExtension(order.getExtensionId());
|
|
||||||
PayRefundUnifiedReqDTO unifiedReqDTO = new PayRefundUnifiedReqDTO()
|
PayRefundUnifiedReqDTO unifiedReqDTO = new PayRefundUnifiedReqDTO()
|
||||||
.setPayPrice(order.getPrice())
|
.setPayPrice(order.getPrice())
|
||||||
.setRefundPrice(reqDTO.getPrice())
|
.setRefundPrice(reqDTO.getPrice())
|
||||||
.setOutTradeNo(orderExtension.getNo())
|
.setOutTradeNo(order.getNo())
|
||||||
.setOutRefundNo(refund.getNo())
|
.setOutRefundNo(refund.getNo())
|
||||||
.setNotifyUrl(genChannelRefundNotifyUrl(channel))
|
.setNotifyUrl(genChannelRefundNotifyUrl(channel))
|
||||||
.setReason(reqDTO.getReason());
|
.setReason(reqDTO.getReason());
|
||||||
PayRefundRespDTO refundRespDTO = client.unifiedRefund(unifiedReqDTO);
|
PayRefundRespDTO refundRespDTO = client.unifiedRefund(unifiedReqDTO);
|
||||||
// 2.3 处理退款返回
|
// 2.3 处理退款返回
|
||||||
notifyRefund(channel, refundRespDTO);
|
getSelf().notifyRefund(channel, refundRespDTO);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
// 注意:这里仅打印异常,不进行抛出。
|
||||||
|
// 原因是:虽然调用支付渠道进行退款发生异常(网络请求超时),实际退款成功。这个结果,后续通过退款回调、或者退款轮询补偿可以拿到。
|
||||||
|
// 最终,在异常的情况下,支付中心会异步回调业务的退款回调接口,提供退款结果
|
||||||
|
log.error("[createPayRefund][退款 id({}) requestDTO({}) 发生异常]",
|
||||||
|
refund.getId(), reqDTO, e);
|
||||||
|
}
|
||||||
|
|
||||||
// 成功在 退款回调中处理
|
// 返回退款编号
|
||||||
return refund.getId();
|
return refund.getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,12 +159,12 @@ public class PayRefundServiceImpl implements PayRefundService {
|
|||||||
if (order == null) {
|
if (order == null) {
|
||||||
throw exception(ErrorCodeConstants.ORDER_NOT_FOUND);
|
throw exception(ErrorCodeConstants.ORDER_NOT_FOUND);
|
||||||
}
|
}
|
||||||
// 校验状态,必须是支付状态
|
// 校验状态,必须是已支付、或者已退款
|
||||||
if (!PayOrderStatusEnum.SUCCESS.getStatus().equals(order.getStatus())) {
|
if (!PayOrderStatusEnum.isSuccessOrRefund(order.getStatus())) {
|
||||||
throw exception(ErrorCodeConstants.ORDER_STATUS_IS_NOT_SUCCESS);
|
throw exception(ORDER_REFUND_FAIL_STATUS_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 校验金额 退款金额不能大于原定的金额
|
// 校验金额,退款金额不能大于原定的金额
|
||||||
if (reqDTO.getPrice() + order.getRefundPrice() > order.getPrice()){
|
if (reqDTO.getPrice() + order.getRefundPrice() > order.getPrice()){
|
||||||
throw exception(ErrorCodeConstants.REFUND_PRICE_EXCEED);
|
throw exception(ErrorCodeConstants.REFUND_PRICE_EXCEED);
|
||||||
}
|
}
|
||||||
@ -178,38 +186,22 @@ public class PayRefundServiceImpl implements PayRefundService {
|
|||||||
return payProperties.getRefundNotifyUrl() + "/" + channel.getId();
|
return payProperties.getRefundNotifyUrl() + "/" + channel.getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
private String generateRefundNo() {
|
|
||||||
// wx
|
|
||||||
// 2014
|
|
||||||
// 10
|
|
||||||
// 27
|
|
||||||
// 20
|
|
||||||
// 09
|
|
||||||
// 39
|
|
||||||
// 5522657
|
|
||||||
// a690389285100
|
|
||||||
// 目前的算法
|
|
||||||
// 时间序列,年月日时分秒 14 位
|
|
||||||
// 纯随机,6 位 TODO 芋艿:此处估计是会有问题的,后续在调整
|
|
||||||
return DateUtil.format(LocalDateTime.now(), "yyyyMMddHHmmss") + // 时间序列
|
|
||||||
RandomUtil.randomInt(100000, 999999) // 随机。为什么是这个范围,因为偷懒
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void notifyRefund(Long channelId, PayRefundRespDTO notify) {
|
public void notifyRefund(Long channelId, PayRefundRespDTO notify) {
|
||||||
// 校验支付渠道是否有效
|
|
||||||
channelService.validPayChannel(channelId);
|
|
||||||
// 通知结果
|
|
||||||
|
|
||||||
// 校验支付渠道是否有效
|
// 校验支付渠道是否有效
|
||||||
PayChannelDO channel = channelService.validPayChannel(channelId);
|
PayChannelDO channel = channelService.validPayChannel(channelId);
|
||||||
// 更新退款订单
|
// 更新退款订单
|
||||||
TenantUtils.execute(channel.getTenantId(), () -> notifyRefund(channel, notify));
|
TenantUtils.execute(channel.getTenantId(), () -> getSelf().notifyRefund(channel, notify));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO 芋艿:事务问题
|
/**
|
||||||
private void notifyRefund(PayChannelDO channel, PayRefundRespDTO notify) {
|
* 通知并更新订单的退款结果
|
||||||
|
*
|
||||||
|
* @param channel 支付渠道
|
||||||
|
* @param notify 通知
|
||||||
|
*/
|
||||||
|
@Transactional(rollbackFor = Exception.class) // 注意,如果是方法内调用该方法,需要通过 getSelf().notifyRefund(channel, notify) 调用,否则事务不生效
|
||||||
|
public void notifyRefund(PayChannelDO channel, PayRefundRespDTO notify) {
|
||||||
// 情况一:退款成功
|
// 情况一:退款成功
|
||||||
if (PayRefundStatusRespEnum.isSuccess(notify.getStatus())) {
|
if (PayRefundStatusRespEnum.isSuccess(notify.getStatus())) {
|
||||||
notifyRefundSuccess(channel, notify);
|
notifyRefundSuccess(channel, notify);
|
||||||
@ -226,14 +218,14 @@ public class PayRefundServiceImpl implements PayRefundService {
|
|||||||
PayRefundDO refund = refundMapper.selectByAppIdAndNo(
|
PayRefundDO refund = refundMapper.selectByAppIdAndNo(
|
||||||
channel.getAppId(), notify.getOutRefundNo());
|
channel.getAppId(), notify.getOutRefundNo());
|
||||||
if (refund == null) {
|
if (refund == null) {
|
||||||
throw exception(ErrorCodeConstants.REFUND_NOT_FOUND);
|
throw exception(REFUND_NOT_FOUND);
|
||||||
}
|
}
|
||||||
if (PayRefundStatusEnum.isSuccess(refund.getStatus())) { // 如果已经是成功,直接返回,不用重复更新
|
if (PayRefundStatusEnum.isSuccess(refund.getStatus())) { // 如果已经是成功,直接返回,不用重复更新
|
||||||
log.info("[notifyRefundSuccess][退款订单({}) 已经是退款成功,无需更新]", refund.getId());
|
log.info("[notifyRefundSuccess][退款订单({}) 已经是退款成功,无需更新]", refund.getId());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!PayRefundStatusEnum.WAITING.getStatus().equals(refund.getStatus())) {
|
if (!PayRefundStatusEnum.WAITING.getStatus().equals(refund.getStatus())) {
|
||||||
throw exception(ErrorCodeConstants.REFUND_STATUS_IS_NOT_WAITING);
|
throw exception(REFUND_STATUS_IS_NOT_WAITING);
|
||||||
}
|
}
|
||||||
// 1.2 更新 PayRefundDO
|
// 1.2 更新 PayRefundDO
|
||||||
PayRefundDO updateRefundObj = new PayRefundDO()
|
PayRefundDO updateRefundObj = new PayRefundDO()
|
||||||
@ -243,7 +235,7 @@ public class PayRefundServiceImpl implements PayRefundService {
|
|||||||
.setChannelNotifyData(toJsonString(notify));
|
.setChannelNotifyData(toJsonString(notify));
|
||||||
int updateCounts = refundMapper.updateByIdAndStatus(refund.getId(), refund.getStatus(), updateRefundObj);
|
int updateCounts = refundMapper.updateByIdAndStatus(refund.getId(), refund.getStatus(), updateRefundObj);
|
||||||
if (updateCounts == 0) { // 校验状态,必须是等待状态
|
if (updateCounts == 0) { // 校验状态,必须是等待状态
|
||||||
throw exception(ErrorCodeConstants.REFUND_STATUS_IS_NOT_WAITING);
|
throw exception(REFUND_STATUS_IS_NOT_WAITING);
|
||||||
}
|
}
|
||||||
log.info("[notifyRefundSuccess][退款订单({}) 更新为退款成功]", refund.getId());
|
log.info("[notifyRefundSuccess][退款订单({}) 更新为退款成功]", refund.getId());
|
||||||
|
|
||||||
@ -261,14 +253,14 @@ public class PayRefundServiceImpl implements PayRefundService {
|
|||||||
PayRefundDO refund = refundMapper.selectByAppIdAndNo(
|
PayRefundDO refund = refundMapper.selectByAppIdAndNo(
|
||||||
channel.getAppId(), notify.getOutRefundNo());
|
channel.getAppId(), notify.getOutRefundNo());
|
||||||
if (refund == null) {
|
if (refund == null) {
|
||||||
throw exception(ErrorCodeConstants.REFUND_NOT_FOUND);
|
throw exception(REFUND_NOT_FOUND);
|
||||||
}
|
}
|
||||||
if (PayRefundStatusEnum.isFailure(refund.getStatus())) { // 如果已经是成功,直接返回,不用重复更新
|
if (PayRefundStatusEnum.isFailure(refund.getStatus())) { // 如果已经是成功,直接返回,不用重复更新
|
||||||
log.info("[notifyRefundSuccess][退款订单({}) 已经是退款关闭,无需更新]", refund.getId());
|
log.info("[notifyRefundSuccess][退款订单({}) 已经是退款关闭,无需更新]", refund.getId());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!PayRefundStatusEnum.WAITING.getStatus().equals(refund.getStatus())) {
|
if (!PayRefundStatusEnum.WAITING.getStatus().equals(refund.getStatus())) {
|
||||||
throw exception(ErrorCodeConstants.REFUND_STATUS_IS_NOT_WAITING);
|
throw exception(REFUND_STATUS_IS_NOT_WAITING);
|
||||||
}
|
}
|
||||||
// 1.2 更新 PayRefundDO
|
// 1.2 更新 PayRefundDO
|
||||||
PayRefundDO updateRefundObj = new PayRefundDO()
|
PayRefundDO updateRefundObj = new PayRefundDO()
|
||||||
@ -278,7 +270,7 @@ public class PayRefundServiceImpl implements PayRefundService {
|
|||||||
.setChannelErrorCode(notify.getChannelErrorCode()).setChannelErrorMsg(notify.getChannelErrorMsg());
|
.setChannelErrorCode(notify.getChannelErrorCode()).setChannelErrorMsg(notify.getChannelErrorMsg());
|
||||||
int updateCounts = refundMapper.updateByIdAndStatus(refund.getId(), refund.getStatus(), updateRefundObj);
|
int updateCounts = refundMapper.updateByIdAndStatus(refund.getId(), refund.getStatus(), updateRefundObj);
|
||||||
if (updateCounts == 0) { // 校验状态,必须是等待状态
|
if (updateCounts == 0) { // 校验状态,必须是等待状态
|
||||||
throw exception(ErrorCodeConstants.REFUND_STATUS_IS_NOT_WAITING);
|
throw exception(REFUND_STATUS_IS_NOT_WAITING);
|
||||||
}
|
}
|
||||||
log.info("[notifyRefundFailure][退款订单({}) 更新为退款失败]", refund.getId());
|
log.info("[notifyRefundFailure][退款订单({}) 更新为退款失败]", refund.getId());
|
||||||
|
|
||||||
@ -287,4 +279,13 @@ public class PayRefundServiceImpl implements PayRefundService {
|
|||||||
.type(PayNotifyTypeEnum.REFUND.getType()).dataId(refund.getId()).build());
|
.type(PayNotifyTypeEnum.REFUND.getType()).dataId(refund.getId()).build());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得自身的代理对象,解决 AOP 生效问题
|
||||||
|
*
|
||||||
|
* @return 自己
|
||||||
|
*/
|
||||||
|
private PayRefundServiceImpl getSelf() {
|
||||||
|
return SpringUtil.getBean(getClass());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,6 @@ import cn.iocoder.yudao.module.pay.service.notify.PayNotifyService;
|
|||||||
import cn.iocoder.yudao.module.pay.service.notify.dto.PayNotifyTaskCreateReqDTO;
|
import cn.iocoder.yudao.module.pay.service.notify.dto.PayNotifyTaskCreateReqDTO;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.mockito.ArgumentMatcher;
|
|
||||||
import org.mockito.MockedStatic;
|
import org.mockito.MockedStatic;
|
||||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||||
import org.springframework.context.annotation.Import;
|
import org.springframework.context.annotation.Import;
|
||||||
@ -44,8 +43,7 @@ import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString
|
|||||||
import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
|
import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
|
||||||
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
|
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
|
||||||
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
|
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
|
||||||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
|
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
|
||||||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString;
|
|
||||||
import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*;
|
import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*;
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
@ -85,6 +83,51 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
|
|||||||
when(properties.getOrderNotifyUrl()).thenReturn("http://127.0.0.1");
|
when(properties.getOrderNotifyUrl()).thenReturn("http://127.0.0.1");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetOrder_id() {
|
||||||
|
// mock 数据(PayOrderDO)
|
||||||
|
PayOrderDO order = randomPojo(PayOrderDO.class);
|
||||||
|
orderMapper.insert(order);
|
||||||
|
// 准备参数
|
||||||
|
Long id = order.getId();
|
||||||
|
|
||||||
|
// 调用
|
||||||
|
PayOrderDO dbOrder = orderService.getOrder(id);
|
||||||
|
// 断言
|
||||||
|
assertPojoEquals(dbOrder, order);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetOrder_appIdAndMerchantOrderId() {
|
||||||
|
// mock 数据(PayOrderDO)
|
||||||
|
PayOrderDO order = randomPojo(PayOrderDO.class);
|
||||||
|
orderMapper.insert(order);
|
||||||
|
// 准备参数
|
||||||
|
Long appId = order.getAppId();
|
||||||
|
String merchantOrderId = order.getMerchantOrderId();
|
||||||
|
|
||||||
|
// 调用
|
||||||
|
PayOrderDO dbOrder = orderService.getOrder(appId, merchantOrderId);
|
||||||
|
// 断言
|
||||||
|
assertPojoEquals(dbOrder, order);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetOrderCountByAppId() {
|
||||||
|
// mock 数据(PayOrderDO)
|
||||||
|
PayOrderDO order01 = randomPojo(PayOrderDO.class);
|
||||||
|
orderMapper.insert(order01);
|
||||||
|
PayOrderDO order02 = randomPojo(PayOrderDO.class);
|
||||||
|
orderMapper.insert(order02);
|
||||||
|
// 准备参数
|
||||||
|
Long appId = order01.getAppId();
|
||||||
|
|
||||||
|
// 调用
|
||||||
|
Long count = orderService.getOrderCountByAppId(appId);
|
||||||
|
// 断言
|
||||||
|
assertEquals(count, 1L);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetOrderPage() {
|
public void testGetOrderPage() {
|
||||||
// mock 数据
|
// mock 数据
|
||||||
@ -350,7 +393,7 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
|
|||||||
// mock 方法(client)
|
// mock 方法(client)
|
||||||
PayClient client = mock(PayClient.class);
|
PayClient client = mock(PayClient.class);
|
||||||
when(payClientFactory.getPayClient(eq(10L))).thenReturn(client);
|
when(payClientFactory.getPayClient(eq(10L))).thenReturn(client);
|
||||||
// mock 方法()
|
// mock 方法(支付渠道的调用)
|
||||||
PayOrderRespDTO unifiedOrderResp = randomPojo(PayOrderRespDTO.class, o -> o.setChannelErrorCode(null).setChannelErrorMsg(null)
|
PayOrderRespDTO unifiedOrderResp = randomPojo(PayOrderRespDTO.class, o -> o.setChannelErrorCode(null).setChannelErrorMsg(null)
|
||||||
.setDisplayMode(PayOrderDisplayModeEnum.URL.getMode()).setDisplayContent("tudou"));
|
.setDisplayMode(PayOrderDisplayModeEnum.URL.getMode()).setDisplayContent("tudou"));
|
||||||
when(client.unifiedOrder(argThat(payOrderUnifiedReqDTO -> {
|
when(client.unifiedOrder(argThat(payOrderUnifiedReqDTO -> {
|
||||||
@ -553,14 +596,193 @@ public class PayOrderServiceTest extends BaseDbAndRedisUnitTest {
|
|||||||
assertPojoEquals(order, orderMapper.selectOne(null),
|
assertPojoEquals(order, orderMapper.selectOne(null),
|
||||||
"updateTime", "updater");
|
"updateTime", "updater");
|
||||||
// 断言,调用
|
// 断言,调用
|
||||||
verify(notifyService).createPayNotifyTask(argThat(new ArgumentMatcher<PayNotifyTaskCreateReqDTO>() {
|
verify(notifyService).createPayNotifyTask(argThat(reqDTO -> {
|
||||||
@Override
|
|
||||||
public boolean matches(PayNotifyTaskCreateReqDTO reqDTO) {
|
|
||||||
assertEquals(reqDTO.getType(), PayNotifyTypeEnum.ORDER.getType());
|
assertEquals(reqDTO.getType(), PayNotifyTypeEnum.ORDER.getType());
|
||||||
assertEquals(reqDTO.getDataId(), orderExtension.getOrderId());
|
assertEquals(reqDTO.getDataId(), orderExtension.getOrderId());
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNotifyOrderClosed_orderExtension_notFound() {
|
||||||
|
// 准备参数
|
||||||
|
PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L));
|
||||||
|
PayOrderRespDTO notify = randomPojo(PayOrderRespDTO.class,
|
||||||
|
o -> o.setStatus(PayOrderStatusRespEnum.CLOSED.getStatus()));
|
||||||
|
|
||||||
|
// 调用,并断言异常
|
||||||
|
assertServiceException(() -> orderService.notifyOrder(channel, notify),
|
||||||
|
ORDER_EXTENSION_NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNotifyOrderClosed_orderExtension_closed() {
|
||||||
|
// mock 数据(PayOrderExtensionDO)
|
||||||
|
PayOrderExtensionDO orderExtension = randomPojo(PayOrderExtensionDO.class,
|
||||||
|
o -> o.setStatus(PayOrderStatusEnum.CLOSED.getStatus())
|
||||||
|
.setNo("P110"));
|
||||||
|
orderExtensionMapper.insert(orderExtension);
|
||||||
|
// 准备参数
|
||||||
|
PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L));
|
||||||
|
PayOrderRespDTO notify = randomPojo(PayOrderRespDTO.class,
|
||||||
|
o -> o.setStatus(PayOrderStatusRespEnum.CLOSED.getStatus())
|
||||||
|
.setOutTradeNo("P110"));
|
||||||
|
|
||||||
|
// 调用,并断言
|
||||||
|
orderService.notifyOrder(channel, notify);
|
||||||
|
// 断言 PayOrderExtensionDO :数据未更新,因为它是 CLOSED
|
||||||
|
assertPojoEquals(orderExtension, orderExtensionMapper.selectOne(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNotifyOrderClosed_orderExtension_paid() {
|
||||||
|
// mock 数据(PayOrderExtensionDO)
|
||||||
|
PayOrderExtensionDO orderExtension = randomPojo(PayOrderExtensionDO.class,
|
||||||
|
o -> o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus())
|
||||||
|
.setNo("P110"));
|
||||||
|
orderExtensionMapper.insert(orderExtension);
|
||||||
|
// 准备参数
|
||||||
|
PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L));
|
||||||
|
PayOrderRespDTO notify = randomPojo(PayOrderRespDTO.class,
|
||||||
|
o -> o.setStatus(PayOrderStatusRespEnum.CLOSED.getStatus())
|
||||||
|
.setOutTradeNo("P110"));
|
||||||
|
|
||||||
|
// 调用,并断言
|
||||||
|
orderService.notifyOrder(channel, notify);
|
||||||
|
// 断言 PayOrderExtensionDO :数据未更新,因为它是 SUCCESS
|
||||||
|
assertPojoEquals(orderExtension, orderExtensionMapper.selectOne(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNotifyOrderClosed_orderExtension_refund() {
|
||||||
|
// mock 数据(PayOrderExtensionDO)
|
||||||
|
PayOrderExtensionDO orderExtension = randomPojo(PayOrderExtensionDO.class,
|
||||||
|
o -> o.setStatus(PayOrderStatusEnum.REFUND.getStatus())
|
||||||
|
.setNo("P110"));
|
||||||
|
orderExtensionMapper.insert(orderExtension);
|
||||||
|
// 准备参数
|
||||||
|
PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L));
|
||||||
|
PayOrderRespDTO notify = randomPojo(PayOrderRespDTO.class,
|
||||||
|
o -> o.setStatus(PayOrderStatusRespEnum.CLOSED.getStatus())
|
||||||
|
.setOutTradeNo("P110"));
|
||||||
|
|
||||||
|
// 调用,并断言异常
|
||||||
|
assertServiceException(() -> orderService.notifyOrder(channel, notify),
|
||||||
|
ORDER_EXTENSION_STATUS_IS_NOT_WAITING);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNotifyOrderClosed_orderExtension_waiting() {
|
||||||
|
// mock 数据(PayOrderExtensionDO)
|
||||||
|
PayOrderExtensionDO orderExtension = randomPojo(PayOrderExtensionDO.class,
|
||||||
|
o -> o.setStatus(PayOrderStatusEnum.WAITING.getStatus())
|
||||||
|
.setNo("P110"));
|
||||||
|
orderExtensionMapper.insert(orderExtension);
|
||||||
|
// 准备参数
|
||||||
|
PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L));
|
||||||
|
PayOrderRespDTO notify = randomPojo(PayOrderRespDTO.class,
|
||||||
|
o -> o.setStatus(PayOrderStatusRespEnum.CLOSED.getStatus())
|
||||||
|
.setOutTradeNo("P110"));
|
||||||
|
|
||||||
|
// 调用
|
||||||
|
orderService.notifyOrder(channel, notify);
|
||||||
|
// 断言 PayOrderExtensionDO
|
||||||
|
orderExtension.setStatus(PayOrderStatusEnum.CLOSED.getStatus()).setChannelNotifyData(toJsonString(notify))
|
||||||
|
.setChannelErrorCode(notify.getChannelErrorCode()).setChannelErrorMsg(notify.getChannelErrorMsg());
|
||||||
|
assertPojoEquals(orderExtension, orderExtensionMapper.selectOne(null),
|
||||||
|
"updateTime", "updater");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateOrderRefundPrice_notFound() {
|
||||||
|
// 准备参数
|
||||||
|
Long id = randomLongId();
|
||||||
|
Integer incrRefundPrice = randomInteger();
|
||||||
|
|
||||||
|
// 调用,并断言异常
|
||||||
|
assertServiceException(() -> orderService.updateOrderRefundPrice(id, incrRefundPrice),
|
||||||
|
ORDER_NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateOrderRefundPrice_waiting() {
|
||||||
|
testUpdateOrderRefundPrice_waitingOrClosed(PayOrderStatusEnum.WAITING.getStatus());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateOrderRefundPrice_closed() {
|
||||||
|
testUpdateOrderRefundPrice_waitingOrClosed(PayOrderStatusEnum.CLOSED.getStatus());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testUpdateOrderRefundPrice_waitingOrClosed(Integer status) {
|
||||||
|
// mock 数据(PayOrderDO)
|
||||||
|
PayOrderDO order = randomPojo(PayOrderDO.class,
|
||||||
|
o -> o.setStatus(status));
|
||||||
|
orderMapper.insert(order);
|
||||||
|
// 准备参数
|
||||||
|
Long id = order.getId();
|
||||||
|
Integer incrRefundPrice = randomInteger();
|
||||||
|
|
||||||
|
// 调用,并断言异常
|
||||||
|
assertServiceException(() -> orderService.updateOrderRefundPrice(id, incrRefundPrice),
|
||||||
|
ORDER_REFUND_FAIL_STATUS_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateOrderRefundPrice_priceExceed() {
|
||||||
|
// mock 数据(PayOrderDO)
|
||||||
|
PayOrderDO order = randomPojo(PayOrderDO.class,
|
||||||
|
o -> o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus())
|
||||||
|
.setRefundPrice(1).setPrice(10));
|
||||||
|
orderMapper.insert(order);
|
||||||
|
// 准备参数
|
||||||
|
Long id = order.getId();
|
||||||
|
Integer incrRefundPrice = 10;
|
||||||
|
|
||||||
|
// 调用,并断言异常
|
||||||
|
assertServiceException(() -> orderService.updateOrderRefundPrice(id, incrRefundPrice),
|
||||||
|
REFUND_PRICE_EXCEED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateOrderRefundPrice_refund() {
|
||||||
|
testUpdateOrderRefundPrice_refundOrSuccess(PayOrderStatusEnum.REFUND.getStatus());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateOrderRefundPrice_success() {
|
||||||
|
testUpdateOrderRefundPrice_refundOrSuccess(PayOrderStatusEnum.SUCCESS.getStatus());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testUpdateOrderRefundPrice_refundOrSuccess(Integer status) {
|
||||||
|
// mock 数据(PayOrderDO)
|
||||||
|
PayOrderDO order = randomPojo(PayOrderDO.class,
|
||||||
|
o -> o.setStatus(status).setRefundPrice(1).setPrice(10));
|
||||||
|
orderMapper.insert(order);
|
||||||
|
// 准备参数
|
||||||
|
Long id = order.getId();
|
||||||
|
Integer incrRefundPrice = 8;
|
||||||
|
|
||||||
|
// 调用
|
||||||
|
orderService.updateOrderRefundPrice(id, incrRefundPrice);
|
||||||
|
// 断言
|
||||||
|
order.setRefundPrice(9).setStatus(PayOrderStatusEnum.REFUND.getStatus());
|
||||||
|
assertPojoEquals(order, orderMapper.selectOne(null),
|
||||||
|
"updateTime", "updater");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetOrderExtension() {
|
||||||
|
// mock 数据(PayOrderExtensionDO)
|
||||||
|
PayOrderExtensionDO orderExtension = randomPojo(PayOrderExtensionDO.class);
|
||||||
|
orderExtensionMapper.insert(orderExtension);
|
||||||
|
// 准备参数
|
||||||
|
Long id = orderExtension.getId();
|
||||||
|
|
||||||
|
// 调用
|
||||||
|
PayOrderExtensionDO dbOrderExtension = orderService.getOrderExtension(id);
|
||||||
|
// 断言
|
||||||
|
assertPojoEquals(dbOrderExtension, orderExtension);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,19 @@
|
|||||||
package cn.iocoder.yudao.module.pay.service.refund;
|
package cn.iocoder.yudao.module.pay.service.refund;
|
||||||
|
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.yudao.framework.pay.core.client.PayClient;
|
||||||
import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory;
|
import cn.iocoder.yudao.framework.pay.core.client.PayClientFactory;
|
||||||
import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
|
import cn.iocoder.yudao.framework.pay.core.enums.channel.PayChannelEnum;
|
||||||
import cn.iocoder.yudao.framework.test.core.ut.BaseDbAndRedisUnitTest;
|
import cn.iocoder.yudao.framework.test.core.ut.BaseDbAndRedisUnitTest;
|
||||||
import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
|
import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
|
||||||
import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundExportReqVO;
|
import cn.iocoder.yudao.module.pay.api.refund.dto.PayRefundCreateReqDTO;import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundExportReqVO;
|
||||||
import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundPageReqVO;
|
import cn.iocoder.yudao.module.pay.controller.admin.refund.vo.PayRefundPageReqVO;
|
||||||
|
import cn.iocoder.yudao.module.pay.dal.dataobject.app.PayAppDO;
|
||||||
|
import cn.iocoder.yudao.module.pay.dal.dataobject.channel.PayChannelDO;
|
||||||
|
import cn.iocoder.yudao.module.pay.dal.dataobject.order.PayOrderDO;
|
||||||
import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO;
|
import cn.iocoder.yudao.module.pay.dal.dataobject.refund.PayRefundDO;
|
||||||
import cn.iocoder.yudao.module.pay.dal.mysql.refund.PayRefundMapper;
|
import cn.iocoder.yudao.module.pay.dal.mysql.refund.PayRefundMapper;
|
||||||
|
import cn.iocoder.yudao.module.pay.dal.redis.no.PayNoRedisDAO;
|
||||||
import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
|
import cn.iocoder.yudao.module.pay.enums.order.PayOrderStatusEnum;
|
||||||
import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum;
|
import cn.iocoder.yudao.module.pay.enums.refund.PayRefundStatusEnum;
|
||||||
import cn.iocoder.yudao.module.pay.framework.pay.config.PayProperties;
|
import cn.iocoder.yudao.module.pay.framework.pay.config.PayProperties;
|
||||||
@ -24,12 +29,25 @@ import javax.annotation.Resource;
|
|||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildBetweenTime;
|
||||||
|
import static cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils.buildTime;
|
||||||
import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
|
import static cn.iocoder.yudao.framework.common.util.object.ObjectUtils.cloneIgnoreId;
|
||||||
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
|
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
|
||||||
|
import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
|
||||||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
|
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
|
||||||
|
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomString;
|
||||||
|
import static cn.iocoder.yudao.module.pay.enums.ErrorCodeConstants.*;
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
@Import(PayRefundServiceImpl.class)
|
/**
|
||||||
|
* {@link PayRefundServiceImpl} 的单元测试类
|
||||||
|
*
|
||||||
|
* @author 芋艿
|
||||||
|
*/
|
||||||
|
@Import({PayRefundServiceImpl.class, PayNoRedisDAO.class})
|
||||||
public class PayRefundServiceTest extends BaseDbAndRedisUnitTest {
|
public class PayRefundServiceTest extends BaseDbAndRedisUnitTest {
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
@ -56,45 +74,41 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest {
|
|||||||
// mock 数据
|
// mock 数据
|
||||||
PayRefundDO dbRefund = randomPojo(PayRefundDO.class, o -> { // 等会查询到
|
PayRefundDO dbRefund = randomPojo(PayRefundDO.class, o -> { // 等会查询到
|
||||||
o.setAppId(1L);
|
o.setAppId(1L);
|
||||||
o.setChannelId(1L);
|
|
||||||
o.setChannelCode(PayChannelEnum.WX_PUB.getCode());
|
o.setChannelCode(PayChannelEnum.WX_PUB.getCode());
|
||||||
o.setOrderId(1L);
|
|
||||||
o.setNo("OT0000001");
|
|
||||||
o.setMerchantOrderId("MOT0000001");
|
o.setMerchantOrderId("MOT0000001");
|
||||||
o.setMerchantRefundId("MRF0000001");
|
o.setMerchantRefundId("MRF0000001");
|
||||||
o.setNotifyUrl("https://www.cancanzi.com");
|
|
||||||
o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus());
|
o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus());
|
||||||
o.setPayPrice(100);
|
|
||||||
o.setRefundPrice(500);
|
|
||||||
o.setReason("就是想退款了,你有意见吗");
|
|
||||||
o.setUserIp("127.0.0.1");
|
|
||||||
o.setChannelOrderNo("CH0000001");
|
o.setChannelOrderNo("CH0000001");
|
||||||
o.setChannelRefundNo("CHR0000001");
|
o.setChannelRefundNo("CHR0000001");
|
||||||
o.setChannelErrorCode("");
|
o.setCreateTime(buildTime(2021, 1, 10));
|
||||||
o.setChannelErrorMsg("");
|
|
||||||
o.setSuccessTime(LocalDateTime.of(2021, 1, 1, 10, 10, 15));
|
|
||||||
o.setCreateTime(LocalDateTime.of(2021, 1, 1, 10, 10, 10));
|
|
||||||
o.setUpdateTime(LocalDateTime.of(2021, 1, 1, 10, 10, 35));
|
|
||||||
});
|
});
|
||||||
refundMapper.insert(dbRefund);
|
refundMapper.insert(dbRefund);
|
||||||
// 测试 appId 不匹配
|
// 测试 appId 不匹配
|
||||||
refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setAppId(2L)));
|
refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setAppId(2L)));
|
||||||
// 测试 channelCode 不匹配
|
// 测试 channelCode 不匹配
|
||||||
refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setChannelCode(PayChannelEnum.ALIPAY_APP.getCode())));
|
refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setChannelCode(PayChannelEnum.ALIPAY_APP.getCode())));
|
||||||
// 测试 merchantRefundNo 不匹配
|
// 测试 merchantOrderId 不匹配
|
||||||
refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setMerchantRefundId("MRF1111112")));
|
refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setMerchantOrderId(randomString())));
|
||||||
|
// 测试 merchantRefundId 不匹配
|
||||||
|
refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setMerchantRefundId(randomString())));
|
||||||
|
// 测试 channelOrderNo 不匹配
|
||||||
|
refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setChannelOrderNo(randomString())));
|
||||||
|
// 测试 channelRefundNo 不匹配
|
||||||
|
refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setChannelRefundNo(randomString())));
|
||||||
// 测试 status 不匹配
|
// 测试 status 不匹配
|
||||||
refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setStatus(PayOrderStatusEnum.WAITING.getStatus())));
|
refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setStatus(PayOrderStatusEnum.WAITING.getStatus())));
|
||||||
// 测试 createTime 不匹配
|
// 测试 createTime 不匹配
|
||||||
refundMapper.insert(cloneIgnoreId(dbRefund, o ->
|
refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setCreateTime(buildTime(2021, 1, 1))));
|
||||||
o.setCreateTime(LocalDateTime.of(2022, 1, 1, 10, 10, 10))));
|
|
||||||
// 准备参数
|
// 准备参数
|
||||||
PayRefundPageReqVO reqVO = new PayRefundPageReqVO();
|
PayRefundPageReqVO reqVO = new PayRefundPageReqVO();
|
||||||
reqVO.setAppId(1L);
|
reqVO.setAppId(1L);
|
||||||
reqVO.setChannelCode(PayChannelEnum.WX_PUB.getCode());
|
reqVO.setChannelCode(PayChannelEnum.WX_PUB.getCode());
|
||||||
|
reqVO.setMerchantOrderId("MOT0000001");
|
||||||
reqVO.setMerchantRefundId("MRF0000001");
|
reqVO.setMerchantRefundId("MRF0000001");
|
||||||
reqVO.setStatus(PayRefundStatusEnum.SUCCESS.getStatus());
|
reqVO.setStatus(PayOrderStatusEnum.SUCCESS.getStatus());
|
||||||
reqVO.setCreateTime((new LocalDateTime[]{LocalDateTime.of(2021, 1, 1, 10, 10, 10), LocalDateTime.of(2021, 1, 1, 10, 10, 12)}));
|
reqVO.setChannelOrderNo("CH0000001");
|
||||||
|
reqVO.setChannelRefundNo("CHR0000001");
|
||||||
|
reqVO.setCreateTime(buildBetweenTime(2021, 1, 9, 2021, 1, 11));
|
||||||
|
|
||||||
// 调用
|
// 调用
|
||||||
PageResult<PayRefundDO> pageResult = refundService.getRefundPage(reqVO);
|
PageResult<PayRefundDO> pageResult = refundService.getRefundPage(reqVO);
|
||||||
@ -109,45 +123,41 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest {
|
|||||||
// mock 数据
|
// mock 数据
|
||||||
PayRefundDO dbRefund = randomPojo(PayRefundDO.class, o -> { // 等会查询到
|
PayRefundDO dbRefund = randomPojo(PayRefundDO.class, o -> { // 等会查询到
|
||||||
o.setAppId(1L);
|
o.setAppId(1L);
|
||||||
o.setChannelId(1L);
|
|
||||||
o.setChannelCode(PayChannelEnum.WX_PUB.getCode());
|
o.setChannelCode(PayChannelEnum.WX_PUB.getCode());
|
||||||
o.setOrderId(1L);
|
|
||||||
o.setNo("OT0000001");
|
|
||||||
o.setMerchantOrderId("MOT0000001");
|
o.setMerchantOrderId("MOT0000001");
|
||||||
o.setMerchantRefundId("MRF0000001");
|
o.setMerchantRefundId("MRF0000001");
|
||||||
o.setNotifyUrl("https://www.cancanzi.com");
|
|
||||||
o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus());
|
o.setStatus(PayOrderStatusEnum.SUCCESS.getStatus());
|
||||||
o.setPayPrice(100);
|
|
||||||
o.setRefundPrice(500);
|
|
||||||
o.setReason("就是想退款了,你有意见吗");
|
|
||||||
o.setUserIp("127.0.0.1");
|
|
||||||
o.setChannelOrderNo("CH0000001");
|
o.setChannelOrderNo("CH0000001");
|
||||||
o.setChannelRefundNo("CHR0000001");
|
o.setChannelRefundNo("CHR0000001");
|
||||||
o.setChannelErrorCode("");
|
o.setCreateTime(buildTime(2021, 1, 10));
|
||||||
o.setChannelErrorMsg("");
|
|
||||||
o.setSuccessTime(LocalDateTime.of(2021, 1, 1, 10, 10, 15));
|
|
||||||
o.setCreateTime(LocalDateTime.of(2021, 1, 1, 10, 10, 10));
|
|
||||||
o.setUpdateTime(LocalDateTime.of(2021, 1, 1, 10, 10, 35));
|
|
||||||
});
|
});
|
||||||
refundMapper.insert(dbRefund);
|
refundMapper.insert(dbRefund);
|
||||||
// 测试 appId 不匹配
|
// 测试 appId 不匹配
|
||||||
refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setAppId(2L)));
|
refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setAppId(2L)));
|
||||||
// 测试 channelCode 不匹配
|
// 测试 channelCode 不匹配
|
||||||
refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setChannelCode(PayChannelEnum.ALIPAY_APP.getCode())));
|
refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setChannelCode(PayChannelEnum.ALIPAY_APP.getCode())));
|
||||||
// 测试 merchantRefundNo 不匹配
|
// 测试 merchantOrderId 不匹配
|
||||||
refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setMerchantRefundId("MRF1111112")));
|
refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setMerchantOrderId(randomString())));
|
||||||
|
// 测试 merchantRefundId 不匹配
|
||||||
|
refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setMerchantRefundId(randomString())));
|
||||||
|
// 测试 channelOrderNo 不匹配
|
||||||
|
refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setChannelOrderNo(randomString())));
|
||||||
|
// 测试 channelRefundNo 不匹配
|
||||||
|
refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setChannelRefundNo(randomString())));
|
||||||
// 测试 status 不匹配
|
// 测试 status 不匹配
|
||||||
refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setStatus(PayOrderStatusEnum.WAITING.getStatus())));
|
refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setStatus(PayOrderStatusEnum.WAITING.getStatus())));
|
||||||
// 测试 createTime 不匹配
|
// 测试 createTime 不匹配
|
||||||
refundMapper.insert(cloneIgnoreId(dbRefund, o ->
|
refundMapper.insert(cloneIgnoreId(dbRefund, o -> o.setCreateTime(buildTime(2021, 1, 1))));
|
||||||
o.setCreateTime(LocalDateTime.of(2022, 1, 1, 10, 10, 10))));
|
|
||||||
|
|
||||||
// 准备参数
|
// 准备参数
|
||||||
PayRefundExportReqVO reqVO = new PayRefundExportReqVO();
|
PayRefundExportReqVO reqVO = new PayRefundExportReqVO();
|
||||||
reqVO.setAppId(1L);
|
reqVO.setAppId(1L);
|
||||||
reqVO.setChannelCode(PayChannelEnum.WX_PUB.getCode());
|
reqVO.setChannelCode(PayChannelEnum.WX_PUB.getCode());
|
||||||
reqVO.setStatus(PayRefundStatusEnum.SUCCESS.getStatus());
|
reqVO.setMerchantOrderId("MOT0000001");
|
||||||
reqVO.setCreateTime((new LocalDateTime[]{LocalDateTime.of(2021, 1, 1, 10, 10, 10), LocalDateTime.of(2021, 1, 1, 10, 10, 12)}));
|
reqVO.setMerchantRefundId("MRF0000001");
|
||||||
|
reqVO.setStatus(PayOrderStatusEnum.SUCCESS.getStatus());
|
||||||
|
reqVO.setChannelOrderNo("CH0000001");
|
||||||
|
reqVO.setChannelRefundNo("CHR0000001");
|
||||||
|
reqVO.setCreateTime(buildBetweenTime(2021, 1, 9, 2021, 1, 11));
|
||||||
|
|
||||||
// 调用
|
// 调用
|
||||||
List<PayRefundDO> list = refundService.getRefundList(reqVO);
|
List<PayRefundDO> list = refundService.getRefundList(reqVO);
|
||||||
@ -156,4 +166,151 @@ public class PayRefundServiceTest extends BaseDbAndRedisUnitTest {
|
|||||||
assertPojoEquals(dbRefund, list.get(0));
|
assertPojoEquals(dbRefund, list.get(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateRefund_orderNotFound() {
|
||||||
|
PayRefundCreateReqDTO reqDTO = randomPojo(PayRefundCreateReqDTO.class,
|
||||||
|
o -> o.setAppId(1L));
|
||||||
|
// mock 方法(app)
|
||||||
|
PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L));
|
||||||
|
when(appService.validPayApp(eq(1L))).thenReturn(app);
|
||||||
|
|
||||||
|
// 调用,并断言异常
|
||||||
|
assertServiceException(() -> refundService.createPayRefund(reqDTO),
|
||||||
|
ORDER_NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateRefund_orderWaiting() {
|
||||||
|
testCreateRefund_orderWaitingOrClosed(PayOrderStatusEnum.WAITING.getStatus());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateRefund_orderClosed() {
|
||||||
|
testCreateRefund_orderWaitingOrClosed(PayOrderStatusEnum.CLOSED.getStatus());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testCreateRefund_orderWaitingOrClosed(Integer status) {
|
||||||
|
// 准备参数
|
||||||
|
PayRefundCreateReqDTO reqDTO = randomPojo(PayRefundCreateReqDTO.class,
|
||||||
|
o -> o.setAppId(1L).setMerchantOrderId("100"));
|
||||||
|
// mock 方法(app)
|
||||||
|
PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L));
|
||||||
|
when(appService.validPayApp(eq(1L))).thenReturn(app);
|
||||||
|
// mock 数据(order)
|
||||||
|
PayOrderDO order = randomPojo(PayOrderDO.class, o -> o.setStatus(status));
|
||||||
|
when(orderService.getOrder(eq(1L), eq("100"))).thenReturn(order);
|
||||||
|
|
||||||
|
// 调用,并断言异常
|
||||||
|
assertServiceException(() -> refundService.createPayRefund(reqDTO),
|
||||||
|
ORDER_REFUND_FAIL_STATUS_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateRefund_refundPriceExceed() {
|
||||||
|
// 准备参数
|
||||||
|
PayRefundCreateReqDTO reqDTO = randomPojo(PayRefundCreateReqDTO.class,
|
||||||
|
o -> o.setAppId(1L).setMerchantOrderId("100").setPrice(10));
|
||||||
|
// mock 方法(app)
|
||||||
|
PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L));
|
||||||
|
when(appService.validPayApp(eq(1L))).thenReturn(app);
|
||||||
|
// mock 数据(order)
|
||||||
|
PayOrderDO order = randomPojo(PayOrderDO.class, o ->
|
||||||
|
o.setStatus(PayOrderStatusEnum.REFUND.getStatus())
|
||||||
|
.setPrice(10).setRefundPrice(1));
|
||||||
|
when(orderService.getOrder(eq(1L), eq("100"))).thenReturn(order);
|
||||||
|
|
||||||
|
// 调用,并断言异常
|
||||||
|
assertServiceException(() -> refundService.createPayRefund(reqDTO),
|
||||||
|
REFUND_PRICE_EXCEED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateRefund_orderHasRefunding() {
|
||||||
|
// 准备参数
|
||||||
|
PayRefundCreateReqDTO reqDTO = randomPojo(PayRefundCreateReqDTO.class,
|
||||||
|
o -> o.setAppId(1L).setMerchantOrderId("100").setPrice(10));
|
||||||
|
// mock 方法(app)
|
||||||
|
PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L));
|
||||||
|
when(appService.validPayApp(eq(1L))).thenReturn(app);
|
||||||
|
// mock 数据(order)
|
||||||
|
PayOrderDO order = randomPojo(PayOrderDO.class, o ->
|
||||||
|
o.setStatus(PayOrderStatusEnum.REFUND.getStatus())
|
||||||
|
.setPrice(10).setRefundPrice(1));
|
||||||
|
when(orderService.getOrder(eq(1L), eq("100"))).thenReturn(order);
|
||||||
|
// mock 数据(refund 在退款中)
|
||||||
|
PayRefundDO refund = randomPojo(PayRefundDO.class, o ->
|
||||||
|
o.setOrderId(order.getId()).setStatus(PayOrderStatusEnum.WAITING.getStatus()));
|
||||||
|
refundMapper.insert(refund);
|
||||||
|
|
||||||
|
// 调用,并断言异常
|
||||||
|
assertServiceException(() -> refundService.createPayRefund(reqDTO),
|
||||||
|
REFUND_PRICE_EXCEED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateRefund_channelNotFound() {
|
||||||
|
// 准备参数
|
||||||
|
PayRefundCreateReqDTO reqDTO = randomPojo(PayRefundCreateReqDTO.class,
|
||||||
|
o -> o.setAppId(1L).setMerchantOrderId("100").setPrice(9));
|
||||||
|
// mock 方法(app)
|
||||||
|
PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L));
|
||||||
|
when(appService.validPayApp(eq(1L))).thenReturn(app);
|
||||||
|
// mock 数据(order)
|
||||||
|
PayOrderDO order = randomPojo(PayOrderDO.class, o ->
|
||||||
|
o.setStatus(PayOrderStatusEnum.REFUND.getStatus())
|
||||||
|
.setPrice(10).setRefundPrice(1)
|
||||||
|
.setChannelId(1L).setChannelCode(PayChannelEnum.ALIPAY_APP.getCode()));
|
||||||
|
when(orderService.getOrder(eq(1L), eq("100"))).thenReturn(order);
|
||||||
|
// mock 方法(channel)
|
||||||
|
PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L)
|
||||||
|
.setCode(PayChannelEnum.ALIPAY_APP.getCode()));
|
||||||
|
when(channelService.validPayChannel(eq(1L))).thenReturn(channel);
|
||||||
|
|
||||||
|
// 调用,并断言异常
|
||||||
|
assertServiceException(() -> refundService.createPayRefund(reqDTO),
|
||||||
|
CHANNEL_NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateRefund_refundExists() {
|
||||||
|
// 准备参数
|
||||||
|
PayRefundCreateReqDTO reqDTO = randomPojo(PayRefundCreateReqDTO.class,
|
||||||
|
o -> o.setAppId(1L).setMerchantOrderId("100").setPrice(9)
|
||||||
|
.setReason("测试退款"));
|
||||||
|
// mock 方法(app)
|
||||||
|
PayAppDO app = randomPojo(PayAppDO.class, o -> o.setId(1L));
|
||||||
|
when(appService.validPayApp(eq(1L))).thenReturn(app);
|
||||||
|
// mock 数据(order)
|
||||||
|
PayOrderDO order = randomPojo(PayOrderDO.class, o ->
|
||||||
|
o.setStatus(PayOrderStatusEnum.REFUND.getStatus())
|
||||||
|
.setPrice(10).setRefundPrice(1)
|
||||||
|
.setChannelId(1L).setChannelCode(PayChannelEnum.ALIPAY_APP.getCode()));
|
||||||
|
when(orderService.getOrder(eq(1L), eq("100"))).thenReturn(order);
|
||||||
|
// mock 方法(channel)
|
||||||
|
PayChannelDO channel = randomPojo(PayChannelDO.class, o -> o.setId(10L)
|
||||||
|
.setCode(PayChannelEnum.ALIPAY_APP.getCode()));
|
||||||
|
when(channelService.validPayChannel(eq(1L))).thenReturn(channel);
|
||||||
|
// mock 方法(client)
|
||||||
|
PayClient client = mock(PayClient.class);
|
||||||
|
when(payClientFactory.getPayClient(eq(10L))).thenReturn(client);
|
||||||
|
// mock 数据(refund 已存在)
|
||||||
|
PayRefundDO refund = randomPojo(PayRefundDO.class, o ->
|
||||||
|
o.setOrderId(order.getId()).setStatus(PayOrderStatusEnum.WAITING.getStatus()));
|
||||||
|
refundMapper.insert(refund);
|
||||||
|
|
||||||
|
// 调用,并断言异常
|
||||||
|
assertServiceException(() -> refundService.createPayRefund(reqDTO),
|
||||||
|
REFUND_EXISTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateRefund_invokeException() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateRefund_invokeSuccess() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -82,29 +82,25 @@ CREATE TABLE IF NOT EXISTS `pay_order_extension` (
|
|||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS `pay_refund` (
|
CREATE TABLE IF NOT EXISTS `pay_refund` (
|
||||||
"id" number NOT NULL GENERATED BY DEFAULT AS IDENTITY,
|
"id" number NOT NULL GENERATED BY DEFAULT AS IDENTITY,
|
||||||
|
`no` varchar(64) NOT NULL,
|
||||||
`app_id` bigint(20) NOT NULL,
|
`app_id` bigint(20) NOT NULL,
|
||||||
`channel_id` bigint(20) NOT NULL,
|
`channel_id` bigint(20) NOT NULL,
|
||||||
`channel_code` varchar(32) NOT NULL,
|
`channel_code` varchar(32) NOT NULL,
|
||||||
`order_id` bigint(20) NOT NULL,
|
`order_id` bigint(20) NOT NULL,
|
||||||
`trade_no` varchar(64) NOT NULL,
|
|
||||||
`merchant_order_id` varchar(64) NOT NULL,
|
`merchant_order_id` varchar(64) NOT NULL,
|
||||||
`merchant_refund_no` varchar(64) NOT NULL,
|
`merchant_refund_id` varchar(64) NOT NULL,
|
||||||
`notify_url` varchar(1024) NOT NULL,
|
`notify_url` varchar(1024) NOT NULL,
|
||||||
`notify_status` tinyint(4) NOT NULL,
|
|
||||||
`status` tinyint(4) NOT NULL,
|
`status` tinyint(4) NOT NULL,
|
||||||
`type` tinyint(4) NOT NULL,
|
`pay_price` bigint(20) NOT NULL,
|
||||||
`pay_amount` bigint(20) NOT NULL,
|
`refund_price` bigint(20) NOT NULL,
|
||||||
`refund_amount` bigint(20) NOT NULL,
|
|
||||||
`reason` varchar(256) NOT NULL,
|
`reason` varchar(256) NOT NULL,
|
||||||
`user_ip` varchar(50) NULL DEFAULT NULL,
|
`user_ip` varchar(50) NULL DEFAULT NULL,
|
||||||
`channel_order_no` varchar(64) NOT NULL,
|
`channel_order_no` varchar(64) NOT NULL,
|
||||||
`channel_refund_no` varchar(64) NULL DEFAULT NULL,
|
`channel_refund_no` varchar(64) NULL DEFAULT NULL,
|
||||||
|
`success_time` datetime(0) NULL DEFAULT NULL,
|
||||||
`channel_error_code` varchar(128) NULL DEFAULT NULL,
|
`channel_error_code` varchar(128) NULL DEFAULT NULL,
|
||||||
`channel_error_msg` varchar(256) NULL DEFAULT NULL,
|
`channel_error_msg` varchar(256) NULL DEFAULT NULL,
|
||||||
`channel_extras` varchar(1024) NULL DEFAULT NULL,
|
`channel_notify_data` varchar(1024) NULL,
|
||||||
`expire_time` datetime(0) NULL DEFAULT NULL,
|
|
||||||
`success_time` datetime(0) NULL DEFAULT NULL,
|
|
||||||
`notify_time` datetime(0) NULL DEFAULT NULL,
|
|
||||||
`creator` varchar(64) NULL DEFAULT '',
|
`creator` varchar(64) NULL DEFAULT '',
|
||||||
`create_time` datetime(0) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
`create_time` datetime(0) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
`updater` varchar(64) NULL DEFAULT '',
|
`updater` varchar(64) NULL DEFAULT '',
|
||||||
|
Loading…
Reference in New Issue
Block a user