feat(P19AI1-1,P19AI1-2): 实现AI建议引擎与权限门禁后端
这个提交包含在:
@@ -0,0 +1,100 @@
|
||||
const {
|
||||
buildAssetSnapshot,
|
||||
buildPurchaseSnapshot,
|
||||
buildReimbursementSnapshot,
|
||||
} = require("../../../src/services/ai/sanitizer");
|
||||
|
||||
describe("AI sanitizer", () => {
|
||||
it("keeps reimbursement whitelist fields only", () => {
|
||||
const snapshot = buildReimbursementSnapshot({
|
||||
id: "r-1",
|
||||
form_number: "BX-001",
|
||||
status: "paid",
|
||||
reimbursement_date: new Date("2026-03-10T00:00:00.000Z"),
|
||||
total_amount: 123.45,
|
||||
items: [
|
||||
{ amount: 100, expense_type: { category: "travel" }, description: "敏感长文本" },
|
||||
],
|
||||
invoice_pool_items: [{ status: "verified", invoice_number: "123456" }],
|
||||
owner: { id: "owner-1", name: "张三" },
|
||||
owner_id: "owner-1",
|
||||
payment_voucher_no: "PV-001",
|
||||
budgetHint: { controlMode: "warn", exceedsThreshold: true, exceedsBudget: false, nextUsagePercent: 90 },
|
||||
pendingWorkflow: { stepName: "财务复核", assigneeRole: "finance_mgr" },
|
||||
});
|
||||
|
||||
expect(snapshot).toEqual(
|
||||
expect.objectContaining({
|
||||
formNumber: "BX-001",
|
||||
status: "paid",
|
||||
totalAmount: "123.45",
|
||||
itemCount: 1,
|
||||
}),
|
||||
);
|
||||
expect(snapshot).not.toHaveProperty("owner");
|
||||
expect(snapshot).not.toHaveProperty("paymentVoucherNo");
|
||||
expect(JSON.stringify(snapshot)).not.toContain("123456");
|
||||
expect(JSON.stringify(snapshot)).not.toContain("张三");
|
||||
});
|
||||
|
||||
it("keeps purchase whitelist fields only", () => {
|
||||
const snapshot = buildPurchaseSnapshot({
|
||||
id: "p-1",
|
||||
request_no: "PR-001",
|
||||
status: "approved",
|
||||
title: "办公电脑采购计划办公电脑采购计划办公电脑采购计划办公电脑采购计划办公电脑采购计划",
|
||||
currency_code: "CNY",
|
||||
total_amount: 8888,
|
||||
supplier: { code: "SUP-1", name: "海音达供应商" },
|
||||
legal_entity: { code: "HY", name: "海音达" },
|
||||
cost_center: { code: "IT001", name: "IT中心" },
|
||||
budget_pool: { code: "B-001", name: "年度预算" },
|
||||
items: [{ is_asset_candidate: true, description: "敏感描述" }],
|
||||
order_archive: { po_no: "PO-001", contract_no: "CT-001", archived_at: new Date("2026-03-10T00:00:00.000Z") },
|
||||
submitter: { id: "u-1", name: "李四" },
|
||||
external_code: "ERP-001",
|
||||
reason: "不要进入提示的大段原因",
|
||||
});
|
||||
|
||||
expect(snapshot).toEqual(
|
||||
expect.objectContaining({
|
||||
requestNo: "PR-001",
|
||||
totalAmount: "8888.00",
|
||||
assetCandidateCount: 1,
|
||||
}),
|
||||
);
|
||||
expect(snapshot).not.toHaveProperty("submitter");
|
||||
expect(JSON.stringify(snapshot)).not.toContain("ERP-001");
|
||||
expect(JSON.stringify(snapshot)).not.toContain("不要进入提示");
|
||||
});
|
||||
|
||||
it("keeps asset whitelist fields only", () => {
|
||||
const snapshot = buildAssetSnapshot({
|
||||
id: "a-1",
|
||||
asset_no: "ZC-001",
|
||||
name: "ThinkPad X1 Carbon ThinkPad X1 Carbon ThinkPad X1 Carbon ThinkPad X1 Carbon ThinkPad X1 Carbon",
|
||||
status: "in_use",
|
||||
category: { code: "LAPTOP", name: "笔记本电脑", document_category: { code: "ASSET_STD" } },
|
||||
legal_entity: { code: "HY", name: "海音达" },
|
||||
cost_center: { code: "IT001", name: "IT中心" },
|
||||
purchase_request: { request_no: "PR-001", title: "办公电脑采购" },
|
||||
location: "上海办公室-A区",
|
||||
activated_at: new Date("2026-03-10T00:00:00.000Z"),
|
||||
retired_at: null,
|
||||
assignee_employee_id: "emp-1",
|
||||
assignee: { id: "emp-1", employee_no: "E001", name: "张三" },
|
||||
external_code: "ERP-ASSET-001",
|
||||
});
|
||||
|
||||
expect(snapshot).toEqual(
|
||||
expect.objectContaining({
|
||||
assetNo: "ZC-001",
|
||||
assignmentState: "assigned",
|
||||
location: "上海办公室-A区",
|
||||
}),
|
||||
);
|
||||
expect(snapshot).not.toHaveProperty("assignee");
|
||||
expect(JSON.stringify(snapshot)).not.toContain("张三");
|
||||
expect(JSON.stringify(snapshot)).not.toContain("ERP-ASSET-001");
|
||||
});
|
||||
});
|
||||
在新工单中引用
屏蔽一个用户