package jnpf.dmsService.impl; import jnpf.base.UserInfo; import jnpf.dmsEntity.DmsWenjianBanbenKongzhiEntity; import jnpf.dmsEntity.DmsWenjianXinzengGuanliEntity; import jnpf.dmsEntity.DmsWenjianXinzengShenheEntity; import jnpf.dmsEntity.DmsWenjianXiudingShenheEntity; import jnpf.dmsEntity.DmsWenjianXiudingShenqingEntity; import jnpf.dmsEntity.wenjianbianhao.DmsFlowEventType; import jnpf.dmsMapper.DmsWenjianBanbenKongzhiMapper; import jnpf.dmsMapper.DmsWenjianXinzengGuanliMapper; import jnpf.dmsMapper.DmsWenjianXinzengShenheMapper; import jnpf.dmsMapper.DmsWenjianXiudingShenheMapper; import jnpf.dmsMapper.DmsWenjianXiudingShenqingMapper; import jnpf.dmsPermission.DmsCurrentIdentity; import jnpf.exception.DataException; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import java.util.Collections; import java.util.Date; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) class DmsWenjianBanbenServiceImplTest { private static final String TENANT_ID = "tenant-1"; private static final String FLOW_ID = "flow-1"; private static final String TASK_ID = "task-1"; @Mock private DmsCurrentIdentity identity; @Mock private DmsWenjianBanbenKongzhiMapper controlMapper; @Mock private DmsWenjianXinzengGuanliMapper newRequestMapper; @Mock private DmsWenjianXinzengShenheMapper newAuditMapper; @Mock private DmsWenjianXiudingShenqingMapper revisionRequestMapper; @Mock private DmsWenjianXiudingShenheMapper revisionAuditMapper; @InjectMocks private DmsWenjianBanbenServiceImpl service; @BeforeEach void setUpIdentity() { UserInfo user = new UserInfo(); user.setUserId("operator-1"); user.setTenantId(TENANT_ID); when(identity.requireUser()).thenReturn(user); when(identity.tenantId(user)).thenReturn(TENANT_ID); } @Test void newAuditPassInitializesD00AndWritesAuditResult() { DmsWenjianXinzengShenheEntity audit = newAudit(2); DmsWenjianXinzengGuanliEntity request = newRequest(); when(newAuditMapper.selectByFlowForUpdate(TENANT_ID, FLOW_ID, TASK_ID)) .thenReturn(Collections.singletonList(audit)); when(newRequestMapper.selectByIdForUpdate(TENANT_ID, "new-request-1")) .thenReturn(request); when(controlMapper.selectByFileForUpdate(TENANT_ID, "new-request-1")) .thenReturn(null); when(controlMapper.insertControl(any())).thenReturn(1); when(newAuditMapper.updateEffectiveVersion(audit)).thenReturn(1); service.syncNewAuditFlow(FLOW_ID, TASK_ID, 2, DmsFlowEventType.END); ArgumentCaptor captor = ArgumentCaptor.forClass(DmsWenjianBanbenKongzhiEntity.class); verify(controlMapper).insertControl(captor.capture()); DmsWenjianBanbenKongzhiEntity control = captor.getValue(); assertEquals("new-request-1", control.getWenjianId()); assertEquals(0, control.getBanbenXuhao()); assertEquals(0L, control.getBiangengXuhao()); assertEquals("xinzeng", control.getZuihouShengxiaoLeixing()); assertEquals("D(00)", audit.getShengxiaoBanbenhao()); assertNotNull(audit.getBanbenShengxiaoShijian()); } @Test void upgradeRevisionAdvancesVersionAndChangeSequence() { DmsWenjianXiudingShenheEntity audit = revisionAudit(2, "shengji"); DmsWenjianXiudingShenqingEntity request = revisionRequest(2, 4L); DmsWenjianBanbenKongzhiEntity control = control(2, 4L); when(revisionAuditMapper.selectByFlowForUpdate(TENANT_ID, FLOW_ID, TASK_ID)) .thenReturn(Collections.singletonList(audit)); when(revisionRequestMapper.selectByIdForUpdate(TENANT_ID, "revision-request-1")) .thenReturn(request); when(controlMapper.selectByFileForUpdate(TENANT_ID, "file-1")).thenReturn(control); when(controlMapper.advance(any(), any(), any())).thenReturn(1); when(revisionAuditMapper.updateEffectiveVersion(audit)).thenReturn(1); service.syncRevisionAuditFlow(FLOW_ID, TASK_ID, 2, DmsFlowEventType.END); assertEquals(3, control.getBanbenXuhao()); assertEquals(5L, control.getBiangengXuhao()); assertEquals("D(03)", audit.getShengxiaoBanbenhao()); assertEquals(5L, audit.getShengxiaoBiangengXuhao()); verify(controlMapper).advance(control, 2, 4L); } @Test void unchangedRevisionKeepsVersionButAdvancesChangeSequence() { DmsWenjianXiudingShenheEntity audit = revisionAudit(2, "wubianhua"); DmsWenjianXiudingShenqingEntity request = revisionRequest(2, 4L); DmsWenjianBanbenKongzhiEntity control = control(2, 4L); when(revisionAuditMapper.selectByFlowForUpdate(TENANT_ID, FLOW_ID, TASK_ID)) .thenReturn(Collections.singletonList(audit)); when(revisionRequestMapper.selectByIdForUpdate(TENANT_ID, "revision-request-1")) .thenReturn(request); when(controlMapper.selectByFileForUpdate(TENANT_ID, "file-1")).thenReturn(control); when(controlMapper.advance(any(), any(), any())).thenReturn(1); when(revisionAuditMapper.updateEffectiveVersion(audit)).thenReturn(1); service.syncRevisionAuditFlow(FLOW_ID, TASK_ID, 2, DmsFlowEventType.END); assertEquals(2, control.getBanbenXuhao()); assertEquals(5L, control.getBiangengXuhao()); assertEquals("D(02)", audit.getShengxiaoBanbenhao()); } @Test void staleRevisionSnapshotIsRejectedBeforeAnyUpdate() { DmsWenjianXiudingShenheEntity audit = revisionAudit(2, "shengji"); DmsWenjianXiudingShenqingEntity request = revisionRequest(2, 3L); DmsWenjianBanbenKongzhiEntity control = control(2, 4L); when(revisionAuditMapper.selectByFlowForUpdate(TENANT_ID, FLOW_ID, TASK_ID)) .thenReturn(Collections.singletonList(audit)); when(revisionRequestMapper.selectByIdForUpdate(TENANT_ID, "revision-request-1")) .thenReturn(request); when(controlMapper.selectByFileForUpdate(TENANT_ID, "file-1")).thenReturn(control); DataException exception = assertThrows(DataException.class, () -> service.syncRevisionAuditFlow( FLOW_ID, TASK_ID, 2, DmsFlowEventType.END)); assertEquals("来源文件已有其他修订生效,请重新发起修订申请", exception.getMessage()); verify(controlMapper, never()).advance(any(), any(), any()); verify(revisionAuditMapper, never()).updateEffectiveVersion(any()); } @Test void repeatedRevisionEndIsIdempotentAfterLaterVersionsExist() { DmsWenjianXiudingShenheEntity audit = revisionAudit(2, "shengji"); audit.setShengxiaoBanbenXuhao(3); audit.setShengxiaoBanbenhao("D(03)"); audit.setShengxiaoBiangengXuhao(5L); audit.setBanbenShengxiaoShijian(new Date()); when(revisionAuditMapper.selectByFlowForUpdate(TENANT_ID, FLOW_ID, TASK_ID)) .thenReturn(Collections.singletonList(audit)); service.syncRevisionAuditFlow(FLOW_ID, TASK_ID, 2, DmsFlowEventType.END); verify(revisionRequestMapper, never()).selectByIdForUpdate(any(), any()); verify(controlMapper, never()).advance(any(), any(), any()); } private DmsWenjianXinzengShenheEntity newAudit(int state) { DmsWenjianXinzengShenheEntity audit = new DmsWenjianXinzengShenheEntity(); audit.setId("new-audit-1"); audit.setTenantId(TENANT_ID); audit.setFlowId(FLOW_ID); audit.setFlowTaskId(TASK_ID); audit.setFlowState(state); audit.setShenqingdanId("new-request-1"); return audit; } private DmsWenjianXinzengGuanliEntity newRequest() { DmsWenjianXinzengGuanliEntity request = new DmsWenjianXinzengGuanliEntity(); request.setId("new-request-1"); request.setTenantId(TENANT_ID); request.setFlowState(2); request.setXinxiuding("xinding"); request.setBanbenXuhao(0); request.setBanbenhao("D(00)"); return request; } private DmsWenjianXiudingShenheEntity revisionAudit(int state, String type) { DmsWenjianXiudingShenheEntity audit = new DmsWenjianXiudingShenheEntity(); audit.setId("revision-audit-1"); audit.setTenantId(TENANT_ID); audit.setFlowId(FLOW_ID); audit.setFlowTaskId(TASK_ID); audit.setFlowState(state); audit.setXiudingShenqingId("revision-request-1"); audit.setBiangengFangshi(type); return audit; } private DmsWenjianXiudingShenqingEntity revisionRequest(int version, long change) { DmsWenjianXiudingShenqingEntity request = new DmsWenjianXiudingShenqingEntity(); request.setId("revision-request-1"); request.setTenantId(TENANT_ID); request.setFlowState(2); request.setWenjianId("file-1"); request.setBanbenXuhao(version); request.setBanbenhao(DmsWenjianBanbenServiceImpl.formatVersion(version)); request.setYuanBiangengXuhao(change); return request; } private DmsWenjianBanbenKongzhiEntity control(int version, long change) { DmsWenjianBanbenKongzhiEntity control = new DmsWenjianBanbenKongzhiEntity(); control.setId("control-1"); control.setTenantId(TENANT_ID); control.setWenjianId("file-1"); control.setBanbenXuhao(version); control.setBiangengXuhao(change); control.setBizStatus("effective"); return control; } }