fix: list unadapted XFT approval tasks safely

This commit is contained in:
2026-08-29 18:09:29 +00:00
parent b00c22d74e
commit f301cef3e8
9 changed files with 283 additions and 45 deletions
+64 -11
View File
@@ -186,30 +186,83 @@ test("Xft OpenAPI does not turn missing or blank amounts into zero", async () =>
}
});
test("Xft OpenAPI continues past an irrelevant full first todo page", async () => {
test("Xft OpenAPI keeps unadapted personal todos visible instead of filtering them", async () => {
const pages: number[] = [];
const irrelevant = Array.from({ length: 100 }, (_, index) => ({
todoTaskId: `OTHER-${index}`, groupId: `OTHER-${index}`, appCode: "other-app",
}));
const client = new XftOpenApiClient(config(), async (input, init) => {
const path = new URL(String(input)).pathname;
if (path.includes("user-mapping")) return encrypted({ code: "0", data: { records: [{ thirdStaffId: "ding-u1", enterpriseUserId: "EMP-1" }] } });
if (path.endsWith("todo-task/page/by-user")) {
const page = Number(decodedBody(init).currentPage);
pages.push(page);
return encrypted({ code: "0", data: { records: page === 1 ? irrelevant : [{
todoTaskId: "TD-TARGET", groupId: "2026081400000001", appCode: "xft-itrip",
}] } });
return encrypted({ code: "0", data: { records: [{
todoTaskId: "OTHER-1", groupId: "OTHER-1", appCode: "other-app", title: "其他审批",
}], totalSize: 1 } });
}
if (path.endsWith("todo-task/detail/by-ids")) return encrypted({ code: "0", data: [] });
throw new Error(`unexpected ${path}`);
});
const result = await client.listMyTodos({ userId: "ding-u1" }, 10);
assert.equal(result.items[0]?.title, "其他审批");
assert.equal(result.items[0]?.capability, "list_only");
assert.equal(result.items[0]?.unavailableReason, "missing_bill_identifier");
assert.equal(result.diagnostics.billApiCount, 0);
assert.equal(result.diagnostics.clientOnlyCount, 1);
assert.deepEqual(pages, [1]);
});
test("Xft OpenAPI upgrades an unknown app todo when the official bill API recognizes it", async () => {
const targetBillId = "2026081400000001";
const client = new XftOpenApiClient(config(), async (input) => {
const path = new URL(String(input)).pathname;
if (path.includes("user-mapping")) return encrypted({ code: "0", data: { records: [{ thirdStaffId: "ding-u1", enterpriseUserId: "EMP-1" }] } });
if (path.endsWith("todo-task/page/by-user")) return encrypted({ code: "0", data: { records: [{
todoTaskId: "TD-INVITATION", groupId: targetBillId, appCode: "new-approval-app",
}], totalSize: 1 } });
if (path.endsWith("todo-task/detail/by-ids")) return encrypted({ code: "0", data: [] });
if (path.endsWith("bill-list")) return encrypted({ code: "0", data: { list: [{
billId: "2026081400000001", eventType: "COMMON_REIM", title: "目标费用单",
billId: targetBillId, eventType: "INVITATION_APPLY", title: "招待费用申请单",
}] } });
throw new Error(`unexpected ${path}`);
});
const result = await client.listMyTodos({ userId: "ding-u1" }, 1);
assert.equal(result.items[0]?.billId, "2026081400000001");
assert.deepEqual(pages, [1, 2]);
const result = await client.listMyTodos({ userId: "ding-u1" }, 10);
assert.equal(result.items[0]?.billId, targetBillId);
assert.equal(result.items[0]?.title, "招待费用申请单");
assert.equal(result.items[0]?.capability, "bill_api");
assert.equal(result.diagnostics.billApiCount, 1);
assert.equal(result.diagnostics.clientOnlyCount, 0);
});
test("Xft OpenAPI degrades a failed unknown bill probe without hiding known expense todos", async () => {
const knownBillId = "2026081400000001";
const unknownBillId = "2026081400000002";
const client = new XftOpenApiClient(config(), async (input, init) => {
const path = new URL(String(input)).pathname;
if (path.includes("user-mapping")) return encrypted({ code: "0", data: { records: [{ thirdStaffId: "ding-u1", enterpriseUserId: "EMP-1" }] } });
if (path.endsWith("todo-task/page/by-user")) return encrypted({ code: "0", data: { records: [{
todoTaskId: "TD-KNOWN", groupId: knownBillId, appCode: "xft-itrip",
}, {
todoTaskId: "TD-UNKNOWN", groupId: unknownBillId, appCode: "new-approval-app", title: "新类型审批",
}], totalSize: 2 } });
if (path.endsWith("todo-task/detail/by-ids")) return encrypted({ code: "0", data: [] });
if (path.endsWith("bill-list")) {
const ids = (decodedBody(init).billIds as Array<string | number>).map(String);
if (ids.includes(unknownBillId)) return encrypted({ code: "BIZ_LOOKUP_FAILED", message: "lookup unavailable" });
return encrypted({ code: "0", data: { list: [{ billId: knownBillId, eventType: "COMMON_REIM", title: "费用报销单" }] } });
}
throw new Error(`unexpected ${path}`);
});
const result = await client.listMyTodos({ userId: "ding-u1" }, 10);
assert.equal(result.items.length, 2);
assert.equal(result.items[0]?.billId, knownBillId);
assert.equal(result.items[0]?.capability, "bill_api");
assert.equal(result.items[1]?.title, "新类型审批");
assert.equal(result.items[1]?.billId, undefined);
assert.equal(result.items[1]?.capability, "list_only");
assert.equal(result.items[1]?.unavailableReason, "bill_lookup_unavailable");
assert.equal(result.diagnostics.billApiCount, 1);
assert.equal(result.diagnostics.clientOnlyCount, 1);
});
test("Xft write transport failures are uncertain while deterministic rejections stay failed", async () => {