补齐审批退回结果通知 [09-04-approval-return-notification-gap]

这个提交包含在:
2026-09-04 16:22:27 +08:00
父节点 a6ffb7fc3c
当前提交 2e69fe4edb
共修改 19 个文件,包含 857 行新增和 14 行删除
@@ -150,6 +150,14 @@ async function buildApp(options = {}) {
create: vi.fn(async () => ({ id: "delivery-1" })),
update: vi.fn(async () => ({})),
},
notification: {
create: vi.fn(async ({ data }) => {
if (options.notificationCreateError) {
throw options.notificationCreateError;
}
return { id: "notification-1", ...data };
}),
},
};
const prisma = {
@@ -295,6 +303,50 @@ describe("workflow batch routes", () => {
await app.close();
});
it("keeps a return committed when outcome notification creation fails", async () => {
const { app, state, tx } = await buildApp({
notificationCreateError: new Error("synthetic notification failure"),
});
const taskId = "11111111-1111-4111-8111-111111111111";
const response = await app.inject({
method: "POST",
url: `/api/workflow/tasks/${taskId}/return`,
payload: {
comment: "材料不完整,请修改后重新提交。",
},
});
expect(response.statusCode).toBe(200);
expect(response.json().data).toEqual(
expect.objectContaining({
taskId,
outcome: "returned",
reimbursementStatus: "draft",
}),
);
expect(tx.notification.create).toHaveBeenCalledTimes(1);
expect(state.tasks.get(taskId)).toEqual(
expect.objectContaining({
status: "completed",
outcome: "returned",
}),
);
expect(tx.reimbursementForm.update).toHaveBeenCalledWith({
where: { id: taskId },
data: expect.objectContaining({ status: "draft" }),
});
expect(state.history).toEqual([
expect.objectContaining({
instance_id: taskId,
task_id: taskId,
action: "return",
}),
]);
await app.close();
});
it("does not roll back successful tasks when one task fails or has unsupported entity type", async () => {
const { app, state } = await buildApp({
updateErrorTaskId: "44444444-4444-4444-8444-444444444444",