package jnpf.dmsService; import jnpf.base.ActionResult; import jnpf.base.BillRuleApi; import jnpf.dmsEntity.fenfa.*; import jnpf.dmsMapper.DmsWenjianDayinJishuMapper; import jnpf.exception.DataException; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import java.time.ZoneId; import java.time.ZonedDateTime; import java.util.*; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; class DmsWenjianDayinHaomaServiceTest { final DmsWenjianDayinJishuMapper mapper = mock(DmsWenjianDayinJishuMapper.class); final BillRuleApi bills = mock(BillRuleApi.class); final DmsWenjianDayinHaomaService service = new DmsWenjianDayinHaomaService(mapper, bills); final DmsWenjianDayinRenwuEntity task = new DmsWenjianDayinRenwuEntity(); final List stored = new ArrayList<>(); @BeforeEach void setup() { task.setId("task"); task.setWenjianBianhao("DOC"); task.setBanbenhao("A"); task.setDayinFenshu(5); when(mapper.selectTaskNumbers("tenant", "task")).thenAnswer(c -> new ArrayList<>(stored)); when(mapper.reserve(anyString(), eq("tenant"), eq("DOC"), eq("A"), anyInt(), anyInt())).thenAnswer(c -> { DmsWenjianDayinJishu counter = new DmsWenjianDayinJishu(); counter.setId("counter"); counter.setValue(10 + (Integer)c.getArgument(5)); return counter; }); when(bills.getBillNumber("wenjianDayinLiushuihao")).thenAnswer(c -> ActionResult.success("ok", UUID.randomUUID().toString())); when(mapper.insertTaskNumber(eq("tenant"), eq("task"), any())).thenAnswer(c -> {stored.add(c.getArgument(2)); return 1;}); } @Test void creationFixesAllCopiesAndRetryNeverAllocatesAgain() { List first = service.ensureTaskNumbers("tenant", task, 0); assertEquals(5, first.size()); assertEquals(List.of(1,2,3,4,5), first.stream().map(DmsWenjianDayinHaoma::getTaskSequence).toList()); int year = ZonedDateTime.now(ZoneId.of("Asia/Shanghai")).getYear(); assertEquals(year + "0011", first.getFirst().getCountSerialNumber()); assertEquals(first, service.ensureTaskNumbers("tenant", task, 2)); verify(mapper, times(1)).reserve(anyString(), anyString(), anyString(), anyString(), anyInt(), eq(5)); verify(bills, times(5)).getBillNumber(anyString()); } @Test void legacyTaskAllocatesOnlyRemainingCopiesWithoutCountingHistory() { List result = service.ensureTaskNumbers("tenant", task, 3); assertEquals(List.of(4,5), result.stream().map(DmsWenjianDayinHaoma::getTaskSequence).toList()); verify(mapper).reserve(anyString(), eq("tenant"), eq("DOC"), eq("A"), anyInt(), eq(2)); assertEquals(result, service.ensureTaskNumbers("tenant", task, 3)); } @Test void damagedOrChangedTaskDoesNotSilentlyAllocateNewNumbers() { service.ensureTaskNumbers("tenant", task, 0); stored.remove(2); assertThrows(DataException.class, () -> service.ensureTaskNumbers("tenant", task, 0)); verify(bills, times(5)).getBillNumber(anyString()); } @Test void confirmationRequiresExactNextFixedCopiesAndNeverAllocates() { var fixed = service.ensureTaskNumbers("tenant", task, 0); clearInvocations(mapper, bills); service.requireReservedNumbers("tenant", task, 2, fixed.subList(2,4)); assertThrows(DataException.class, () -> service.requireReservedNumbers("tenant", task, 2, fixed.subList(3,5))); verifyNoInteractions(bills); verify(mapper, never()).reserve(anyString(), anyString(), anyString(), anyString(), anyInt(), anyInt()); } @Test void overflowStopsBeforeUniqueBillAllocation() { when(mapper.reserve(anyString(), anyString(), anyString(), anyString(), anyInt(), anyInt())).thenReturn(null); assertThrows(DataException.class, () -> service.ensureTaskNumbers("tenant", task, 0)); verifyNoInteractions(bills); } @Test void invalidConsumedSequenceIsRejected() { assertThrows(DataException.class, () -> service.ensureTaskNumbers("tenant", task, 6)); verifyNoInteractions(mapper, bills); } }