package jnpf.dmsService; import com.baomidou.mybatisplus.core.conditions.Wrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.core.metadata.TableInfoHelper; import jnpf.audit.sdk.annotation.AuditLog; import jnpf.base.ActionResult; import jnpf.base.ActionResultCode; import jnpf.base.UserInfo; import jnpf.dmsEntity.DmsWenjianFushenJihuaFenpeiZixiangEntity; import jnpf.dmsEntity.DmsWenjianFushenZhixingEntity; import jnpf.dmsEntity.DmsWenjianFushenZhixingZixiangEntity; import jnpf.dmsEntity.DmsWenjianZiyuanEntity; import jnpf.dmsEntity.form.DmsWenjianFushenZhixingBatchReturnForm; import jnpf.dmsEntity.storage.form.DmsFileExtendValidityForm; import jnpf.dmsMapper.DmsWenjianFushenJihuaFenpeiZixiangMapper; import jnpf.dmsMapper.DmsWenjianFushenZhixingMapper; import jnpf.dmsMapper.DmsWenjianFushenZhixingZixiangMapper; import jnpf.dmsMapper.DmsWenjianZiyuanMapper; import jnpf.dmsPermission.DmsCurrentIdentity; import jnpf.flowable.TaskApi; import jnpf.flowable.WorkFlowApi; import jnpf.flowable.entity.TemplateJsonEntity; import jnpf.flowable.model.task.AuditModel; import jnpf.flowable.model.task.FlowModel; import jnpf.dmsService.impl.DmsWenjianFushenZhixingServiceImpl; import jnpf.exception.DataException; import org.apache.ibatis.builder.MapperBuilderAssistant; import org.apache.ibatis.session.Configuration; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; import java.lang.reflect.Method; import java.util.Arrays; import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Map; import java.util.UUID; 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.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; class DmsWenjianFushenZhixingServiceTest { @BeforeEach void setUp() { if (TableInfoHelper.getTableInfo(DmsWenjianFushenJihuaFenpeiZixiangEntity.class) == null) { TableInfoHelper.initTableInfo(new MapperBuilderAssistant(new Configuration(), ""), DmsWenjianFushenJihuaFenpeiZixiangEntity.class); } initTableInfo(DmsWenjianFushenZhixingEntity.class); initTableInfo(DmsWenjianFushenZhixingZixiangEntity.class); initTableInfo(DmsWenjianZiyuanEntity.class); } @Test void declaresTheBatchReturnAuditEvent() throws NoSuchMethodException { Method method = DmsWenjianFushenZhixingServiceImpl.class.getMethod("batchReturn", List.class); AuditLog auditLog = method.getAnnotation(AuditLog.class); assertNotNull(auditLog); assertEquals("FILE_REVIEW_BATCH_RETURN", auditLog.action()); assertEquals("文件复审执行批量退回", auditLog.label()); assertEquals("DMS_FILE_REVIEW", auditLog.bizType()); assertEquals("wenjian_fushen_jihua_fenpei_zixiang", auditLog.targetTable()); assertEquals("#p0[0].fenpeiZixiangId", auditLog.targetIdExpr()); assertEquals("#p0.![fenpeiZixiangId]", auditLog.targetIdsExpr()); assertTrue(auditLog.diff()); assertEquals(DmsWenjianFushenJihuaFenpeiZixiangEntity.class, auditLog.entityClass()); } @Test void declaresTheExecutionWriteBackAuditEvent() throws NoSuchMethodException { Method method = DmsWenjianFushenZhixingServiceImpl.class.getMethod("writeBack", String.class); AuditLog auditLog = method.getAnnotation(AuditLog.class); assertNotNull(auditLog); assertEquals("FILE_REVIEW_EXECUTION_WRITE_BACK", auditLog.action()); assertEquals("文件复审执行结果回写", auditLog.label()); assertEquals("wenjian_fushen_zhixing", auditLog.targetTable()); assertEquals("#p0", auditLog.targetIdExpr()); } @Test void batchReturnsEveryRequestedDetailWithoutDeletingIt() throws Exception { DmsWenjianFushenJihuaFenpeiZixiangMapper mapper = mock( DmsWenjianFushenJihuaFenpeiZixiangMapper.class); when(mapper.update(isNull(), any())).thenReturn(2); service(mapper).batchReturn(Arrays.asList(item("detail-1"), item("detail-2"))); ArgumentCaptor> captor = ArgumentCaptor.forClass( Wrapper.class); verify(mapper).update(isNull(), captor.capture()); LambdaUpdateWrapper update = (LambdaUpdateWrapper) captor.getValue(); String sqlSet = update.getSqlSet(); assertTrue(sqlSet.contains("huigu_ren")); assertTrue(sqlSet.contains("fenpei_bumen_id")); assertTrue(sqlSet.contains("fenpei_bumen_fuzeren")); assertTrue(sqlSet.contains("fenpei_riqi")); assertTrue(sqlSet.contains("biz_status")); assertTrue(update.getExpression().getNormal().getSqlSegment().contains("f_id")); assertTrue(update.getExpression().getNormal().getSqlSegment().contains("f_delete_mark")); assertTrue(update.getParamNameValuePairs().containsValue("detail-1")); assertTrue(update.getParamNameValuePairs().containsValue("detail-2")); assertTrue(update.getParamNameValuePairs().containsValue("daifenpei")); } @Test void rejectsDuplicateDetailIdsBeforeUpdating() { DmsWenjianFushenJihuaFenpeiZixiangMapper mapper = mock( DmsWenjianFushenJihuaFenpeiZixiangMapper.class); DataException error = assertThrows(DataException.class, () -> service(mapper).batchReturn(Arrays.asList(item("detail-1"), item("detail-1")))); assertEquals("文件复审执行批量退回参数中不能包含重复fenpei_zixiang_id", error.getMessage()); verify(mapper, never()).update(any(), any()); } @Test void rejectsPartialUpdatesToKeepTheBatchAtomic() { DmsWenjianFushenJihuaFenpeiZixiangMapper mapper = mock( DmsWenjianFushenJihuaFenpeiZixiangMapper.class); when(mapper.update(isNull(), any())).thenReturn(1); DataException error = assertThrows(DataException.class, () -> service(mapper).batchReturn(Arrays.asList(item("detail-1"), item("detail-2")))); assertEquals("存在未找到或已退回的文件复审计划分配子项,无法批量退回", error.getMessage()); } @Test void writesBackTheExecutionDateAndEachDetailResultToItsAssignedDetail() throws Exception { DmsWenjianFushenJihuaFenpeiZixiangMapper fenpeiMapper = mock( DmsWenjianFushenJihuaFenpeiZixiangMapper.class); DmsWenjianFushenZhixingMapper zhixingMapper = mock(DmsWenjianFushenZhixingMapper.class); DmsWenjianFushenZhixingZixiangMapper zhixingZixiangMapper = mock( DmsWenjianFushenZhixingZixiangMapper.class); Date huiguRiqi = new Date(); when(zhixingMapper.selectOne(any())).thenReturn(zhixing("execution-1", huiguRiqi)); when(zhixingZixiangMapper.selectList(any())).thenReturn(Arrays.asList( zhixingZixiangWithResult("execution-detail-1", "assigned-detail-1", "总结一", "结论一"), zhixingZixiangWithResult("execution-detail-2", "assigned-detail-2", "总结二", "结论二"))); when(fenpeiMapper.update(isNull(), any())).thenReturn(1); service(fenpeiMapper, zhixingMapper, zhixingZixiangMapper) .writeBack("execution-1"); ArgumentCaptor> captor = ArgumentCaptor.forClass( Wrapper.class); verify(fenpeiMapper, org.mockito.Mockito.times(2)).update(isNull(), captor.capture()); List> updates = captor.getAllValues(); LambdaUpdateWrapper first = (LambdaUpdateWrapper) updates.get(0); LambdaUpdateWrapper second = (LambdaUpdateWrapper) updates.get(1); assertWriteBackUpdate(first, "assigned-detail-1", huiguRiqi, "总结一", "结论一"); assertWriteBackUpdate(second, "assigned-detail-2", huiguRiqi, "总结二", "结论二"); } @Test void rejectsAnExecutionDetailWithoutAnAssignedDetailId() { DmsWenjianFushenJihuaFenpeiZixiangMapper fenpeiMapper = mock( DmsWenjianFushenJihuaFenpeiZixiangMapper.class); DmsWenjianFushenZhixingMapper zhixingMapper = mock(DmsWenjianFushenZhixingMapper.class); DmsWenjianFushenZhixingZixiangMapper zhixingZixiangMapper = mock( DmsWenjianFushenZhixingZixiangMapper.class); when(zhixingMapper.selectOne(any())).thenReturn(zhixing("execution-1", new Date())); when(zhixingZixiangMapper.selectList(any())).thenReturn(Arrays.asList( zhixingZixiangWithResult("execution-detail-1", " ", "总结", "结论"))); DataException error = assertThrows(DataException.class, () -> service(fenpeiMapper, zhixingMapper, zhixingZixiangMapper) .writeBack("execution-1")); assertEquals("文件复审执行子项fenpei_zixiang_id不能为空", error.getMessage()); verify(fenpeiMapper, never()).update(any(), any()); } @Test void rejectsWhenAnAssignedDetailCannotBeUpdated() { DmsWenjianFushenJihuaFenpeiZixiangMapper fenpeiMapper = mock( DmsWenjianFushenJihuaFenpeiZixiangMapper.class); DmsWenjianFushenZhixingMapper zhixingMapper = mock(DmsWenjianFushenZhixingMapper.class); DmsWenjianFushenZhixingZixiangMapper zhixingZixiangMapper = mock( DmsWenjianFushenZhixingZixiangMapper.class); when(zhixingMapper.selectOne(any())).thenReturn(zhixing("execution-1", new Date())); when(zhixingZixiangMapper.selectList(any())).thenReturn(Arrays.asList( zhixingZixiangWithResult("execution-detail-1", "assigned-detail-1", "总结", "结论"))); when(fenpeiMapper.update(isNull(), any())).thenReturn(0); DataException error = assertThrows(DataException.class, () -> service(fenpeiMapper, zhixingMapper, zhixingZixiangMapper) .writeBack("execution-1")); assertEquals("未找到可回写的文件复审计划分配子项:f_id=assigned-detail-1", error.getMessage()); } @Test void processesEverySupportedConclusionGroupAfterWritingBack() throws Exception { DmsWenjianFushenJihuaFenpeiZixiangMapper fenpeiMapper = mock( DmsWenjianFushenJihuaFenpeiZixiangMapper.class); DmsWenjianFushenZhixingMapper zhixingMapper = mock(DmsWenjianFushenZhixingMapper.class); DmsWenjianFushenZhixingZixiangMapper zhixingZixiangMapper = mock( DmsWenjianFushenZhixingZixiangMapper.class); DmsWenjianZiyuanMapper ziyuanMapper = mock(DmsWenjianZiyuanMapper.class); DmsFileValidityService validityService = mock(DmsFileValidityService.class); DmsCurrentIdentity identity = mock(DmsCurrentIdentity.class); TaskApi taskApi = mock(TaskApi.class); WorkFlowApi workFlowApi = mock(WorkFlowApi.class); UserInfo user = new UserInfo(); user.setUserId("user-1"); user.setTenantId("tenant-1"); user.setOrganizeId("organization-1"); Date currentExpiry = new Date(); when(zhixingMapper.selectOne(any())).thenReturn(zhixing("execution-1", new Date())); when(zhixingZixiangMapper.selectList(any())).thenReturn(Arrays.asList( zhixingZixiang("execution-detail-1", "assigned-detail-1", "file-1", "keyanyong"), zhixingZixiang("execution-detail-2", "assigned-detail-2", "file-2", "xuxiuding"), zhixingZixiang("execution-detail-3", "assigned-detail-3", "file-3", "xuchexiao"))); when(fenpeiMapper.update(isNull(), any())).thenReturn(1); when(ziyuanMapper.selectByTenantAndId("tenant-1", "file-1")) .thenReturn(resource("file-1", currentExpiry, "018f0000-0000-7000-8000-000000000801")); when(ziyuanMapper.selectByTenantAndId("tenant-1", "file-2")) .thenReturn(resource("file-2", currentExpiry, "018f0000-0000-7000-8000-000000000802")); when(ziyuanMapper.selectByTenantAndId("tenant-1", "file-3")) .thenReturn(resource("file-3", currentExpiry, "018f0000-0000-7000-8000-000000000803")); when(ziyuanMapper.updateReviewExecutionExtension(any(), any(), any(), any(), any())).thenReturn(1); when(identity.requireUser()).thenReturn(user); when(identity.tenantId(user)).thenReturn("tenant-1"); when(workFlowApi.getFlowIdsByTemplate(any())).thenReturn(Arrays.asList(activeVersion("flow-version-1"))); ActionResult draftSuccess = mock(ActionResult.class); when(draftSuccess.getCode()).thenReturn(ActionResultCode.SUCCESS.getCode()); when(taskApi.saveDraft(any())).thenReturn(draftSuccess); service(fenpeiMapper, zhixingMapper, zhixingZixiangMapper, ziyuanMapper, validityService, identity, taskApi, workFlowApi).writeBack("execution-1"); ArgumentCaptor validityCaptor = ArgumentCaptor.forClass( DmsFileExtendValidityForm.class); verify(validityService).extendValidity(validityCaptor.capture()); DmsFileExtendValidityForm validityForm = validityCaptor.getValue(); assertEquals("", validityForm.getSourceId()); assertEquals("", validityForm.getTaskId()); assertEquals(1, validityForm.getFiles().size()); assertEquals(UUID.fromString("018f0000-0000-7000-8000-000000000801"), validityForm.getFiles().get(0).getFileVersionId()); verify(ziyuanMapper).updateReviewExecutionExtension( org.mockito.Mockito.eq("tenant-1"), org.mockito.Mockito.eq("file-1"), any(Date.class), org.mockito.Mockito.eq("execution-1"), any(String.class)); ArgumentCaptor draftCaptor = ArgumentCaptor.forClass(FlowModel.class); verify(taskApi, org.mockito.Mockito.times(2)).saveDraft(draftCaptor.capture()); List drafts = draftCaptor.getAllValues(); assertEquals(0, drafts.get(0).getStatus().intValue()); assertEquals(1, drafts.get(0).getIsFlow().intValue()); assertEquals("flow-version-1", drafts.get(0).getFlowId()); List> revisionDetails = (List>) drafts.get(0).getFormData() .get("xiuding_shenqing_zixiang"); assertEquals(1, revisionDetails.size()); assertEquals(Collections.singletonList("wenjian"), revisionDetails.get(0).get("biangeng_neirong")); List revokeDetails=(List) drafts.get(1).getFormData().get("chexiao_wenjian_mingxi"); assertEquals(1,revokeDetails.size()); Map revoke=(Map)revokeDetails.get(0); assertEquals("file-3",revoke.get("wenjian_id")); assertEquals("business-version-file-3",revoke.get("wenjian_banben_id")); assertEquals("current-version",revoke.get("banben_hao")); } private DmsWenjianFushenZhixingService service(DmsWenjianFushenJihuaFenpeiZixiangMapper mapper) { return service(mapper, mock(DmsWenjianFushenZhixingMapper.class), mock(DmsWenjianFushenZhixingZixiangMapper.class)); } private DmsWenjianFushenZhixingService service(DmsWenjianFushenJihuaFenpeiZixiangMapper fenpeiMapper, DmsWenjianFushenZhixingMapper zhixingMapper, DmsWenjianFushenZhixingZixiangMapper zhixingZixiangMapper) { return service(fenpeiMapper, zhixingMapper, zhixingZixiangMapper, mock(DmsWenjianZiyuanMapper.class), mock(DmsFileValidityService.class), mock(DmsCurrentIdentity.class), mock(TaskApi.class), mock(WorkFlowApi.class)); } private DmsWenjianFushenZhixingService service(DmsWenjianFushenJihuaFenpeiZixiangMapper fenpeiMapper, DmsWenjianFushenZhixingMapper zhixingMapper, DmsWenjianFushenZhixingZixiangMapper zhixingZixiangMapper, DmsWenjianZiyuanMapper ziyuanMapper, DmsFileValidityService validityService, DmsCurrentIdentity identity, TaskApi taskApi, WorkFlowApi workFlowApi) { return new DmsWenjianFushenZhixingServiceImpl(fenpeiMapper, zhixingMapper, zhixingZixiangMapper, ziyuanMapper, validityService, identity, taskApi, workFlowApi); } private DmsWenjianFushenZhixingBatchReturnForm item(String id) { DmsWenjianFushenZhixingBatchReturnForm form = new DmsWenjianFushenZhixingBatchReturnForm(); form.setFenpeiZixiangId(id); return form; } private DmsWenjianFushenZhixingEntity zhixing(String id, Date huiguRiqi) { DmsWenjianFushenZhixingEntity result = new DmsWenjianFushenZhixingEntity(); result.setId(id); result.setHuiguRiqi(huiguRiqi); return result; } private DmsWenjianFushenZhixingZixiangEntity zhixingZixiangWithResult(String id, String fenpeiZixiangId, String huiguNeirongZongjie, String zuizhongJielun) { DmsWenjianFushenZhixingZixiangEntity result = new DmsWenjianFushenZhixingZixiangEntity(); result.setId(id); result.setFenpeiZixiangId(fenpeiZixiangId); result.setHuiguNeirongZongjie(huiguNeirongZongjie); result.setZuizhongJielun(zuizhongJielun); return result; } private DmsWenjianFushenZhixingZixiangEntity zhixingZixiang(String id, String fenpeiZixiangId, String wenjianId, String conclusion) { DmsWenjianFushenZhixingZixiangEntity result = zhixingZixiangWithResult( id, fenpeiZixiangId, "总结", conclusion); result.setWenjianId(wenjianId); result.setWenjianBianhao("编号-" + wenjianId); result.setWenjianMingcheng("名称-" + wenjianId); result.setBanbenhao("D(01)"); return result; } private DmsWenjianZiyuanEntity resource(String id, Date expiry, String fileVersionId) { DmsWenjianZiyuanEntity result = new DmsWenjianZiyuanEntity(); result.setId(id); result.setYouxiaoQiZhi(expiry); result.setWenjianZhongxinBanbenId(fileVersionId); result.setWenjianBianhao("编号-" + id); result.setWenjianMingcheng("名称-" + id); result.setDangqianBanbenId("business-version-" + id); result.setDangqianBanbenhao("current-version"); return result; } private TemplateJsonEntity activeVersion(String id) { TemplateJsonEntity result = new TemplateJsonEntity(); result.setId(id); result.setState(1); return result; } private void assertWriteBackUpdate(LambdaUpdateWrapper update, String fenpeiZixiangId, Date huiguRiqi, String huiguNeirongZongjie, String zuizhongJielun) { String sqlSet = update.getSqlSet(); assertTrue(sqlSet.contains("huigu_riqi")); assertTrue(sqlSet.contains("huigu_neirong_zongjie")); assertTrue(sqlSet.contains("zuizhong_jielun")); assertTrue(sqlSet.contains("biz_status")); assertTrue(update.getExpression().getNormal().getSqlSegment().contains("f_id")); assertTrue(update.getExpression().getNormal().getSqlSegment().contains("f_delete_mark")); assertTrue(update.getParamNameValuePairs().containsValue(fenpeiZixiangId)); assertTrue(update.getParamNameValuePairs().containsValue(huiguRiqi)); assertTrue(update.getParamNameValuePairs().containsValue(huiguNeirongZongjie)); assertTrue(update.getParamNameValuePairs().containsValue(zuizhongJielun)); assertTrue(update.getParamNameValuePairs().containsValue("yiwancheng")); } private void initTableInfo(Class entityClass) { if (TableInfoHelper.getTableInfo(entityClass) == null) { TableInfoHelper.initTableInfo(new MapperBuilderAssistant(new Configuration(), ""), entityClass); } } }