Files
BMS/bms-back/bms-admin/src/test/java/com/bms/receivable/ArBillConfirmTest.java
T
2026-11-12 17:08:56 +08:00

123 lines
5.6 KiB
Java

package com.bms.receivable;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertSame;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.when;
import java.math.BigDecimal;
import java.util.List;
import java.util.Set;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.test.util.ReflectionTestUtils;
import com.bms.common.core.domain.entity.SysUser;
import com.bms.common.core.domain.model.LoginUser;
import com.bms.common.exception.ServiceException;
import com.bms.receivable.domain.ArBill;
import com.bms.receivable.domain.ArBillLog;
import com.bms.receivable.mapper.ArBillDetailMapper;
import com.bms.receivable.mapper.ArBillExportMapper;
import com.bms.receivable.mapper.ArBillMapper;
import com.bms.receivable.security.ArBillScopeResolver;
import com.bms.receivable.service.IArBillLogService;
import com.bms.receivable.service.impl.ArBillServiceImpl;
class ArBillConfirmTest {
private final ArBillMapper billMapper = mock(ArBillMapper.class);
private final ArBillDetailMapper detailMapper = mock(ArBillDetailMapper.class);
private final ArBillExportMapper exportMapper = mock(ArBillExportMapper.class);
private final ArBillScopeResolver scope = mock(ArBillScopeResolver.class);
private final IArBillLogService logService = mock(IArBillLogService.class);
private final ArBillServiceImpl service = new ArBillServiceImpl();
@BeforeEach
void setUp() {
ReflectionTestUtils.setField(service, "billMapper", billMapper);
ReflectionTestUtils.setField(service, "detailMapper", detailMapper);
ReflectionTestUtils.setField(service, "exportMapper", exportMapper);
ReflectionTestUtils.setField(service, "billScope", scope);
ReflectionTestUtils.setField(service, "logService", logService);
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken(
new LoginUser(7L, 1L, new SysUser(), Set.of()), null));
}
@AfterEach
void clearSecurity() {
SecurityContextHolder.clearContext();
}
@Test
void readyDraftCanBeConfirmedWithoutReadingDetails() {
ArBill draft = bill("DRAFT", "READY");
draft.setTotalAmount(new BigDecimal("123.45"));
ArBill confirmed = bill("CONFIRMED", "READY");
when(billMapper.selectArBillByIdForUpdate(11L)).thenReturn(draft);
when(billMapper.updateArBillStatus(11L, "CONFIRMED", null, "finance", "DRAFT")).thenReturn(1);
when(billMapper.selectArBillByIdScoped(11L, null)).thenReturn(confirmed);
when(exportMapper.selectByBillId(11L)).thenReturn(List.of());
assertSame(confirmed, service.confirmBill(11L, null, "finance", "request-1"));
verify(scope).requireBillAccessible(11L);
verifyNoInteractions(detailMapper);
verify(logService).record(any(ArBillLog.class));
}
@Test
void unfinishedOrNonDraftBillStillCannotBeConfirmed() {
when(billMapper.selectArBillByIdForUpdate(11L)).thenReturn(
bill("DRAFT", "GENERATING"), bill("CONFIRMED", "READY"));
ServiceException unfinished = assertThrows(ServiceException.class,
() -> service.confirmBill(11L, null, "finance", "request-1"));
assertEquals("账单尚未生成完成,暂不能确认", unfinished.getMessage());
ServiceException notDraft = assertThrows(ServiceException.class,
() -> service.confirmBill(11L, null, "finance", "request-2"));
assertEquals("只有草稿账单可以确认,当前状态为 CONFIRMED", notDraft.getMessage());
verify(billMapper, never()).updateArBillStatus(eq(11L), any(), nullable(String.class), any(), any());
verifyNoInteractions(detailMapper);
}
@Test
void inaccessibleBillStillCannotBeConfirmed() {
when(billMapper.selectArBillByIdForUpdate(11L)).thenReturn(bill("DRAFT", "READY"));
doThrow(new ServiceException("账单不存在或无权访问")).when(scope).requireBillAccessible(11L);
assertThrows(ServiceException.class, () -> service.confirmBill(11L, null, "finance", "request-1"));
verify(billMapper, never()).updateArBillStatus(eq(11L), any(), nullable(String.class), any(), any());
verifyNoInteractions(detailMapper);
}
@Test
void concurrentStatusChangeStillPreventsConfirmation() {
when(billMapper.selectArBillByIdForUpdate(11L)).thenReturn(bill("DRAFT", "READY"));
ServiceException error = assertThrows(ServiceException.class,
() -> service.confirmBill(11L, null, "finance", "request-1"));
assertEquals("账单状态已发生变化,请刷新后重试", error.getMessage());
verify(logService, never()).record(any(ArBillLog.class));
verifyNoInteractions(detailMapper);
}
private static ArBill bill(String status, String generationStatus) {
ArBill bill = new ArBill();
bill.setArBillId(11L);
bill.setStatus(status);
bill.setGenerationStatus(generationStatus);
return bill;
}
}