puzhibing
2026-09-28 0f7f9ebdf8c7eb42c74a994b602f33c0d38aafb7
ruoyi-service/ruoyi-account/src/test/java/com/ruoyi/account/service/impl/TChargingCardServiceImplTest.java
@@ -3,6 +3,8 @@
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.account.api.dto.ChargingCardAllocateDTO;
import com.ruoyi.account.api.dto.ChargingCardAllocateItemDTO;
import com.ruoyi.account.api.dto.ChargingCardAuthDTO;
import com.ruoyi.account.api.dto.ChargingCardBalanceDTO;
import com.ruoyi.account.api.dto.ChargingCardDeductDTO;
@@ -10,6 +12,7 @@
import com.ruoyi.account.api.dto.ChargingCardSaveDTO;
import com.ruoyi.account.api.dto.ChargingCardStatusDTO;
import com.ruoyi.account.api.model.TChargingCard;
import com.ruoyi.account.api.vo.ChargingCardAllocateVO;
import com.ruoyi.account.api.vo.ChargingCardDeductVO;
import com.ruoyi.account.mapper.TChargingCardMapper;
import com.ruoyi.common.core.context.SecurityContextHolder;
@@ -17,6 +20,9 @@
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.security.service.TokenService;
import com.ruoyi.common.security.utils.SecurityUtils;
import com.ruoyi.other.api.domain.TFleet;
import com.ruoyi.other.api.domain.TGroupCompany;
import com.ruoyi.other.api.feignClient.GroupCompanyClient;
import com.ruoyi.system.api.domain.SysUser;
import com.ruoyi.system.api.feignClient.SysUserClient;
import com.ruoyi.system.api.model.LoginUser;
@@ -27,6 +33,8 @@
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.transaction.support.TransactionCallback;
@@ -35,6 +43,7 @@
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Collections;
import java.util.concurrent.TimeUnit;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
@@ -42,11 +51,13 @@
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.anyCollection;
import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
@@ -59,15 +70,23 @@
    @Mock private TokenService tokenService;
    @Mock private SysUserClient sysUserClient;
    @Mock private TransactionTemplate transactionTemplate;
    @Mock private GroupCompanyClient groupCompanyClient;
    @Mock private RedissonClient redissonClient;
    @Mock private RLock quotaLock;
    private TChargingCardServiceImpl service;
    @BeforeEach
    void setUp() {
    void setUp() throws InterruptedException {
        service = spy(new TChargingCardServiceImpl());
        ReflectionTestUtils.setField(service, "baseMapper", mapper);
        ReflectionTestUtils.setField(service, "tokenService", tokenService);
        ReflectionTestUtils.setField(service, "sysUserClient", sysUserClient);
        ReflectionTestUtils.setField(service, "transactionTemplate", transactionTemplate);
        ReflectionTestUtils.setField(service, "groupCompanyClient", groupCompanyClient);
        ReflectionTestUtils.setField(service, "redissonClient", redissonClient);
        lenient().when(redissonClient.getLock(anyString())).thenReturn(quotaLock);
        lenient().when(quotaLock.tryLock(anyLong(), anyLong(), any(TimeUnit.class))).thenReturn(true);
        lenient().when(quotaLock.isHeldByCurrentThread()).thenReturn(true);
        SecurityContextHolder.setUserId("123");
    }
@@ -380,6 +399,216 @@
        verify(mapper, never()).adjustBalance(anyList(), any(), any(), any(), any());
    }
    // ==================== 卡片所属公司/车队 + 初始分配额度 ====================
    @Test
    void saveCardDeductsCompanyBalanceWhenAllocationQuotaProvided() {
        when(mapper.countByCardNo(anyString(), isNull())).thenReturn(0);
        when(mapper.insert(any(TChargingCard.class))).thenReturn(1);
        when(groupCompanyClient.getCompanyById(9)).thenReturn(R.ok(allocationCompany(9, "测试公司")));
        when(groupCompanyClient.getFleetById(3)).thenReturn(R.ok(fleet(3, 9, "测试车队")));
        when(groupCompanyClient.deductBalance(9, new BigDecimal("100.00")))
                .thenReturn(R.ok(new BigDecimal("900.00")));
        ChargingCardSaveDTO dto = new ChargingCardSaveDTO();
        dto.setCardNo(" CARD-Q1 ");
        dto.setCompanyId(9);
        dto.setFleetId(3);
        dto.setInitQuota(new BigDecimal("100"));
        assertTrue(service.saveCard(dto));
        ArgumentCaptor<TChargingCard> card = ArgumentCaptor.forClass(TChargingCard.class);
        verify(mapper).insert(card.capture());
        assertEquals(Integer.valueOf(9), card.getValue().getCompanyId());
        assertEquals(Integer.valueOf(3), card.getValue().getFleetId());
        assertEquals(new BigDecimal("100.00"), card.getValue().getInitQuota());
        verify(groupCompanyClient).deductBalance(9, new BigDecimal("100.00"));
    }
    @Test
    void saveCardRejectsQuotaForShareModeCompany() {
        when(mapper.countByCardNo(anyString(), isNull())).thenReturn(0);
        TGroupCompany shareCompany = allocationCompany(9, "共享公司");
        shareCompany.setAccountMode(1);
        when(groupCompanyClient.getCompanyById(9)).thenReturn(R.ok(shareCompany));
        ChargingCardSaveDTO dto = new ChargingCardSaveDTO();
        dto.setCardNo("CARD-Q2");
        dto.setCompanyId(9);
        dto.setInitQuota(new BigDecimal("10.00"));
        ServiceException exception = assertThrows(ServiceException.class, () -> service.saveCard(dto));
        assertEquals("仅分配模式的公司可填写初始分配额度", exception.getMessage());
        verify(groupCompanyClient, never()).deductBalance(any(), any());
        verify(mapper, never()).insert(any(TChargingCard.class));
    }
    @Test
    void saveCardKeepsQuotaEmptyAndSkipsBalanceWhenCompanyMissing() {
        when(mapper.countByCardNo(anyString(), isNull())).thenReturn(0);
        when(mapper.insert(any(TChargingCard.class))).thenReturn(1);
        ChargingCardSaveDTO dto = new ChargingCardSaveDTO();
        dto.setCardNo("CARD-Q3");
        assertTrue(service.saveCard(dto));
        ArgumentCaptor<TChargingCard> card = ArgumentCaptor.forClass(TChargingCard.class);
        verify(mapper).insert(card.capture());
        assertEquals(null, card.getValue().getCompanyId());
        assertEquals(null, card.getValue().getInitQuota());
        verify(groupCompanyClient, never()).deductBalance(any(), any());
    }
    @Test
    void saveCardRejectsFleetNotBelongingToCompany() {
        when(mapper.countByCardNo(anyString(), isNull())).thenReturn(0);
        when(groupCompanyClient.getCompanyById(9)).thenReturn(R.ok(allocationCompany(9, "测试公司")));
        when(groupCompanyClient.getFleetById(3)).thenReturn(R.ok(fleet(3, 11, "他司车队")));
        ChargingCardSaveDTO dto = new ChargingCardSaveDTO();
        dto.setCardNo("CARD-Q4");
        dto.setCompanyId(9);
        dto.setFleetId(3);
        ServiceException exception = assertThrows(ServiceException.class, () -> service.saveCard(dto));
        assertEquals("所属车队不属于所选公司", exception.getMessage());
    }
    @Test
    void updateCardDeductsQuotaDiffWhenQuotaIncreased() {
        ChargingCardSaveDTO dto = quotaUpdateDto(7L, "CARD-7", 9, new BigDecimal("150.00"));
        when(mapper.countByCardNo("CARD-7", 7L)).thenReturn(0);
        when(mapper.selectById(7L)).thenReturn(cardWithQuota(7L, 9, new BigDecimal("100.00")));
        when(mapper.updateById(any(TChargingCard.class))).thenReturn(1);
        when(mapper.update(isNull(), any(Wrapper.class))).thenReturn(1);
        when(groupCompanyClient.getCompanyById(9)).thenReturn(R.ok(allocationCompany(9, "测试公司")));
        when(groupCompanyClient.deductBalance(9, new BigDecimal("50.00")))
                .thenReturn(R.ok(new BigDecimal("50.00")));
        assertTrue(service.updateCard(dto));
        verify(groupCompanyClient).deductBalance(9, new BigDecimal("50.00"));
        verify(groupCompanyClient, never()).refundBalance(any(), any());
    }
    @Test
    void updateCardRefundsQuotaDiffWhenQuotaReduced() {
        ChargingCardSaveDTO dto = quotaUpdateDto(7L, "CARD-7", 9, new BigDecimal("80.00"));
        when(mapper.countByCardNo("CARD-7", 7L)).thenReturn(0);
        when(mapper.selectById(7L)).thenReturn(cardWithQuota(7L, 9, new BigDecimal("150.00")));
        when(mapper.updateById(any(TChargingCard.class))).thenReturn(1);
        when(mapper.update(isNull(), any(Wrapper.class))).thenReturn(1);
        when(groupCompanyClient.getCompanyById(9)).thenReturn(R.ok(allocationCompany(9, "测试公司")));
        when(groupCompanyClient.refundBalance(9, new BigDecimal("70.00")))
                .thenReturn(R.ok(new BigDecimal("70.00")));
        assertTrue(service.updateCard(dto));
        verify(groupCompanyClient).refundBalance(9, new BigDecimal("70.00"));
        verify(groupCompanyClient, never()).deductBalance(any(), any());
    }
    @Test
    void updateCardSwitchesCompanyRefundsOldAndDeductsNew() {
        ChargingCardSaveDTO dto = quotaUpdateDto(7L, "CARD-7", 11, new BigDecimal("60.00"));
        when(mapper.countByCardNo("CARD-7", 7L)).thenReturn(0);
        when(mapper.selectById(7L)).thenReturn(cardWithQuota(7L, 9, new BigDecimal("100.00")));
        when(mapper.updateById(any(TChargingCard.class))).thenReturn(1);
        when(mapper.update(isNull(), any(Wrapper.class))).thenReturn(1);
        when(groupCompanyClient.getCompanyById(11)).thenReturn(R.ok(allocationCompany(11, "新公司")));
        when(groupCompanyClient.refundBalance(9, new BigDecimal("100.00")))
                .thenReturn(R.ok(new BigDecimal("100.00")));
        when(groupCompanyClient.deductBalance(11, new BigDecimal("60.00")))
                .thenReturn(R.ok(new BigDecimal("60.00")));
        assertTrue(service.updateCard(dto));
        verify(groupCompanyClient).refundBalance(9, new BigDecimal("100.00"));
        verify(groupCompanyClient).deductBalance(11, new BigDecimal("60.00"));
    }
    @Test
    void updateCardCompensatesRefundWhenUpdateFails() {
        ChargingCardSaveDTO dto = quotaUpdateDto(7L, "CARD-7", 9, new BigDecimal("150.00"));
        when(mapper.countByCardNo("CARD-7", 7L)).thenReturn(0);
        when(mapper.selectById(7L)).thenReturn(cardWithQuota(7L, 9, new BigDecimal("100.00")));
        when(mapper.updateById(any(TChargingCard.class))).thenReturn(0);
        when(groupCompanyClient.getCompanyById(9)).thenReturn(R.ok(allocationCompany(9, "测试公司")));
        when(groupCompanyClient.deductBalance(9, new BigDecimal("50.00")))
                .thenReturn(R.ok(new BigDecimal("100.00")));
        when(groupCompanyClient.refundBalance(9, new BigDecimal("50.00")))
                .thenReturn(R.ok(new BigDecimal("150.00")));
        ServiceException exception = assertThrows(ServiceException.class, () -> service.updateCard(dto));
        assertEquals("修改卡片失败", exception.getMessage());
        verify(groupCompanyClient).refundBalance(9, new BigDecimal("50.00"));
    }
    @Test
    void updateCardRejectsWhenQuotaLockUnavailable() throws InterruptedException {
        ChargingCardSaveDTO dto = quotaUpdateDto(7L, "CARD-7", 9, new BigDecimal("150.00"));
        when(mapper.countByCardNo("CARD-7", 7L)).thenReturn(0);
        when(mapper.selectById(7L)).thenReturn(cardWithQuota(7L, 9, new BigDecimal("100.00")));
        when(quotaLock.tryLock(anyLong(), anyLong(), any(TimeUnit.class))).thenReturn(false);
        ServiceException exception = assertThrows(ServiceException.class, () -> service.updateCard(dto));
        assertEquals("该卡片额度正在处理中,请稍后重试", exception.getMessage());
        verify(groupCompanyClient, never()).deductBalance(any(), any());
    }
    @Test
    void selectCardPageFillsCompanyAndFleetNames() {
        TChargingCard record = cardWithQuota(1L, 9, new BigDecimal("10.00"));
        record.setFleetId(3);
        Page<TChargingCard> page = new Page<>(1, 10);
        page.setRecords(Collections.singletonList(record));
        when(mapper.selectCardPage(any(Page.class), any())).thenReturn(page);
        when(groupCompanyClient.getCompanyById(9)).thenReturn(R.ok(allocationCompany(9, "测试公司")));
        when(groupCompanyClient.listFleetsByIds(anyList()))
                .thenReturn(R.ok(Collections.singletonList(fleet(3, 9, "测试车队"))));
        IPage<TChargingCard> result = service.selectCardPage(null);
        assertEquals("测试公司", result.getRecords().get(0).getCompanyName());
        assertEquals("测试车队", result.getRecords().get(0).getFleetName());
    }
    private TGroupCompany allocationCompany(Integer id, String name) {
        TGroupCompany company = new TGroupCompany();
        company.setId(id);
        company.setName(name);
        company.setAccountMode(2);
        company.setStatus(1);
        return company;
    }
    private TFleet fleet(Integer id, Integer companyId, String name) {
        TFleet fleet = new TFleet();
        fleet.setId(id);
        fleet.setCompanyId(companyId);
        fleet.setFleetName(name);
        return fleet;
    }
    private TChargingCard cardWithQuota(Long id, Integer companyId, BigDecimal quota) {
        TChargingCard card = new TChargingCard();
        card.setId(id);
        card.setCompanyId(companyId);
        card.setInitQuota(quota);
        return card;
    }
    private ChargingCardSaveDTO quotaUpdateDto(Long id, String cardNo, Integer companyId, BigDecimal quota) {
        ChargingCardSaveDTO dto = new ChargingCardSaveDTO();
        dto.setId(id);
        dto.setCardNo(cardNo);
        dto.setCompanyId(companyId);
        dto.setInitQuota(quota);
        return dto;
    }
    // ==================== V0.2 定稿:刷卡启动鉴权(条件密码校验) ====================
    @Test
@@ -597,4 +826,191 @@
        dto.setAmount(amount);
        return dto;
    }
    // ==================== 卡片额度分配 ====================
    @Test
    void getAllocateOverviewNormalizesAmounts() {
        TGroupCompany company = allocationCompany(9, "测试公司");
        company.setAvailableBalance(new BigDecimal("8420.5"));
        company.setTotalRechargeAmount(null);
        when(groupCompanyClient.getCompanyById(9)).thenReturn(R.ok(company));
        ChargingCardAllocateVO vo = service.getAllocateOverview(9);
        assertEquals(Integer.valueOf(9), vo.getCompanyId());
        assertEquals("测试公司", vo.getCompanyName());
        assertEquals(new BigDecimal("8420.50"), vo.getAvailableBalance());
        assertEquals(new BigDecimal("0.00"), vo.getTotalRechargeAmount());
    }
    @Test
    void getAllocateOverviewRejectsMissingCompanyId() {
        ServiceException exception = assertThrows(ServiceException.class, () -> service.getAllocateOverview(null));
        assertEquals("请选择公司", exception.getMessage());
    }
    @Test
    void allocateQuotaAddsCardBalanceAndDeductsCompanyBalance() {
        mockOperationPassword();
        when(groupCompanyClient.getCompanyById(9)).thenReturn(R.ok(allocationCompany(9, "测试公司")));
        TChargingCard first = allocateCard(1L, 9, "CARD-1", "10.00");
        TChargingCard second = allocateCard(2L, 9, "CARD-2", "20.00");
        doReturn(Arrays.asList(first, second)).when(service).listByIds(anyCollection());
        when(mapper.adjustBalance(anyList(), any(BigDecimal.class), any(Integer.class), any(BigDecimal.class),
                any(Long.class))).thenReturn(1);
        when(mapper.insertBalanceRecord(anyLong(), any(Integer.class), any(BigDecimal.class), any(), any(Long.class)))
                .thenReturn(1);
        when(groupCompanyClient.deductBalance(9, new BigDecimal("30.00"))).thenReturn(R.ok(new BigDecimal("970.00")));
        ChargingCardAllocateVO vo = service.allocateQuota(allocateDto(9, "pwd",
                allocateItem(1L, "10.00"), allocateItem(2L, "20.00")));
        assertEquals(new BigDecimal("970.00"), vo.getAvailableBalance());
        assertEquals("测试公司", vo.getCompanyName());
        verify(groupCompanyClient).deductBalance(9, new BigDecimal("30.00"));
        verify(mapper).insertBalanceRecord(1L, 1, new BigDecimal("10.00"), "额度分配(公司:测试公司)", 123L);
        verify(mapper).insertBalanceRecord(2L, 1, new BigDecimal("20.00"), "额度分配(公司:测试公司)", 123L);
        verify(redissonClient).getLock("CHARGING_CARD_QUOTA:COMPANY:9");
    }
    @Test
    void allocateQuotaRejectsSharedModeCompany() {
        mockOperationPassword();
        TGroupCompany shared = allocationCompany(9, "共享公司");
        shared.setAccountMode(1);
        when(groupCompanyClient.getCompanyById(9)).thenReturn(R.ok(shared));
        ServiceException exception = assertThrows(ServiceException.class,
                () -> service.allocateQuota(allocateDto(9, "pwd", allocateItem(1L, "10.00"))));
        assertEquals("该公司为共享模式,不支持额度分配", exception.getMessage());
        verify(groupCompanyClient, never()).deductBalance(any(Integer.class), any(BigDecimal.class));
    }
    @Test
    void allocateQuotaRejectsCardOfAnotherCompany() {
        mockOperationPassword();
        when(groupCompanyClient.getCompanyById(9)).thenReturn(R.ok(allocationCompany(9, "测试公司")));
        TChargingCard foreign = allocateCard(1L, 8, "CARD-1", "10.00");
        doReturn(Collections.singletonList(foreign)).when(service).listByIds(anyCollection());
        ServiceException exception = assertThrows(ServiceException.class,
                () -> service.allocateQuota(allocateDto(9, "pwd", allocateItem(1L, "10.00"))));
        assertTrue(exception.getMessage().contains("不属于所选公司"));
        verify(groupCompanyClient, never()).deductBalance(any(Integer.class), any(BigDecimal.class));
    }
    @Test
    void allocateQuotaRefundsCompanyBalanceWhenCardUpdateFails() {
        mockOperationPassword();
        when(groupCompanyClient.getCompanyById(9)).thenReturn(R.ok(allocationCompany(9, "测试公司")));
        TChargingCard card = allocateCard(1L, 9, "CARD-1", "10.00");
        doReturn(Collections.singletonList(card)).when(service).listByIds(anyCollection());
        when(groupCompanyClient.deductBalance(9, new BigDecimal("10.00")))
                .thenReturn(R.ok(new BigDecimal("990.00")));
        when(mapper.adjustBalance(anyList(), any(BigDecimal.class), any(Integer.class), any(BigDecimal.class),
                any(Long.class))).thenReturn(0);
        ServiceException exception = assertThrows(ServiceException.class,
                () -> service.allocateQuota(allocateDto(9, "pwd", allocateItem(1L, "10.00"))));
        assertTrue(exception.getMessage().contains("余额分配失败"));
        verify(groupCompanyClient).refundBalance(9, new BigDecimal("10.00"));
    }
    @Test
    void allocateQuotaReportsInsufficientCompanyBalance() {
        mockOperationPassword();
        when(groupCompanyClient.getCompanyById(9)).thenReturn(R.ok(allocationCompany(9, "测试公司")));
        TChargingCard card = allocateCard(1L, 9, "CARD-1", "0.00");
        doReturn(Collections.singletonList(card)).when(service).listByIds(anyCollection());
        when(groupCompanyClient.deductBalance(9, new BigDecimal("500.00"))).thenReturn(R.fail("公司可用余额不足"));
        ServiceException exception = assertThrows(ServiceException.class,
                () -> service.allocateQuota(allocateDto(9, "pwd", allocateItem(1L, "500.00"))));
        assertEquals("公司可分配余额不足,无法完成本次分配", exception.getMessage());
        verify(mapper, never()).adjustBalance(anyList(), any(BigDecimal.class), any(Integer.class),
                any(BigDecimal.class), any(Long.class));
    }
    @Test
    void allocateQuotaRejectsInvalidAmount() {
        ServiceException exception = assertThrows(ServiceException.class,
                () -> service.allocateQuota(allocateDto(9, "pwd", allocateItem(1L, "0"))));
        assertEquals("分配金额必须大于0", exception.getMessage());
        verify(groupCompanyClient, never()).getCompanyById(any(Integer.class));
    }
    @Test
    void allocateQuotaRejectsDuplicateCards() {
        ServiceException exception = assertThrows(ServiceException.class,
                () -> service.allocateQuota(allocateDto(9, "pwd", allocateItem(1L, "10.00"), allocateItem(1L, "5.00"))));
        assertEquals("分配明细中存在重复卡片", exception.getMessage());
    }
    @Test
    void allocateQuotaRejectsMissingPassword() {
        ServiceException exception = assertThrows(ServiceException.class,
                () -> service.allocateQuota(allocateDto(9, null, allocateItem(1L, "10.00"))));
        assertEquals("请输入操作密码", exception.getMessage());
        verify(mapper, never()).adjustBalance(anyList(), any(BigDecimal.class), any(Integer.class),
                any(BigDecimal.class), any(Long.class));
    }
    @Test
    void allocateQuotaRejectsChargingLockedCard() {
        mockOperationPassword();
        when(groupCompanyClient.getCompanyById(9)).thenReturn(R.ok(allocationCompany(9, "测试公司")));
        TChargingCard card = allocateCard(1L, 9, "CARD-1", "10.00");
        card.setChargingFlag(1);
        doReturn(Collections.singletonList(card)).when(service).listByIds(anyCollection());
        ServiceException exception = assertThrows(ServiceException.class,
                () -> service.allocateQuota(allocateDto(9, "pwd", allocateItem(1L, "10.00"))));
        assertTrue(exception.getMessage().contains("充电中"));
        verify(groupCompanyClient, never()).deductBalance(any(Integer.class), any(BigDecimal.class));
    }
    private void mockOperationPassword() {
        LoginUser loginUser = new LoginUser();
        loginUser.setUserid(123L);
        SysUser user = new SysUser();
        user.setOperationPassword(SecurityUtils.encryptPassword("pwd"));
        when(tokenService.getLoginUser()).thenReturn(loginUser);
        when(sysUserClient.getSysUser(123L)).thenReturn(R.ok(user));
    }
    private TChargingCard allocateCard(Long id, Integer companyId, String cardNo, String balance) {
        TChargingCard card = new TChargingCard();
        card.setId(id);
        card.setCompanyId(companyId);
        card.setCardNo(cardNo);
        card.setBalance(new BigDecimal(balance));
        card.setStatus(1);
        card.setChargingFlag(0);
        return card;
    }
    private ChargingCardAllocateItemDTO allocateItem(Long cardId, String amount) {
        ChargingCardAllocateItemDTO item = new ChargingCardAllocateItemDTO();
        item.setCardId(cardId);
        item.setAmount(new BigDecimal(amount));
        return item;
    }
    private ChargingCardAllocateDTO allocateDto(Integer companyId, String password, ChargingCardAllocateItemDTO... items) {
        ChargingCardAllocateDTO dto = new ChargingCardAllocateDTO();
        dto.setCompanyId(companyId);
        dto.setItems(Arrays.asList(items));
        dto.setOperationPassword(password);
        return dto;
    }
}