WACP3R 自动发现并复跑审批补偿拉取
这个提交包含在:
@@ -89,11 +89,15 @@ describe("check-wecom-approval-compensation-poc", () => {
|
||||
"--size=50",
|
||||
"--template=leave:tpl-leave",
|
||||
"--template=missed_punch:tpl-missed",
|
||||
"--discover-template-ids",
|
||||
"--discover-applicant-employee-no=SMOKE002",
|
||||
]);
|
||||
|
||||
expect(options.live).toBe(true);
|
||||
expect(options.format).toBe("json");
|
||||
expect(options.size).toBe(50);
|
||||
expect(options.discoverTemplateIds).toBe(true);
|
||||
expect(options.discoverApplicantEmployeeNo).toBe("SMOKE002");
|
||||
expect(options.templates).toEqual({
|
||||
leave: "tpl-leave",
|
||||
missed_punch: "tpl-missed",
|
||||
@@ -218,6 +222,120 @@ describe("check-wecom-approval-compensation-poc", () => {
|
||||
expect(report.checks.targets.every((item) => item.status === "DRY_RUN_READY")).toBe(true);
|
||||
});
|
||||
|
||||
it("auto-discovers missing template IDs by applicant creator without leaking full identifiers", async () => {
|
||||
const discoveredLeaveTemplateId = "tpllv-auto-discovered-leave-sensitive";
|
||||
const discoveredMissedTemplateId = "tplmp-auto-discovered-missed-sensitive";
|
||||
const fetchApprovalInfoListImpl = vi.fn(async ({ filters }) => {
|
||||
if (filters[0].key === "creator") {
|
||||
return {
|
||||
ok: true,
|
||||
tokenSource: "WECOM_AGENT_SECRET",
|
||||
response: {
|
||||
errcode: 0,
|
||||
spNoCount: 2,
|
||||
spNoPrefixes: [maskApprovalIdentifier("sp-discovery-leave"), maskApprovalIdentifier("sp-discovery-missed")],
|
||||
},
|
||||
spNos: ["sp-discovery-leave", "sp-discovery-missed"],
|
||||
nextCursor: "",
|
||||
};
|
||||
}
|
||||
return {
|
||||
ok: true,
|
||||
tokenSource: "WECOM_AGENT_SECRET",
|
||||
response: {
|
||||
errcode: 0,
|
||||
spNoCount: 1,
|
||||
spNoPrefixes: [maskApprovalIdentifier(`${filters[0].value}-sp`)],
|
||||
},
|
||||
spNos: [`${filters[0].value}-sp`],
|
||||
nextCursor: "",
|
||||
};
|
||||
});
|
||||
const fetchApprovalDetailImpl = vi.fn(async ({ spNo }) => {
|
||||
if (spNo === "sp-discovery-leave") {
|
||||
return {
|
||||
ok: true,
|
||||
tokenSource: "WECOM_AGENT_SECRET",
|
||||
templateId: discoveredLeaveTemplateId,
|
||||
spName: "OA-POC-请假-2026-05-19",
|
||||
summary: detailSummary(spNo, { templateIdPrefix: maskApprovalIdentifier(discoveredLeaveTemplateId) }),
|
||||
response: { errcode: 0, spStatus: "2" },
|
||||
};
|
||||
}
|
||||
if (spNo === "sp-discovery-missed") {
|
||||
return {
|
||||
ok: true,
|
||||
tokenSource: "WECOM_AGENT_SECRET",
|
||||
templateId: discoveredMissedTemplateId,
|
||||
spName: "OA-POC-补卡-2026-05-19",
|
||||
summary: detailSummary(spNo, { templateIdPrefix: maskApprovalIdentifier(discoveredMissedTemplateId) }),
|
||||
response: { errcode: 0, spStatus: "2" },
|
||||
};
|
||||
}
|
||||
return {
|
||||
ok: true,
|
||||
tokenSource: "WECOM_AGENT_SECRET",
|
||||
summary: detailSummary(spNo, {
|
||||
templateIdPrefix: spNo.startsWith(discoveredLeaveTemplateId)
|
||||
? maskApprovalIdentifier(discoveredLeaveTemplateId)
|
||||
: maskApprovalIdentifier(discoveredMissedTemplateId),
|
||||
}),
|
||||
response: { errcode: 0, spStatus: "2" },
|
||||
};
|
||||
});
|
||||
|
||||
const report = await executeCompensationPoc(baseOptions({
|
||||
templates: {},
|
||||
discoverTemplateIds: true,
|
||||
discoverApplicantEmployeeNo: "SMOKE002",
|
||||
}), {
|
||||
config: baseConfig(),
|
||||
env: {},
|
||||
generatedAt: "2026-05-20T00:00:00.000Z",
|
||||
queryApplicantActorImpl: vi.fn(async () => ({
|
||||
employeeNo: "SMOKE002",
|
||||
status: "active",
|
||||
archived: false,
|
||||
wecomExternalUserId: SENSITIVE_USER_ID,
|
||||
})),
|
||||
fetchApprovalInfoListImpl,
|
||||
fetchApprovalDetailImpl,
|
||||
readCallbackEvidenceImpl: vi.fn(async () => [
|
||||
{
|
||||
callbackKind: "approval_status_change",
|
||||
spStatus: "2",
|
||||
statusLabel: "已通过",
|
||||
spNoPrefix: maskApprovalIdentifier(`${discoveredLeaveTemplateId}-sp`),
|
||||
},
|
||||
{
|
||||
callbackKind: "approval_status_change",
|
||||
spStatus: "2",
|
||||
statusLabel: "已通过",
|
||||
spNoPrefix: maskApprovalIdentifier(`${discoveredMissedTemplateId}-sp`),
|
||||
},
|
||||
]),
|
||||
});
|
||||
|
||||
expect(report.status).toBe("PASS_COMPENSATION_POC");
|
||||
expect(fetchApprovalInfoListImpl.mock.calls[0][0].filters).toEqual([
|
||||
{ key: "creator", value: SENSITIVE_USER_ID },
|
||||
]);
|
||||
expect(fetchApprovalInfoListImpl.mock.calls[1][0].filters).toEqual([
|
||||
{ key: "template_id", value: discoveredLeaveTemplateId },
|
||||
]);
|
||||
expect(fetchApprovalInfoListImpl.mock.calls[2][0].filters).toEqual([
|
||||
{ key: "template_id", value: discoveredMissedTemplateId },
|
||||
]);
|
||||
const serialized = JSON.stringify(report);
|
||||
expect(serialized).not.toContain(discoveredLeaveTemplateId);
|
||||
expect(serialized).not.toContain(discoveredMissedTemplateId);
|
||||
expect(serialized).not.toContain(SENSITIVE_USER_ID);
|
||||
expect(report.checks.templateDiscovery.discoveredTemplatePrefixes).toEqual({
|
||||
leave: maskApprovalIdentifier(discoveredLeaveTemplateId),
|
||||
missed_punch: maskApprovalIdentifier(discoveredMissedTemplateId),
|
||||
});
|
||||
});
|
||||
|
||||
it("pulls approval numbers and details, then passes when callback evidence matches", async () => {
|
||||
const fetchApprovalInfoListImpl = vi.fn(async ({ filters }) => ({
|
||||
ok: true,
|
||||
@@ -310,6 +428,34 @@ describe("check-wecom-approval-compensation-poc", () => {
|
||||
expect(report.checks.callbackCompare.findings.map((item) => item.id)).toContain("callback_status_mismatch");
|
||||
});
|
||||
|
||||
it("treats missing callback evidence after successful detail pull as findings", async () => {
|
||||
const report = await executeCompensationPoc(baseOptions({
|
||||
templates: { leave: SENSITIVE_TEMPLATE_ID, missed_punch: "tpl-missed-punch" },
|
||||
}), {
|
||||
config: baseConfig(),
|
||||
env: {},
|
||||
generatedAt: "2026-05-20T00:00:00.000Z",
|
||||
fetchApprovalInfoListImpl: vi.fn(async () => ({
|
||||
ok: true,
|
||||
tokenSource: "WECOM_AGENT_SECRET",
|
||||
response: { errcode: 0, spNoCount: 1 },
|
||||
spNos: [SENSITIVE_SP_NO],
|
||||
nextCursor: "",
|
||||
})),
|
||||
fetchApprovalDetailImpl: vi.fn(async ({ spNo }) => ({
|
||||
ok: true,
|
||||
tokenSource: "WECOM_AGENT_SECRET",
|
||||
summary: detailSummary(spNo, { spStatus: "2" }),
|
||||
response: { errcode: 0, spStatus: "2" },
|
||||
})),
|
||||
readCallbackEvidenceImpl: vi.fn(async () => []),
|
||||
});
|
||||
|
||||
expect(report.status).toBe("PASS_WITH_FINDINGS");
|
||||
expect(report.configGaps.map((item) => item.id)).not.toContain("callback_evidence_missing");
|
||||
expect(report.checks.callbackCompare.findings.map((item) => item.id)).toContain("callback_missing_for_pulled_detail");
|
||||
});
|
||||
|
||||
it("classifies WeCom API errors as BLOCKED_BY_EXTERNAL_CONFIG", async () => {
|
||||
const report = await executeCompensationPoc(baseOptions({
|
||||
templates: { leave: SENSITIVE_TEMPLATE_ID },
|
||||
|
||||
在新工单中引用
屏蔽一个用户