| ¶Ô±ÈÐÂÎļþ |
| | |
| | | package cn.iocoder.yudao.module.crm.service.customer; |
| | | |
| | | import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.customer.CrmCustomerImportExcelVO; |
| | | import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.customer.CrmCustomerImportReqVO; |
| | | import cn.iocoder.yudao.module.crm.controller.admin.customer.vo.customer.CrmCustomerPageReqVO; |
| | | import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerDO; |
| | | import cn.iocoder.yudao.module.crm.dal.dataobject.customer.CrmCustomerPoolConfigDO; |
| | | import cn.iocoder.yudao.module.crm.dal.mysql.customer.CrmCustomerMapper; |
| | | import cn.iocoder.yudao.module.crm.framework.excel.core.AutoPoolEnabledConvert; |
| | | import cn.iocoder.yudao.module.crm.framework.permission.core.aop.CrmPermissionAspect; |
| | | import cn.iocoder.yudao.module.crm.enums.common.CrmBizTypeEnum; |
| | | import cn.iocoder.yudao.module.crm.enums.common.CrmSceneTypeEnum; |
| | | import cn.iocoder.yudao.module.crm.controller.admin.customer.CrmCustomerController; |
| | | import cn.iocoder.yudao.module.system.api.user.AdminUserApi; |
| | | import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; |
| | | import cn.iocoder.yudao.module.system.api.dept.DeptApi; |
| | | import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; |
| | | import cn.idev.excel.metadata.data.ReadCellData; |
| | | import com.baomidou.mybatisplus.core.MybatisConfiguration; |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.baomidou.mybatisplus.core.metadata.TableInfoHelper; |
| | | import org.apache.ibatis.builder.MapperBuilderAssistant; |
| | | import org.junit.jupiter.api.Test; |
| | | import org.springframework.test.util.ReflectionTestUtils; |
| | | |
| | | import java.lang.reflect.Proxy; |
| | | import java.math.BigDecimal; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.concurrent.atomic.AtomicReference; |
| | | |
| | | import static org.junit.jupiter.api.Assertions.*; |
| | | |
| | | class CrmCustomerAutoPoolTest { |
| | | |
| | | @Test |
| | | void excelReadsYesNoAndRejectsInvalidValues() { |
| | | var converter = new AutoPoolEnabledConvert(); |
| | | assertTrue(converter.convertToJavaData(new ReadCellData<>("æ¯"), null, null)); |
| | | assertFalse(converter.convertToJavaData(new ReadCellData<>("å¦"), null, null)); |
| | | assertFalse(converter.convertToJavaData(new ReadCellData<>(BigDecimal.ZERO), null, null)); |
| | | assertNull(converter.convertToJavaData(new ReadCellData<>(" "), null, null)); |
| | | assertThrows(IllegalArgumentException.class, |
| | | () -> converter.convertToJavaData(new ReadCellData<>("ä¸ç¡®å®"), null, null)); |
| | | assertEquals("å¦", converter.convertToExcelData(false, null, null).getStringValue()); |
| | | } |
| | | |
| | | @Test |
| | | void oldTemplateCreatesCustomerWithAutoPoolEnabled() { |
| | | assertTrue(importCustomer(null, false).getAutoPoolEnabled()); |
| | | } |
| | | |
| | | @Test |
| | | void importingDisabledCustomerKeepsItDisabled() { |
| | | assertFalse(importCustomer(false, false).getAutoPoolEnabled()); |
| | | } |
| | | |
| | | @Test |
| | | void blankImportUpdateDoesNotOverwriteExistingSetting() { |
| | | // null ç± MyBatis çéç©ºæ´æ°çç¥å¿½ç¥ï¼ä¸è¦çå·²æç falseã |
| | | assertNull(importCustomer(null, true).getAutoPoolEnabled()); |
| | | } |
| | | |
| | | @Test |
| | | void explicitImportUpdateCanDisableAutoPool() { |
| | | assertFalse(importCustomer(false, true).getAutoPoolEnabled()); |
| | | } |
| | | |
| | | @Test |
| | | void publicPoolListStillFiltersDisabledCustomersInAllScene() { |
| | | assertPoolListFilter(false); |
| | | } |
| | | |
| | | @Test |
| | | void superAdminPoolListIncludesDisabledCustomers() { |
| | | assertPoolListFilter(true); |
| | | } |
| | | |
| | | @Test |
| | | void poolCustomersUseSameOwnerAndDepartmentAsCustomerManagement() { |
| | | var controller = new CrmCustomerController(); |
| | | var users = AdminUserApi.class.cast(Proxy.newProxyInstance(getClass().getClassLoader(), |
| | | new Class<?>[]{AdminUserApi.class}, (proxy, method, args) -> { |
| | | assertEquals("getUserMap", method.getName()); |
| | | return Map.of(10L, new AdminUserRespDTO().setId(10L).setNickname("éå®è´è´£äºº").setDeptId(20L)); |
| | | })); |
| | | var departments = DeptApi.class.cast(Proxy.newProxyInstance(getClass().getClassLoader(), |
| | | new Class<?>[]{DeptApi.class}, (proxy, method, args) -> { |
| | | assertEquals("getDeptMap", method.getName()); |
| | | return Map.of(20L, new DeptRespDTO().setId(20L).setName("éå®é¨")); |
| | | })); |
| | | var config = CrmCustomerPoolConfigService.class.cast(Proxy.newProxyInstance(getClass().getClassLoader(), |
| | | new Class<?>[]{CrmCustomerPoolConfigService.class}, (proxy, method, args) -> null)); |
| | | ReflectionTestUtils.setField(controller, "adminUserApi", users); |
| | | ReflectionTestUtils.setField(controller, "deptApi", departments); |
| | | ReflectionTestUtils.setField(controller, "customerPoolConfigService", config); |
| | | var customer = controller.buildCustomerDetailList(List.of(new CrmCustomerDO().setId(1L) |
| | | .setOwnerUserId(10L).setAutoPoolEnabled(true))).getFirst(); |
| | | assertEquals(10L, customer.getOwnerUserId()); |
| | | assertEquals("éå®è´è´£äºº", customer.getOwnerUserName()); |
| | | assertEquals("éå®é¨", customer.getOwnerUserDeptName()); |
| | | } |
| | | |
| | | private void assertPoolListFilter(boolean superAdmin) { |
| | | TableInfoHelper.initTableInfo(new MapperBuilderAssistant(new MybatisConfiguration(), "test"), CrmCustomerDO.class); |
| | | var mapper = CrmCustomerMapper.class.cast(Proxy.newProxyInstance(getClass().getClassLoader(), |
| | | new Class<?>[]{CrmCustomerMapper.class}, (proxy, method, args) -> { |
| | | if (method.getName().equals("selectJoinPage")) { |
| | | var query = (com.github.yulichang.wrapper.MPJLambdaWrapper<?>) args[2]; |
| | | String sql = query.getSqlSegment(); |
| | | assertFalse(sql.contains("owner_user_id IS NULL"), sql); |
| | | assertEquals(!superAdmin, sql.contains("auto_pool_enabled ="), sql); |
| | | return new cn.iocoder.yudao.framework.common.pojo.PageResult<>(List.of(), 0L); |
| | | } |
| | | return java.lang.reflect.InvocationHandler.invokeDefault(proxy, method, args); |
| | | })); |
| | | mapper.selectPage(new CrmCustomerPageReqVO().setPool(true) |
| | | .setSceneType(CrmSceneTypeEnum.ALL.getType()), 1L, superAdmin); |
| | | } |
| | | |
| | | @Test |
| | | void hiddenCustomerDoesNotGetPublicReadFallback() { |
| | | var aspect = new CrmPermissionAspect(); |
| | | var enabled = new AtomicReference<>(false); |
| | | var mapper = CrmCustomerMapper.class.cast(Proxy.newProxyInstance(getClass().getClassLoader(), |
| | | new Class<?>[]{CrmCustomerMapper.class}, (proxy, method, args) -> |
| | | new CrmCustomerDO().setId(1L).setAutoPoolEnabled(enabled.get()))); |
| | | ReflectionTestUtils.setField(aspect, "customerMapper", mapper); |
| | | assertEquals(false, ReflectionTestUtils.invokeMethod(aspect, "isPublicPoolVisible", |
| | | CrmBizTypeEnum.CRM_CUSTOMER.getType(), 1L)); |
| | | enabled.set(true); |
| | | assertEquals(true, ReflectionTestUtils.invokeMethod(aspect, "isPublicPoolVisible", |
| | | CrmBizTypeEnum.CRM_CUSTOMER.getType(), 1L)); |
| | | } |
| | | |
| | | @Test |
| | | void automaticPoolQueryRequiresEnabledFlagOutsideTimeoutOrConditions() { |
| | | TableInfoHelper.initTableInfo(new MapperBuilderAssistant(new MybatisConfiguration(), "test"), CrmCustomerDO.class); |
| | | var captured = new AtomicReference<LambdaQueryWrapper<CrmCustomerDO>>(); |
| | | var mapper = CrmCustomerMapper.class.cast(Proxy.newProxyInstance(getClass().getClassLoader(), |
| | | new Class<?>[]{CrmCustomerMapper.class}, (proxy, method, args) -> { |
| | | if (method.isDefault()) { |
| | | return java.lang.reflect.InvocationHandler.invokeDefault(proxy, method, args); |
| | | } |
| | | assertEquals("selectList", method.getName()); |
| | | captured.set((LambdaQueryWrapper<CrmCustomerDO>) args[0]); |
| | | return List.of(); |
| | | })); |
| | | mapper.selectListByAutoPool(new CrmCustomerPoolConfigDO().setDealExpireDays(30).setContactExpireDays(7)); |
| | | String sql = captured.get().getSqlSegment(); |
| | | assertTrue(sql.contains("auto_pool_enabled ="), sql); |
| | | assertTrue(sql.indexOf("auto_pool_enabled") < sql.indexOf(" OR "), sql); |
| | | assertTrue(captured.get().getParamNameValuePairs().containsValue(true)); |
| | | } |
| | | |
| | | private CrmCustomerDO importCustomer(Boolean enabled, boolean existing) { |
| | | var service = new CrmCustomerServiceImpl(); |
| | | var saved = new AtomicReference<CrmCustomerDO>(); |
| | | var mapper = CrmCustomerMapper.class.cast(Proxy.newProxyInstance(getClass().getClassLoader(), |
| | | new Class<?>[]{CrmCustomerMapper.class}, (proxy, method, args) -> switch (method.getName()) { |
| | | case "selectByCustomerName" -> existing |
| | | ? new CrmCustomerDO().setId(1L).setAutoPoolEnabled(false) : null; |
| | | case "insert", "updateById" -> { |
| | | saved.set((CrmCustomerDO) args[0]); |
| | | yield 1; |
| | | } |
| | | default -> throw new AssertionError(method.getName()); |
| | | })); |
| | | ReflectionTestUtils.setField(service, "customerMapper", mapper); |
| | | var result = service.importCustomerList(List.of(new CrmCustomerImportExcelVO() |
| | | .setName("æµè¯å®¢æ·").setAutoPoolEnabled(enabled)), |
| | | CrmCustomerImportReqVO.builder().updateSupport(true).build()); |
| | | assertTrue(result.getFailureCustomerNames().isEmpty()); |
| | | return saved.get(); |
| | | } |
| | | } |