吸收数字员工资产通知日报业务收口

This commit is contained in:
baiyanyun
2026-06-15 14:59:29 +08:00
parent 87b440e93f
commit de33710423
8 changed files with 327 additions and 10 deletions

View File

@@ -72,8 +72,14 @@ public class DigitalEmployeeAdminWorkbenchRowDto {
private Boolean hardInterruptDisabled;
@JsonProperty("artifact_id")
private String artifactId;
@JsonProperty("artifact_graph_id")
private String artifactGraphId;
@JsonProperty("artifact_group_id")
private String artifactGroupId;
@JsonProperty("group_key")
private String groupKey;
@JsonProperty("related_artifact_ids")
private List<String> relatedArtifactIds;
@JsonProperty("artifact_count")
private Long artifactCount;
@JsonProperty("device_count")
@@ -90,10 +96,20 @@ public class DigitalEmployeeAdminWorkbenchRowDto {
private Long cleanupEligibleCount;
@JsonProperty("batch_cleanup_disabled")
private Boolean batchCleanupDisabled;
@JsonProperty("retention_conflict_status")
private String retentionConflictStatus;
@JsonProperty("cleanup_conflict_status")
private String cleanupConflictStatus;
@JsonProperty("remote_delete_disabled")
private Boolean remoteDeleteDisabled;
@JsonProperty("notification_id")
private String notificationId;
@JsonProperty("collaboration_thread_id")
private String collaborationThreadId;
@JsonProperty("subscription_policy_id")
private String subscriptionPolicyId;
@JsonProperty("subscription_conflict_status")
private String subscriptionConflictStatus;
@JsonProperty("notification_policy_id")
private String notificationPolicyId;
@JsonProperty("subscription_status")
@@ -105,16 +121,38 @@ public class DigitalEmployeeAdminWorkbenchRowDto {
private String channel;
@JsonProperty("delivery_status")
private String deliveryStatus;
@JsonProperty("delivery_attempt_id")
private String deliveryAttemptId;
@JsonProperty("send_request_id")
private String sendRequestId;
@JsonProperty("real_push_disabled")
private Boolean realPushDisabled;
@JsonProperty("conflict_status")
private String conflictStatus;
@JsonProperty("report_id")
private String reportId;
@JsonProperty("daily_report_fact_id")
private String dailyReportFactId;
@JsonProperty("daily_report_physical_fact_status")
private String dailyReportPhysicalFactStatus;
@JsonProperty("send_record_id")
private String sendRecordId;
@JsonProperty("send_channel")
private String sendChannel;
@JsonProperty("send_request_status")
private String sendRequestStatus;
@JsonProperty("external_send_disabled")
private Boolean externalSendDisabled;
@JsonProperty("third_party_channel_disabled")
private Boolean thirdPartyChannelDisabled;
@JsonProperty("approval_decision_status")
private String approvalDecisionStatus;
@JsonProperty("advanced_query_supported")
private Boolean advancedQuerySupported;
@JsonProperty("aggregation_scope")
private String aggregationScope;
@JsonProperty("materialized_source")
private String materializedSource;
@JsonProperty("daily_report_approval_id")
private String dailyReportApprovalId;
@JsonProperty("daily_report_approval_action")

View File

@@ -58,5 +58,11 @@ public class DigitalEmployeeBusinessViewRowDto {
private String latestEventAt;
@JsonProperty("last_event_message")
private String lastEventMessage;
@JsonProperty("advanced_query_supported")
private Boolean advancedQuerySupported;
@JsonProperty("aggregation_scope")
private String aggregationScope;
@JsonProperty("materialized_source")
private String materializedSource;
private Boolean materialized;
}

View File

@@ -71,7 +71,8 @@ public class DigitalEmployeeSyncApplicationServiceImpl implements DigitalEmploye
"notification:mark_read", "notification:dismiss",
"notification_policy:pull_policy", "notification_policy:mark_reviewed", "notification_policy:dismiss",
"artifact:mark_keep", "artifact:mark_expire", "artifact:mark_reviewed", "artifact:record_cleanup_request",
"daily_report:mark_delivered", "daily_report:mark_confirmed", "daily_report:request_approval", "daily_report:record_approval_decision",
"notification:record_send_request", "notification:record_send_result",
"daily_report:mark_delivered", "daily_report:mark_confirmed", "daily_report:request_approval", "daily_report:record_approval_decision", "daily_report:record_send_request", "daily_report:record_send_result",
"memory:archive_memory", "memory:restore_memory", "memory:mark_reviewed",
"memory_policy:pull_policy", "memory_policy:mark_reviewed", "memory_policy:dismiss",
"skill:mark_reviewed", "skill:dismiss",
@@ -1028,6 +1029,11 @@ public class DigitalEmployeeSyncApplicationServiceImpl implements DigitalEmploye
case "auto_merge_policy" -> List.of("auto_merge_policy_disabled");
case "auto_decide_approval" -> List.of("auto_decision_disabled");
case "route_recover_execute" -> List.of("route_recovery_disabled");
case "cleanup_file_batch" -> List.of("batch_cleanup_disabled");
case "remote_delete_artifact" -> List.of("remote_delete_disabled");
case "real_push_notification" -> List.of("real_push_disabled");
case "external_send_daily_report" -> List.of("external_send_disabled");
case "third_party_send" -> List.of("third_party_channel_disabled");
case "run_schedule_now" -> List.of("run_schedule_now_disabled");
case "start_scheduler" -> List.of("start_scheduler_disabled");
case "hard_interrupt" -> List.of("hard_interrupt_disabled");
@@ -1114,7 +1120,10 @@ public class DigitalEmployeeSyncApplicationServiceImpl implements DigitalEmploye
.policyGuardStatus(firstString(businessView.get("policy_guard_status"), businessView.get("policyGuardStatus"), payload.get("policy_guard_status"), payload.get("policyGuardStatus")))
.hardInterruptDisabled(nullableBooleanValue(firstPresent(businessView.get("hard_interrupt_disabled"), businessView.get("hardInterruptDisabled"), payload.get("hard_interrupt_disabled"), payload.get("hardInterruptDisabled"))))
.artifactId(firstString(businessView.get("artifact_id"), payload.get("artifact_id"), "artifact".equals(record.getEntityType()) ? record.getEntityId() : null))
.artifactGraphId(firstString(businessView.get("artifact_graph_id"), businessView.get("artifactGraphId"), payload.get("artifact_graph_id"), payload.get("artifactGraphId")))
.artifactGroupId(firstString(businessView.get("artifact_group_id"), businessView.get("artifactGroupId"), payload.get("artifact_group_id"), payload.get("artifactGroupId")))
.groupKey(firstString(businessView.get("group_key"), businessView.get("groupKey"), payload.get("group_key"), payload.get("groupKey")))
.relatedArtifactIds(stringListValue(firstPresent(businessView.get("related_artifact_ids"), businessView.get("relatedArtifactIds"), payload.get("related_artifact_ids"), payload.get("relatedArtifactIds"))))
.artifactCount(numberValue(firstPresent(businessView.get("artifact_count"), businessView.get("artifactCount"), payload.get("artifact_count"), payload.get("artifactCount"))))
.deviceCount(numberValue(firstPresent(businessView.get("device_count"), businessView.get("deviceCount"), payload.get("device_count"), payload.get("deviceCount"))))
.versionCount(numberValue(firstPresent(businessView.get("version_count"), businessView.get("versionCount"), payload.get("version_count"), payload.get("versionCount"))))
@@ -1123,19 +1132,35 @@ public class DigitalEmployeeSyncApplicationServiceImpl implements DigitalEmploye
.cleanupRequestId(firstString(businessView.get("cleanup_request_id"), businessView.get("cleanupRequestId"), payload.get("cleanup_request_id"), payload.get("cleanupRequestId")))
.cleanupEligibleCount(numberValue(firstPresent(businessView.get("cleanup_eligible_count"), businessView.get("cleanupEligibleCount"), payload.get("cleanup_eligible_count"), payload.get("cleanupEligibleCount"))))
.batchCleanupDisabled(nullableBooleanValue(firstPresent(businessView.get("batch_cleanup_disabled"), businessView.get("batchCleanupDisabled"), payload.get("batch_cleanup_disabled"), payload.get("batchCleanupDisabled"))))
.retentionConflictStatus(firstString(businessView.get("retention_conflict_status"), businessView.get("retentionConflictStatus"), payload.get("retention_conflict_status"), payload.get("retentionConflictStatus")))
.cleanupConflictStatus(firstString(businessView.get("cleanup_conflict_status"), businessView.get("cleanupConflictStatus"), payload.get("cleanup_conflict_status"), payload.get("cleanupConflictStatus")))
.remoteDeleteDisabled(nullableBooleanValue(firstPresent(businessView.get("remote_delete_disabled"), businessView.get("remoteDeleteDisabled"), payload.get("remote_delete_disabled"), payload.get("remoteDeleteDisabled"))))
.notificationId(firstString(businessView.get("notification_id"), payload.get("notification_id")))
.collaborationThreadId(firstString(businessView.get("collaboration_thread_id"), businessView.get("collaborationThreadId"), payload.get("collaboration_thread_id"), payload.get("collaborationThreadId")))
.subscriptionPolicyId(firstString(businessView.get("subscription_policy_id"), businessView.get("subscriptionPolicyId"), payload.get("subscription_policy_id"), payload.get("subscriptionPolicyId")))
.subscriptionConflictStatus(firstString(businessView.get("subscription_conflict_status"), businessView.get("subscriptionConflictStatus"), payload.get("subscription_conflict_status"), payload.get("subscriptionConflictStatus")))
.notificationPolicyId(firstString(businessView.get("notification_policy_id"), businessView.get("notificationPolicyId"), payload.get("notification_policy_id"), payload.get("notificationPolicyId")))
.subscriptionStatus(firstString(businessView.get("subscription_status"), businessView.get("subscriptionStatus"), payload.get("subscription_status"), payload.get("subscriptionStatus")))
.desktopEnabled(nullableBooleanValue(firstPresent(businessView.get("desktop_enabled"), businessView.get("desktopEnabled"), payload.get("desktop_enabled"), payload.get("desktopEnabled"))))
.minimumLevel(firstString(businessView.get("minimum_level"), businessView.get("minimumLevel"), payload.get("minimum_level"), payload.get("minimumLevel")))
.channel(firstString(businessView.get("channel"), payload.get("channel")))
.deliveryStatus(firstString(businessView.get("delivery_status"), businessView.get("deliveryStatus"), payload.get("delivery_status"), payload.get("deliveryStatus")))
.deliveryAttemptId(firstString(businessView.get("delivery_attempt_id"), businessView.get("deliveryAttemptId"), payload.get("delivery_attempt_id"), payload.get("deliveryAttemptId")))
.sendRequestId(firstString(businessView.get("send_request_id"), businessView.get("sendRequestId"), payload.get("send_request_id"), payload.get("sendRequestId")))
.realPushDisabled(nullableBooleanValue(firstPresent(businessView.get("real_push_disabled"), businessView.get("realPushDisabled"), payload.get("real_push_disabled"), payload.get("realPushDisabled"))))
.conflictStatus(firstString(businessView.get("conflict_status"), businessView.get("conflictStatus"), payload.get("conflict_status"), payload.get("conflictStatus")))
.reportId(firstString(businessView.get("report_id"), payload.get("report_id")))
.dailyReportFactId(firstString(businessView.get("daily_report_fact_id"), businessView.get("dailyReportFactId"), payload.get("daily_report_fact_id"), payload.get("dailyReportFactId")))
.dailyReportPhysicalFactStatus(firstString(businessView.get("daily_report_physical_fact_status"), businessView.get("dailyReportPhysicalFactStatus"), payload.get("daily_report_physical_fact_status"), payload.get("dailyReportPhysicalFactStatus")))
.sendRecordId(firstString(businessView.get("send_record_id"), businessView.get("sendRecordId"), payload.get("send_record_id"), payload.get("sendRecordId")))
.sendChannel(firstString(businessView.get("send_channel"), businessView.get("sendChannel"), payload.get("send_channel"), payload.get("sendChannel")))
.sendRequestStatus(firstString(businessView.get("send_request_status"), businessView.get("sendRequestStatus"), payload.get("send_request_status"), payload.get("sendRequestStatus")))
.externalSendDisabled(nullableBooleanValue(firstPresent(businessView.get("external_send_disabled"), businessView.get("externalSendDisabled"), payload.get("external_send_disabled"), payload.get("externalSendDisabled"))))
.thirdPartyChannelDisabled(nullableBooleanValue(firstPresent(businessView.get("third_party_channel_disabled"), businessView.get("thirdPartyChannelDisabled"), payload.get("third_party_channel_disabled"), payload.get("thirdPartyChannelDisabled"))))
.approvalDecisionStatus(firstString(businessView.get("approval_decision_status"), businessView.get("approvalDecisionStatus"), payload.get("approval_decision_status"), payload.get("approvalDecisionStatus")))
.advancedQuerySupported(nullableBooleanValue(firstPresent(businessView.get("advanced_query_supported"), businessView.get("advancedQuerySupported"), payload.get("advanced_query_supported"), payload.get("advancedQuerySupported"))))
.aggregationScope(firstString(businessView.get("aggregation_scope"), businessView.get("aggregationScope"), payload.get("aggregation_scope"), payload.get("aggregationScope")))
.materializedSource(firstString(businessView.get("materialized_source"), businessView.get("materializedSource"), payload.get("materialized_source"), payload.get("materializedSource")))
.dailyReportApprovalId(firstString(businessView.get("daily_report_approval_id"), businessView.get("dailyReportApprovalId"), payload.get("daily_report_approval_id"), payload.get("dailyReportApprovalId")))
.dailyReportApprovalAction(firstString(businessView.get("daily_report_approval_action"), businessView.get("dailyReportApprovalAction"), payload.get("daily_report_approval_action"), payload.get("dailyReportApprovalAction")))
.dailyReportApprovalActor(firstString(businessView.get("daily_report_approval_actor"), businessView.get("dailyReportApprovalActor"), payload.get("daily_report_approval_actor"), payload.get("dailyReportApprovalActor")))
@@ -1304,9 +1329,14 @@ public class DigitalEmployeeSyncApplicationServiceImpl implements DigitalEmploye
return StringUtils.equals(row.getEntityType(), "artifact")
|| startsWithAny(row.getKind(), "artifact_")
|| StringUtils.equals(row.getCategory(), "artifact_lifecycle")
|| StringUtils.isNotBlank(row.getArtifactGraphId())
|| StringUtils.isNotBlank(row.getArtifactGroupId())
|| StringUtils.isNotBlank(row.getGroupKey())
|| StringUtils.isNotBlank(row.getLatestArtifactId())
|| row.getArtifactCount() != null;
|| row.getArtifactCount() != null
|| StringUtils.isNotBlank(row.getRetentionConflictStatus())
|| StringUtils.isNotBlank(row.getCleanupConflictStatus())
|| row.getRemoteDeleteDisabled() != null;
}
private boolean isServiceOperationsRow(DigitalEmployeeAdminWorkbenchRowDto row) {
@@ -1338,6 +1368,10 @@ public class DigitalEmployeeSyncApplicationServiceImpl implements DigitalEmploye
return StringUtils.equals(row.getCategory(), "notification")
|| StringUtils.equals(row.getCategory(), "action_notification")
|| contains(row.getKind(), "notification")
|| StringUtils.isNotBlank(row.getCollaborationThreadId())
|| StringUtils.isNotBlank(row.getDeliveryAttemptId())
|| StringUtils.isNotBlank(row.getSendRequestId())
|| row.getRealPushDisabled() != null
|| StringUtils.isNotBlank(row.getNotificationId());
}
@@ -1381,6 +1415,11 @@ public class DigitalEmployeeSyncApplicationServiceImpl implements DigitalEmploye
return StringUtils.equals(row.getCategory(), "daily_report")
|| startsWithAny(row.getKind(), "daily_report")
|| StringUtils.isNotBlank(row.getReportId())
|| StringUtils.isNotBlank(row.getDailyReportPhysicalFactStatus())
|| StringUtils.isNotBlank(row.getSendChannel())
|| StringUtils.isNotBlank(row.getSendRequestStatus())
|| row.getExternalSendDisabled() != null
|| row.getThirdPartyChannelDisabled() != null
|| StringUtils.isNotBlank(row.getDailyReportApprovalId())
|| StringUtils.isNotBlank(row.getDailyReportApprovalAction());
}
@@ -1702,6 +1741,9 @@ public class DigitalEmployeeSyncApplicationServiceImpl implements DigitalEmploye
.businessView(businessView)
.payload(payload)
.lastEventMessage(lastEventMessage(entityType, businessView, payload))
.advancedQuerySupported(nullableBooleanValue(firstPresent(businessView.get("advanced_query_supported"), businessView.get("advancedQuerySupported"), payload.get("advanced_query_supported"), payload.get("advancedQuerySupported"))))
.aggregationScope(firstString(businessView.get("aggregation_scope"), businessView.get("aggregationScope"), payload.get("aggregation_scope"), payload.get("aggregationScope")))
.materializedSource(firstString(businessView.get("materialized_source"), businessView.get("materializedSource"), payload.get("materialized_source"), payload.get("materializedSource")))
.materialized(false)
.build();
}
@@ -1733,6 +1775,9 @@ public class DigitalEmployeeSyncApplicationServiceImpl implements DigitalEmploye
.businessView(readJsonObject(fact.getBusinessView()))
.payload(readJsonObject(fact.getPayload()))
.lastEventMessage(lastEventMessage(fact.getEntityType(), readJsonObject(fact.getBusinessView()), readJsonObject(fact.getPayload())))
.advancedQuerySupported(nullableBooleanValue(firstPresent(readJsonObject(fact.getBusinessView()).get("advanced_query_supported"), readJsonObject(fact.getBusinessView()).get("advancedQuerySupported"))))
.aggregationScope(firstString(readJsonObject(fact.getBusinessView()).get("aggregation_scope"), readJsonObject(fact.getBusinessView()).get("aggregationScope")))
.materializedSource(firstString(readJsonObject(fact.getBusinessView()).get("materialized_source"), readJsonObject(fact.getBusinessView()).get("materializedSource")))
.materialized(true)
.build();
}

View File

@@ -183,6 +183,30 @@ class DigitalEmployeeSyncApplicationServiceImplTest {
verify(repository, never()).queryBusinessRecords(any(), any(), any(), any(), any(), any(), any(), any(), any(Long.class), any(Long.class));
}
@Test
void queryBusinessViewsExposeAdvancedQueryAndMaterializedSource() {
when(repository.queryBusinessRecords(eq(101L), eq(null), eq(null), eq("plan"), eq(null), eq(null), eq(null), eq(null), eq(1L), eq(20L)))
.thenReturn(page(List.of(
record("outbox-plan-query", "plan", "plan-query-1", 101L, new Date(10_000),
Map.of(
"entity_type", "plan",
"title", "组合检索计划",
"status", "active",
"advanced_query_supported", true,
"aggregation_scope", "client_device",
"materialized_source", "sync_record_fallback"
),
Map.of("id", "plan-query-1", "status", "active"))
)));
DigitalEmployeeBusinessViewPageDto result = service.queryBusinessViews("plan", null, null, null, null, null, null, null, 1L, 20L);
assertThat(result.getRecords()).hasSize(1);
assertThat(result.getRecords().get(0).getAdvancedQuerySupported()).isTrue();
assertThat(result.getRecords().get(0).getAggregationScope()).isEqualTo("client_device");
assertThat(result.getRecords().get(0).getMaterializedSource()).isEqualTo("sync_record_fallback");
}
@Test
void queryEventsFiltersStatusEntityAndTimeRangeFromBusinessView() {
Date from = new Date(10_000);
@@ -1476,9 +1500,14 @@ class DigitalEmployeeSyncApplicationServiceImplTest {
Map.entry("status", "unread"),
Map.entry("title", "通知未读"),
Map.entry("notification_id", "notification-1"),
Map.entry("collaboration_thread_id", "thread-1"),
Map.entry("subscription_policy_id", "subscription-policy-1"),
Map.entry("subscription_conflict_status", "conflict"),
Map.entry("channel", "desktop"),
Map.entry("delivery_status", "delivered"),
Map.entry("delivery_attempt_id", "delivery-attempt-1"),
Map.entry("send_request_id", "send-request-1"),
Map.entry("real_push_disabled", true),
Map.entry("conflict_status", "none"),
Map.entry("summary", "等待处理")
),
@@ -1528,14 +1557,24 @@ class DigitalEmployeeSyncApplicationServiceImplTest {
assertThat(result.getRecords().get(0).getCategory()).isEqualTo("notification");
assertThat(result.getRecords().get(0).getStatus()).isEqualTo("unread");
assertThat(result.getRecords().get(0).getSummary()).isEqualTo("等待处理");
assertThat(result.getRecords().get(0).getCollaborationThreadId()).isEqualTo("thread-1");
assertThat(result.getRecords().get(0).getSubscriptionPolicyId()).isEqualTo("subscription-policy-1");
assertThat(result.getRecords().get(0).getSubscriptionConflictStatus()).isEqualTo("conflict");
assertThat(result.getRecords().get(0).getChannel()).isEqualTo("desktop");
assertThat(result.getRecords().get(0).getDeliveryStatus()).isEqualTo("delivered");
assertThat(result.getRecords().get(0).getDeliveryAttemptId()).isEqualTo("delivery-attempt-1");
assertThat(result.getRecords().get(0).getSendRequestId()).isEqualTo("send-request-1");
assertThat(result.getRecords().get(0).getRealPushDisabled()).isTrue();
assertThat(result.getRecords().get(0).getConflictStatus()).isEqualTo("none");
assertThat(result.getRecords().get(1).getCategory()).isEqualTo("action_notification");
assertThat(result.getRecords().get(2).getNotificationId()).isEqualTo("notification-preference");
}
@Test
void queryAdminWorkbenchNotificationsReturnsCollaborationAndDeliveryRows() {
queryAdminWorkbenchNotificationsReturnsNotificationRowsOnly();
}
@Test
void queryAdminWorkbenchNotificationPoliciesReturnsSubscriptionPolicyRowsOnly() {
when(repository.queryBusinessRecords(eq(101L), eq(null), eq(null), eq(null), eq(null), eq(null), eq(null), eq(null), eq(1L), eq(20L)))
@@ -1611,11 +1650,17 @@ class DigitalEmployeeSyncApplicationServiceImplTest {
"title", "日报 PDF",
"status", "available",
"artifact_id", "artifact-1",
"artifact_graph_id", "artifact-graph-1",
"group_key", "daily-report:pdf",
"related_artifact_ids", List.of("artifact-2", "artifact-3"),
"retention_status", "expired",
"cleanup_status", "pending",
"retention_conflict_status", "conflict",
"cleanup_conflict_status", "pending_review",
"cleanup_request_id", "cleanup-request-1",
"cleanup_eligible_count", 3,
"batch_cleanup_disabled", true,
"remote_delete_disabled", true,
"artifact_group_id", "daily-report-2026-06-13",
"artifact_count", 4,
"device_count", 2,
@@ -1679,18 +1724,29 @@ class DigitalEmployeeSyncApplicationServiceImplTest {
assertThat(result.getRecords().get(0).getCleanupRequestId()).isEqualTo("cleanup-request-1");
assertThat(result.getRecords().get(0).getCleanupEligibleCount()).isEqualTo(3L);
assertThat(result.getRecords().get(0).getBatchCleanupDisabled()).isTrue();
assertThat(result.getRecords().get(0).getArtifactGraphId()).isEqualTo("artifact-graph-1");
assertThat(result.getRecords().get(0).getArtifactGroupId()).isEqualTo("daily-report-2026-06-13");
assertThat(result.getRecords().get(0).getGroupKey()).isEqualTo("daily-report:pdf");
assertThat(result.getRecords().get(0).getRelatedArtifactIds()).containsExactly("artifact-2", "artifact-3");
assertThat(result.getRecords().get(0).getArtifactCount()).isEqualTo(4L);
assertThat(result.getRecords().get(0).getDeviceCount()).isEqualTo(2L);
assertThat(result.getRecords().get(0).getVersionCount()).isEqualTo(3L);
assertThat(result.getRecords().get(0).getLatestArtifactId()).isEqualTo("artifact-4");
assertThat(result.getRecords().get(0).getVersionKey()).isEqualTo("daily-report:2026-06-13");
assertThat(result.getRecords().get(0).getRetentionConflictStatus()).isEqualTo("conflict");
assertThat(result.getRecords().get(0).getCleanupConflictStatus()).isEqualTo("pending_review");
assertThat(result.getRecords().get(0).getRemoteDeleteDisabled()).isTrue();
assertThat(result.getRecords().get(0).getBusinessView()).containsEntry("retention_status", "expired");
assertThat(result.getRecords().get(1).getArtifactId()).isEqualTo("artifact-2");
assertThat(result.getRecords().get(2).getBusinessView()).containsEntry("cleanup_status", "deleted");
assertThat(result.getRecords().get(2).getBusinessView()).containsEntry("deleted_at", "2026-06-13T00:00:00+08:00");
}
@Test
void queryAdminWorkbenchArtifactLifecycleReturnsGraphAndConflictRows() {
queryAdminWorkbenchArtifactLifecycleReturnsArtifactRowsOnly();
}
@Test
void queryAdminWorkbenchAuditsReturnsAuditRowsOnly() {
when(repository.queryBusinessRecords(eq(101L), eq(null), eq(null), eq(null), eq(null), eq(null), eq(null), eq(null), eq(1L), eq(20L)))
@@ -1951,7 +2007,12 @@ class DigitalEmployeeSyncApplicationServiceImplTest {
Map.entry("title", "6 13 日日报"),
Map.entry("report_id", "report-1"),
Map.entry("daily_report_fact_id", "daily-report-fact-1"),
Map.entry("daily_report_physical_fact_status", "pending_materialization"),
Map.entry("send_record_id", "send-record-1"),
Map.entry("send_channel", "email"),
Map.entry("send_request_status", "recorded"),
Map.entry("external_send_disabled", true),
Map.entry("third_party_channel_disabled", true),
Map.entry("approval_decision_status", "pending"),
Map.entry("summary", "日报已生成"),
Map.entry("artifact_id", "artifact-report-1")
@@ -2021,7 +2082,12 @@ class DigitalEmployeeSyncApplicationServiceImplTest {
assertThat(result.getRecords().get(0).getStatus()).isEqualTo("generated");
assertThat(result.getRecords().get(0).getSummary()).isEqualTo("日报已生成");
assertThat(result.getRecords().get(0).getDailyReportFactId()).isEqualTo("daily-report-fact-1");
assertThat(result.getRecords().get(0).getDailyReportPhysicalFactStatus()).isEqualTo("pending_materialization");
assertThat(result.getRecords().get(0).getSendRecordId()).isEqualTo("send-record-1");
assertThat(result.getRecords().get(0).getSendChannel()).isEqualTo("email");
assertThat(result.getRecords().get(0).getSendRequestStatus()).isEqualTo("recorded");
assertThat(result.getRecords().get(0).getExternalSendDisabled()).isTrue();
assertThat(result.getRecords().get(0).getThirdPartyChannelDisabled()).isTrue();
assertThat(result.getRecords().get(0).getApprovalDecisionStatus()).isEqualTo("pending");
assertThat(result.getRecords().get(1).getReportId()).isEqualTo("report-2");
assertThat(result.getRecords().get(1).getBusinessView()).containsEntry("delivery_status", "delivered");
@@ -2033,6 +2099,11 @@ class DigitalEmployeeSyncApplicationServiceImplTest {
assertThat(result.getRecords().get(3).getDailyReportApprovalRecordedAt()).isEqualTo("2026-06-13T10:30:00+08:00");
}
@Test
void queryAdminWorkbenchDailyReportsReturnsPhysicalFactAndSendShellRows() {
queryAdminWorkbenchDailyReportsReturnsDailyReportRowsOnly();
}
@Test
void createAdminActionRecordsLowRiskActionAsPending() {
DigitalEmployeeAdminActionRequestDto request = adminActionRequest("approval", "approval-1", "keep_local");
@@ -2062,12 +2133,33 @@ class DigitalEmployeeSyncApplicationServiceImplTest {
assertThat(result.getOk()).isFalse();
assertThat(result.getStatus()).isEqualTo("rejected");
assertThat(result.getReasonCodes()).contains("high_risk_action_disabled");
assertThat(result.getReasonCodes()).contains("batch_cleanup_disabled");
ArgumentCaptor<DigitalEmployeeAdminAction> captor = ArgumentCaptor.forClass(DigitalEmployeeAdminAction.class);
verify(adminActionRepository).save(captor.capture());
assertThat(captor.getValue().getStatus()).isEqualTo("rejected");
}
@Test
void createAdminActionAllowsLowRiskAssetNotificationReportIntents() {
assertThat(service.createAdminAction(adminActionRequest("artifact", "artifact-1", "record_cleanup_request")).getOk()).isTrue();
assertThat(service.createAdminAction(adminActionRequest("notification", "notification-1", "record_send_request")).getOk()).isTrue();
assertThat(service.createAdminAction(adminActionRequest("notification", "notification-1", "record_send_result")).getOk()).isTrue();
assertThat(service.createAdminAction(adminActionRequest("daily_report", "report-1", "record_send_request")).getOk()).isTrue();
assertThat(service.createAdminAction(adminActionRequest("daily_report", "report-1", "record_send_result")).getOk()).isTrue();
assertThat(service.createAdminAction(adminActionRequest("daily_report", "report-1", "request_approval")).getOk()).isTrue();
assertThat(service.createAdminAction(adminActionRequest("daily_report", "report-1", "mark_delivered")).getOk()).isTrue();
assertThat(service.createAdminAction(adminActionRequest("daily_report", "report-1", "mark_confirmed")).getOk()).isTrue();
}
@Test
void createAdminActionRejectsHighRiskAssetNotificationReportExecution() {
assertThat(service.createAdminAction(adminActionRequest("artifact", "artifact-1", "cleanup_file_batch")).getReasonCodes()).contains("batch_cleanup_disabled");
assertThat(service.createAdminAction(adminActionRequest("artifact", "artifact-1", "remote_delete_artifact")).getReasonCodes()).contains("remote_delete_disabled");
assertThat(service.createAdminAction(adminActionRequest("notification", "notification-1", "real_push_notification")).getReasonCodes()).contains("real_push_disabled");
assertThat(service.createAdminAction(adminActionRequest("daily_report", "report-1", "external_send_daily_report")).getReasonCodes()).contains("external_send_disabled");
assertThat(service.createAdminAction(adminActionRequest("daily_report", "report-1", "third_party_send")).getReasonCodes()).contains("third_party_channel_disabled");
}
@Test
void createAdminActionReturnsSpecificPolicyAndSchedulerDisabledReasons() {
DigitalEmployeeAdminActionResultDto editPolicy = service.createAdminAction(