Merge remote-tracking branch 'origin/feature/mall_product' into member_dev
# Conflicts: # yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/level/MemberLevelServiceImpl.java
This commit is contained in:
commit
b7f54a3061
|
@ -0,0 +1,180 @@
|
||||||
|
package cn.iocoder.yudao.framework.pay.core.client.impl.alipay;
|
||||||
|
|
||||||
|
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||||
|
import cn.hutool.core.util.ReflectUtil;
|
||||||
|
import cn.iocoder.yudao.framework.common.exception.ServiceException;
|
||||||
|
import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
|
||||||
|
import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
|
||||||
|
import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO;
|
||||||
|
import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO;
|
||||||
|
import cn.iocoder.yudao.framework.pay.core.client.exception.PayException;
|
||||||
|
import cn.iocoder.yudao.framework.pay.core.enums.refund.PayRefundStatusRespEnum;
|
||||||
|
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
|
||||||
|
import com.alipay.api.AlipayApiException;
|
||||||
|
import com.alipay.api.DefaultAlipayClient;
|
||||||
|
import com.alipay.api.DefaultSigner;
|
||||||
|
import com.alipay.api.domain.AlipayTradeRefundModel;
|
||||||
|
import com.alipay.api.request.AlipayTradeRefundRequest;
|
||||||
|
import com.alipay.api.response.AlipayTradeRefundResponse;
|
||||||
|
import org.junit.jupiter.api.DisplayName;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.mockito.ArgumentMatcher;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
|
||||||
|
import javax.validation.ConstraintViolationException;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import static cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayPayClientConfig.MODE_PUBLIC_KEY;
|
||||||
|
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
import static org.mockito.ArgumentMatchers.argThat;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author jason
|
||||||
|
*/
|
||||||
|
public abstract class AbstractAlipayClientTest extends BaseMockitoUnitTest {
|
||||||
|
|
||||||
|
private final String privateKey = randomString();
|
||||||
|
|
||||||
|
protected AlipayPayClientConfig config = randomPojo(AlipayPayClientConfig.class, t -> {
|
||||||
|
t.setServerUrl(randomURL());
|
||||||
|
t.setPrivateKey(privateKey);
|
||||||
|
t.setMode(MODE_PUBLIC_KEY);
|
||||||
|
t.setSignType(AlipayPayClientConfig.SIGN_TYPE_DEFAULT);
|
||||||
|
t.setAppCertContent("");
|
||||||
|
t.setAlipayPublicCertContent("");
|
||||||
|
t.setRootCertContent("");
|
||||||
|
});
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
protected DefaultAlipayClient defaultAlipayClient;
|
||||||
|
|
||||||
|
private AbstractAlipayPayClient client;
|
||||||
|
|
||||||
|
public void setClient(AbstractAlipayPayClient client) {
|
||||||
|
this.client = client;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("支付宝 Client 初始化")
|
||||||
|
public void test_do_init() {
|
||||||
|
client.doInit();
|
||||||
|
DefaultAlipayClient realClient = (DefaultAlipayClient) ReflectUtil.getFieldValue(client, "client");
|
||||||
|
assertNotSame(defaultAlipayClient, realClient);
|
||||||
|
assertInstanceOf(DefaultSigner.class, realClient.getSigner());
|
||||||
|
assertEquals(privateKey, ((DefaultSigner) realClient.getSigner()).getPrivateKey());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("支付宝 Client 统一退款成功")
|
||||||
|
public void test_unified_refund_success() throws AlipayApiException {
|
||||||
|
// 准备返回对象
|
||||||
|
String notifyUrl = randomURL();
|
||||||
|
Date refundTime = randomDate();
|
||||||
|
String outRefundNo = randomString();
|
||||||
|
String outTradeNo = randomString();
|
||||||
|
Integer refundAmount = randomInteger();
|
||||||
|
AlipayTradeRefundResponse response = randomPojo(AlipayTradeRefundResponse.class, o -> {
|
||||||
|
o.setSubCode("");
|
||||||
|
o.setGmtRefundPay(refundTime);
|
||||||
|
});
|
||||||
|
// mock
|
||||||
|
when(defaultAlipayClient.execute(argThat((ArgumentMatcher<AlipayTradeRefundRequest>) request -> {
|
||||||
|
assertInstanceOf(AlipayTradeRefundModel.class, request.getBizModel());
|
||||||
|
AlipayTradeRefundModel bizModel = (AlipayTradeRefundModel) request.getBizModel();
|
||||||
|
assertEquals(outRefundNo, bizModel.getOutRequestNo());
|
||||||
|
assertEquals(outTradeNo, bizModel.getOutTradeNo());
|
||||||
|
assertEquals(String.valueOf(refundAmount / 100.0), bizModel.getRefundAmount());
|
||||||
|
return true;
|
||||||
|
}))).thenReturn(response);
|
||||||
|
// 准备请求参数
|
||||||
|
PayRefundUnifiedReqDTO refundReqDTO = randomPojo(PayRefundUnifiedReqDTO.class, o -> {
|
||||||
|
o.setOutRefundNo(outRefundNo);
|
||||||
|
o.setOutTradeNo(outTradeNo);
|
||||||
|
o.setNotifyUrl(notifyUrl);
|
||||||
|
o.setRefundPrice(refundAmount);
|
||||||
|
});
|
||||||
|
PayRefundRespDTO resp = client.unifiedRefund(refundReqDTO);
|
||||||
|
// 断言
|
||||||
|
assertEquals(PayRefundStatusRespEnum.SUCCESS.getStatus(), resp.getStatus());
|
||||||
|
assertNull(resp.getChannelRefundNo());
|
||||||
|
assertEquals(LocalDateTimeUtil.of(refundTime), resp.getSuccessTime());
|
||||||
|
assertEquals(outRefundNo, resp.getOutRefundNo());
|
||||||
|
assertSame(response, resp.getRawData());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("支付宝 Client 统一退款,渠道返回失败")
|
||||||
|
public void test_unified_refund_channel_failed() throws AlipayApiException {
|
||||||
|
// 准备返回对象
|
||||||
|
String notifyUrl = randomURL();
|
||||||
|
String subCode = randomString();
|
||||||
|
String subMsg = randomString();
|
||||||
|
AlipayTradeRefundResponse response = randomPojo(AlipayTradeRefundResponse.class, o -> {
|
||||||
|
o.setSubCode(subCode);
|
||||||
|
o.setSubMsg(subMsg);
|
||||||
|
});
|
||||||
|
// mock
|
||||||
|
when(defaultAlipayClient.execute(argThat((ArgumentMatcher<AlipayTradeRefundRequest>) request -> {
|
||||||
|
assertInstanceOf(AlipayTradeRefundModel.class, request.getBizModel());
|
||||||
|
return true;
|
||||||
|
}))).thenReturn(response);
|
||||||
|
// 准备请求参数
|
||||||
|
String outRefundNo = randomString();
|
||||||
|
String outTradeNo = randomString();
|
||||||
|
PayRefundUnifiedReqDTO refundReqDTO = randomPojo(PayRefundUnifiedReqDTO.class, o -> {
|
||||||
|
o.setOutRefundNo(outRefundNo);
|
||||||
|
o.setOutTradeNo(outTradeNo);
|
||||||
|
o.setNotifyUrl(notifyUrl);
|
||||||
|
});
|
||||||
|
PayRefundRespDTO resp = client.unifiedRefund(refundReqDTO);
|
||||||
|
// 断言
|
||||||
|
assertEquals(PayRefundStatusRespEnum.FAILURE.getStatus(), resp.getStatus());
|
||||||
|
assertNull(resp.getChannelRefundNo());
|
||||||
|
assertEquals(subCode, resp.getChannelErrorCode());
|
||||||
|
assertEquals(subMsg, resp.getChannelErrorMsg());
|
||||||
|
assertNull(resp.getSuccessTime());
|
||||||
|
assertEquals(outRefundNo, resp.getOutRefundNo());
|
||||||
|
assertSame(response, resp.getRawData());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("支付宝 Client 统一退款,参数校验不通过")
|
||||||
|
public void test_unified_refund_param_validate() {
|
||||||
|
// 准备请求参数
|
||||||
|
String notifyUrl = randomURL();
|
||||||
|
PayRefundUnifiedReqDTO refundReqDTO = randomPojo(PayRefundUnifiedReqDTO.class, o -> {
|
||||||
|
o.setOutTradeNo("");
|
||||||
|
o.setNotifyUrl(notifyUrl);
|
||||||
|
});
|
||||||
|
// 断言
|
||||||
|
assertThrows(ConstraintViolationException.class, () -> client.unifiedRefund(refundReqDTO));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("支付宝 Client 统一退款,抛出业务异常")
|
||||||
|
public void test_unified_refund_throw_service_exception() throws AlipayApiException {
|
||||||
|
// mock
|
||||||
|
when(defaultAlipayClient.execute(argThat((ArgumentMatcher<AlipayTradeRefundRequest>) request -> true)))
|
||||||
|
.thenThrow(ServiceExceptionUtil.exception(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR));
|
||||||
|
// 准备请求参数
|
||||||
|
String notifyUrl = randomURL();
|
||||||
|
PayRefundUnifiedReqDTO refundReqDTO = randomPojo(PayRefundUnifiedReqDTO.class, o -> o.setNotifyUrl(notifyUrl));
|
||||||
|
// 断言
|
||||||
|
assertThrows(ServiceException.class, () -> client.unifiedRefund(refundReqDTO));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("支付宝 Client 统一退款,抛出系统异常")
|
||||||
|
public void test_unified_refund_throw_pay_exception() throws AlipayApiException {
|
||||||
|
// mock
|
||||||
|
when(defaultAlipayClient.execute(argThat((ArgumentMatcher<AlipayTradeRefundRequest>) request -> true)))
|
||||||
|
.thenThrow(new RuntimeException("系统异常"));
|
||||||
|
// 准备请求参数
|
||||||
|
String notifyUrl = randomURL();
|
||||||
|
PayRefundUnifiedReqDTO refundReqDTO = randomPojo(PayRefundUnifiedReqDTO.class, o -> o.setNotifyUrl(notifyUrl));
|
||||||
|
// 断言
|
||||||
|
assertThrows(PayException.class, () -> client.unifiedRefund(refundReqDTO));
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,68 +1,44 @@
|
||||||
package cn.iocoder.yudao.framework.pay.core.client.impl.alipay;
|
package cn.iocoder.yudao.framework.pay.core.client.impl.alipay;
|
||||||
|
|
||||||
import cn.hutool.core.date.LocalDateTimeUtil;
|
|
||||||
import cn.hutool.core.util.RandomUtil;
|
import cn.hutool.core.util.RandomUtil;
|
||||||
import cn.hutool.core.util.ReflectUtil;
|
|
||||||
import cn.iocoder.yudao.framework.common.exception.ServiceException;
|
import cn.iocoder.yudao.framework.common.exception.ServiceException;
|
||||||
import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
|
import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
|
||||||
import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
|
import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
|
||||||
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
|
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderRespDTO;
|
||||||
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
|
import cn.iocoder.yudao.framework.pay.core.client.dto.order.PayOrderUnifiedReqDTO;
|
||||||
import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundRespDTO;
|
|
||||||
import cn.iocoder.yudao.framework.pay.core.client.dto.refund.PayRefundUnifiedReqDTO;
|
|
||||||
import cn.iocoder.yudao.framework.pay.core.client.exception.PayException;
|
import cn.iocoder.yudao.framework.pay.core.client.exception.PayException;
|
||||||
import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum;
|
import cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderDisplayModeEnum;
|
||||||
import cn.iocoder.yudao.framework.pay.core.enums.refund.PayRefundStatusRespEnum;
|
|
||||||
import cn.iocoder.yudao.framework.test.core.ut.BaseMockitoUnitTest;
|
|
||||||
import com.alipay.api.AlipayApiException;
|
import com.alipay.api.AlipayApiException;
|
||||||
import com.alipay.api.DefaultAlipayClient;
|
|
||||||
import com.alipay.api.domain.AlipayTradeRefundModel;
|
|
||||||
import com.alipay.api.request.AlipayTradePrecreateRequest;
|
import com.alipay.api.request.AlipayTradePrecreateRequest;
|
||||||
import com.alipay.api.request.AlipayTradeRefundRequest;
|
|
||||||
import com.alipay.api.response.AlipayTradePrecreateResponse;
|
import com.alipay.api.response.AlipayTradePrecreateResponse;
|
||||||
import com.alipay.api.response.AlipayTradeRefundResponse;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.DisplayName;
|
import org.junit.jupiter.api.DisplayName;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.mockito.ArgumentMatcher;
|
import org.mockito.ArgumentMatcher;
|
||||||
import org.mockito.InjectMocks;
|
import org.mockito.InjectMocks;
|
||||||
import org.mockito.Mock;
|
|
||||||
|
|
||||||
import javax.validation.ConstraintViolationException;
|
import javax.validation.ConstraintViolationException;
|
||||||
import java.util.Date;
|
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.pay.core.client.impl.alipay.AlipayPayClientConfig.MODE_PUBLIC_KEY;
|
|
||||||
import static cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum.CLOSED;
|
import static cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum.CLOSED;
|
||||||
import static cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum.WAITING;
|
import static cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum.WAITING;
|
||||||
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
|
import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
|
||||||
import static org.junit.jupiter.api.Assertions.*;
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
import static org.mockito.ArgumentMatchers.argThat;
|
import static org.mockito.ArgumentMatchers.argThat;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@link AlipayQrPayClient} 单元测试
|
* {@link AlipayQrPayClient} 单元测试
|
||||||
*
|
*
|
||||||
* @author jason
|
* @author jason
|
||||||
*/
|
*/
|
||||||
public class AlipayQrPayClientTest extends BaseMockitoUnitTest {
|
public class AlipayQrPayClientTest extends AbstractAlipayClientTest {
|
||||||
|
|
||||||
private final AlipayPayClientConfig config = randomPojo(AlipayPayClientConfig.class, t -> {
|
|
||||||
t.setServerUrl(randomURL());
|
|
||||||
t.setMode(MODE_PUBLIC_KEY);
|
|
||||||
t.setSignType(AlipayPayClientConfig.SIGN_TYPE_DEFAULT);
|
|
||||||
t.setAppCertContent("");
|
|
||||||
t.setAlipayPublicCertContent("");
|
|
||||||
t.setRootCertContent("");
|
|
||||||
});
|
|
||||||
|
|
||||||
@InjectMocks
|
@InjectMocks
|
||||||
AlipayQrPayClient client = new AlipayQrPayClient(randomLongId(), config);
|
private AlipayQrPayClient client = new AlipayQrPayClient(randomLongId(), config);
|
||||||
|
|
||||||
@Mock
|
@BeforeEach
|
||||||
private DefaultAlipayClient defaultAlipayClient;
|
public void setUp() {
|
||||||
|
setClient(client);
|
||||||
@Test
|
|
||||||
public void test_do_init() {
|
|
||||||
client.doInit();
|
|
||||||
assertNotSame(defaultAlipayClient, ReflectUtil.getFieldValue(client, "defaultAlipayClient"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -176,119 +152,4 @@ public class AlipayQrPayClientTest extends BaseMockitoUnitTest {
|
||||||
o.setBody(RandomUtil.randomString(32));
|
o.setBody(RandomUtil.randomString(32));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
@DisplayName("支付包扫描退款成功")
|
|
||||||
public void test_unified_refund_success() throws AlipayApiException {
|
|
||||||
// 准备返回对象
|
|
||||||
String notifyUrl = randomURL();
|
|
||||||
Date refundTime = randomDate();
|
|
||||||
String outRefundNo = randomString();
|
|
||||||
String outTradeNo = randomString();
|
|
||||||
Integer refundAmount = randomInteger();
|
|
||||||
AlipayTradeRefundResponse response = randomPojo(AlipayTradeRefundResponse.class, o -> {
|
|
||||||
o.setSubCode("");
|
|
||||||
o.setGmtRefundPay(refundTime);
|
|
||||||
});
|
|
||||||
// mock
|
|
||||||
when(defaultAlipayClient.execute(argThat((ArgumentMatcher<AlipayTradeRefundRequest>) request -> {
|
|
||||||
assertInstanceOf(AlipayTradeRefundModel.class, request.getBizModel());
|
|
||||||
AlipayTradeRefundModel bizModel = (AlipayTradeRefundModel) request.getBizModel();
|
|
||||||
assertEquals(outRefundNo, bizModel.getOutRequestNo());
|
|
||||||
assertEquals(outTradeNo, bizModel.getOutTradeNo());
|
|
||||||
assertEquals(String.valueOf(refundAmount / 100.0), bizModel.getRefundAmount());
|
|
||||||
return true;
|
|
||||||
}))).thenReturn(response);
|
|
||||||
// 准备请求参数
|
|
||||||
PayRefundUnifiedReqDTO refundReqDTO = randomPojo(PayRefundUnifiedReqDTO.class, o -> {
|
|
||||||
o.setOutRefundNo(outRefundNo);
|
|
||||||
o.setOutTradeNo(outTradeNo);
|
|
||||||
o.setNotifyUrl(notifyUrl);
|
|
||||||
o.setRefundPrice(refundAmount);
|
|
||||||
});
|
|
||||||
PayRefundRespDTO resp = client.unifiedRefund(refundReqDTO);
|
|
||||||
// 断言
|
|
||||||
assertEquals(PayRefundStatusRespEnum.SUCCESS.getStatus(), resp.getStatus());
|
|
||||||
assertNull(resp.getChannelRefundNo());
|
|
||||||
assertEquals(LocalDateTimeUtil.of(refundTime), resp.getSuccessTime());
|
|
||||||
assertEquals(outRefundNo, resp.getOutRefundNo());
|
|
||||||
assertSame(response, resp.getRawData());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@DisplayName("支付包扫描退款,渠道返回失败")
|
|
||||||
public void test_unified_refund_channel_failed() throws AlipayApiException {
|
|
||||||
// 准备返回对象
|
|
||||||
String notifyUrl = randomURL();
|
|
||||||
String subCode = randomString();
|
|
||||||
String subMsg = randomString();
|
|
||||||
AlipayTradeRefundResponse response = randomPojo(AlipayTradeRefundResponse.class, o -> {
|
|
||||||
o.setSubCode(subCode);
|
|
||||||
o.setSubMsg(subMsg);
|
|
||||||
});
|
|
||||||
// mock
|
|
||||||
when(defaultAlipayClient.execute(argThat((ArgumentMatcher<AlipayTradeRefundRequest>) request -> {
|
|
||||||
assertInstanceOf(AlipayTradeRefundModel.class, request.getBizModel());
|
|
||||||
return true;
|
|
||||||
}))).thenReturn(response);
|
|
||||||
// 准备请求参数
|
|
||||||
String outRefundNo = randomString();
|
|
||||||
String outTradeNo = randomString();
|
|
||||||
PayRefundUnifiedReqDTO refundReqDTO = randomPojo(PayRefundUnifiedReqDTO.class, o -> {
|
|
||||||
o.setOutRefundNo(outRefundNo);
|
|
||||||
o.setOutTradeNo(outTradeNo);
|
|
||||||
o.setNotifyUrl(notifyUrl);
|
|
||||||
});
|
|
||||||
PayRefundRespDTO resp = client.unifiedRefund(refundReqDTO);
|
|
||||||
// 断言
|
|
||||||
assertEquals(PayRefundStatusRespEnum.FAILURE.getStatus(), resp.getStatus());
|
|
||||||
assertNull(resp.getChannelRefundNo());
|
|
||||||
assertEquals(subCode, resp.getChannelErrorCode());
|
|
||||||
assertEquals(subMsg, resp.getChannelErrorMsg());
|
|
||||||
assertNull(resp.getSuccessTime());
|
|
||||||
assertEquals(outRefundNo, resp.getOutRefundNo());
|
|
||||||
assertSame(response, resp.getRawData());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@DisplayName("支付包扫描退款,参数校验不通过")
|
|
||||||
public void test_unified_refund_param_validate() {
|
|
||||||
// 准备请求参数
|
|
||||||
String notifyUrl = randomURL();
|
|
||||||
PayRefundUnifiedReqDTO refundReqDTO = randomPojo(PayRefundUnifiedReqDTO.class, o -> {
|
|
||||||
o.setOutTradeNo("");
|
|
||||||
o.setNotifyUrl(notifyUrl);
|
|
||||||
});
|
|
||||||
// 断言
|
|
||||||
assertThrows(ConstraintViolationException.class, () -> client.unifiedRefund(refundReqDTO));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@DisplayName("支付包扫描退款,抛出业务异常")
|
|
||||||
public void test_unified_refund_throw_service_exception() throws AlipayApiException {
|
|
||||||
// mock
|
|
||||||
when(defaultAlipayClient.execute(argThat((ArgumentMatcher<AlipayTradeRefundRequest>) request -> true)))
|
|
||||||
.thenThrow(ServiceExceptionUtil.exception(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR));
|
|
||||||
// 准备请求参数
|
|
||||||
String notifyUrl = randomURL();
|
|
||||||
PayRefundUnifiedReqDTO refundReqDTO = randomPojo(PayRefundUnifiedReqDTO.class, o -> {
|
|
||||||
o.setNotifyUrl(notifyUrl);
|
|
||||||
});
|
|
||||||
// 断言
|
|
||||||
assertThrows(ServiceException.class, () -> client.unifiedRefund(refundReqDTO));
|
|
||||||
}
|
|
||||||
@Test
|
|
||||||
@DisplayName("支付包扫描退款,抛出系统异常")
|
|
||||||
public void test_unified_refund_throw_pay_exception() throws AlipayApiException {
|
|
||||||
// mock
|
|
||||||
when(defaultAlipayClient.execute(argThat((ArgumentMatcher<AlipayTradeRefundRequest>) request -> true)))
|
|
||||||
.thenThrow(new RuntimeException("系统异常"));
|
|
||||||
// 准备请求参数
|
|
||||||
String notifyUrl = randomURL();
|
|
||||||
PayRefundUnifiedReqDTO refundReqDTO = randomPojo(PayRefundUnifiedReqDTO.class, o -> {
|
|
||||||
o.setNotifyUrl(notifyUrl);
|
|
||||||
});
|
|
||||||
// 断言
|
|
||||||
assertThrows(PayException.class, () -> client.unifiedRefund(refundReqDTO));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,6 +52,7 @@ public class MemberLevelRecordDO extends BaseDO {
|
||||||
* 会员此时的经验
|
* 会员此时的经验
|
||||||
*/
|
*/
|
||||||
private Integer userExperience;
|
private Integer userExperience;
|
||||||
|
// TODO @疯狂:是不是 remark 和 description 可以合并成 description 就够了
|
||||||
/**
|
/**
|
||||||
* 备注
|
* 备注
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -39,6 +39,16 @@ public interface MemberExperienceRecordService {
|
||||||
*/
|
*/
|
||||||
PageResult<MemberExperienceRecordDO> getExperienceLogPage(MemberExperienceRecordPageReqVO pageReqVO);
|
PageResult<MemberExperienceRecordDO> getExperienceLogPage(MemberExperienceRecordPageReqVO pageReqVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得会员经验记录列表, 用于 Excel 导出
|
||||||
|
*
|
||||||
|
* @param exportReqVO 查询条件
|
||||||
|
* @return 会员经验记录列表
|
||||||
|
*/
|
||||||
|
List<MemberExperienceLogDO> getExperienceLogList(MemberExperienceLogExportReqVO exportReqVO);
|
||||||
|
|
||||||
|
// TODO @疯狂:类似 MemberLevelLogService 的方法,这里也需要提供一个通用的方法,用于创建经验变动记录
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建 手动调整 经验变动记录
|
* 创建 手动调整 经验变动记录
|
||||||
*
|
*
|
||||||
|
|
|
@ -47,6 +47,16 @@ public interface MemberLevelRecordService {
|
||||||
*/
|
*/
|
||||||
PageResult<MemberLevelRecordDO> getLevelLogPage(MemberLevelRecordPageReqVO pageReqVO);
|
PageResult<MemberLevelRecordDO> getLevelLogPage(MemberLevelRecordPageReqVO pageReqVO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获得会员等级记录列表, 用于 Excel 导出
|
||||||
|
*
|
||||||
|
* @param exportReqVO 查询条件
|
||||||
|
* @return 会员等级记录列表
|
||||||
|
*/
|
||||||
|
List<MemberLevelLogDO> getLevelLogList(MemberLevelLogExportReqVO exportReqVO);
|
||||||
|
|
||||||
|
// TODO @疯狂:把 createCancelLog、createAdjustLog、createAutoUpgradeLog 几个日志合并成一个通用的日志方法;整体的内容,交给 MemberLevelService 去做;以及对应的 level 变化的通知;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 创建记录: 取消等级
|
* 创建记录: 取消等级
|
||||||
*
|
*
|
||||||
|
|
|
@ -141,7 +141,6 @@ public class MemberLevelServiceImpl implements MemberLevelService {
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
void validateConfigValid(Long id, String name, Integer level, Integer experience) {
|
void validateConfigValid(Long id, String name, Integer level, Integer experience) {
|
||||||
List<MemberLevelDO> list = levelMapper.selectList();
|
List<MemberLevelDO> list = levelMapper.selectList();
|
||||||
|
|
||||||
// 校验名称唯一
|
// 校验名称唯一
|
||||||
validateNameUnique(list, id, name);
|
validateNameUnique(list, id, name);
|
||||||
// 校验等级唯一
|
// 校验等级唯一
|
||||||
|
@ -178,19 +177,14 @@ public class MemberLevelServiceImpl implements MemberLevelService {
|
||||||
return levelMapper.selectListByStatus(status);
|
return levelMapper.selectListByStatus(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
|
||||||
@Override
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public void updateUserLevel(MemberUserUpdateLevelReqVO updateReqVO) {
|
public void updateUserLevel(MemberUserUpdateLevelReqVO updateReqVO) {
|
||||||
MemberUserDO user = memberUserMapper.selectById(updateReqVO.getId());
|
MemberUserDO user = memberUserMapper.selectById(updateReqVO.getId());
|
||||||
if (user == null) {
|
if (user == null) {
|
||||||
throw exception(USER_NOT_EXISTS);
|
throw exception(USER_NOT_EXISTS);
|
||||||
}
|
}
|
||||||
|
// 等级未发生变化
|
||||||
// 未调整的情况1
|
|
||||||
if (user.getLevelId() == null && updateReqVO.getLevelId() == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 未调整的情况2
|
|
||||||
if (ObjUtil.equal(user.getLevelId(), updateReqVO.getLevelId())) {
|
if (ObjUtil.equal(user.getLevelId(), updateReqVO.getLevelId())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -218,36 +212,40 @@ public class MemberLevelServiceImpl implements MemberLevelService {
|
||||||
updateUserLevelIdAndExperience(user.getId(), updateReqVO.getLevelId(), totalExperience);
|
updateUserLevelIdAndExperience(user.getId(), updateReqVO.getLevelId(), totalExperience);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 记录会员经验变动
|
// 记录会员经验变动
|
||||||
memberExperienceRecordService.createAdjustLog(user.getId(), experience, totalExperience);
|
memberExperienceRecordService.createAdjustLog(user.getId(), experience, totalExperience);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional(rollbackFor = Exception.class)
|
// TODO @疯狂:方法名,建议改成 increase 或者 add 经验,和项目更统一一些
|
||||||
|
// TODO @疯狂:bizType 改成具体数值,主要是枚举在 api 不好传递,rpc 情况下
|
||||||
@Override
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public void plusExperience(Long userId, Integer experience, MemberExperienceBizTypeEnum bizType, String bizId) {
|
public void plusExperience(Long userId, Integer experience, MemberExperienceBizTypeEnum bizType, String bizId) {
|
||||||
if (experience == 0) {
|
if (experience == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
MemberUserDO user = memberUserMapper.selectById(userId);
|
MemberUserDO user = memberUserMapper.selectById(userId);
|
||||||
if (user.getExperience() == null) {
|
|
||||||
user.setExperience(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 防止扣出负数
|
// 防止扣出负数
|
||||||
int userExperience = NumberUtil.max(user.getExperience() + experience, 0);
|
int userExperience = NumberUtil.max(user.getExperience() + experience, 0);
|
||||||
|
|
||||||
// 创建经验记录
|
// 创建经验记录
|
||||||
memberExperienceRecordService.createBizLog(userId, experience, userExperience, bizType, bizId);
|
memberExperienceRecordService.createBizLog(userId, experience, userExperience, bizType, bizId);
|
||||||
|
|
||||||
// 计算会员等级
|
// 计算会员等级
|
||||||
Long levelId = calcLevel(user, userExperience);
|
MemberLevelDO newLevel = calculateNewLevel(user, userExperience);
|
||||||
|
Long newLevelId = null;
|
||||||
// 更新会员表上的等级编号、经验值
|
if (newLevel != null) {
|
||||||
updateUserLevelIdAndExperience(user.getId(), levelId, userExperience);
|
newLevelId = newLevel.getId();
|
||||||
|
// 保存等级变更记录
|
||||||
|
memberLevelRecordService.createAutoUpgradeLog(user, newLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 更新会员表上的等级编号、经验值
|
||||||
|
updateUserLevelIdAndExperience(user.getId(), newLevelId, userExperience);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO @疯狂:让 memberUserService 那开个方法;每个模块,不直接操作对方的 mapper;
|
||||||
private void updateUserLevelIdAndExperience(Long userId, Long levelId, Integer experience) {
|
private void updateUserLevelIdAndExperience(Long userId, Long levelId, Integer experience) {
|
||||||
memberUserMapper.updateById(new MemberUserDO()
|
memberUserMapper.updateById(new MemberUserDO()
|
||||||
.setId(userId)
|
.setId(userId)
|
||||||
|
@ -262,7 +260,7 @@ public class MemberLevelServiceImpl implements MemberLevelService {
|
||||||
* @param userExperience 会员当前的经验值
|
* @param userExperience 会员当前的经验值
|
||||||
* @return 会员等级编号,null表示无变化
|
* @return 会员等级编号,null表示无变化
|
||||||
*/
|
*/
|
||||||
private Long calcLevel(MemberUserDO user, int userExperience) {
|
private MemberLevelDO calculateNewLevel(MemberUserDO user, int userExperience) {
|
||||||
List<MemberLevelDO> list = getEnableLevelList();
|
List<MemberLevelDO> list = getEnableLevelList();
|
||||||
if (CollUtil.isEmpty(list)) {
|
if (CollUtil.isEmpty(list)) {
|
||||||
log.warn("计算会员等级失败:会员等级配置不存在");
|
log.warn("计算会员等级失败:会员等级配置不存在");
|
||||||
|
@ -283,8 +281,6 @@ public class MemberLevelServiceImpl implements MemberLevelService {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 保存等级变更记录
|
return matchLevel;
|
||||||
memberLevelRecordService.createAutoUpgradeLog(user, matchLevel);
|
|
||||||
return matchLevel.getId();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue