实现报销费用政策与票据明细门禁(08-29-reimbursement-expense-policy-invoice-guard)
这个提交包含在:
@@ -48,6 +48,49 @@ describe("default travel expense types", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("reimbursement expense policy defaults", () => {
|
||||
it("keeps only the two allowances invoice-free and replaces ambiguous selectable types", () => {
|
||||
expect(ENABLED_EXPENSE_TYPES).toEqual(expect.arrayContaining([
|
||||
expect.objectContaining({ code: "business_client_meal", name: "业务招待费" }),
|
||||
expect.objectContaining({ code: "business_meeting", name: "会议费" }),
|
||||
expect.objectContaining({ code: "business_training_fee", name: "培训费" }),
|
||||
expect.objectContaining({ code: "assets_office_electronics", name: "办公电子设备" }),
|
||||
expect.objectContaining({ code: "travel_meal", requiresInvoice: false }),
|
||||
expect.objectContaining({ code: "travel_local_transport_allowance", requiresInvoice: false }),
|
||||
]));
|
||||
expect(ENABLED_EXPENSE_TYPES.some((item) => item.code === "business_training")).toBe(false);
|
||||
expect(ENABLED_EXPENSE_TYPES.some((item) => item.code === "assets_it_hardware")).toBe(false);
|
||||
});
|
||||
|
||||
it("provides employee-readable guidance for every selectable expense type", () => {
|
||||
for (const expenseType of ENABLED_EXPENSE_TYPES) {
|
||||
expect(expenseType.description, expenseType.code).toEqual(expect.any(String));
|
||||
expect(expenseType.description.trim().length, expenseType.code).toBeGreaterThan(0);
|
||||
}
|
||||
});
|
||||
|
||||
it("seeds the invoice guard disabled by default", () => {
|
||||
expect(DEFAULT_FEATURE_FLAGS).toContainEqual({
|
||||
flag_key: "reimbursement_invoice_guard_v1",
|
||||
override_mode: "force_off",
|
||||
rollout_type: "global",
|
||||
department_ids: [],
|
||||
note: "bootstrap default: force_off",
|
||||
});
|
||||
});
|
||||
|
||||
it("preserves finance-maintained account mappings during repeated init", async () => {
|
||||
const upsert = vi.fn().mockResolvedValue({});
|
||||
|
||||
await seedExpenseTypes({ expenseType: { upsert } });
|
||||
|
||||
for (const call of upsert.mock.calls) {
|
||||
expect(call[0].update).not.toHaveProperty("account_code_default");
|
||||
expect(call[0].create).toEqual(expect.objectContaining({ account_code_default: null }));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("small-team default reimbursement approval rules", () => {
|
||||
it("uses finance for every owner fallback and finance review node", () => {
|
||||
expect(DEFAULT_APPROVAL_RULES).toEqual([
|
||||
|
||||
在新工单中引用
屏蔽一个用户