package jnpf.dmsService; import jnpf.base.UserInfo; import jnpf.audit.sdk.annotation.AuditLog; import jnpf.dmsEntity.fenfa.*; import jnpf.dmsEntity.fenfa.vo.*; import jnpf.dmsMapper.*; import jnpf.dmsPermission.DmsCurrentIdentity; import jnpf.exception.DataException; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.*; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.transaction.annotation.Transactional; import java.util.*; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import static org.mockito.ArgumentMatchers.*; @ExtendWith(MockitoExtension.class) class DmsWenjianBupinghengServiceTest { @Mock jnpf.dmsIntegration.audit.DmsSystemAudit systemAudit; @Mock DmsCurrentIdentity identity; @Mock DmsWenjianFenfaMapper fenfa; @Mock DmsWenjianBupinghengMapper mapper; @Mock private jnpf.dmsService.DmsWenjianDayinHaomaService numbers; @Mock private jnpf.dmsService.DmsWenjianChongdaGuard reprintGuard; @InjectMocks DmsWenjianBupinghengService service; void user() throws Exception { UserInfo u=new UserInfo();u.setUserId("operator");u.setTenantId("tenant"); when(identity.requireUser()).thenReturn(u);when(identity.tenantId(u)).thenReturn("tenant"); } DmsWenjianBupinghengExecution document(String... measures) throws Exception { user();DmsWenjianBupinghengExecution doc=new DmsWenjianBupinghengExecution();doc.setId("doc");doc.setBizSign("signed"); when(mapper.lockDocument("tenant","doc")).thenReturn(doc); List items=new ArrayList<>(); for(int i=0;iservice.execute("doc")); verify(mapper,never()).voidPrint(any(),any(),any(),any()); verify(mapper,never()).completeDocument(any(),any(),any()); verify(fenfa,never()).insertPrintTaskIfAbsent(any()); } @Test void executesPersistedItemsAndLinksReplacementToNativeIds() throws Exception { document("cuoshi1","cuoshi2");copy(0,"daifafang");copy(1,"daiqianshou");task();success(); when(fenfa.insertPrintTaskIfAbsent(any())).thenReturn(1); when(mapper.linkReplacement(eq("tenant"),eq("detail-0"),eq("doc"),anyString())).thenReturn(1); List r=service.execute("doc"); ArgumentCaptor cap=ArgumentCaptor.forClass(DmsWenjianDayinRenwuEntity.class); verify(fenfa).insertPrintTaskIfAbsent(cap.capture());DmsWenjianDayinRenwuEntity t=cap.getValue(); assertEquals("doc",t.getLaiyuanDanjuId());assertEquals("detail-0",t.getLaiyuanMingxiId());assertEquals("wenjian_bupingheng",t.getLaiyuanLeixing()); assertEquals(1,t.getDayinFenshu());assertEquals("daidayin",t.getBizStatus());assertEquals("历史快照",t.getWenjianMingcheng());assertEquals("D(04)",t.getBanbenhao()); assertEquals(t.getId(),r.get(0).getXinDayinRenwuId());assertNull(r.get(1).getXinDayinRenwuId()); verify(fenfa,never()).insertPrintRecord(any());verify(fenfa,never()).insertDistributionTaskIfAbsent(any()); InOrder order=inOrder(mapper);order.verify(mapper).lockDocument("tenant","doc");order.verify(mapper).lockItems("tenant","doc"); order.verify(mapper).voidPrint(eq("tenant"),eq("copy-0"),eq("operator"),any()); order.verify(mapper).linkReplacement(eq("tenant"),eq("detail-0"),eq("doc"),eq(t.getId())); order.verify(mapper).voidPrint(eq("tenant"),eq("copy-1"),eq("operator"),any()); order.verify(mapper).finishDistribution(eq("tenant"),eq("task"),eq("operator"),any());order.verify(mapper).completeDocument(eq("tenant"),eq("doc"),any()); } @Test void measureTwoOnlyVoidsCopy() throws Exception { document("cuoshi2");copy(0,"daifafang");task();success();service.execute("doc"); verify(fenfa,never()).insertPrintTaskIfAbsent(any());verify(mapper,never()).linkReplacement(any(),any(),any(),any()); } @Test void repeatedCompletedDocumentDoesNotMutateBusinessObjects() throws Exception { DmsWenjianBupinghengExecution d=document("cuoshi1");d.setZhixingShijian(new Date()); mapper.lockItems("tenant","doc").get(0).setXinDayinRenwuId("replacement"); assertEquals("replacement",service.execute("doc").get(0).getXinDayinRenwuId()); verifyNoInteractions(fenfa);verify(mapper,never()).voidPrint(any(),any(),any(),any());verify(mapper,never()).completeDocument(any(),any(),any()); } @Test void missingOrCrossTenantDocumentCannotExecute() throws Exception { user();assertThrows(DataException.class,()->service.execute("doc"));verifyNoInteractions(fenfa);verify(mapper,never()).lockItems(any(),any()); } @Test void unsignedNativeDocumentCannotExecute() throws Exception { user();DmsWenjianBupinghengExecution d=new DmsWenjianBupinghengExecution(); when(mapper.lockDocument("tenant","doc")).thenReturn(d); assertThrows(DataException.class,()->service.execute("doc"));verifyNoInteractions(fenfa); } @Test void invalidStoredMeasureCannotExecute() throws Exception { document("unknown");assertThrows(DataException.class,()->service.execute("doc"));verifyNoInteractions(fenfa); } @Test void duplicateStoredCopiesCannotExecute() throws Exception { document("cuoshi1","cuoshi2");mapper.lockItems("tenant","doc").get(1).setDayinJiluId("copy-0"); assertThrows(DataException.class,()->service.execute("doc"));verifyNoInteractions(fenfa); } @Test void staleCopyRejectsAllBeforeMutation() throws Exception { document("cuoshi1","cuoshi2");copy(0,"daifafang");copy(1,"yiguidang"); assertThrows(DataException.class,()->service.execute("doc"));verify(mapper,never()).voidPrint(any(),any(),any(),any()); } @Test void compareAndSetFailureDoesNotMarkExecuted() throws Exception { document("cuoshi2");copy(0,"daifafang");task(); assertThrows(DataException.class,()->service.execute("doc"));verify(mapper,never()).completeDocument(any(),any(),any()); } @Test void receiptFailureThrowsAndTransactionCoversAllBusinessEffects() throws Exception { document("cuoshi2");copy(0,"daifafang");task();when(mapper.voidPrint(any(),any(),any(),any())).thenReturn(1); assertThrows(DataException.class,()->service.execute("doc")); java.lang.reflect.Method method=DmsWenjianBupinghengService.class.getMethod("execute",String.class); assertTrue(Arrays.asList(method.getAnnotation(Transactional.class).rollbackFor()).contains(Exception.class)); assertEquals("#p0",method.getAnnotation(AuditLog.class).targetIdExpr()); } @Test void scheduledExecutionUsesSystemZeroAndOriginalTenantAndSignature() throws Exception { DmsWenjianBupinghengExecution d = new DmsWenjianBupinghengExecution(); d.setId("doc"); d.setBizSign("signed"); d.setDengjiRenId("registrar"); d.setVersion(3L); when(mapper.lockDocument("tenant", "doc")).thenReturn(d); DmsWenjianBupinghengExecution.Item item = new DmsWenjianBupinghengExecution.Item(); item.setId("detail-0"); item.setDayinJiluId("copy-0"); item.setCuoshi("cuoshi1"); item.setYuanyin("破损"); when(mapper.lockItems("tenant", "doc")).thenReturn(List.of(item)); copy(0, "daifafang"); task(); when(mapper.voidPrint(eq("tenant"), eq("copy-0"), eq("0"), any())).thenReturn(1); when(mapper.completeDocument(eq("tenant"), eq("doc"), any())).thenReturn(1); when(fenfa.insertPrintTaskIfAbsent(any())).thenReturn(1); when(mapper.linkReplacement(eq("tenant"), eq("detail-0"), eq("doc"), any())).thenReturn(1); service.executeScheduled("tenant", "doc", 3L); verifyNoInteractions(identity); ArgumentCaptor replacement = ArgumentCaptor.forClass(DmsWenjianDayinRenwuEntity.class); verify(fenfa).insertPrintTaskIfAbsent(replacement.capture()); assertEquals("0", replacement.getValue().getCreatorUserId()); assertEquals("tenant", replacement.getValue().getTenantId()); ArgumentCaptor event = ArgumentCaptor.forClass(jnpf.audit.model.AuditEventDTO.class); verify(systemAudit).record(event.capture()); assertEquals("0", event.getValue().getOperatorId()); assertEquals("tenant", event.getValue().getTenantId()); assertEquals("signed", event.getValue().getRelatedSigns().get(0).getSignId()); assertTrue(event.getValue().getExtra().contains("registrar")); } @Test void scheduledExecutionRejectsChangedDocumentBeforeAnyEffects() throws Exception { DmsWenjianBupinghengExecution d = new DmsWenjianBupinghengExecution(); d.setBizSign("signed"); d.setVersion(4L); when(mapper.lockDocument("tenant", "doc")).thenReturn(d); assertThrows(DataException.class, () -> service.executeScheduled("tenant", "doc", 3L)); verifyNoInteractions(identity, fenfa, systemAudit); verify(mapper, never()).lockItems(any(), any()); } @Test void scheduledExecutionRequiresExplicitTenantAndVersion() { assertThrows(DataException.class, () -> service.executeScheduled("", "doc", 0L)); assertThrows(DataException.class, () -> service.executeScheduled("tenant", "doc", null)); verifyNoInteractions(mapper, identity, fenfa, systemAudit); } }