实现报销费用政策与票据明细门禁(08-29-reimbursement-expense-policy-invoice-guard)
这个提交包含在:
@@ -30,6 +30,7 @@ const TRAIN_TYPE_ID = "22222222-2222-4222-8222-222222222222";
|
||||
const BUS_TYPE_ID = "33333333-3333-4333-8333-333333333333";
|
||||
const TAXI_TYPE_ID = "44444444-4444-4444-8444-444444444444";
|
||||
const TRANSPORT_TYPE_ID = "55555555-5555-4555-8555-555555555555";
|
||||
const MEAL_ALLOWANCE_TYPE_ID = "66666666-6666-4666-8666-666666666666";
|
||||
|
||||
function cloneDate(value) {
|
||||
return value ? new Date(value) : value;
|
||||
@@ -130,6 +131,7 @@ async function buildApp(options = {}) {
|
||||
{ id: BUS_TYPE_ID, code: "travel_bus", name: "大巴车票", category: "travel", enabled: true },
|
||||
{ id: TAXI_TYPE_ID, code: "travel_taxi", name: "打车费", category: "travel", enabled: true },
|
||||
{ id: TRANSPORT_TYPE_ID, code: "transport", name: "legacy-交通费", category: "travel", enabled: true },
|
||||
{ id: MEAL_ALLOWANCE_TYPE_ID, code: "travel_meal", name: "伙食补助费", category: "travel", enabled: true, requires_invoice: false },
|
||||
],
|
||||
travelRequests: (options.travelRequests ?? [buildTravelRequest()]).map((item) => cloneTravelRequest(item)),
|
||||
auditLogs: [],
|
||||
@@ -195,6 +197,9 @@ async function buildApp(options = {}) {
|
||||
if (where?.enabled === true && !item.enabled) {
|
||||
return false;
|
||||
}
|
||||
if (where?.requires_invoice === true && item.requires_invoice !== true) {
|
||||
return false;
|
||||
}
|
||||
if (ids && !ids.includes(item.id)) {
|
||||
return false;
|
||||
}
|
||||
@@ -464,6 +469,34 @@ describe("reimbursement create enhancements", () => {
|
||||
await app.close();
|
||||
});
|
||||
|
||||
it("keeps invoice-free allowance types available to reimbursement templates", async () => {
|
||||
const { app, state } = await buildApp({
|
||||
templates: [buildTemplate({
|
||||
items: [{
|
||||
expenseTypeId: MEAL_ALLOWANCE_TYPE_ID,
|
||||
description: "伙食补助",
|
||||
defaultAmount: "300.00",
|
||||
}],
|
||||
})],
|
||||
});
|
||||
|
||||
const response = await app.inject({
|
||||
method: "POST",
|
||||
url: "/api/reimbursements",
|
||||
payload: { templateId: TEMPLATE_ID, reimbursementDate: "2026-04-09" },
|
||||
});
|
||||
|
||||
expect(response.statusCode).toBe(200);
|
||||
expect(response.json().data.items).toEqual([
|
||||
expect.objectContaining({
|
||||
expenseTypeId: MEAL_ALLOWANCE_TYPE_ID,
|
||||
amount: "300.00",
|
||||
}),
|
||||
]);
|
||||
expect(state.reimbursementItems).toHaveLength(1);
|
||||
await app.close();
|
||||
});
|
||||
|
||||
it("rejects templateId and linkedTravelRequestId when both are provided", async () => {
|
||||
const { app } = await buildApp();
|
||||
|
||||
|
||||
在新工单中引用
屏蔽一个用户