package jnpf.dmsService; import jnpf.base.UserInfo; import jnpf.dmsEntity.fenfa.DmsWenjianDayinRenwuEntity; import jnpf.dmsEntity.print.DmsWenjianBufaPrintSource; import jnpf.dmsEntity.wenjianbianhao.DmsFlowEventType; import jnpf.dmsEntity.wenjianbianhao.form.DmsFlowEventForm; import jnpf.dmsMapper.DmsWenjianBufaPrintMapper; import jnpf.dmsMapper.DmsWenjianFenfaMapper; import jnpf.dmsPermission.DmsCurrentIdentity; import jnpf.exception.DataException; import jnpf.flowable.WorkFlowApi; import jnpf.flowable.entity.TaskEntity; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; import java.util.*; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; class DmsWenjianBufaPrintServiceTest { private final DmsCurrentIdentity identity = mock(DmsCurrentIdentity.class); private final WorkFlowApi workflow = mock(WorkFlowApi.class); private final DmsWenjianBufaPrintMapper source = mock(DmsWenjianBufaPrintMapper.class); private final DmsWenjianFenfaMapper tasks = mock(DmsWenjianFenfaMapper.class); private final DmsWenjianBufaPrintService service = new DmsWenjianBufaPrintService(identity, workflow, source, tasks, mock(DmsWenjianDayinHaomaService.class)); private final DmsFlowEventForm form = new DmsFlowEventForm(); private final TaskEntity flow = new TaskEntity(); private final DmsWenjianBufaPrintSource request = new DmsWenjianBufaPrintSource(); private DmsWenjianBufaPrintSource.Detail detail; @BeforeEach void setup() { UserInfo user = new UserInfo(); user.setUserId("approver"); when(identity.requireUser()).thenReturn(user); when(identity.tenantId(user)).thenReturn("tenant-a"); form.setFlowId("flow"); form.setTaskId("flow-task"); form.setEventType(DmsFlowEventType.END); flow.setId("flow-task"); flow.setFlowId("flow"); flow.setTemplateId("template"); flow.setStatus(2); flow.setEndTime(new Date(10000)); when(workflow.getInfoSubmit("flow-task")).thenReturn(flow); request.setId("request"); request.setFlowId("flow"); request.setFlowState(2); request.setApplicantId("applicant"); request.setDepartmentId("department"); request.setRemark("remark"); when(source.lockRequests("tenant-a", "flow-task")).thenReturn(Collections.singletonList(request)); detail = detail("detail"); when(source.selectDetails("tenant-a", "request")).thenReturn(Collections.singletonList(detail)); when(tasks.insertPrintTaskIfAbsent(any())).thenReturn(1); } @Test void createsTaskFromApprovedPersistedRequestAndVersion() { assertEquals(1, service.onFlowEnd(form)); ArgumentCaptor captor = ArgumentCaptor.forClass(DmsWenjianDayinRenwuEntity.class); verify(tasks).insertPrintTaskIfAbsent(captor.capture()); DmsWenjianDayinRenwuEntity task = captor.getValue(); assertEquals("tenant-a", task.getTenantId()); assertEquals("wenjian_bufa", task.getLaiyuanLeixing()); assertEquals("request", task.getLaiyuanDanjuId()); assertEquals("detail", task.getLaiyuanMingxiId()); assertEquals("file", task.getWenjianId()); assertEquals("V1", task.getBanbenhao()); assertEquals("department", task.getJieshouBumenId()); assertEquals(3, task.getDayinFenshu()); assertEquals("applicant", task.getCreatorUserId()); assertEquals(flow.getEndTime(), task.getShenheWanchengRiqi()); assertEquals(detail.getEffectiveDate(), task.getShengxiaoRiqi()); assertEquals("no", task.getShifouShoukong()); assertEquals("daidayin", task.getBizStatus()); } @Test void rejectsSubmissionAndRecallBeforeAnyQuery() { for (DmsFlowEventType event : Arrays.asList(DmsFlowEventType.START, DmsFlowEventType.RECALL)) { form.setEventType(event); assertThrows(DataException.class, () -> service.onFlowEnd(form)); } verifyNoInteractions(workflow, source, tasks); } @Test void nonApprovedEndEventsGenerateNothing() { for (int status : new int[]{0,1,3,4,5,6,7,8,9,10}) { flow.setStatus(status); assertEquals(0, service.onFlowEnd(form)); } verifyNoInteractions(source, tasks); } @Test void rejectsWrongWorkflowAndMissingEndTime() { flow.setId("other"); assertThrows(DataException.class, () -> service.onFlowEnd(form)); flow.setId("flow-task"); flow.setFlowId("other"); flow.setTemplateId("other"); assertThrows(DataException.class, () -> service.onFlowEnd(form)); flow.setFlowId("flow"); flow.setEndTime(null); assertThrows(DataException.class, () -> service.onFlowEnd(form)); verifyNoInteractions(source, tasks); } @Test void scopesRequestToCurrentTenantAndRequiresUniqueApprovedMatch() { when(source.lockRequests("tenant-a", "flow-task")).thenReturn(Collections.emptyList()); assertThrows(DataException.class, () -> service.onFlowEnd(form)); when(source.lockRequests("tenant-a", "flow-task")).thenReturn(Arrays.asList(request, request)); assertThrows(DataException.class, () -> service.onFlowEnd(form)); when(source.lockRequests("tenant-a", "flow-task")).thenReturn(Collections.singletonList(request)); request.setFlowState(1); assertThrows(DataException.class, () -> service.onFlowEnd(form)); request.setFlowState(2); request.setFlowId("wrong"); assertThrows(DataException.class, () -> service.onFlowEnd(form)); verifyNoInteractions(tasks); } @Test void validatesWholeBatchBeforeInsertingAnyTask() { DmsWenjianBufaPrintSource.Detail invalid = detail("invalid"); invalid.setResolvedVersionId(null); when(source.selectDetails("tenant-a", "request")).thenReturn(Arrays.asList(detail, invalid)); assertThrows(DataException.class, () -> service.onFlowEnd(form)); verifyNoInteractions(tasks); } @Test void rejectsEmptyDetailsAndInvalidCopies() { for (String count : Arrays.asList(null, "", "0", "-1", "1.5", "999999999999", "bad")) { detail.setCopies(count); assertThrows(DataException.class, () -> service.onFlowEnd(form), count); } when(source.selectDetails("tenant-a", "request")).thenReturn(Collections.emptyList()); assertThrows(DataException.class, () -> service.onFlowEnd(form)); verifyNoInteractions(tasks); } @Test void replayKeepsSourceIdentityAndReportsOnlyNewRows() { when(tasks.insertPrintTaskIfAbsent(any())).thenReturn(1, 0); assertEquals(1, service.onFlowEnd(form)); assertEquals(0, service.onFlowEnd(form)); ArgumentCaptor captor = ArgumentCaptor.forClass(DmsWenjianDayinRenwuEntity.class); verify(tasks, times(2)).insertPrintTaskIfAbsent(captor.capture()); assertEquals(captor.getAllValues().get(0).getLaiyuanMingxiId(), captor.getAllValues().get(1).getLaiyuanMingxiId()); verify(source, times(2)).lockRequests("tenant-a", "flow-task"); } @Test void insertionFailurePropagatesForTransactionRollback() { when(tasks.insertPrintTaskIfAbsent(any())).thenThrow(new IllegalStateException("db failure")); assertThrows(IllegalStateException.class, () -> service.onFlowEnd(form)); } private DmsWenjianBufaPrintSource.Detail detail(String id) { DmsWenjianBufaPrintSource.Detail row = new DmsWenjianBufaPrintSource.Detail(); row.setId(id); row.setFileId("file"); row.setVersionId("version"); row.setResolvedVersionId("version"); row.setFileName("Document"); row.setFileNumber("DOC-01"); row.setVersionLabel("V1"); row.setCopies("3"); row.setControlled("no"); row.setEffectiveDate(new Date(5000)); return row; } }