补齐报销待组批财务入口 [09-04-reimbursement-state-gap-finance-view][R1]

这个提交包含在:
2026-09-05 09:14:13 +08:00
父节点 8e0af8235e
当前提交 5fe9f78bc9
共修改 9 个文件,包含 243 行新增和 67 行删除
@@ -444,7 +444,8 @@ describe("GET /api/reimbursements/:id detail enhancements", () => {
expect.objectContaining({ key: "submitted", state: "completed", actorName: "李四", result: "已提交" }),
expect.objectContaining({ key: "approval_manager-task", label: "主管审批", state: "completed", actorName: "王经理", result: "通过" }),
expect.objectContaining({ key: "approval_finance-task", label: "财务审批", state: "current", actorName: "财务专员", result: "处理中" }),
expect.objectContaining({ key: "payment_batch_review", state: "pending", actorName: null, detail: "待财务安排付款" }),
expect.objectContaining({ key: "payment_batch_created", label: "组建付款批次", state: "pending", actorName: null }),
expect.objectContaining({ key: "payment_batch_review", state: "pending", actorName: null, detail: "待付款批次创建并提交复核" }),
expect.objectContaining({ key: "payment_and_receipt", state: "pending", actorName: null }),
]);
@@ -516,6 +517,7 @@ describe("GET /api/reimbursements/:id detail enhancements", () => {
expect.objectContaining({ key: "submitted", state: "current", actorName: "张三", detail: "待申请人提交" }),
expect.objectContaining({ key: "manager_approval", state: "pending", actorName: null }),
expect.objectContaining({ key: "finance_review", state: "pending", actorName: null }),
expect.objectContaining({ key: "payment_batch_created", state: "pending", actorName: null }),
expect.objectContaining({ key: "payment_batch_review", state: "pending", actorName: null }),
expect.objectContaining({ key: "payment_and_receipt", state: "pending", actorName: null }),
]);
@@ -856,9 +858,10 @@ describe("GET /api/reimbursements/:id detail enhancements", () => {
});
expect(response.statusCode).toBe(200);
const stages = response.json().data.processingProgress.stages;
expect(stages[3]).toMatchObject({ state: reviewState, targetHref: null });
expect(stages[4]).toMatchObject({ state: paymentState, detail, targetHref: null });
if (status === "draft") expect(stages[3].actorName).toBe(null);
expect(stages[3]).toMatchObject({ key: "payment_batch_created", state: "completed", targetHref: null });
expect(stages[4]).toMatchObject({ state: reviewState, targetHref: null });
expect(stages[5]).toMatchObject({ state: paymentState, detail, targetHref: null });
if (status === "draft") expect(stages[4].actorName).toBe(null);
await app.close();
});
@@ -895,7 +898,7 @@ describe("GET /api/reimbursements/:id detail enhancements", () => {
headers: { authorization: "Bearer test" },
});
expect(response.statusCode).toBe(200);
expect(response.json().data.processingProgress.stages[3]).toMatchObject({
expect(response.json().data.processingProgress.stages[4]).toMatchObject({
detail: "待非制单人复核付款",
actorName: null,
targetHref: "/payment-batches?id=batch-1",
@@ -906,12 +909,12 @@ describe("GET /api/reimbursements/:id detail enhancements", () => {
it("attaches the payment-batch link to exactly one status-owning stage", async () => {
const cases = [
{ status: "draft", reviewedAt: null, targetIndex: 3 },
{ status: "reviewed", reviewedAt: new Date("2026-04-11T08:00:00.000Z"), targetIndex: 4 },
{ status: "executed", reviewedAt: new Date("2026-04-11T08:00:00.000Z"), targetIndex: 4 },
{ status: "failed", reviewedAt: new Date("2026-04-11T08:00:00.000Z"), targetIndex: 4 },
{ status: "cancelled", reviewedAt: null, targetIndex: 3 },
{ status: "cancelled", reviewedAt: new Date("2026-04-11T08:00:00.000Z"), targetIndex: 4 },
{ status: "draft", reviewedAt: null, targetIndex: 4 },
{ status: "reviewed", reviewedAt: new Date("2026-04-11T08:00:00.000Z"), targetIndex: 5 },
{ status: "executed", reviewedAt: new Date("2026-04-11T08:00:00.000Z"), targetIndex: 5 },
{ status: "failed", reviewedAt: new Date("2026-04-11T08:00:00.000Z"), targetIndex: 5 },
{ status: "cancelled", reviewedAt: null, targetIndex: 4 },
{ status: "cancelled", reviewedAt: new Date("2026-04-11T08:00:00.000Z"), targetIndex: 5 },
];
for (const item of cases) {
@@ -967,10 +970,11 @@ describe("GET /api/reimbursements/:id detail enhancements", () => {
});
expect(response.statusCode).toBe(200);
expect(response.json().data.processingProgress.stages[3]).toMatchObject({
key: "payment_batch_created",
state: "current",
actorName: null,
result: "待安排",
detail: "待财务安排付款",
result: "待组批",
detail: "待财务组建付款批次",
});
await app.close();
@@ -991,7 +995,7 @@ describe("GET /api/reimbursements/:id detail enhancements", () => {
headers: { authorization: "Bearer test" },
});
expect(response.statusCode).toBe(200);
expect(response.json().data.processingProgress.stages[4]).toMatchObject({
expect(response.json().data.processingProgress.stages[5]).toMatchObject({
state: "completed",
actorName: "实际付款人",
occurredAt: "2026-04-12T08:00:00.000Z",