diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayClientTest.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayClientTest.java new file mode 100644 index 0000000000..1ca7a13e94 --- /dev/null +++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AbstractAlipayClientTest.java @@ -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) 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) 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) 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) request -> true))) + .thenThrow(new RuntimeException("系统异常")); + // 准备请求参数 + String notifyUrl = randomURL(); + PayRefundUnifiedReqDTO refundReqDTO = randomPojo(PayRefundUnifiedReqDTO.class, o -> o.setNotifyUrl(notifyUrl)); + // 断言 + assertThrows(PayException.class, () -> client.unifiedRefund(refundReqDTO)); + } +} diff --git a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayQrPayClientTest.java b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayQrPayClientTest.java index 0b37db8b85..811bf561b8 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayQrPayClientTest.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-pay/src/test/java/cn/iocoder/yudao/framework/pay/core/client/impl/alipay/AlipayQrPayClientTest.java @@ -1,68 +1,44 @@ 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.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.order.PayOrderRespDTO; 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.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.DefaultAlipayClient; -import com.alipay.api.domain.AlipayTradeRefundModel; import com.alipay.api.request.AlipayTradePrecreateRequest; -import com.alipay.api.request.AlipayTradeRefundRequest; 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.Test; import org.mockito.ArgumentMatcher; import org.mockito.InjectMocks; -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.pay.core.enums.order.PayOrderStatusRespEnum.CLOSED; import static cn.iocoder.yudao.framework.pay.core.enums.order.PayOrderStatusRespEnum.WAITING; 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; + /** * {@link AlipayQrPayClient} 单元测试 * * @author jason */ -public class AlipayQrPayClientTest extends BaseMockitoUnitTest { - - 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(""); - }); +public class AlipayQrPayClientTest extends AbstractAlipayClientTest { @InjectMocks - AlipayQrPayClient client = new AlipayQrPayClient(randomLongId(), config); + private AlipayQrPayClient client = new AlipayQrPayClient(randomLongId(), config); - @Mock - private DefaultAlipayClient defaultAlipayClient; - - @Test - public void test_do_init() { - client.doInit(); - assertNotSame(defaultAlipayClient, ReflectUtil.getFieldValue(client, "defaultAlipayClient")); + @BeforeEach + public void setUp() { + setClient(client); } @Test @@ -176,119 +152,4 @@ public class AlipayQrPayClientTest extends BaseMockitoUnitTest { 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) 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) 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) 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) request -> true))) - .thenThrow(new RuntimeException("系统异常")); - // 准备请求参数 - String notifyUrl = randomURL(); - PayRefundUnifiedReqDTO refundReqDTO = randomPojo(PayRefundUnifiedReqDTO.class, o -> { - o.setNotifyUrl(notifyUrl); - }); - // 断言 - assertThrows(PayException.class, () -> client.unifiedRefund(refundReqDTO)); - } } diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/level/MemberLevelRecordDO.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/level/MemberLevelRecordDO.java index 289dae983b..b341daf009 100644 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/level/MemberLevelRecordDO.java +++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/level/MemberLevelRecordDO.java @@ -52,6 +52,7 @@ public class MemberLevelRecordDO extends BaseDO { * 会员此时的经验 */ private Integer userExperience; + // TODO @疯狂:是不是 remark 和 description 可以合并成 description 就够了 /** * 备注 */ diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/level/MemberExperienceRecordService.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/level/MemberExperienceRecordService.java index 92b34b3650..56efbb3f9f 100644 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/level/MemberExperienceRecordService.java +++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/level/MemberExperienceRecordService.java @@ -39,6 +39,16 @@ public interface MemberExperienceRecordService { */ PageResult getExperienceLogPage(MemberExperienceRecordPageReqVO pageReqVO); + /** + * 获得会员经验记录列表, 用于 Excel 导出 + * + * @param exportReqVO 查询条件 + * @return 会员经验记录列表 + */ + List getExperienceLogList(MemberExperienceLogExportReqVO exportReqVO); + + // TODO @疯狂:类似 MemberLevelLogService 的方法,这里也需要提供一个通用的方法,用于创建经验变动记录 + /** * 创建 手动调整 经验变动记录 * diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/level/MemberLevelRecordService.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/level/MemberLevelRecordService.java index 7dfd2c830b..7cc2dd3599 100644 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/level/MemberLevelRecordService.java +++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/level/MemberLevelRecordService.java @@ -47,6 +47,16 @@ public interface MemberLevelRecordService { */ PageResult getLevelLogPage(MemberLevelRecordPageReqVO pageReqVO); + /** + * 获得会员等级记录列表, 用于 Excel 导出 + * + * @param exportReqVO 查询条件 + * @return 会员等级记录列表 + */ + List getLevelLogList(MemberLevelLogExportReqVO exportReqVO); + + // TODO @疯狂:把 createCancelLog、createAdjustLog、createAutoUpgradeLog 几个日志合并成一个通用的日志方法;整体的内容,交给 MemberLevelService 去做;以及对应的 level 变化的通知; + /** * 创建记录: 取消等级 * diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/level/MemberLevelServiceImpl.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/level/MemberLevelServiceImpl.java index 1364e7dbbd..dd6815bac4 100644 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/level/MemberLevelServiceImpl.java +++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/level/MemberLevelServiceImpl.java @@ -141,7 +141,6 @@ public class MemberLevelServiceImpl implements MemberLevelService { @VisibleForTesting void validateConfigValid(Long id, String name, Integer level, Integer experience) { List list = levelMapper.selectList(); - // 校验名称唯一 validateNameUnique(list, id, name); // 校验等级唯一 @@ -178,19 +177,14 @@ public class MemberLevelServiceImpl implements MemberLevelService { return levelMapper.selectListByStatus(status); } - @Transactional(rollbackFor = Exception.class) @Override + @Transactional(rollbackFor = Exception.class) public void updateUserLevel(MemberUserUpdateLevelReqVO updateReqVO) { MemberUserDO user = memberUserMapper.selectById(updateReqVO.getId()); if (user == null) { throw exception(USER_NOT_EXISTS); } - - // 未调整的情况1 - if (user.getLevelId() == null && updateReqVO.getLevelId() == null) { - return; - } - // 未调整的情况2 + // 等级未发生变化 if (ObjUtil.equal(user.getLevelId(), updateReqVO.getLevelId())) { return; } @@ -218,36 +212,40 @@ public class MemberLevelServiceImpl implements MemberLevelService { updateUserLevelIdAndExperience(user.getId(), updateReqVO.getLevelId(), totalExperience); } - // 记录会员经验变动 memberExperienceRecordService.createAdjustLog(user.getId(), experience, totalExperience); } - @Transactional(rollbackFor = Exception.class) + // TODO @疯狂:方法名,建议改成 increase 或者 add 经验,和项目更统一一些 + // TODO @疯狂:bizType 改成具体数值,主要是枚举在 api 不好传递,rpc 情况下 @Override + @Transactional(rollbackFor = Exception.class) public void plusExperience(Long userId, Integer experience, MemberExperienceBizTypeEnum bizType, String bizId) { if (experience == 0) { return; } MemberUserDO user = memberUserMapper.selectById(userId); - if (user.getExperience() == null) { - user.setExperience(0); - } // 防止扣出负数 int userExperience = NumberUtil.max(user.getExperience() + experience, 0); - // 创建经验记录 memberExperienceRecordService.createBizLog(userId, experience, userExperience, bizType, bizId); // 计算会员等级 - Long levelId = calcLevel(user, userExperience); + MemberLevelDO newLevel = calculateNewLevel(user, userExperience); + Long newLevelId = null; + if (newLevel != null) { + newLevelId = newLevel.getId(); + // 保存等级变更记录 + memberLevelRecordService.createAutoUpgradeLog(user, newLevel); + } // 更新会员表上的等级编号、经验值 - updateUserLevelIdAndExperience(user.getId(), levelId, userExperience); + updateUserLevelIdAndExperience(user.getId(), newLevelId, userExperience); } + // TODO @疯狂:让 memberUserService 那开个方法;每个模块,不直接操作对方的 mapper; private void updateUserLevelIdAndExperience(Long userId, Long levelId, Integer experience) { memberUserMapper.updateById(new MemberUserDO() .setId(userId) @@ -262,7 +260,7 @@ public class MemberLevelServiceImpl implements MemberLevelService { * @param userExperience 会员当前的经验值 * @return 会员等级编号,null表示无变化 */ - private Long calcLevel(MemberUserDO user, int userExperience) { + private MemberLevelDO calculateNewLevel(MemberUserDO user, int userExperience) { List list = getEnableLevelList(); if (CollUtil.isEmpty(list)) { log.warn("计算会员等级失败:会员等级配置不存在"); @@ -283,8 +281,6 @@ public class MemberLevelServiceImpl implements MemberLevelService { return null; } - // 保存等级变更记录 - memberLevelRecordService.createAutoUpgradeLog(user, matchLevel); - return matchLevel.getId(); + return matchLevel; } }