WARCH2 增加企微审批历史只读查询

这个提交包含在:
2026-05-20 10:23:23 +08:00
父节点 7a32399ca9
当前提交 123ebc9c95
共修改 23 个文件,包含 1358 行新增和 36 行删除
@@ -1,5 +1,6 @@
const {
normalizeApprovalDetailPayload,
listApprovalArchives,
persistApprovalDetail,
publicArchiveSummary,
recordApprovalCallbackEvent,
@@ -132,6 +133,78 @@ describe("wecomApprovalArchive", () => {
expect(JSON.stringify(summary)).not.toContain(SENSITIVE_TEMPLATE_ID);
});
it("lists query archives with whitelist-only DTO fields", async () => {
const archive = {
id: "archive-1",
sp_no: SENSITIVE_SP_NO,
template_id: SENSITIVE_TEMPLATE_ID,
template_type: "leave",
sp_name: "OA-POC-请假",
normalized_status: "approved",
applicant_employee_id: null,
applicant_external_user_id: SENSITIVE_USER_ID,
applied_at: new Date("2026-05-19T08:00:00.000Z"),
submitted_at: new Date("2026-05-19T08:00:00.000Z"),
completed_at: new Date("2026-05-19T09:00:00.000Z"),
status_observed_at: new Date("2026-05-19T09:00:00.000Z"),
last_callback_at: null,
last_compensation_at: new Date("2026-05-19T10:00:00.000Z"),
last_source: "compensation_pull",
readability_status: "PASS_READABLE",
single_tap_approve_risk: true,
template_adjustment_required: false,
source_summary: { raw: "raw payload should not leak" },
applicant: null,
participants: [],
actions: [],
field_summaries: [{
id: "field-1",
field_key: "reason",
field_index: 1,
field_name: "请假原因",
field_type: "Textarea",
normalized_value: SENSITIVE_REASON,
value_preview: SENSITIVE_REASON.slice(0, 8),
sensitive_level: "restricted",
display_allowed: false,
}],
reconcile_findings: [{
id: "finding-1",
finding_type: "callback_missing_for_pulled_detail",
status: "open",
severity: "info",
source: "compensation_compare",
description: SENSITIVE_REASON,
detected_at: new Date("2026-05-19T11:00:00.000Z"),
resolved_at: null,
}],
};
const prisma = {
employee: { findMany: vi.fn(async () => []) },
wecomApprovalArchive: {
count: vi.fn(async () => 1),
findMany: vi.fn(async () => [archive]),
},
};
const result = await listApprovalArchives({
prisma,
actor: { id: "hr-1", roleCodes: ["hr"], permissionCodes: [] },
query: { scope: "all" },
});
expect(result.items).toHaveLength(1);
const text = JSON.stringify(result);
expect(text).not.toContain(SENSITIVE_SP_NO);
expect(text).not.toContain(SENSITIVE_TEMPLATE_ID);
expect(text).not.toContain(SENSITIVE_USER_ID);
expect(text).not.toContain(SENSITIVE_REASON);
expect(text).not.toContain("normalized_value");
expect(text).not.toContain("value_preview");
expect(text).not.toContain("source_summary");
expect(text).not.toContain("description");
});
it("persists full keys internally but returns redacted output", async () => {
const prisma = buildMockPrisma();
const result = await persistApprovalDetail({