文件
hyb-oa/server/tests/unit/services/invoiceExpenseClassification.test.js
wangsli e5685f18b2
ci-e2e / e2e (push) Canceled after 0s
ci-minimal / check-minimal (push) Canceled after 0s
feat: 选票自动生成报销明细并支持集中分类(08-29-reimbursement-expense-policy-invoice-guard)
2026-09-09 23:19:02 +08:00

55 行
2.4 KiB
JavaScript

const { suggestInvoiceExpenseType } = require("../../../src/services/invoiceExpenseClassification");
const enabledTypes = [
{ id: "train-type", code: "travel_train", enabled: true },
{ id: "hotel-type", code: "travel_hotel", enabled: true },
{ id: "meal-type", code: "business_client_meal", enabled: true },
];
function invoiceWithCategory(documentCategory, extra = {}) {
return { ocr_result: { result_json: { documentCategory } }, ...extra };
}
describe("invoice expense classification", () => {
it("suggests the enabled train type from a recognized electronic train ticket", () => {
expect(suggestInvoiceExpenseType(invoiceWithCategory("electronic_train_ticket"), enabledTypes))
.toEqual({ expenseTypeId: "train-type", source: "document_category" });
});
it.each(["vat_invoice", "full_vat_invoice", "unknown", null])(
"does not guess an expense type from category %s, seller, filename or amount",
(category) => {
expect(suggestInvoiceExpenseType(invoiceWithCategory(category, {
seller_name: "合成酒店餐饮公司",
original_name: "办公用品.pdf",
total_amount: "100.00",
}), enabledTypes)).toBeNull();
},
);
it("does not substitute another enabled type when the matching type is disabled", () => {
const expenseTypes = enabledTypes.map((type) => ({ ...type, enabled: type.code !== "travel_train" }));
expect(suggestInvoiceExpenseType(invoiceWithCategory("electronic_train_ticket"), expenseTypes)).toBeNull();
});
it("does not substitute the first enabled type when the matching type is absent", () => {
expect(suggestInvoiceExpenseType(invoiceWithCategory("electronic_train_ticket"), enabledTypes.slice(1)))
.toBeNull();
});
it("does not infer from the historical provider or generic upload type", () => {
expect(suggestInvoiceExpenseType({ ocr_provider: "tencent", ocr_type: "vat" }, enabledTypes)).toBeNull();
});
it("does not infer from client-facing category fields instead of persisted OCR metadata", () => {
expect(suggestInvoiceExpenseType({ documentCategory: "electronic_train_ticket" }, enabledTypes)).toBeNull();
});
it("does not mutate invoice data or expense types", () => {
const invoice = invoiceWithCategory("electronic_train_ticket");
const before = JSON.stringify({ invoice, enabledTypes });
suggestInvoiceExpenseType(invoice, enabledTypes);
expect(JSON.stringify({ invoice, enabledTypes })).toBe(before);
});
});