package com.ruoyi.other.service.impl; import com.baomidou.mybatisplus.core.MybatisConfiguration; import com.baomidou.mybatisplus.core.metadata.TableInfoHelper; import com.ruoyi.account.api.dto.SendMessageDTO; import com.ruoyi.account.api.feignClient.AppUserClient; import com.ruoyi.account.api.feignClient.AppUserWhitelistClient; import com.ruoyi.account.api.feignClient.ChargingCardClient; import com.ruoyi.account.api.feignClient.VinManagementClient; import com.ruoyi.account.api.model.TAppUserWhitelist; import com.ruoyi.account.api.model.TChargingCard; import com.ruoyi.account.api.model.TVinManagement; import com.ruoyi.common.core.domain.R; import com.ruoyi.other.api.domain.TBalanceWarningRecord; import com.ruoyi.other.api.domain.TCompanyBalanceWarning; import com.ruoyi.other.api.domain.TGroup; import com.ruoyi.other.api.domain.TGroupCompany; import com.ruoyi.other.mapper.TCompanyBalanceWarningMapper; import com.ruoyi.other.mapper.TGroupCompanyMapper; import com.ruoyi.other.mapper.TGroupMapper; import com.ruoyi.other.service.TBalanceWarningRecordService; import org.apache.ibatis.builder.MapperBuilderAssistant; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; import org.mockito.Mockito; import org.springframework.test.util.ReflectionTestUtils; import java.math.BigDecimal; import java.util.Arrays; import java.util.Collections; import java.util.List; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; /** * 公司余额预警扫描服务单测,不依赖 Spring 容器与数据库。 */ class TBalanceWarningScanServiceImplTest { @BeforeAll static void initTableInfo() { // 初始化 MyBatis-Plus 表元数据,使 scan() 中的 LambdaQueryWrapper 可在无 Spring/DB 环境下解析字段 TableInfoHelper.initTableInfo(new MapperBuilderAssistant(new MybatisConfiguration(), ""), TCompanyBalanceWarning.class); } @Test void sendsCompanyWarnSmsWhenBalanceBelowThreshold() { TCompanyBalanceWarningMapper warningMapper = Mockito.mock(TCompanyBalanceWarningMapper.class); TCompanyBalanceWarning warning = warning(); warning.setSubWarnAmount(null); Mockito.when(warningMapper.selectList(Mockito.any())).thenReturn(Collections.singletonList(warning)); TGroupCompany company = company(); company.setAccountMode(1); company.setAvailableBalance(new BigDecimal("500")); company.setContactPhone("13800138000"); TGroupCompanyMapper companyMapper = Mockito.mock(TGroupCompanyMapper.class); Mockito.when(companyMapper.selectById(11)).thenReturn(company); TBalanceWarningRecordService recordService = Mockito.mock(TBalanceWarningRecordService.class); AppUserClient appUserClient = Mockito.mock(AppUserClient.class); Mockito.when(appUserClient.sendMessage(Mockito.any(SendMessageDTO.class))).thenReturn(R.ok("ok")); buildService(warningMapper, companyMapper, null, recordService, Mockito.mock(VinManagementClient.class), Mockito.mock(ChargingCardClient.class), Mockito.mock(AppUserWhitelistClient.class), appUserClient).scan(); ArgumentCaptor captor = ArgumentCaptor.forClass(SendMessageDTO.class); Mockito.verify(appUserClient).sendMessage(captor.capture()); SendMessageDTO dto = captor.getValue(); assertEquals(5, dto.getType()); assertEquals("13800138000", dto.getPhone()); assertEquals("利普芯科技有限公司", dto.getCompanyName()); assertEquals("500.00", dto.getBalance()); assertEquals("1000.00", dto.getWarnAmount()); ArgumentCaptor recordCaptor = ArgumentCaptor.forClass(TBalanceWarningRecord.class); Mockito.verify(recordService).save(recordCaptor.capture()); assertEquals(11, recordCaptor.getValue().getCompanyId()); assertEquals(1, recordCaptor.getValue().getWarnScope()); } @Test void skipsWhenAlreadyNotifiedToday() { TCompanyBalanceWarningMapper warningMapper = Mockito.mock(TCompanyBalanceWarningMapper.class); TCompanyBalanceWarning warning = warning(); warning.setSubWarnAmount(null); Mockito.when(warningMapper.selectList(Mockito.any())).thenReturn(Collections.singletonList(warning)); TGroupCompany company = company(); company.setAccountMode(1); company.setAvailableBalance(new BigDecimal("500")); company.setContactPhone("13800138000"); TGroupCompanyMapper companyMapper = Mockito.mock(TGroupCompanyMapper.class); Mockito.when(companyMapper.selectById(11)).thenReturn(company); TBalanceWarningRecordService recordService = Mockito.mock(TBalanceWarningRecordService.class); Mockito.when(recordService.isNotifiedToday(11, 1, "")).thenReturn(true); AppUserClient appUserClient = Mockito.mock(AppUserClient.class); buildService(warningMapper, companyMapper, null, recordService, Mockito.mock(VinManagementClient.class), Mockito.mock(ChargingCardClient.class), Mockito.mock(AppUserWhitelistClient.class), appUserClient).scan(); Mockito.verify(appUserClient, Mockito.never()).sendMessage(Mockito.any(SendMessageDTO.class)); Mockito.verify(recordService, Mockito.never()).save(Mockito.any(TBalanceWarningRecord.class)); } @Test void skipsWhenNotifyPhoneBlank() { TCompanyBalanceWarningMapper warningMapper = Mockito.mock(TCompanyBalanceWarningMapper.class); TCompanyBalanceWarning warning = warning(); warning.setSubWarnAmount(null); Mockito.when(warningMapper.selectList(Mockito.any())).thenReturn(Collections.singletonList(warning)); TGroupCompany company = company(); company.setAccountMode(1); company.setAvailableBalance(new BigDecimal("500")); company.setContactPhone(null); TGroupCompanyMapper companyMapper = Mockito.mock(TGroupCompanyMapper.class); Mockito.when(companyMapper.selectById(11)).thenReturn(company); TBalanceWarningRecordService recordService = Mockito.mock(TBalanceWarningRecordService.class); AppUserClient appUserClient = Mockito.mock(AppUserClient.class); buildService(warningMapper, companyMapper, null, recordService, Mockito.mock(VinManagementClient.class), Mockito.mock(ChargingCardClient.class), Mockito.mock(AppUserWhitelistClient.class), appUserClient).scan(); Mockito.verifyNoInteractions(appUserClient, recordService); } @Test void sendsSubAccountWarnSmsForAllocationMode() { TCompanyBalanceWarningMapper warningMapper = Mockito.mock(TCompanyBalanceWarningMapper.class); TCompanyBalanceWarning warning = warning(); warning.setCompanyWarnAmount(new BigDecimal("100000")); Mockito.when(warningMapper.selectList(Mockito.any())).thenReturn(Collections.singletonList(warning)); TGroupCompany company = company(); company.setAccountMode(2); company.setAvailableBalance(new BigDecimal("500000")); company.setContactPhone("13800138000"); TGroupCompanyMapper companyMapper = Mockito.mock(TGroupCompanyMapper.class); Mockito.when(companyMapper.selectById(11)).thenReturn(company); // VIN1 余额低于子账户预警线且车牌号为空(回退VIN码),VIN2 余额充足不提醒 TVinManagement vin1 = vin("VIN123456", null, new BigDecimal("100")); TVinManagement vin2 = vin("VIN999999", "川B88888", new BigDecimal("300")); VinManagementClient vinClient = Mockito.mock(VinManagementClient.class); Mockito.when(vinClient.listByCompany(11)).thenReturn(R.ok(Arrays.asList(vin1, vin2))); // 卡余额低于预警线 TChargingCard card = new TChargingCard(); card.setCardNo("CARD001"); card.setBalance(new BigDecimal("150")); ChargingCardClient cardClient = Mockito.mock(ChargingCardClient.class); Mockito.when(cardClient.listByCompany(11)).thenReturn(R.ok(Collections.singletonList(card))); // 白名单1余额低于预警线(姓名回退手机号),白名单2余额充足 TAppUserWhitelist wl1 = whitelist("13900000001", null, new BigDecimal("180")); TAppUserWhitelist wl2 = whitelist("13900000002", "李四", new BigDecimal("250")); AppUserWhitelistClient whitelistClient = Mockito.mock(AppUserWhitelistClient.class); Mockito.when(whitelistClient.listByCompany(11)).thenReturn(R.ok(Arrays.asList(wl1, wl2))); TBalanceWarningRecordService recordService = Mockito.mock(TBalanceWarningRecordService.class); AppUserClient appUserClient = Mockito.mock(AppUserClient.class); Mockito.when(appUserClient.sendMessage(Mockito.any(SendMessageDTO.class))).thenReturn(R.ok("ok")); buildService(warningMapper, companyMapper, null, recordService, vinClient, cardClient, whitelistClient, appUserClient).scan(); ArgumentCaptor captor = ArgumentCaptor.forClass(SendMessageDTO.class); Mockito.verify(appUserClient, Mockito.times(3)).sendMessage(captor.capture()); List sent = captor.getAllValues(); for (SendMessageDTO dto : sent) { assertEquals(6, dto.getType()); assertEquals("13800138000", dto.getPhone()); assertEquals("200.00", dto.getWarnAmount()); } // VIN:车牌号为空回退VIN码 assertTrue(sent.stream().anyMatch(dto -> "VIN123456".equals(dto.getUserInfo()) && "100.00".equals(dto.getBalance()))); // 卡:用户信息取卡号 assertTrue(sent.stream().anyMatch(dto -> "CARD001".equals(dto.getUserInfo()) && "150.00".equals(dto.getBalance()))); // 白名单:姓名为空回退手机号 assertTrue(sent.stream().anyMatch(dto -> "13900000001".equals(dto.getUserInfo()) && "180.00".equals(dto.getBalance()))); } @Test void skipsSubAccountScanInSharedMode() { TCompanyBalanceWarningMapper warningMapper = Mockito.mock(TCompanyBalanceWarningMapper.class); TCompanyBalanceWarning warning = warning(); warning.setCompanyWarnAmount(new BigDecimal("100000")); Mockito.when(warningMapper.selectList(Mockito.any())).thenReturn(Collections.singletonList(warning)); TGroupCompany company = company(); company.setAccountMode(1); company.setAvailableBalance(new BigDecimal("500000")); company.setContactPhone("13800138000"); TGroupCompanyMapper companyMapper = Mockito.mock(TGroupCompanyMapper.class); Mockito.when(companyMapper.selectById(11)).thenReturn(company); VinManagementClient vinClient = Mockito.mock(VinManagementClient.class); ChargingCardClient cardClient = Mockito.mock(ChargingCardClient.class); AppUserWhitelistClient whitelistClient = Mockito.mock(AppUserWhitelistClient.class); AppUserClient appUserClient = Mockito.mock(AppUserClient.class); buildService(warningMapper, companyMapper, null, Mockito.mock(TBalanceWarningRecordService.class), vinClient, cardClient, whitelistClient, appUserClient).scan(); Mockito.verifyNoInteractions(vinClient, cardClient, whitelistClient, appUserClient); } @Test void routesToGroupContactWhenNotifyObjectIsGroup() { TCompanyBalanceWarningMapper warningMapper = Mockito.mock(TCompanyBalanceWarningMapper.class); TCompanyBalanceWarning warning = warning(); warning.setSubWarnAmount(null); warning.setNotifyObject(1); Mockito.when(warningMapper.selectList(Mockito.any())).thenReturn(Collections.singletonList(warning)); TGroupCompany company = company(); company.setAccountMode(1); company.setAvailableBalance(new BigDecimal("500")); company.setContactPhone("13800138000"); company.setGroupId(5); TGroupCompanyMapper companyMapper = Mockito.mock(TGroupCompanyMapper.class); Mockito.when(companyMapper.selectById(11)).thenReturn(company); TGroup group = new TGroup(); group.setId(5); group.setContactPhone("13711112222"); TGroupMapper groupMapper = Mockito.mock(TGroupMapper.class); Mockito.when(groupMapper.selectById(5)).thenReturn(group); AppUserClient appUserClient = Mockito.mock(AppUserClient.class); Mockito.when(appUserClient.sendMessage(Mockito.any(SendMessageDTO.class))).thenReturn(R.ok("ok")); buildService(warningMapper, companyMapper, groupMapper, Mockito.mock(TBalanceWarningRecordService.class), Mockito.mock(VinManagementClient.class), Mockito.mock(ChargingCardClient.class), Mockito.mock(AppUserWhitelistClient.class), appUserClient).scan(); ArgumentCaptor captor = ArgumentCaptor.forClass(SendMessageDTO.class); Mockito.verify(appUserClient).sendMessage(captor.capture()); assertEquals("13711112222", captor.getValue().getPhone()); } private TBalanceWarningScanServiceImpl buildService(TCompanyBalanceWarningMapper warningMapper, TGroupCompanyMapper companyMapper, TGroupMapper groupMapper, TBalanceWarningRecordService recordService, VinManagementClient vinClient, ChargingCardClient cardClient, AppUserWhitelistClient whitelistClient, AppUserClient appUserClient) { TBalanceWarningScanServiceImpl service = new TBalanceWarningScanServiceImpl(); ReflectionTestUtils.setField(service, "companyBalanceWarningMapper", warningMapper); ReflectionTestUtils.setField(service, "groupCompanyMapper", companyMapper); ReflectionTestUtils.setField(service, "groupMapper", groupMapper); ReflectionTestUtils.setField(service, "balanceWarningRecordService", recordService); ReflectionTestUtils.setField(service, "vinManagementClient", vinClient); ReflectionTestUtils.setField(service, "chargingCardClient", cardClient); ReflectionTestUtils.setField(service, "appUserWhitelistClient", whitelistClient); ReflectionTestUtils.setField(service, "appUserClient", appUserClient); return service; } private TCompanyBalanceWarning warning() { TCompanyBalanceWarning warning = new TCompanyBalanceWarning(); warning.setCompanyId(11); warning.setCompanyWarnAmount(new BigDecimal("1000")); warning.setSubWarnAmount(new BigDecimal("200")); warning.setNotifyObject(2); warning.setNotifyType(1); return warning; } private TGroupCompany company() { TGroupCompany company = new TGroupCompany(); company.setId(11); company.setName("利普芯科技有限公司"); company.setStatus(1); company.setAccountMode(2); return company; } private TVinManagement vin(String vin, String plateNumber, BigDecimal balance) { TVinManagement entity = new TVinManagement(); entity.setVin(vin); entity.setPlateNumber(plateNumber); entity.setBalance(balance); return entity; } private TAppUserWhitelist whitelist(String phone, String name, BigDecimal balance) { TAppUserWhitelist entity = new TAppUserWhitelist(); entity.setPhone(phone); entity.setName(name); entity.setBalance(balance); return entity; } }