吸收数字员工日报物理事实发送记录预览
This commit is contained in:
@@ -133,6 +133,10 @@ public class DigitalEmployeeAdminWorkbenchRowDto {
|
|||||||
private String reportId;
|
private String reportId;
|
||||||
@JsonProperty("daily_report_fact_id")
|
@JsonProperty("daily_report_fact_id")
|
||||||
private String dailyReportFactId;
|
private String dailyReportFactId;
|
||||||
|
@JsonProperty("daily_report_table")
|
||||||
|
private String dailyReportTable;
|
||||||
|
@JsonProperty("daily_report_materialized")
|
||||||
|
private Boolean dailyReportMaterialized;
|
||||||
@JsonProperty("daily_report_physical_fact_status")
|
@JsonProperty("daily_report_physical_fact_status")
|
||||||
private String dailyReportPhysicalFactStatus;
|
private String dailyReportPhysicalFactStatus;
|
||||||
@JsonProperty("send_record_id")
|
@JsonProperty("send_record_id")
|
||||||
@@ -141,6 +145,10 @@ public class DigitalEmployeeAdminWorkbenchRowDto {
|
|||||||
private String sendChannel;
|
private String sendChannel;
|
||||||
@JsonProperty("send_request_status")
|
@JsonProperty("send_request_status")
|
||||||
private String sendRequestStatus;
|
private String sendRequestStatus;
|
||||||
|
@JsonProperty("send_record_status")
|
||||||
|
private String sendRecordStatus;
|
||||||
|
@JsonProperty("formal_daily_report_page_disabled")
|
||||||
|
private Boolean formalDailyReportPageDisabled;
|
||||||
@JsonProperty("external_send_disabled")
|
@JsonProperty("external_send_disabled")
|
||||||
private Boolean externalSendDisabled;
|
private Boolean externalSendDisabled;
|
||||||
@JsonProperty("third_party_channel_disabled")
|
@JsonProperty("third_party_channel_disabled")
|
||||||
|
|||||||
@@ -25,12 +25,20 @@ public class DigitalEmployeeDailyReportFact {
|
|||||||
private String clientKey;
|
private String clientKey;
|
||||||
private String deviceId;
|
private String deviceId;
|
||||||
private String reportId;
|
private String reportId;
|
||||||
|
private String dailyReportFactId;
|
||||||
private String planId;
|
private String planId;
|
||||||
private String status;
|
private String status;
|
||||||
|
private String physicalFactStatus;
|
||||||
private String deliveryStatus;
|
private String deliveryStatus;
|
||||||
private String approvalStatus;
|
private String approvalStatus;
|
||||||
|
private String approvalDecisionStatus;
|
||||||
private String confirmedAt;
|
private String confirmedAt;
|
||||||
private String reportDate;
|
private String reportDate;
|
||||||
|
private String sendRecordId;
|
||||||
|
private String sendChannel;
|
||||||
|
private String sendRequestStatus;
|
||||||
|
private String sendRecordStatus;
|
||||||
|
private String materializedSource;
|
||||||
private String businessView;
|
private String businessView;
|
||||||
private Date syncedAt;
|
private Date syncedAt;
|
||||||
private Date modified;
|
private Date modified;
|
||||||
|
|||||||
@@ -300,12 +300,20 @@ public class DigitalEmployeeSyncApplicationServiceImpl implements DigitalEmploye
|
|||||||
.clientKey(record.getClientKey())
|
.clientKey(record.getClientKey())
|
||||||
.deviceId(record.getDeviceId())
|
.deviceId(record.getDeviceId())
|
||||||
.reportId(reportId)
|
.reportId(reportId)
|
||||||
|
.dailyReportFactId(firstString(view.get("daily_report_fact_id"), view.get("dailyReportFactId")))
|
||||||
.planId(row.getPlanId())
|
.planId(row.getPlanId())
|
||||||
.status(row.getStatus())
|
.status(row.getStatus())
|
||||||
|
.physicalFactStatus(firstString(view.get("daily_report_physical_fact_status"), view.get("dailyReportPhysicalFactStatus"), view.get("physical_fact_status"), view.get("physicalFactStatus")))
|
||||||
.deliveryStatus(firstString(view.get("delivery_status"), view.get("deliveryStatus")))
|
.deliveryStatus(firstString(view.get("delivery_status"), view.get("deliveryStatus")))
|
||||||
.approvalStatus(firstString(view.get("approval_status"), view.get("approvalStatus")))
|
.approvalStatus(firstString(view.get("approval_status"), view.get("approvalStatus")))
|
||||||
|
.approvalDecisionStatus(firstString(view.get("approval_decision_status"), view.get("approvalDecisionStatus")))
|
||||||
.confirmedAt(firstString(view.get("confirmed_at"), view.get("confirmedAt")))
|
.confirmedAt(firstString(view.get("confirmed_at"), view.get("confirmedAt")))
|
||||||
.reportDate(firstString(view.get("report_date"), view.get("reportDate")))
|
.reportDate(firstString(view.get("report_date"), view.get("reportDate")))
|
||||||
|
.sendRecordId(firstString(view.get("send_record_id"), view.get("sendRecordId")))
|
||||||
|
.sendChannel(firstString(view.get("send_channel"), view.get("sendChannel")))
|
||||||
|
.sendRequestStatus(firstString(view.get("send_request_status"), view.get("sendRequestStatus")))
|
||||||
|
.sendRecordStatus(firstString(view.get("send_record_status"), view.get("sendRecordStatus"), view.get("send_request_status"), view.get("sendRequestStatus")))
|
||||||
|
.materializedSource(firstString(view.get("materialized_source"), view.get("materializedSource"), "digital_employee_daily_report_fact"))
|
||||||
.businessView(record.getBusinessView())
|
.businessView(record.getBusinessView())
|
||||||
.syncedAt(record.getSyncedAt())
|
.syncedAt(record.getSyncedAt())
|
||||||
.modified(now)
|
.modified(now)
|
||||||
@@ -1160,10 +1168,14 @@ public class DigitalEmployeeSyncApplicationServiceImpl implements DigitalEmploye
|
|||||||
.conflictStatus(firstString(businessView.get("conflict_status"), businessView.get("conflictStatus"), payload.get("conflict_status"), payload.get("conflictStatus")))
|
.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")))
|
.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")))
|
.dailyReportFactId(firstString(businessView.get("daily_report_fact_id"), businessView.get("dailyReportFactId"), payload.get("daily_report_fact_id"), payload.get("dailyReportFactId")))
|
||||||
|
.dailyReportTable(firstString(businessView.get("daily_report_table"), businessView.get("dailyReportTable"), payload.get("daily_report_table"), payload.get("dailyReportTable"), "digital_employee_daily_report_fact"))
|
||||||
|
.dailyReportMaterialized(nullableBooleanValue(firstPresent(businessView.get("daily_report_materialized"), businessView.get("dailyReportMaterialized"), payload.get("daily_report_materialized"), payload.get("dailyReportMaterialized"))))
|
||||||
.dailyReportPhysicalFactStatus(firstString(businessView.get("daily_report_physical_fact_status"), businessView.get("dailyReportPhysicalFactStatus"), payload.get("daily_report_physical_fact_status"), payload.get("dailyReportPhysicalFactStatus")))
|
.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")))
|
.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")))
|
.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")))
|
.sendRequestStatus(firstString(businessView.get("send_request_status"), businessView.get("sendRequestStatus"), payload.get("send_request_status"), payload.get("sendRequestStatus")))
|
||||||
|
.sendRecordStatus(firstString(businessView.get("send_record_status"), businessView.get("sendRecordStatus"), payload.get("send_record_status"), payload.get("sendRecordStatus"), businessView.get("send_request_status"), payload.get("send_request_status")))
|
||||||
|
.formalDailyReportPageDisabled(nullableBooleanValue(firstPresent(businessView.get("formal_daily_report_page_disabled"), businessView.get("formalDailyReportPageDisabled"), payload.get("formal_daily_report_page_disabled"), payload.get("formalDailyReportPageDisabled"))))
|
||||||
.externalSendDisabled(nullableBooleanValue(firstPresent(businessView.get("external_send_disabled"), businessView.get("externalSendDisabled"), payload.get("external_send_disabled"), payload.get("externalSendDisabled"))))
|
.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"))))
|
.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")))
|
.approvalDecisionStatus(firstString(businessView.get("approval_decision_status"), businessView.get("approvalDecisionStatus"), payload.get("approval_decision_status"), payload.get("approvalDecisionStatus")))
|
||||||
@@ -1448,8 +1460,12 @@ public class DigitalEmployeeSyncApplicationServiceImpl implements DigitalEmploye
|
|||||||
|| startsWithAny(row.getKind(), "daily_report")
|
|| startsWithAny(row.getKind(), "daily_report")
|
||||||
|| StringUtils.isNotBlank(row.getReportId())
|
|| StringUtils.isNotBlank(row.getReportId())
|
||||||
|| StringUtils.isNotBlank(row.getDailyReportPhysicalFactStatus())
|
|| StringUtils.isNotBlank(row.getDailyReportPhysicalFactStatus())
|
||||||
|
|| StringUtils.isNotBlank(row.getDailyReportTable())
|
||||||
|
|| row.getDailyReportMaterialized() != null
|
||||||
|| StringUtils.isNotBlank(row.getSendChannel())
|
|| StringUtils.isNotBlank(row.getSendChannel())
|
||||||
|| StringUtils.isNotBlank(row.getSendRequestStatus())
|
|| StringUtils.isNotBlank(row.getSendRequestStatus())
|
||||||
|
|| StringUtils.isNotBlank(row.getSendRecordStatus())
|
||||||
|
|| row.getFormalDailyReportPageDisabled() != null
|
||||||
|| row.getExternalSendDisabled() != null
|
|| row.getExternalSendDisabled() != null
|
||||||
|| row.getThirdPartyChannelDisabled() != null
|
|| row.getThirdPartyChannelDisabled() != null
|
||||||
|| StringUtils.isNotBlank(row.getDailyReportApprovalId())
|
|| StringUtils.isNotBlank(row.getDailyReportApprovalId())
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import com.xspaceagi.agent.core.adapter.repository.DigitalEmployeeDailyReportFac
|
|||||||
import com.xspaceagi.agent.core.adapter.repository.DigitalEmployeeSyncRecordRepository;
|
import com.xspaceagi.agent.core.adapter.repository.DigitalEmployeeSyncRecordRepository;
|
||||||
import com.xspaceagi.agent.core.adapter.repository.entity.DigitalEmployeeAdminAction;
|
import com.xspaceagi.agent.core.adapter.repository.entity.DigitalEmployeeAdminAction;
|
||||||
import com.xspaceagi.agent.core.adapter.repository.entity.DigitalEmployeeBusinessFact;
|
import com.xspaceagi.agent.core.adapter.repository.entity.DigitalEmployeeBusinessFact;
|
||||||
|
import com.xspaceagi.agent.core.adapter.repository.entity.DigitalEmployeeDailyReportFact;
|
||||||
import com.xspaceagi.agent.core.adapter.repository.entity.DigitalEmployeeSyncRecord;
|
import com.xspaceagi.agent.core.adapter.repository.entity.DigitalEmployeeSyncRecord;
|
||||||
import com.xspaceagi.system.spec.common.RequestContext;
|
import com.xspaceagi.system.spec.common.RequestContext;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
@@ -123,6 +124,59 @@ class DigitalEmployeeSyncApplicationServiceImplTest {
|
|||||||
assertThat(factCaptor.getValue().getStatus()).isEqualTo("active");
|
assertThat(factCaptor.getValue().getStatus()).isEqualTo("active");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void syncOutboxMaterializesDailyReportPhysicalFactAndSendRecord() {
|
||||||
|
DigitalEmployeeSyncItemDto item = new DigitalEmployeeSyncItemDto();
|
||||||
|
item.setOutboxId("outbox-daily-report-1");
|
||||||
|
item.setEntityType("daily_report");
|
||||||
|
item.setEntityId("report-1");
|
||||||
|
item.setOperation("upsert");
|
||||||
|
item.setBusinessView(Map.ofEntries(
|
||||||
|
Map.entry("entity_type", "daily_report"),
|
||||||
|
Map.entry("category", "daily_report"),
|
||||||
|
Map.entry("kind", "daily_report_generated"),
|
||||||
|
Map.entry("status", "generated"),
|
||||||
|
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", "materialized"),
|
||||||
|
Map.entry("approval_decision_status", "approved"),
|
||||||
|
Map.entry("send_record_id", "send-record-1"),
|
||||||
|
Map.entry("send_channel", "email"),
|
||||||
|
Map.entry("send_request_status", "recorded"),
|
||||||
|
Map.entry("send_record_status", "materialized"),
|
||||||
|
Map.entry("materialized_source", "digital_employee_daily_report_fact"),
|
||||||
|
Map.entry("summary", "日报已物化")
|
||||||
|
));
|
||||||
|
item.setPayload(Map.of("id", "report-1", "kind", "daily_report_generated"));
|
||||||
|
|
||||||
|
DigitalEmployeeSyncRequestDto request = new DigitalEmployeeSyncRequestDto();
|
||||||
|
request.setClientKey("client-key-001");
|
||||||
|
request.setDeviceId("device-001");
|
||||||
|
request.setItems(List.of(item));
|
||||||
|
doAnswer(invocation -> {
|
||||||
|
DigitalEmployeeSyncRecord saved = invocation.getArgument(0);
|
||||||
|
saved.setId(1002L);
|
||||||
|
return true;
|
||||||
|
}).when(repository).save(any(DigitalEmployeeSyncRecord.class));
|
||||||
|
|
||||||
|
service.syncOutbox(request);
|
||||||
|
|
||||||
|
ArgumentCaptor<DigitalEmployeeDailyReportFact> factCaptor = ArgumentCaptor.forClass(DigitalEmployeeDailyReportFact.class);
|
||||||
|
verify(dailyReportFactRepository).upsertBySyncRecord(factCaptor.capture());
|
||||||
|
DigitalEmployeeDailyReportFact fact = factCaptor.getValue();
|
||||||
|
assertThat(fact.getSyncRecordId()).isEqualTo(1002L);
|
||||||
|
assertThat(fact.getReportId()).isEqualTo("report-1");
|
||||||
|
assertThat(fact.getDailyReportFactId()).isEqualTo("daily-report-fact-1");
|
||||||
|
assertThat(fact.getPhysicalFactStatus()).isEqualTo("materialized");
|
||||||
|
assertThat(fact.getApprovalDecisionStatus()).isEqualTo("approved");
|
||||||
|
assertThat(fact.getSendRecordId()).isEqualTo("send-record-1");
|
||||||
|
assertThat(fact.getSendChannel()).isEqualTo("email");
|
||||||
|
assertThat(fact.getSendRequestStatus()).isEqualTo("recorded");
|
||||||
|
assertThat(fact.getSendRecordStatus()).isEqualTo("materialized");
|
||||||
|
assertThat(fact.getMaterializedSource()).isEqualTo("digital_employee_daily_report_fact");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void queryRecordsReturnsStoredBusinessMetadata() {
|
void queryRecordsReturnsStoredBusinessMetadata() {
|
||||||
DigitalEmployeeSyncRecord record = planRecord("plan-1", "客户回访", "active", 101L, new Date(1_000));
|
DigitalEmployeeSyncRecord record = planRecord("plan-1", "客户回访", "active", 101L, new Date(1_000));
|
||||||
@@ -2053,10 +2107,14 @@ class DigitalEmployeeSyncApplicationServiceImplTest {
|
|||||||
Map.entry("title", "6 月 13 日日报"),
|
Map.entry("title", "6 月 13 日日报"),
|
||||||
Map.entry("report_id", "report-1"),
|
Map.entry("report_id", "report-1"),
|
||||||
Map.entry("daily_report_fact_id", "daily-report-fact-1"),
|
Map.entry("daily_report_fact_id", "daily-report-fact-1"),
|
||||||
|
Map.entry("daily_report_table", "digital_employee_daily_report_fact"),
|
||||||
|
Map.entry("daily_report_materialized", true),
|
||||||
Map.entry("daily_report_physical_fact_status", "pending_materialization"),
|
Map.entry("daily_report_physical_fact_status", "pending_materialization"),
|
||||||
Map.entry("send_record_id", "send-record-1"),
|
Map.entry("send_record_id", "send-record-1"),
|
||||||
Map.entry("send_channel", "email"),
|
Map.entry("send_channel", "email"),
|
||||||
Map.entry("send_request_status", "recorded"),
|
Map.entry("send_request_status", "recorded"),
|
||||||
|
Map.entry("send_record_status", "materialized"),
|
||||||
|
Map.entry("formal_daily_report_page_disabled", true),
|
||||||
Map.entry("external_send_disabled", true),
|
Map.entry("external_send_disabled", true),
|
||||||
Map.entry("third_party_channel_disabled", true),
|
Map.entry("third_party_channel_disabled", true),
|
||||||
Map.entry("approval_decision_status", "pending"),
|
Map.entry("approval_decision_status", "pending"),
|
||||||
@@ -2128,10 +2186,14 @@ class DigitalEmployeeSyncApplicationServiceImplTest {
|
|||||||
assertThat(result.getRecords().get(0).getStatus()).isEqualTo("generated");
|
assertThat(result.getRecords().get(0).getStatus()).isEqualTo("generated");
|
||||||
assertThat(result.getRecords().get(0).getSummary()).isEqualTo("日报已生成");
|
assertThat(result.getRecords().get(0).getSummary()).isEqualTo("日报已生成");
|
||||||
assertThat(result.getRecords().get(0).getDailyReportFactId()).isEqualTo("daily-report-fact-1");
|
assertThat(result.getRecords().get(0).getDailyReportFactId()).isEqualTo("daily-report-fact-1");
|
||||||
|
assertThat(result.getRecords().get(0).getDailyReportTable()).isEqualTo("digital_employee_daily_report_fact");
|
||||||
|
assertThat(result.getRecords().get(0).getDailyReportMaterialized()).isTrue();
|
||||||
assertThat(result.getRecords().get(0).getDailyReportPhysicalFactStatus()).isEqualTo("pending_materialization");
|
assertThat(result.getRecords().get(0).getDailyReportPhysicalFactStatus()).isEqualTo("pending_materialization");
|
||||||
assertThat(result.getRecords().get(0).getSendRecordId()).isEqualTo("send-record-1");
|
assertThat(result.getRecords().get(0).getSendRecordId()).isEqualTo("send-record-1");
|
||||||
assertThat(result.getRecords().get(0).getSendChannel()).isEqualTo("email");
|
assertThat(result.getRecords().get(0).getSendChannel()).isEqualTo("email");
|
||||||
assertThat(result.getRecords().get(0).getSendRequestStatus()).isEqualTo("recorded");
|
assertThat(result.getRecords().get(0).getSendRequestStatus()).isEqualTo("recorded");
|
||||||
|
assertThat(result.getRecords().get(0).getSendRecordStatus()).isEqualTo("materialized");
|
||||||
|
assertThat(result.getRecords().get(0).getFormalDailyReportPageDisabled()).isTrue();
|
||||||
assertThat(result.getRecords().get(0).getExternalSendDisabled()).isTrue();
|
assertThat(result.getRecords().get(0).getExternalSendDisabled()).isTrue();
|
||||||
assertThat(result.getRecords().get(0).getThirdPartyChannelDisabled()).isTrue();
|
assertThat(result.getRecords().get(0).getThirdPartyChannelDisabled()).isTrue();
|
||||||
assertThat(result.getRecords().get(0).getApprovalDecisionStatus()).isEqualTo("pending");
|
assertThat(result.getRecords().get(0).getApprovalDecisionStatus()).isEqualTo("pending");
|
||||||
|
|||||||
@@ -92,12 +92,20 @@ CREATE TABLE IF NOT EXISTS `digital_employee_daily_report_fact` (
|
|||||||
`client_key` VARCHAR(255) DEFAULT NULL COMMENT '客户端Key',
|
`client_key` VARCHAR(255) DEFAULT NULL COMMENT '客户端Key',
|
||||||
`device_id` VARCHAR(255) DEFAULT NULL COMMENT '设备ID',
|
`device_id` VARCHAR(255) DEFAULT NULL COMMENT '设备ID',
|
||||||
`report_id` VARCHAR(255) NOT NULL COMMENT '日报ID',
|
`report_id` VARCHAR(255) NOT NULL COMMENT '日报ID',
|
||||||
|
`daily_report_fact_id` VARCHAR(255) DEFAULT NULL COMMENT '日报事实ID',
|
||||||
`plan_id` VARCHAR(255) DEFAULT NULL COMMENT '计划ID',
|
`plan_id` VARCHAR(255) DEFAULT NULL COMMENT '计划ID',
|
||||||
`status` VARCHAR(128) DEFAULT NULL COMMENT '状态',
|
`status` VARCHAR(128) DEFAULT NULL COMMENT '状态',
|
||||||
|
`physical_fact_status` VARCHAR(128) DEFAULT NULL COMMENT '物理事实状态',
|
||||||
`delivery_status` VARCHAR(128) DEFAULT NULL COMMENT '交付状态',
|
`delivery_status` VARCHAR(128) DEFAULT NULL COMMENT '交付状态',
|
||||||
`approval_status` VARCHAR(128) DEFAULT NULL COMMENT '审批状态',
|
`approval_status` VARCHAR(128) DEFAULT NULL COMMENT '审批状态',
|
||||||
|
`approval_decision_status` VARCHAR(128) DEFAULT NULL COMMENT '审批裁决状态',
|
||||||
`confirmed_at` VARCHAR(64) DEFAULT NULL COMMENT '确认时间',
|
`confirmed_at` VARCHAR(64) DEFAULT NULL COMMENT '确认时间',
|
||||||
`report_date` VARCHAR(64) DEFAULT NULL COMMENT '日报日期',
|
`report_date` VARCHAR(64) DEFAULT NULL COMMENT '日报日期',
|
||||||
|
`send_record_id` VARCHAR(255) DEFAULT NULL COMMENT '发送记录ID',
|
||||||
|
`send_channel` VARCHAR(128) DEFAULT NULL COMMENT '发送渠道',
|
||||||
|
`send_request_status` VARCHAR(128) DEFAULT NULL COMMENT '发送请求状态',
|
||||||
|
`send_record_status` VARCHAR(128) DEFAULT NULL COMMENT '发送记录状态',
|
||||||
|
`materialized_source` VARCHAR(128) DEFAULT NULL COMMENT '物化来源',
|
||||||
`business_view` JSON DEFAULT NULL COMMENT '业务视图快照',
|
`business_view` JSON DEFAULT NULL COMMENT '业务视图快照',
|
||||||
`synced_at` DATETIME DEFAULT NULL COMMENT '同步时间',
|
`synced_at` DATETIME DEFAULT NULL COMMENT '同步时间',
|
||||||
`modified` DATETIME NOT NULL COMMENT '修改时间',
|
`modified` DATETIME NOT NULL COMMENT '修改时间',
|
||||||
|
|||||||
@@ -1223,6 +1223,10 @@ const DigitalEmployeeOps: React.FC = () => {
|
|||||||
{detailRecord.report_id || detailRecord.entity_id || '--'}
|
{detailRecord.report_id || detailRecord.entity_id || '--'}
|
||||||
{detailRecord.daily_report_fact_id &&
|
{detailRecord.daily_report_fact_id &&
|
||||||
` · 事实 ${detailRecord.daily_report_fact_id}`}
|
` · 事实 ${detailRecord.daily_report_fact_id}`}
|
||||||
|
{detailRecord.daily_report_table &&
|
||||||
|
` · 正式日报物理表 ${detailRecord.daily_report_table}`}
|
||||||
|
{detailRecord.daily_report_materialized != null &&
|
||||||
|
` · 物化 ${detailRecord.daily_report_materialized ? '已写入' : '未写入'}`}
|
||||||
{detailRecord.daily_report_physical_fact_status &&
|
{detailRecord.daily_report_physical_fact_status &&
|
||||||
` · 物理事实 ${detailRecord.daily_report_physical_fact_status}`}
|
` · 物理事实 ${detailRecord.daily_report_physical_fact_status}`}
|
||||||
{detailRecord.send_record_id &&
|
{detailRecord.send_record_id &&
|
||||||
@@ -1230,8 +1234,11 @@ const DigitalEmployeeOps: React.FC = () => {
|
|||||||
{detailRecord.send_channel && ` · 渠道 ${detailRecord.send_channel}`}
|
{detailRecord.send_channel && ` · 渠道 ${detailRecord.send_channel}`}
|
||||||
{detailRecord.send_request_status &&
|
{detailRecord.send_request_status &&
|
||||||
` · 发送请求状态 ${detailRecord.send_request_status}`}
|
` · 发送请求状态 ${detailRecord.send_request_status}`}
|
||||||
|
{detailRecord.send_record_status &&
|
||||||
|
` · 发送记录物化 ${detailRecord.send_record_status}`}
|
||||||
{detailRecord.approval_decision_status &&
|
{detailRecord.approval_decision_status &&
|
||||||
` · 审批状态 ${detailRecord.approval_decision_status}`}
|
` · 审批状态 ${detailRecord.approval_decision_status}`}
|
||||||
|
{detailRecord.formal_daily_report_page_disabled && ' · 正式外部日报页面禁用'}
|
||||||
{detailRecord.external_send_disabled && ' · 外部发送禁用'}
|
{detailRecord.external_send_disabled && ' · 外部发送禁用'}
|
||||||
{detailRecord.third_party_channel_disabled && ' · 第三方发送禁用'}
|
{detailRecord.third_party_channel_disabled && ' · 第三方发送禁用'}
|
||||||
{detailRecord.daily_report_approval_id &&
|
{detailRecord.daily_report_approval_id &&
|
||||||
@@ -1246,7 +1253,7 @@ const DigitalEmployeeOps: React.FC = () => {
|
|||||||
` · 裁决记录 ${detailRecord.daily_report_approval_recorded_at}`}
|
` · 裁决记录 ${detailRecord.daily_report_approval_recorded_at}`}
|
||||||
<Typography.Text type="secondary">
|
<Typography.Text type="secondary">
|
||||||
{' '}
|
{' '}
|
||||||
· 展示发送记录、审批状态、审批裁决、物理事实状态和事实来源,只记录发送请求/发送结果/审批/回执/裁决意图,不触发真实外部发送或第三方发送。
|
· 展示正式日报物理表、发送记录物化、审批状态、审批裁决、物理事实状态和事实来源,只记录发送请求/发送结果/审批/回执/裁决意图,不触发真实外部发送或第三方发送,正式外部日报页面仍禁用。
|
||||||
</Typography.Text>
|
</Typography.Text>
|
||||||
</Typography.Paragraph>
|
</Typography.Paragraph>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -652,10 +652,14 @@ export interface DigitalEmployeeAdminWorkbenchRow {
|
|||||||
conflict_status?: string;
|
conflict_status?: string;
|
||||||
report_id?: string;
|
report_id?: string;
|
||||||
daily_report_fact_id?: string;
|
daily_report_fact_id?: string;
|
||||||
|
daily_report_table?: string;
|
||||||
|
daily_report_materialized?: boolean;
|
||||||
daily_report_physical_fact_status?: string;
|
daily_report_physical_fact_status?: string;
|
||||||
send_record_id?: string;
|
send_record_id?: string;
|
||||||
send_channel?: string;
|
send_channel?: string;
|
||||||
send_request_status?: string;
|
send_request_status?: string;
|
||||||
|
send_record_status?: string;
|
||||||
|
formal_daily_report_page_disabled?: boolean;
|
||||||
external_send_disabled?: boolean;
|
external_send_disabled?: boolean;
|
||||||
third_party_channel_disabled?: boolean;
|
third_party_channel_disabled?: boolean;
|
||||||
approval_decision_status?: string;
|
approval_decision_status?: string;
|
||||||
|
|||||||
@@ -3129,20 +3129,66 @@ function checkDigitalAdminDailyReportWorkbench() {
|
|||||||
const qimingOps = fs.readFileSync(qimingOpsPath, "utf8");
|
const qimingOps = fs.readFileSync(qimingOpsPath, "utf8");
|
||||||
const qimingTypes = fs.readFileSync(qimingTypesPath, "utf8");
|
const qimingTypes = fs.readFileSync(qimingTypesPath, "utf8");
|
||||||
const docs = fs.readFileSync(docsPath, "utf8");
|
const docs = fs.readFileSync(docsPath, "utf8");
|
||||||
|
const dailyReportFactEntity = fs.readFileSync(
|
||||||
|
path.join(
|
||||||
|
backendRoot,
|
||||||
|
"app-platform-modules",
|
||||||
|
"app-platform-agent",
|
||||||
|
"app-platform-agent-core-adapter",
|
||||||
|
"src",
|
||||||
|
"main",
|
||||||
|
"java",
|
||||||
|
"com",
|
||||||
|
"xspaceagi",
|
||||||
|
"agent",
|
||||||
|
"core",
|
||||||
|
"adapter",
|
||||||
|
"repository",
|
||||||
|
"entity",
|
||||||
|
"DigitalEmployeeDailyReportFact.java",
|
||||||
|
),
|
||||||
|
"utf8",
|
||||||
|
);
|
||||||
|
const sql = fs.readFileSync(path.join(backendRoot, "sql", "update-20260612.sql"), "utf8");
|
||||||
const requiredSnippets = [
|
const requiredSnippets = [
|
||||||
[service, "daily_reports", "backend daily report view"],
|
[service, "daily_reports", "backend daily report view"],
|
||||||
[service, "isDailyReportRow", "backend daily report matcher"],
|
[service, "isDailyReportRow", "backend daily report matcher"],
|
||||||
[service, "daily_report", "backend daily report category"],
|
[service, "daily_report", "backend daily report category"],
|
||||||
[service, "daily_report:record_approval_decision", "backend daily report approval decision action"],
|
[service, "daily_report:record_approval_decision", "backend daily report approval decision action"],
|
||||||
|
[service, "daily_report_table", "backend daily report table projection"],
|
||||||
|
[service, "daily_report_materialized", "backend daily report materialized projection"],
|
||||||
|
[service, "send_record_status", "backend send record status projection"],
|
||||||
|
[service, "formal_daily_report_page_disabled", "backend formal daily report page guard projection"],
|
||||||
[dto, "report_id", "backend report id row field"],
|
[dto, "report_id", "backend report id row field"],
|
||||||
|
[dto, "daily_report_table", "backend daily report table row field"],
|
||||||
|
[dto, "daily_report_materialized", "backend daily report materialized row field"],
|
||||||
|
[dto, "send_record_status", "backend send record status row field"],
|
||||||
|
[dto, "formal_daily_report_page_disabled", "backend formal daily report page guard row field"],
|
||||||
[dto, "daily_report_approval_id", "backend daily report approval id row field"],
|
[dto, "daily_report_approval_id", "backend daily report approval id row field"],
|
||||||
[dto, "daily_report_approval_action", "backend daily report approval action row field"],
|
[dto, "daily_report_approval_action", "backend daily report approval action row field"],
|
||||||
[dto, "daily_report_approval_recorded_at", "backend daily report approval recorded at row field"],
|
[dto, "daily_report_approval_recorded_at", "backend daily report approval recorded at row field"],
|
||||||
|
[dailyReportFactEntity, "dailyReportFactId", "daily report fact entity fact id field"],
|
||||||
|
[dailyReportFactEntity, "physicalFactStatus", "daily report fact entity physical status field"],
|
||||||
|
[dailyReportFactEntity, "sendRecordStatus", "daily report fact entity send status field"],
|
||||||
|
[dailyReportFactEntity, "materializedSource", "daily report fact entity materialized source field"],
|
||||||
|
[sql, "daily_report_fact_id", "daily report fact sql fact id column"],
|
||||||
|
[sql, "physical_fact_status", "daily report fact sql physical status column"],
|
||||||
|
[sql, "send_record_status", "daily report fact sql send status column"],
|
||||||
|
[sql, "materialized_source", "daily report fact sql materialized source column"],
|
||||||
[test, "queryAdminWorkbenchDailyReportsReturnsDailyReportRowsOnly", "backend daily report workbench test"],
|
[test, "queryAdminWorkbenchDailyReportsReturnsDailyReportRowsOnly", "backend daily report workbench test"],
|
||||||
|
[test, "syncOutboxMaterializesDailyReportPhysicalFactAndSendRecord", "backend daily report physical fact materialization test"],
|
||||||
|
[test, "queryAdminWorkbenchDailyReportsReturnsPhysicalFactAndSendShellRows", "backend daily report physical send shell test"],
|
||||||
[test, "getDailyReportApprovalId", "backend daily report approval assertion"],
|
[test, "getDailyReportApprovalId", "backend daily report approval assertion"],
|
||||||
[qimingTypes, "daily_reports", "qiming daily report view type"],
|
[qimingTypes, "daily_reports", "qiming daily report view type"],
|
||||||
|
[qimingTypes, "daily_report_table", "qiming daily report table type field"],
|
||||||
|
[qimingTypes, "daily_report_materialized", "qiming daily report materialized type field"],
|
||||||
|
[qimingTypes, "send_record_status", "qiming send record status type field"],
|
||||||
|
[qimingTypes, "formal_daily_report_page_disabled", "qiming formal daily report page guard type field"],
|
||||||
[qimingTypes, "daily_report_approval_id", "qiming daily report approval id type field"],
|
[qimingTypes, "daily_report_approval_id", "qiming daily report approval id type field"],
|
||||||
[qimingOps, "日报运营", "qiming daily report tab"],
|
[qimingOps, "日报运营", "qiming daily report tab"],
|
||||||
|
[qimingOps, "正式日报物理表", "qiming formal daily report physical table copy"],
|
||||||
|
[qimingOps, "发送记录物化", "qiming send record materialized copy"],
|
||||||
|
[qimingOps, "正式外部日报页面禁用", "qiming formal daily report page disabled copy"],
|
||||||
[qimingOps, "记录已送达", "qiming daily report delivered action"],
|
[qimingOps, "记录已送达", "qiming daily report delivered action"],
|
||||||
[qimingOps, "确认回执", "qiming daily report confirmed action"],
|
[qimingOps, "确认回执", "qiming daily report confirmed action"],
|
||||||
[qimingOps, "请求审批", "qiming daily report approval action"],
|
[qimingOps, "请求审批", "qiming daily report approval action"],
|
||||||
@@ -3150,6 +3196,7 @@ function checkDigitalAdminDailyReportWorkbench() {
|
|||||||
[qimingOps, "记录发送结果", "qiming daily report send record action"],
|
[qimingOps, "记录发送结果", "qiming daily report send record action"],
|
||||||
[docs, "正式管理端日报运营预览", "docs daily report absorption"],
|
[docs, "正式管理端日报运营预览", "docs daily report absorption"],
|
||||||
[docs, "管理端日报审批裁决回写预览", "docs daily report approval decision absorption"],
|
[docs, "管理端日报审批裁决回写预览", "docs daily report approval decision absorption"],
|
||||||
|
[docs, "正式日报物理事实与发送记录预览已开始吸收", "docs daily report physical fact send record absorption"],
|
||||||
];
|
];
|
||||||
const missing = requiredSnippets
|
const missing = requiredSnippets
|
||||||
.filter(([content, snippet]) => !content.includes(snippet))
|
.filter(([content, snippet]) => !content.includes(snippet))
|
||||||
|
|||||||
@@ -614,9 +614,9 @@ GET /api/digital-employee/approvals
|
|||||||
- 建议:先使用 sync record 派生业务查询模型和 embedded 业务视图预览承接联调,再按容量和查询压力决定是否拆 Plan / Task / Run / Event 物理业务表。
|
- 建议:先使用 sync record 派生业务查询模型和 embedded 业务视图预览承接联调,再按容量和查询压力决定是否拆 Plan / Task / Run / Event 物理业务表。
|
||||||
|
|
||||||
13. **日报实体与导出交付**
|
13. **日报实体与导出交付**
|
||||||
- 已吸收:embedded 页面可基于当前 workday projection 导出本地文本日报;生成日报时会通过 qimingclaw bridge 写入 `daily_report` text / HTML / PDF Artifact 与 `daily_report_generated` Event,并可通过 `/api/digital-employee/daily-reports` 和详情接口读取只读日报投影。日报 HTML/PDF 导出、发送记录、管理端确认回执和日报发送审批已开始吸收,交付动作会写入 `daily_report_send_recorded` / `daily_report_confirmed` / `daily_report_approval_requested` 事件,sync `business_view.category = daily_report` 可被管理端筛选消费。管理端正式日报页面预览和正式管理端日报运营预览已开始吸收,embedded 新增“日报运营”入口,展示日报生成、交付、确认、审批和关联产物状态,并复用现有生成、记录发送、确认回执和请求审批动作;qiming-backend 的 `daily_reports` 运营台视图会聚合日报生成、发送记录、确认回执和审批请求,qiming“数字员工运营台”的“日报运营”tab 可记录已送达、确认回执、请求审批和发送结果。发送账单审计外壳已开始吸收,qiming-backend 新增 `/api/digital-employee/admin/daily-reports/send-records`,qiming 运营台可在日报详情中“记录发送结果”,但不接真实第三方发送通道。正式管理端协作运营收口已开始吸收,日报运营详情会展示 `daily_report_fact_id`、`send_record_id` 和 `approval_decision_status`,用于解释事实来源、发送记录和审批状态。管理端日报审批裁决回写预览已开始吸收,日报运营详情可展示 `daily_report_approval_id`、裁决动作、裁决人、原因和记录时间,并只记录审批裁决意图,不触发真实发送或自动审批。资产通知日报业务查询总收口已开始吸收,日报运营详情会补充 `daily_report_physical_fact_status`、发送渠道、发送请求状态、外部发送禁用和第三方发送禁用说明。
|
- 已吸收:embedded 页面可基于当前 workday projection 导出本地文本日报;生成日报时会通过 qimingclaw bridge 写入 `daily_report` text / HTML / PDF Artifact 与 `daily_report_generated` Event,并可通过 `/api/digital-employee/daily-reports` 和详情接口读取只读日报投影。日报 HTML/PDF 导出、发送记录、管理端确认回执和日报发送审批已开始吸收,交付动作会写入 `daily_report_send_recorded` / `daily_report_confirmed` / `daily_report_approval_requested` 事件,sync `business_view.category = daily_report` 可被管理端筛选消费。管理端正式日报页面预览和正式管理端日报运营预览已开始吸收,embedded 新增“日报运营”入口,展示日报生成、交付、确认、审批和关联产物状态,并复用现有生成、记录发送、确认回执和请求审批动作;qiming-backend 的 `daily_reports` 运营台视图会聚合日报生成、发送记录、确认回执和审批请求,qiming“数字员工运营台”的“日报运营”tab 可记录已送达、确认回执、请求审批和发送结果。发送账单审计外壳已开始吸收,qiming-backend 新增 `/api/digital-employee/admin/daily-reports/send-records`,qiming 运营台可在日报详情中“记录发送结果”,但不接真实第三方发送通道。正式管理端协作运营收口已开始吸收,日报运营详情会展示 `daily_report_fact_id`、`send_record_id` 和 `approval_decision_status`,用于解释事实来源、发送记录和审批状态。管理端日报审批裁决回写预览已开始吸收,日报运营详情可展示 `daily_report_approval_id`、裁决动作、裁决人、原因和记录时间,并只记录审批裁决意图,不触发真实发送或自动审批。资产通知日报业务查询总收口已开始吸收,日报运营详情会补充 `daily_report_physical_fact_status`、发送渠道、发送请求状态、外部发送禁用和第三方发送禁用说明。正式日报物理事实与发送记录预览已开始吸收,后端复用 `digital_employee_daily_report_fact` 增量物化日报事实、物理事实状态、审批裁决状态、发送记录状态和物化来源,qiming 日报运营详情展示正式日报物理表、发送记录物化和正式外部日报页面禁用状态。
|
||||||
- 缺口:没有正式 DailyReport 物理表、真实管理端发送通道和正式外部管理端日报页面。
|
- 缺口:真实管理端发送通道、第三方发送通道、更完整 DailyReport 物理模型和正式外部管理端日报页面。
|
||||||
- 建议:先稳定 Artifact/Event 派生日报交付模型,再根据管理端联调需要决定是否物化 DailyReport 表与发送记录表。
|
- 建议:先稳定 `digital_employee_daily_report_fact` 增量物化与 Artifact/Event 派生交付模型,再根据管理端联调需要决定是否扩展正式 DailyReport 表、发送记录表和外部页面。
|
||||||
|
|
||||||
## 管理端联动原则
|
## 管理端联动原则
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user