gaoluyang
2 天以前 a862c36323b8c6b47f8c41f3860ac93411348c4c
yudao-module-crm/src/test/java/cn/iocoder/yudao/module/crm/service/customer/CrmCustomerAutoPoolTest.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,176 @@
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();
    }
}