123 lines
5.6 KiB
Java
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;
|
|
}
|
|
}
|