package jnpf.dmsIntegration.audit; import com.alibaba.fastjson.JSON; import jnpf.audit.model.AuditEventDTO; import jnpf.audit.model.AuditRelatedSignDTO; import jnpf.audit.sdk.AuditClient; import jnpf.dmsEntity.fenfa.DmsWenjianDayinJiluEntity; import jnpf.dmsEntity.fenfa.DmsWenjianDayinRenwuEntity; import jnpf.dmsEntity.fenfa.DmsWenjianFenfaRenwuEntity; import jnpf.dmsEntity.fenfa.DmsWenjianHuishouMingxiEntity; import jnpf.dmsEntity.permission.entity.DmsFilePermissionEntity; import jnpf.util.JsonUtil; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; import org.springframework.beans.factory.ObjectProvider; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.UUID; import java.util.function.Consumer; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; class DmsAuditAdapterTest { @Test @SuppressWarnings("unchecked") void partialPrintAuditsActualFirstMiddleAndFinalStatus() { for (String[] transition : new String[][]{{"daidayin", "bufendayin"}, {"bufendayin", "bufendayin"}, {"bufendayin", "yidayin"}}) { ObjectProvider provider = mock(ObjectProvider.class); AuditClient client = mock(AuditClient.class); doAnswer(invocation -> { ((Consumer) invocation.getArgument(0)).accept(client); return null; }).when(provider).ifAvailable(any()); DmsWenjianDayinRenwuEntity task = printTask("task", "DOC"); task.setBizStatus(transition[0]); new DmsAuditAdapter(provider).print(DmsWenjianDayinAuditEvent.builder() .tasks(List.of(task)).afterStatuses(Map.of("task", transition[1])) .records(List.of(printRecord("record", "task", "serial", 1))) .distributionTasks(List.of()).build()); ArgumentCaptor captor = ArgumentCaptor.forClass(AuditEventDTO.class); verify(client).record(captor.capture()); List diffs = JSON.parseArray(captor.getValue().getFieldDiffs(), Map.class); List states = diffs.stream().filter(d -> "biz_status".equals(d.get("field")) && "dms_wenjian_dayin_renwu".equals(d.get("targetTable"))).toList(); assertEquals(transition[0].equals(transition[1]) ? 0 : 1, states.size()); if (!states.isEmpty()) { assertEquals("bufendayin".equals(transition[0]) ? "部分打印" : "待打印", states.get(0).get("oldDisplay")); assertEquals("bufendayin".equals(transition[1]) ? "部分打印" : "已打印", states.get(0).get("newDisplay")); } } } @Test @SuppressWarnings("unchecked") void archiveCompletionAuditsEveryCopyWithoutLeakingSignaturesIntoSnapshot() { ObjectProvider provider = mock(ObjectProvider.class); AuditClient client = mock(AuditClient.class); doAnswer(invocation -> { Consumer consumer = invocation.getArgument(0); consumer.accept(client); return null; }).when(provider).ifAvailable(any()); new DmsAuditAdapter(provider).archiveStatus(Arrays.asList("copy-1", "copy-2"), "daiguidang", "yiguidang", java.util.Collections.singletonMap("biz_sign", "archive-sign")); ArgumentCaptor captor = ArgumentCaptor.forClass(AuditEventDTO.class); verify(client).record(captor.capture()); AuditEventDTO event = captor.getValue(); assertEquals("FILE_ARCHIVE_COMPLETE", event.getActionCode()); assertEquals("dms_wenjian_dayin_jilu", event.getTargetTable()); assertTrue(event.getFieldDiffs().contains("copy-1")); assertTrue(event.getFieldDiffs().contains("copy-2")); assertTrue(event.getDataSnapshot().contains("daiguidang")); assertTrue(event.getDataSnapshot().contains("yiguidang")); assertTrue(!event.getDataSnapshot().contains("archive-sign")); assertTrue(!event.getFieldDiffs().contains("archive-sign")); assertEquals(1, event.getRelatedSigns().size()); } @Test @SuppressWarnings("unchecked") void buildsOneBatchPrintEventWithAllTasksAndGeneratedRecords() { ObjectProvider provider = mock(ObjectProvider.class); AuditClient client = mock(AuditClient.class); doAnswer(invocation -> { Consumer consumer = invocation.getArgument(0); consumer.accept(client); return null; }).when(provider).ifAvailable(any()); DmsAuditAdapter adapter = new DmsAuditAdapter(provider); DmsWenjianDayinRenwuEntity first = printTask("task-1", "QC-SOP-001"); DmsWenjianDayinRenwuEntity second = printTask("task-2", "QC-SOP-002"); DmsWenjianDayinJiluEntity firstRecord = printRecord( "record-1", "task-1", "serial-1", 1); DmsWenjianDayinJiluEntity secondRecord = printRecord( "record-2", "task-2", "serial-2", 1); DmsWenjianFenfaRenwuEntity firstDistribution = distributionTask( "distribution-1", "task-1", "FF-1"); DmsWenjianFenfaRenwuEntity secondDistribution = distributionTask( "distribution-2", "task-2", "FF-2"); adapter.print(DmsWenjianDayinAuditEvent.builder() .afterStatuses(Map.of("task-1", "yidayin", "task-2", "yidayin")) .tasks(Arrays.asList(first, second)) .records(Arrays.asList(firstRecord, secondRecord)) .distributionTasks(Arrays.asList(firstDistribution, secondDistribution)) .build()); ArgumentCaptor captor = ArgumentCaptor.forClass(AuditEventDTO.class); verify(client).record(captor.capture()); AuditEventDTO event = captor.getValue(); assertEquals("PRINT", event.getEventType()); assertEquals("PRINT", event.getActionCode()); assertEquals("发起打印", event.getActionLabel()); assertEquals("DMS_FILE_PRINT", event.getBizType()); assertEquals("dms_wenjian_dayin_renwu", event.getTargetTable()); assertEquals(null, event.getTargetId()); assertEquals(null, event.getBizCode()); assertTrue(event.getClientEventId().matches("PRINT-[0-9a-f]{32}")); assertEquals(event.getClientEventId(), event.getOperationId()); assertTrue(event.getRecordTitle().contains("批量打印 2 个任务,共 2 份")); List diffs = JSON.parseArray(event.getFieldDiffs(), Map.class); assertTrue(diffs.stream().anyMatch(item -> "dms_wenjian_dayin_renwu".equals(item.get("targetTable")) && "biz_status".equals(item.get("field")) && "待打印".equals(item.get("oldDisplay")) && "已打印".equals(item.get("newDisplay")))); assertTrue(diffs.stream().anyMatch(item -> "dms_wenjian_dayin_jilu".equals(item.get("targetTable")) && "dayin_liushuihao".equals(item.get("field")))); assertTrue(diffs.stream().anyMatch(item -> "dms_wenjian_fenfa_renwu".equals(item.get("targetTable")) && "fenfa_bianhao".equals(item.get("field")))); Map extra = JsonUtil.stringToMap(event.getExtra()); assertEquals("LIST_PRINT", extra.get("source")); assertEquals("BATCH", extra.get("printMode")); assertEquals(2, ((Number) extra.get("printCount")).intValue()); assertEquals(2, ((Number) extra.get("totalCopies")).intValue()); List> targets = (List>) extra.get("printTargets"); assertEquals(2, targets.size()); assertEquals("task-1", targets.get(0).get("id")); assertEquals("serial-1", ((List) targets.get(0).get("serialNumbers")).get(0)); } @Test @SuppressWarnings("unchecked") void buildsOneRecycleEventWithMainDetailAndPrintStatusChanges() { ObjectProvider provider = mock(ObjectProvider.class); AuditClient client = mock(AuditClient.class); doAnswer(invocation -> { Consumer consumer = invocation.getArgument(0); consumer.accept(client); return null; }).when(provider).ifAvailable(any()); DmsAuditAdapter adapter = new DmsAuditAdapter(provider); adapter.recycle(DmsWenjianHuishouAuditEvent.builder() .beforeStatuses(java.util.Map.of("print-1", "daihuishou", "print-2", "daifafang")) .huishouDanjuId("2030000000000000001") .beizhuShuoming("包装完整") .huishouRenId("user-1") .huishouShijian(new java.util.Date()) .details(Arrays.asList( recycleDetail("2030000000000000011", "print-1", "serial-1"), recycleDetail("2030000000000000012", "print-2", "serial-2"))) .relatedSigns(Arrays.asList(new AuditRelatedSignDTO("sign-1", "PRIMARY"))) .build()); ArgumentCaptor captor = ArgumentCaptor.forClass(AuditEventDTO.class); verify(client).record(captor.capture()); AuditEventDTO event = captor.getValue(); assertEquals("DATA_CHANGE", event.getEventType()); assertEquals("FILE_RECYCLE", event.getActionCode()); assertEquals("DMS", event.getBizModule()); assertEquals("DMS_FILE_RECYCLE", event.getBizType()); assertEquals("dms_wenjian_huishou", event.getTargetTable()); assertEquals("2030000000000000001", event.getTargetId()); assertEquals("API", event.getEntryType()); assertEquals("文件扫码回收", event.getEntryName()); assertEquals("包装完整", event.getReason()); assertEquals("sign-1", event.getRelatedSigns().get(0).getSignId()); assertTrue(event.getRecordTitle().contains("共 2 份")); List diffs = JSON.parseArray(event.getFieldDiffs(), Map.class); assertTrue(diffs.stream().anyMatch(item -> "dms_wenjian_huishou".equals(item.get("targetTable")))); assertTrue(diffs.stream().anyMatch(item -> "dms_wenjian_huishou_zixiang".equals(item.get("targetTable")))); assertTrue(diffs.stream().anyMatch(item -> "dms_wenjian_dayin_jilu".equals(item.get("targetTable")) && "biz_status".equals(item.get("field")) && "待回收".equals(item.get("oldDisplay")) && "待销毁".equals(item.get("newDisplay")))); Map snapshot = JsonUtil.stringToMap(event.getDataSnapshot()); assertEquals(2, ((Number) snapshot.get("huishouFenshu")).intValue()); assertEquals("user-1", snapshot.get("huishouRenId")); List> targets = (List>) snapshot.get("huishouMingxi"); assertEquals("daihuishou", targets.get(0).get("oldStatus")); assertEquals("daifafang", targets.get(1).get("oldStatus")); assertTrue(!event.getDataSnapshot().contains("biz_sign")); assertTrue(!event.getFieldDiffs().contains("biz_sign")); Map extra = JsonUtil.stringToMap(event.getExtra()); assertEquals(2, ((Number) extra.get("batchSize")).intValue()); assertEquals(2, ((List) extra.get("affectedTargets")).size()); } @Test @SuppressWarnings("unchecked") void buildsOneBatchPermissionEventWithFirstTargetAndAffectedDetails() { ObjectProvider provider = mock(ObjectProvider.class); ObjectProvider displayProvider = mock(ObjectProvider.class); AuditClient client = mock(AuditClient.class); DmsPermissionAuditDisplayResolver displayResolver = mock(DmsPermissionAuditDisplayResolver.class); doAnswer(invocation -> { Consumer consumer = invocation.getArgument(0); consumer.accept(client); return null; }).when(provider).ifAvailable(any()); UUID folderId = UUID.fromString("018f0000-0000-7000-8000-000000000801"); UUID documentId = UUID.fromString("018f0000-0000-7000-8000-000000000802"); DmsFilePermissionEntity first = permission(UUID.fromString( "018f0000-0000-7000-8000-000000000803"), "FOLDER", folderId, "ORG", "dept-1", "READ"); DmsFilePermissionEntity second = permission(UUID.fromString( "018f0000-0000-7000-8000-000000000804"), "DOCUMENT", documentId, "USER", "user-2", "UPDATE"); DmsFilePermissionEntity third = permission(UUID.fromString( "018f0000-0000-7000-8000-000000000805"), "FOLDER", folderId, "ORG", "dept-1", "DELETE"); DmsPermissionAuditDisplayResolver.DisplayValues displays = new DmsPermissionAuditDisplayResolver.DisplayValues() .addResource("FOLDER", folderId, "质量管理") .addResource("DOCUMENT", documentId, "[MM-R02] 质量手册") .addPrincipal("ORG", "dept-1", "质量部") .addUser("user-2", "李四(lisi)") .addUser("admin-1", "管理员(admin)"); when(displayProvider.getIfAvailable()).thenReturn(displayResolver); when(displayResolver.resolvePermissions("tenant-1", Arrays.asList(first, second, third))) .thenReturn(displays); DmsAuditAdapter adapter = new DmsAuditAdapter(provider, displayProvider); adapter.permissionChange("PERMISSION_GRANT", "授予 DMS 资源权限", java.util.Collections.emptyList(), Arrays.asList(first, second, third), java.util.Collections.singletonList(new AuditRelatedSignDTO("sign-1", null))); ArgumentCaptor captor = ArgumentCaptor.forClass(AuditEventDTO.class); verify(client).record(captor.capture()); AuditEventDTO event = captor.getValue(); assertEquals("DMS", event.getBizModule()); assertEquals("DMS_PERMISSION", event.getBizType()); assertEquals("dms_folders", event.getTargetTable()); assertEquals(folderId.toString(), event.getTargetId()); assertEquals(folderId.toString(), event.getBizCode()); assertTrue(event.getRecordTitle().contains("查看、修改、删除")); assertTrue(event.getRecordTitle().contains("共 3 条")); assertEquals(1, event.getRelatedSigns().size()); List diffs = JSON.parseArray(event.getFieldDiffs(), Map.class); assertTrue(diffs.stream().allMatch(item -> "dms_file_permissions".equals(item.get("targetTable")))); assertTrue(diffs.stream().anyMatch(item -> "resource_id".equals(item.get("field")) && "质量管理".equals(item.get("newDisplay")))); assertTrue(diffs.stream().anyMatch(item -> "action_code".equals(item.get("field")) && "READ,UPDATE,DELETE".equals(item.get("newData")) && "查看、修改、删除".equals(item.get("newDisplay")))); Map snapshot = JsonUtil.stringToMap(event.getDataSnapshot()); assertEquals("READ,UPDATE,DELETE", snapshot.get("actionCode")); assertEquals("查看、修改、删除", snapshot.get("actionName")); Map extra = JsonUtil.stringToMap(event.getExtra()); assertEquals(3, ((Number) extra.get("batchSize")).intValue()); assertEquals(Arrays.asList("READ", "UPDATE", "DELETE"), extra.get("actionCodes")); assertEquals(Arrays.asList("查看", "修改", "删除"), extra.get("actionNames")); List> targets = (List>) extra.get("affectedTargets"); assertEquals(3, targets.size()); assertEquals(folderId.toString(), targets.get(0).get("resourceId")); assertEquals(documentId.toString(), targets.get(1).get("resourceId")); assertEquals("李四(lisi)", targets.get(1).get("principalName")); assertTrue(((List) targets.get(1).get("changes")).size() > 1); } @Test @SuppressWarnings("unchecked") void buildsOneScopedFileRevisionEventWithoutStorageLocations() { ObjectProvider provider = mock(ObjectProvider.class); AuditClient client = mock(AuditClient.class); doAnswer(invocation -> { Consumer consumer = invocation.getArgument(0); consumer.accept(client); return null; }).when(provider).ifAvailable(any()); DmsAuditAdapter adapter = new DmsAuditAdapter(provider); UUID documentId = UUID.fromString("018f0000-0000-7000-8000-000000000701"); UUID oldVersionId = UUID.fromString("018f0000-0000-7000-8000-000000000702"); UUID newVersionId = UUID.fromString("018f0000-0000-7000-8000-000000000703"); DmsFileVersionAuditSnapshot oldVersion = version(oldVersionId, 1L, "D(00)", "EFFECTIVE"); DmsFileVersionAuditSnapshot newVersion = version(newVersionId, 2L, "D(01)", "EFFECTIVE"); adapter.fileChange(DmsFileAuditEvent.builder() .documentId(documentId) .actionCode("UPDATE") .actionLabel("修订 DMS 文件") .before(fileSnapshot(documentId, oldVersion)) .after(fileSnapshot(documentId, newVersion)) .previousVersionAfter(version(oldVersionId, 1L, "D(00)", "SUPERSEDED")) .reason("更新质量职责") .sourceServiceId("jnpf-file") .sourceId("revision-1") .relatedSigns(Arrays.asList(new AuditRelatedSignDTO("sign-1", null))) .build()); ArgumentCaptor captor = ArgumentCaptor.forClass(AuditEventDTO.class); verify(client).record(captor.capture()); AuditEventDTO event = captor.getValue(); assertEquals("DMS", event.getBizModule()); assertEquals("DMS_FILE", event.getBizType()); assertEquals("dms_documents", event.getTargetTable()); assertEquals(documentId.toString(), event.getTargetId()); assertEquals("MM-R02", event.getBizCode()); assertEquals("更新质量职责", event.getReason()); assertEquals("MENU", event.getEntryType()); assertEquals(1, event.getRelatedSigns().size()); assertTrue(event.getRecordTitle().contains("D(00) -> D(01)")); List diffs = JSON.parseArray(event.getFieldDiffs(), Map.class); assertTrue(diffs.stream().allMatch(item -> item.get("targetTable") != null && item.get("targetId") != null)); assertTrue(diffs.stream().anyMatch(item -> "dms_file_versions".equals(item.get("targetTable")) && newVersionId.toString().equals(item.get("targetId")))); assertTrue(diffs.stream().anyMatch(item -> "dms_version_states".equals(item.get("targetTable")) && oldVersionId.toString().equals(item.get("targetId")))); assertTrue(diffs.stream().anyMatch(item -> "lifecycle_status".equals(item.get("field")) && "生效".equals(item.get("oldDisplay")) && "已替代".equals(item.get("newDisplay")))); assertTrue(!event.getDataSnapshot().contains("objectPath")); assertTrue(!event.getDataSnapshot().contains("bucketName")); assertTrue(!event.getFieldDiffs().contains("biz_sign")); } @Test @SuppressWarnings("unchecked") void buildsStructuredFolderMoveWithRelatedSignatures() { ObjectProvider provider = mock(ObjectProvider.class); AuditClient client = mock(AuditClient.class); doAnswer(invocation -> { Consumer consumer = invocation.getArgument(0); consumer.accept(client); return null; }).when(provider).ifAvailable(any()); DmsAuditAdapter adapter = new DmsAuditAdapter(provider); UUID folderId = UUID.fromString("018f0000-0000-7000-8000-000000000601"); UUID oldParent = UUID.fromString("018f0000-0000-7000-8000-000000000602"); UUID newParent = UUID.fromString("018f0000-0000-7000-8000-000000000603"); adapter.folderChange(DmsFolderAuditEvent.builder() .folderId(folderId) .actionCode("UPDATE") .actionLabel("移动 DMS 文件夹") .before(snapshot(folderId, oldParent, 4L, "/受控文件/报告")) .after(snapshot(folderId, newParent, 5L, "/质量管理/报告")) .requestRevision(4L) .relatedSigns(Arrays.asList( new AuditRelatedSignDTO("sign-1", "PRIMARY"), new AuditRelatedSignDTO("sign-2", "REVIEW"))) .entryType("MENU") .entryId("dms-folder-management") .entryName("DMS 文件夹管理") .build()); ArgumentCaptor captor = ArgumentCaptor.forClass(AuditEventDTO.class); verify(client).record(captor.capture()); AuditEventDTO event = captor.getValue(); assertEquals("DMS", event.getBizModule()); assertEquals("DMS_FOLDER", event.getBizType()); assertEquals("dms_folders", event.getTargetTable()); assertEquals(folderId.toString(), event.getBizCode()); assertEquals("/质量管理/报告", event.getRecordTitle()); assertEquals(2, event.getRelatedSigns().size()); assertTrue(event.getFieldDiffs().contains("parent_id")); assertTrue(event.getFieldDiffs().contains(oldParent.toString())); assertTrue(event.getFieldDiffs().contains(newParent.toString())); Map extra = JsonUtil.stringToMap(event.getExtra()); assertEquals("/受控文件/报告", extra.get("oldPath")); assertEquals("/质量管理/报告", extra.get("newPath")); assertEquals("受控文件", extra.get("oldParentName")); assertEquals("质量管理", extra.get("newParentName")); Map snapshot = JsonUtil.stringToMap(event.getDataSnapshot()); assertEquals(Long.valueOf(5L), Long.valueOf(String.valueOf(snapshot.get("revision")))); assertEquals("报告", snapshot.get("name")); assertEquals("质量管理", snapshot.get("parentName")); } private DmsFolderAuditSnapshot snapshot(UUID id, UUID parentId, long revision, String path) { return DmsFolderAuditSnapshot.builder() .id(id) .parentId(parentId) .name("报告") .parentName(path.contains("受控文件") ? "受控文件" : "质量管理") .revision(revision) .path(path) .build(); } private DmsWenjianHuishouMingxiEntity recycleDetail( String id, String printRecordId, String serialNumber) { DmsWenjianHuishouMingxiEntity detail = new DmsWenjianHuishouMingxiEntity(); detail.setId(id); detail.setForeignId("2030000000000000001"); detail.setDayinJiluId(printRecordId); detail.setDayinLiushuihao(serialNumber); detail.setWenjianBianhao("QC-SOP-01001"); detail.setWenjianMingcheng("质量管理规程"); detail.setBanbenhao("D(01)"); detail.setQianshouBumen("质量部"); detail.setQianshouRen("张三"); detail.setQianshouShijian(new java.util.Date()); detail.setHuishouRenId("user-1"); detail.setHuishouShijian(new java.util.Date()); return detail; } private DmsWenjianDayinRenwuEntity printTask(String id, String documentNumber) { DmsWenjianDayinRenwuEntity task = new DmsWenjianDayinRenwuEntity(); task.setId(id); task.setWenjianId("file-" + id); task.setWenjianBianhao(documentNumber); task.setWenjianMingcheng("质量管理规程"); task.setBanbenhao("D(01)"); task.setDayinFenshu(1); task.setBizStatus("daidayin"); return task; } private DmsWenjianDayinJiluEntity printRecord( String id, String taskId, String serialNumber, int sequence) { DmsWenjianDayinJiluEntity record = new DmsWenjianDayinJiluEntity(); record.setId(id); record.setDayinRenwuId(taskId); record.setDayinXuhao(sequence); record.setDayinLiushuihao(serialNumber); record.setDayinRenId("user-1"); record.setDayinBumenId("org-1"); record.setDayinShijian(new java.util.Date()); record.setBizStatus("daifafang"); return record; } private DmsWenjianFenfaRenwuEntity distributionTask( String id, String taskId, String number) { DmsWenjianFenfaRenwuEntity task = new DmsWenjianFenfaRenwuEntity(); task.setId(id); task.setDayinRenwuId(taskId); task.setFenfaBianhao(number); task.setFafangLeixing("zidongfenfa"); task.setBizStatus("daifafang"); return task; } private DmsFileAuditSnapshot fileSnapshot(UUID documentId, DmsFileVersionAuditSnapshot version) { return DmsFileAuditSnapshot.builder() .documentId(documentId) .documentNo("MM-R02") .documentName("质量手册.docx") .documentType("QUALITY_MANUAL") .folderId(UUID.fromString("018f0000-0000-7000-8000-000000000704")) .folderPath("/质量体系/受控文件") .responsibleDeptId("dept-quality") .currentVersion(version) .build(); } private DmsFileVersionAuditSnapshot version(UUID id, long number, String label, String status) { return DmsFileVersionAuditSnapshot.builder() .fileVersionId(id) .versionNo(number) .versionLabel(label) .fileName("质量手册.docx") .mimeType("application/vnd.openxmlformats-officedocument.wordprocessingml.document") .sizeBytes(1024L) .checksumSha256((number == 1 ? "a" : "b").repeat(64)) .preparedBy("author-1") .preparedOn(java.time.LocalDate.of(2026, 9, 1)) .lifecycleStatus(status) .build(); } private DmsFilePermissionEntity permission(UUID id, String resourceType, UUID resourceId, String principalType, String principalId, String action) { DmsFilePermissionEntity value = new DmsFilePermissionEntity(); value.setId(id); value.setTenantId("tenant-1"); value.setResourceType(resourceType); value.setResourceId(resourceId); value.setResourceScope("FOLDER".equals(resourceType) ? "SUBTREE" : "SELF"); value.setPrincipalType(principalType); value.setPrincipalId(principalId); value.setIncludeChildOrgs("ORG".equals(principalType)); value.setActionCode(action); value.setSourceType("MANUAL"); value.setSourceId("source-1"); value.setValidFrom(new java.util.Date()); value.setUsedCount(0L); value.setGrantReason("授权原因"); value.setGrantedByType("USER"); value.setGrantedById("admin-1"); value.setRevision(0L); return value; } }