| | |
| | | import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper; |
| | | import com.ruoyi.account.api.dto.AppUserWhitelistAllocateDTO; |
| | | import com.ruoyi.account.api.dto.AppUserWhitelistAllocateItemDTO; |
| | | import com.ruoyi.account.api.dto.AppUserWhitelistStatusDTO; |
| | | import com.ruoyi.account.api.model.TAppUser; |
| | | import com.ruoyi.account.api.model.TAppUserWhitelist; |
| | | import com.ruoyi.account.api.model.TCompanyAllocateRecord; |
| | | import com.ruoyi.account.api.vo.AppUserWhitelistAllocateVO; |
| | | import com.ruoyi.account.api.vo.AppUserWhitelistImportResultVO; |
| | | import com.ruoyi.account.api.vo.AppUserWhitelistMatchVO; |
| | | import com.ruoyi.account.mapper.TAppUserWhitelistMapper; |
| | | import com.ruoyi.account.service.PartnerAppUserAccessService; |
| | | import com.ruoyi.account.service.TAppUserService; |
| | | import com.ruoyi.account.service.TAppUserWhitelistSiteService; |
| | | import com.ruoyi.account.service.TCompanyAllocateRecordService; |
| | |
| | | import java.util.concurrent.atomic.AtomicLong; |
| | | |
| | | import static org.junit.jupiter.api.Assertions.assertEquals; |
| | | import static org.junit.jupiter.api.Assertions.assertNull; |
| | | import static org.junit.jupiter.api.Assertions.assertThrows; |
| | | import static org.junit.jupiter.api.Assertions.assertTrue; |
| | | import static org.mockito.ArgumentMatchers.any; |
| | |
| | | import static org.mockito.ArgumentMatchers.eq; |
| | | import static org.mockito.ArgumentMatchers.isNull; |
| | | import static org.mockito.Mockito.doAnswer; |
| | | import static org.mockito.Mockito.doThrow; |
| | | import static org.mockito.Mockito.lenient; |
| | | import static org.mockito.Mockito.mock; |
| | | import static org.mockito.Mockito.never; |
| | |
| | | @Mock private GroupCompanyClient groupCompanyClient; |
| | | @Mock private RedissonClient redissonClient; |
| | | @Mock private TCompanyAllocateRecordService companyAllocateRecordService; |
| | | @Mock private PartnerAppUserAccessService partnerAppUserAccessService; |
| | | |
| | | private TAppUserWhitelistServiceImpl service; |
| | | |
| | |
| | | ReflectionTestUtils.setField(service, "groupCompanyClient", groupCompanyClient); |
| | | ReflectionTestUtils.setField(service, "redissonClient", redissonClient); |
| | | ReflectionTestUtils.setField(service, "companyAllocateRecordService", companyAllocateRecordService); |
| | | ReflectionTestUtils.setField(service, "partnerAppUserAccessService", partnerAppUserAccessService); |
| | | // 默认透传(模拟非公司账号),公司账号隔离场景由具体用例覆盖打桩 |
| | | lenient().when(partnerAppUserAccessService.resolveCompanyFilter(any())).thenAnswer(invocation -> invocation.getArgument(0)); |
| | | lenient().when(partnerAppUserAccessService.getCurrentCompanyId()).thenReturn(null); |
| | | RLock lock = mock(RLock.class); |
| | | // 并发锁仅在额度相关场景使用,宽松桩避免严格模式下未使用即报错 |
| | | lenient().when(redissonClient.getLock(any())).thenReturn(lock); |
| | |
| | | org.mockito.ArgumentCaptor<TAppUserWhitelist> captor = org.mockito.ArgumentCaptor.forClass(TAppUserWhitelist.class); |
| | | verify(mapper, org.mockito.Mockito.times(3)).insert(captor.capture()); |
| | | for (TAppUserWhitelist saved : captor.getAllValues()) { |
| | | // 导入统一按默认值写入:全部免费 + 全部电站 + 启用,忽略模板中的享受权益/白名单电站列 |
| | | assertEquals(1, saved.getBenefitType().intValue()); |
| | | // 导入统一按默认值写入:全部电站 + 启用;白名单权益已下线,不再写入享受权益,忽略模板中的享受权益/白名单电站列 |
| | | assertEquals(null, saved.getBenefitType()); |
| | | assertEquals(1, saved.getScopeType().intValue()); |
| | | assertEquals(1, saved.getStatus().intValue()); |
| | | } |
| | |
| | | |
| | | assertEquals(0, result); |
| | | verify(mapper, never()).update(isNull(), any(Wrapper.class)); |
| | | } |
| | | |
| | | // ---------------- 白名单匹配(含公司/车队归属) ---------------- |
| | | |
| | | @Test |
| | | void matchWhitelistReturnsCompanyAndFleetOwnership() { |
| | | TAppUser appUser = new TAppUser(); |
| | | appUser.setId(100L); |
| | | appUser.setPhone("13540211236"); |
| | | when(appUserService.getById(100L)).thenReturn(appUser); |
| | | |
| | | TAppUserWhitelist whitelist = new TAppUserWhitelist(); |
| | | whitelist.setId(88L); |
| | | whitelist.setPhone("13540211236"); |
| | | whitelist.setStatus(1); |
| | | whitelist.setBenefitType(1); |
| | | whitelist.setScopeType(1); |
| | | whitelist.setCompanyId(12); |
| | | whitelist.setFleetId(3); |
| | | when(mapper.selectOne(any(Wrapper.class))).thenReturn(whitelist); |
| | | |
| | | AppUserWhitelistMatchVO result = service.matchWhitelist(100L, 2001); |
| | | |
| | | assertTrue(result.getMatched()); |
| | | assertEquals(12, result.getCompanyId()); |
| | | assertEquals(3, result.getFleetId()); |
| | | // 白名单权益已下线:历史数据的享受权益不再回传给调用方,充电完全按企业优惠结算 |
| | | assertEquals(null, result.getBenefitType()); |
| | | assertEquals(null, result.getBenefitName()); |
| | | } |
| | | |
| | | @Test |
| | | void matchWhitelistReturnsNullOwnershipWhenUnassigned() { |
| | | TAppUser appUser = new TAppUser(); |
| | | appUser.setId(100L); |
| | | appUser.setPhone("13540211236"); |
| | | when(appUserService.getById(100L)).thenReturn(appUser); |
| | | |
| | | TAppUserWhitelist whitelist = new TAppUserWhitelist(); |
| | | whitelist.setId(88L); |
| | | whitelist.setPhone("13540211236"); |
| | | whitelist.setStatus(1); |
| | | whitelist.setBenefitType(2); |
| | | whitelist.setScopeType(1); |
| | | when(mapper.selectOne(any(Wrapper.class))).thenReturn(whitelist); |
| | | |
| | | AppUserWhitelistMatchVO result = service.matchWhitelist(100L, 2001); |
| | | |
| | | assertTrue(result.getMatched()); |
| | | assertEquals(null, result.getCompanyId()); |
| | | assertEquals(null, result.getFleetId()); |
| | | } |
| | | |
| | | // ---------------- 白名单账户可用余额解析(充电页余额显示) ---------------- |
| | | |
| | | @Test |
| | | void resolveWhitelistAccountBalanceReturnsCompanyBalanceForSharedMode() { |
| | | TGroupCompany company = new TGroupCompany(); |
| | | company.setAccountMode(1); |
| | | company.setAvailableBalance(new BigDecimal("500.50")); |
| | | when(groupCompanyClient.getCompanyById(12)).thenReturn(R.ok(company)); |
| | | |
| | | AppUserWhitelistMatchVO match = new AppUserWhitelistMatchVO(); |
| | | match.setMatched(true); |
| | | match.setCompanyId(12); |
| | | match.setBalance(new BigDecimal("100.00")); |
| | | |
| | | BigDecimal result = service.resolveWhitelistAccountBalance(match); |
| | | |
| | | assertEquals(new BigDecimal("500.50"), result); |
| | | } |
| | | |
| | | @Test |
| | | void resolveWhitelistAccountBalanceReturnsWhitelistBalanceForAllocationMode() { |
| | | TGroupCompany company = new TGroupCompany(); |
| | | company.setAccountMode(2); |
| | | company.setAvailableBalance(new BigDecimal("500.50")); |
| | | when(groupCompanyClient.getCompanyById(12)).thenReturn(R.ok(company)); |
| | | |
| | | AppUserWhitelistMatchVO match = new AppUserWhitelistMatchVO(); |
| | | match.setMatched(true); |
| | | match.setCompanyId(12); |
| | | match.setBalance(new BigDecimal("100.00")); |
| | | |
| | | BigDecimal result = service.resolveWhitelistAccountBalance(match); |
| | | |
| | | assertEquals(new BigDecimal("100.00"), result); |
| | | } |
| | | |
| | | @Test |
| | | void resolveWhitelistAccountBalanceTreatsNullAccountModeAsShared() { |
| | | TGroupCompany company = new TGroupCompany(); |
| | | company.setAccountMode(null); |
| | | company.setAvailableBalance(new BigDecimal("500.50")); |
| | | when(groupCompanyClient.getCompanyById(12)).thenReturn(R.ok(company)); |
| | | |
| | | AppUserWhitelistMatchVO match = new AppUserWhitelistMatchVO(); |
| | | match.setMatched(true); |
| | | match.setCompanyId(12); |
| | | match.setBalance(new BigDecimal("100.00")); |
| | | |
| | | BigDecimal result = service.resolveWhitelistAccountBalance(match); |
| | | |
| | | assertEquals(new BigDecimal("500.50"), result); |
| | | } |
| | | |
| | | @Test |
| | | void resolveWhitelistAccountBalanceReturnsNullWhenCompanyQueryFails() { |
| | | when(groupCompanyClient.getCompanyById(12)).thenReturn(R.fail("公司信息查询失败")); |
| | | |
| | | AppUserWhitelistMatchVO match = new AppUserWhitelistMatchVO(); |
| | | match.setMatched(true); |
| | | match.setCompanyId(12); |
| | | match.setBalance(new BigDecimal("100.00")); |
| | | |
| | | BigDecimal result = service.resolveWhitelistAccountBalance(match); |
| | | |
| | | assertNull(result); |
| | | } |
| | | |
| | | @Test |
| | | void resolveWhitelistAccountBalanceReturnsNullWhenNotMatched() { |
| | | AppUserWhitelistMatchVO match = new AppUserWhitelistMatchVO(); |
| | | match.setMatched(false); |
| | | |
| | | BigDecimal result = service.resolveWhitelistAccountBalance(match); |
| | | |
| | | assertNull(result); |
| | | } |
| | | |
| | | // ---------------- 额度分配 ---------------- |
| | |
| | | assertEquals("分配明细中存在重复白名单用户", exception.getMessage()); |
| | | } |
| | | |
| | | // ---------------- updateStatus ---------------- |
| | | |
| | | @Test |
| | | void updateStatusRejectsInvalidParams() { |
| | | assertThrows(ServiceException.class, () -> service.updateStatus(null)); |
| | | AppUserWhitelistStatusDTO noId = new AppUserWhitelistStatusDTO(); |
| | | noId.setStatus(1); |
| | | assertThrows(ServiceException.class, () -> service.updateStatus(noId)); |
| | | AppUserWhitelistStatusDTO badStatus = new AppUserWhitelistStatusDTO(); |
| | | badStatus.setId(1L); |
| | | badStatus.setStatus(3); |
| | | |
| | | ServiceException exception = assertThrows(ServiceException.class, () -> service.updateStatus(badStatus)); |
| | | |
| | | assertEquals("白名单用户状态参数错误", exception.getMessage()); |
| | | verify(mapper, never()).update(isNull(), any(Wrapper.class)); |
| | | } |
| | | |
| | | @Test |
| | | void updateStatusRejectsMissingRecord() { |
| | | when(mapper.selectById(1L)).thenReturn(null); |
| | | AppUserWhitelistStatusDTO dto = new AppUserWhitelistStatusDTO(); |
| | | dto.setId(1L); |
| | | dto.setStatus(2); |
| | | |
| | | ServiceException exception = assertThrows(ServiceException.class, () -> service.updateStatus(dto)); |
| | | |
| | | assertEquals("白名单用户不存在或已删除", exception.getMessage()); |
| | | verify(mapper, never()).update(isNull(), any(Wrapper.class)); |
| | | } |
| | | |
| | | @Test |
| | | void updateStatusKeepsUnchangedStatusWithoutUpdate() { |
| | | TAppUserWhitelist existing = new TAppUserWhitelist(); |
| | | existing.setId(1L); |
| | | existing.setStatus(1); |
| | | when(mapper.selectById(1L)).thenReturn(existing); |
| | | AppUserWhitelistStatusDTO dto = new AppUserWhitelistStatusDTO(); |
| | | dto.setId(1L); |
| | | dto.setStatus(1); |
| | | |
| | | assertTrue(service.updateStatus(dto)); |
| | | |
| | | // 状态未变化时视为幂等成功,不产生更新语句,避免污染 update_time / update_by |
| | | verify(mapper, never()).update(isNull(), any(Wrapper.class)); |
| | | } |
| | | |
| | | @Test |
| | | void updateStatusDisablesWhitelist() { |
| | | TAppUserWhitelist existing = new TAppUserWhitelist(); |
| | | existing.setId(1L); |
| | | existing.setStatus(1); |
| | | when(mapper.selectById(1L)).thenReturn(existing); |
| | | when(mapper.update(isNull(), any(Wrapper.class))).thenReturn(1); |
| | | AppUserWhitelistStatusDTO dto = new AppUserWhitelistStatusDTO(); |
| | | dto.setId(1L); |
| | | dto.setStatus(2); |
| | | |
| | | assertTrue(service.updateStatus(dto)); |
| | | |
| | | ArgumentCaptor<Wrapper> wrapperCaptor = ArgumentCaptor.forClass(Wrapper.class); |
| | | verify(mapper).update(isNull(), wrapperCaptor.capture()); |
| | | String sqlSet = wrapperCaptor.getValue().getSqlSet(); |
| | | assertTrue(sqlSet.contains("status")); |
| | | assertTrue(sqlSet.contains("update_time")); |
| | | } |
| | | |
| | | @Test |
| | | void updateStatusThrowsWhenUpdateAffectsNoRow() { |
| | | TAppUserWhitelist existing = new TAppUserWhitelist(); |
| | | existing.setId(1L); |
| | | existing.setStatus(1); |
| | | when(mapper.selectById(1L)).thenReturn(existing); |
| | | when(mapper.update(isNull(), any(Wrapper.class))).thenReturn(0); |
| | | AppUserWhitelistStatusDTO dto = new AppUserWhitelistStatusDTO(); |
| | | dto.setId(1L); |
| | | dto.setStatus(2); |
| | | |
| | | ServiceException exception = assertThrows(ServiceException.class, () -> service.updateStatus(dto)); |
| | | |
| | | assertEquals("白名单用户状态更新失败,请重试", exception.getMessage()); |
| | | } |
| | | |
| | | private TGroupCompany allocationCompany(Integer id, String name) { |
| | | TGroupCompany company = new TGroupCompany(); |
| | | company.setId(id); |
| | |
| | | row.createCell(1).setCellValue(benefitType); |
| | | row.createCell(2).setCellValue(whitelistSite); |
| | | } |
| | | |
| | | // ==================== 公司账号数据隔离 ==================== |
| | | |
| | | @Test |
| | | void getAllocateOverviewForcesCompanyFilterForCompanyAccount() { |
| | | // 公司账号:额度概览的公司参数被强制覆盖为本公司 |
| | | when(partnerAppUserAccessService.resolveCompanyFilter(9)).thenReturn(2); |
| | | TGroupCompany company = new TGroupCompany(); |
| | | company.setId(2); |
| | | company.setName("本公司"); |
| | | company.setAccountMode(2); |
| | | company.setAvailableBalance(new BigDecimal("100.00")); |
| | | when(groupCompanyClient.getCompanyById(2)).thenReturn(R.ok(company)); |
| | | |
| | | AppUserWhitelistAllocateVO vo = service.getAllocateOverview(9); |
| | | |
| | | assertEquals(Integer.valueOf(2), vo.getCompanyId()); |
| | | verify(groupCompanyClient).getCompanyById(2); |
| | | } |
| | | |
| | | @Test |
| | | void updateStatusRejectsCrossCompanyRecord() { |
| | | // 公司账号:启停其他公司的白名单被越权校验拦截 |
| | | TAppUserWhitelist existing = new TAppUserWhitelist(); |
| | | existing.setId(1L); |
| | | existing.setStatus(1); |
| | | existing.setCompanyId(9); |
| | | when(mapper.selectById(1L)).thenReturn(existing); |
| | | doThrow(new ServiceException("无权操作其他公司的数据")).when(partnerAppUserAccessService).assertCompanyVisible(9); |
| | | AppUserWhitelistStatusDTO dto = new AppUserWhitelistStatusDTO(); |
| | | dto.setId(1L); |
| | | dto.setStatus(2); |
| | | |
| | | ServiceException exception = assertThrows(ServiceException.class, () -> service.updateStatus(dto)); |
| | | |
| | | assertEquals("无权操作其他公司的数据", exception.getMessage()); |
| | | verify(mapper, never()).update(isNull(), any(Wrapper.class)); |
| | | } |
| | | } |