收口付款批次创建与复核(08-01-reimbursement-notification-progress-clarity)
这个提交包含在:
@@ -107,10 +107,8 @@ test("E2E 主链路:登录→报销→待办审批→票据OCR→支付→登
|
||||
await expect(page.getByText(/状态:(approved|已批准)/)).toBeVisible({ timeout: 30_000 });
|
||||
await expect(page.getByTestId(TEST_IDS.reimbursement.pay)).toHaveCount(0);
|
||||
|
||||
const paymentDate = new Date().toISOString().slice(0, 10);
|
||||
const reimbursement = await apiGetData<{ formNumber: string | null }>(page.request, `/api/reimbursements/${reimbursementId}`);
|
||||
const reimbursementDisplayCode = reimbursement.formNumber ?? reimbursementId;
|
||||
const batchName = `E2E-报销付款批次-${Date.now()}`;
|
||||
await page.goto("/payment-batches");
|
||||
await expect(page.getByTestId("payment-batch-create-panel")).toHaveCount(0);
|
||||
await page.getByRole("button", { name: "新建批次" }).click();
|
||||
@@ -120,18 +118,15 @@ test("E2E 主链路:登录→报销→待办审批→票据OCR→支付→登
|
||||
const url = new URL(response.url());
|
||||
return response.request().method() === "POST" && url.pathname === "/api/payment-batches" && response.ok();
|
||||
});
|
||||
await createCard.getByTestId("payment-batch-create-name").fill(batchName);
|
||||
await createCard.getByTestId("payment-batch-candidate-search").fill(reimbursementDisplayCode);
|
||||
const candidateRow = createCard.getByTestId("payment-batch-candidate-row").filter({ hasText: reimbursementDisplayCode }).first();
|
||||
await expect(candidateRow).toBeVisible();
|
||||
await candidateRow.getByRole("checkbox").check();
|
||||
await createCard.getByTestId("payment-batch-create-payment-date").fill(paymentDate);
|
||||
await createCard.getByTestId("payment-batch-create-payment-channel").selectOption("bank");
|
||||
await createCard.getByTestId("payment-batch-create-voucher-prefix").fill("E2EPB");
|
||||
await createCard.getByRole("button", { name: "创建批次" }).click();
|
||||
const createBatchPayload = (await (await createBatchResponsePromise).json()) as { data?: { item?: { id?: string } } };
|
||||
await createCard.getByRole("button", { name: "创建并提交复核" }).click();
|
||||
const createBatchPayload = (await (await createBatchResponsePromise).json()) as { data?: { item?: { id?: string; name?: string } } };
|
||||
const batchId = createBatchPayload.data?.item?.id;
|
||||
if (!batchId) {
|
||||
const batchName = createBatchPayload.data?.item?.name;
|
||||
if (!batchId || !batchName) {
|
||||
throw new Error(`创建付款批次后未返回 id: ${JSON.stringify(createBatchPayload)}`);
|
||||
}
|
||||
|
||||
@@ -155,24 +150,23 @@ test("E2E 主链路:登录→报销→待办审批→票据OCR→支付→登
|
||||
await expect(executedBatchDetailCard).toContainText("1/1");
|
||||
const receiptCard = page.getByTestId("payment-batch-receipt-panel");
|
||||
await expect(receiptCard).toBeVisible();
|
||||
await receiptCard.getByTestId("payment-batch-receipt-file-input").setInputFiles({
|
||||
name: "e2e-bank-receipt.pdf",
|
||||
mimeType: "application/pdf",
|
||||
buffer: Buffer.from(`%PDF-1.4\npayment receipt ${marker}\n%%EOF\n`, "utf8"),
|
||||
});
|
||||
const receiptUploadResponsePromise = page.waitForResponse((response) => {
|
||||
const url = new URL(response.url());
|
||||
return response.request().method() === "POST" &&
|
||||
url.pathname === `/api/payment-batches/${batchId}/receipt-attachments` &&
|
||||
response.ok();
|
||||
});
|
||||
await receiptCard.getByRole("button", { name: "上传" }).click();
|
||||
await receiptCard.getByTestId("payment-batch-receipt-file-input").setInputFiles({
|
||||
name: "e2e-bank-receipt.pdf",
|
||||
mimeType: "application/pdf",
|
||||
buffer: Buffer.from(`%PDF-1.4\npayment receipt ${marker}\n%%EOF\n`, "utf8"),
|
||||
});
|
||||
await receiptUploadResponsePromise;
|
||||
await expect(receiptCard).toContainText("e2e-bank-receipt.pdf");
|
||||
await executedBatchDetailCard.getByRole("button", { name: "执行" }).click();
|
||||
await expect(page.getByTestId("action-confirm-dialog")).toContainText("确认后将执行付款批次");
|
||||
await executedBatchDetailCard.getByRole("button", { name: "登记付款完成" }).click();
|
||||
await expect(page.getByTestId("action-confirm-dialog")).toContainText("登记付款完成");
|
||||
await page.getByTestId("action-confirm-submit").click();
|
||||
await expect(executedBatchDetailCard).toContainText("已执行", { timeout: 30_000 });
|
||||
await expect(executedBatchDetailCard).toContainText("已付款", { timeout: 30_000 });
|
||||
|
||||
await page.goto(`/reimbursements/${reimbursementId}`);
|
||||
await reimbursementDetail.assertLoaded();
|
||||
|
||||
@@ -1159,8 +1159,6 @@ test(`${trialrunIssueId} 浏览器业务先行试运行:报销、审批、请
|
||||
};
|
||||
}
|
||||
|
||||
const batchName = `${trialrunMarkerPrefix} 浏览器付款批次 ${marker}`;
|
||||
state.paymentBatchName = batchName;
|
||||
await page.goto("/payment-batches");
|
||||
await expect(page.getByRole("heading", { name: "付款", exact: true })).toBeVisible();
|
||||
if (await page.getByText(/当前功能未启用/).first().isVisible().catch(() => false)) {
|
||||
@@ -1174,21 +1172,17 @@ test(`${trialrunIssueId} 浏览器业务先行试运行:报销、审批、请
|
||||
}
|
||||
await page.getByRole("button", { name: "新建批次" }).click();
|
||||
const createCard = page.getByTestId("payment-batch-create-panel");
|
||||
await expect(createCard.getByRole("button", { name: "创建批次" })).toBeDisabled();
|
||||
await expect(createCard.getByRole("button", { name: "创建并提交复核" })).toBeDisabled();
|
||||
const createBatchResponsePromise = page.waitForResponse((response) => {
|
||||
const url = new URL(response.url());
|
||||
return response.request().method() === "POST" && url.pathname === "/api/payment-batches";
|
||||
});
|
||||
await createCard.getByPlaceholder("例如:2026Q2-财务付款批次-01").fill(batchName);
|
||||
const reimbursementCode = state.reimbursementCode ?? state.reimbursementId;
|
||||
await createCard.getByTestId("payment-batch-candidate-search").fill(reimbursementCode);
|
||||
const candidateRow = createCard.getByTestId("payment-batch-candidate-row").filter({ hasText: reimbursementCode }).first();
|
||||
await expect(candidateRow).toBeVisible();
|
||||
await candidateRow.getByRole("checkbox").check();
|
||||
await createCard.locator('input[type="date"]').fill(new Date().toISOString().slice(0, 10));
|
||||
await createCard.locator("select").nth(0).selectOption("bank");
|
||||
await createCard.getByPlaceholder("例如 PBX").fill(`${trialrunSafePrefix}-${marker.slice(-6)}`);
|
||||
await createCard.getByRole("button", { name: "创建批次" }).click();
|
||||
await createCard.getByRole("button", { name: "创建并提交复核" }).click();
|
||||
const createBatchResponse = await createBatchResponsePromise;
|
||||
if (!createBatchResponse.ok()) {
|
||||
throw new Error(`创建付款批次失败:HTTP ${createBatchResponse.status()} ${await createBatchResponse.text()}`);
|
||||
@@ -1198,6 +1192,8 @@ test(`${trialrunIssueId} 浏览器业务先行试运行:报销、审批、请
|
||||
if (!batch?.id) {
|
||||
throw new Error(`创建付款批次后未返回 id: ${JSON.stringify(createBatchPayload)}`);
|
||||
}
|
||||
const batchName = batch.name;
|
||||
state.paymentBatchName = batchName;
|
||||
state.paymentBatchId = batch.id;
|
||||
await logoutLiveUser(page, { name: finance.name }).catch(() => undefined);
|
||||
|
||||
@@ -1215,10 +1211,23 @@ test(`${trialrunIssueId} 浏览器业务先行试运行:报销、审批、请
|
||||
|
||||
const financeAgain = await loginRole(page, "finance");
|
||||
await page.goto(`/payment-batches?id=${batch.id}`);
|
||||
const batchDetailCard = page.locator(".card-std").filter({ hasText: batchName }).filter({ hasText: "复核进度:" }).last();
|
||||
const batchDetailCard = page.getByTestId("payment-batch-detail-panel").filter({ hasText: batchName });
|
||||
await expect(batchDetailCard).toBeVisible();
|
||||
await batchDetailCard.getByRole("button", { name: "执行" }).click();
|
||||
await expect(batchDetailCard).toContainText("状态:已执行", { timeout: 30_000 });
|
||||
const receiptResponsePromise = page.waitForResponse((response) => {
|
||||
const url = new URL(response.url());
|
||||
return response.request().method() === "POST" &&
|
||||
url.pathname === `/api/payment-batches/${batch.id}/receipt-attachments` &&
|
||||
response.ok();
|
||||
});
|
||||
await page.getByTestId("payment-batch-receipt-file-input").setInputFiles({
|
||||
name: `${trialrunSafePrefix}-bank-receipt.pdf`,
|
||||
mimeType: "application/pdf",
|
||||
buffer: Buffer.from(`%PDF-1.4\n${trialrunMarkerPrefix} ${marker}\n%%EOF\n`, "utf8"),
|
||||
});
|
||||
await receiptResponsePromise;
|
||||
await batchDetailCard.getByRole("button", { name: "登记付款完成" }).click();
|
||||
await page.getByTestId("action-confirm-submit").click();
|
||||
await expect(batchDetailCard).toContainText("已付款", { timeout: 30_000 });
|
||||
await page.goto(`/reimbursements/${state.reimbursementId}`);
|
||||
await reimbursementDetail.assertLoaded();
|
||||
await expect(page.getByTestId("reimbursement-payment-status")).toContainText(/已付款|paid/, { timeout: 30_000 });
|
||||
@@ -1232,7 +1241,7 @@ test(`${trialrunIssueId} 浏览器业务先行试运行:报销、审批、请
|
||||
if (/\/403/.test(page.url())) {
|
||||
await expect(page.getByRole("heading", { name: "无权限访问", exact: true })).toBeVisible();
|
||||
} else {
|
||||
const createButton = page.getByRole("button", { name: "创建批次" }).first();
|
||||
const createButton = page.getByRole("button", { name: "创建并提交复核" }).first();
|
||||
await expect(createButton).toBeDisabled();
|
||||
}
|
||||
await logoutLiveUser(page, { name: admin.name }).catch(() => undefined);
|
||||
|
||||
@@ -414,16 +414,14 @@ test("财务从业务候选选择报销并使用所选实体创建付款批次",
|
||||
await expect(page.getByText(PAYMENT_CANDIDATE_ENTITY_ID, { exact: true })).toHaveCount(0);
|
||||
await expect(page.locator('input[placeholder*="UUID"], input[placeholder*="uuid"], input[placeholder*="entityId"], input[placeholder*="内部 ID"], input[placeholder*="内部ID"]')).toHaveCount(0);
|
||||
|
||||
await page.getByTestId("payment-batch-create-name").fill("合成付款批次");
|
||||
await candidateRow.getByRole("checkbox").check();
|
||||
await page.getByRole("button", { name: "创建批次", exact: true }).click();
|
||||
await page.getByRole("button", { name: "创建并提交复核", exact: true }).click();
|
||||
|
||||
await expect(page).toHaveURL(new RegExp(`/payment-batches\\?id=${CREATED_PAYMENT_BATCH_ID}$`));
|
||||
await expect(page.getByRole("heading", { level: 1, name: "付款", exact: true })).toBeVisible();
|
||||
await expect(page.getByText("付款批次已创建", { exact: true })).toBeVisible();
|
||||
await expect(page.getByText("已提交付款复核,等待负责人处理", { exact: true })).toBeVisible();
|
||||
expect(createPayload).toEqual({
|
||||
entityType: "reimbursement",
|
||||
name: "合成付款批次",
|
||||
entityIds: [PAYMENT_CANDIDATE_ENTITY_ID],
|
||||
});
|
||||
expectNoPageErrors(pageErrors);
|
||||
|
||||
@@ -24,7 +24,6 @@ test("E2E 报销付款批次主链路:提交 -> 审批 -> 创建批次 -> 复
|
||||
const adminApi = await createAuthenticatedApiClient(ADMIN);
|
||||
const employeeApi = await createAuthenticatedApiClient(EMPLOYEE);
|
||||
const financeMgrApi = await createAuthenticatedApiClient(FINANCE_MGR);
|
||||
const paymentDate = new Date().toISOString().slice(0, 10);
|
||||
|
||||
try {
|
||||
await ensureFeatureFlagOn(adminApi.api, "payment_batch_v1", "playwright reimbursement payment batch flow");
|
||||
@@ -100,7 +99,6 @@ test("E2E 报销付款批次主链路:提交 -> 审批 -> 创建批次 -> 复
|
||||
await logout(page, secondApprovalUser.name);
|
||||
await login(page, FINANCE);
|
||||
|
||||
const batchName = `R78-报销付款批次-${Date.now()}`;
|
||||
await page.goto("/payment-batches");
|
||||
await expect(page).toHaveURL(/\/payment-batches/);
|
||||
|
||||
@@ -112,27 +110,25 @@ test("E2E 报销付款批次主链路:提交 -> 审批 -> 创建批次 -> 复
|
||||
const url = new URL(response.url());
|
||||
return response.request().method() === "POST" && url.pathname === "/api/payment-batches" && response.ok();
|
||||
});
|
||||
await createCard.getByTestId("payment-batch-create-name").fill(batchName);
|
||||
await createCard.getByTestId("payment-batch-candidate-search").fill(reimbursementDisplayCode);
|
||||
const candidateRow = createCard.getByTestId("payment-batch-candidate-row").filter({ hasText: reimbursementDisplayCode }).first();
|
||||
await expect(candidateRow).toBeVisible();
|
||||
await candidateRow.getByRole("checkbox").check();
|
||||
await createCard.getByTestId("payment-batch-create-payment-date").fill(paymentDate);
|
||||
await createCard.getByTestId("payment-batch-create-payment-channel").selectOption("bank");
|
||||
await createCard.getByTestId("payment-batch-create-voucher-prefix").fill("R78PB");
|
||||
await createCard.getByRole("button", { name: "创建批次" }).click();
|
||||
await createCard.getByRole("button", { name: "创建并提交复核" }).click();
|
||||
|
||||
const createBatchPayload = (await (await createBatchResponsePromise).json()) as {
|
||||
data?: { item?: { id?: string } };
|
||||
data?: { item?: { id?: string; name?: string } };
|
||||
};
|
||||
const batchId = createBatchPayload.data?.item?.id;
|
||||
if (!batchId) {
|
||||
const batchName = createBatchPayload.data?.item?.name;
|
||||
if (!batchId || !batchName) {
|
||||
throw new Error(`创建付款批次后未返回 id: ${JSON.stringify(createBatchPayload)}`);
|
||||
}
|
||||
await page.goto(`/payment-batches?id=${batchId}`);
|
||||
const batchDetailCard = page.getByTestId("payment-batch-detail-panel").filter({ hasText: batchName });
|
||||
await expect(batchDetailCard).toBeVisible();
|
||||
await expect(batchDetailCard).toContainText("草稿");
|
||||
await expect(batchDetailCard).toContainText("待付款复核");
|
||||
await expect(batchDetailCard).toContainText("已提交付款复核,等待负责人处理");
|
||||
await expect(batchDetailCard).toContainText("0/1");
|
||||
|
||||
await logout(page, FINANCE.name);
|
||||
@@ -157,20 +153,22 @@ test("E2E 报销付款批次主链路:提交 -> 审批 -> 创建批次 -> 复
|
||||
await expect(executedBatchDetailCard).toContainText("1/1");
|
||||
const receiptCard = page.getByTestId("payment-batch-receipt-panel");
|
||||
await expect(receiptCard).toBeVisible();
|
||||
await receiptCard.getByTestId("payment-batch-receipt-file-input").setInputFiles({
|
||||
name: "r78-bank-receipt.pdf",
|
||||
mimeType: "application/pdf",
|
||||
buffer: Buffer.from(`%PDF-1.4\npayment receipt ${marker}\n%%EOF\n`, "utf8"),
|
||||
});
|
||||
await expect(executedBatchDetailCard.getByRole("button", { name: "上传银行回单" }).first()).toBeVisible();
|
||||
await expect(executedBatchDetailCard.getByRole("button", { name: "登记付款完成" })).toHaveCount(0);
|
||||
const receiptUploadResponsePromise = page.waitForResponse((response) => {
|
||||
const url = new URL(response.url());
|
||||
return response.request().method() === "POST" &&
|
||||
url.pathname === `/api/payment-batches/${batchId}/receipt-attachments` &&
|
||||
response.ok();
|
||||
});
|
||||
await receiptCard.getByRole("button", { name: "上传" }).click();
|
||||
await receiptCard.getByTestId("payment-batch-receipt-file-input").setInputFiles({
|
||||
name: "r78-bank-receipt.pdf",
|
||||
mimeType: "application/pdf",
|
||||
buffer: Buffer.from(`%PDF-1.4\npayment receipt ${marker}\n%%EOF\n`, "utf8"),
|
||||
});
|
||||
await receiptUploadResponsePromise;
|
||||
await expect(receiptCard).toContainText("r78-bank-receipt.pdf");
|
||||
await expect(executedBatchDetailCard.getByRole("button", { name: "登记付款完成" })).toBeVisible();
|
||||
|
||||
const executeBatchResponsePromise = page.waitForResponse((response) => {
|
||||
const url = new URL(response.url());
|
||||
@@ -178,11 +176,11 @@ test("E2E 报销付款批次主链路:提交 -> 审批 -> 创建批次 -> 复
|
||||
url.pathname === `/api/payment-batches/${batchId}/execute` &&
|
||||
response.ok();
|
||||
});
|
||||
await executedBatchDetailCard.getByRole("button", { name: "执行" }).click();
|
||||
await expect(page.getByTestId("action-confirm-dialog")).toContainText("确认后将执行付款批次");
|
||||
await executedBatchDetailCard.getByRole("button", { name: "登记付款完成" }).click();
|
||||
await expect(page.getByTestId("action-confirm-dialog")).toContainText("登记付款完成");
|
||||
await page.getByTestId("action-confirm-submit").click();
|
||||
await executeBatchResponsePromise;
|
||||
await expect(executedBatchDetailCard).toContainText("已执行", { timeout: 30_000 });
|
||||
await expect(executedBatchDetailCard).toContainText("已付款", { timeout: 30_000 });
|
||||
|
||||
await page.goto(`/reimbursements/${reimbursementId}`);
|
||||
await reimbursementDetail.assertLoaded();
|
||||
|
||||
@@ -182,15 +182,22 @@ function paymentBatch(status: "draft" | "reviewed" = "reviewed") {
|
||||
|
||||
async function mockSystemActionApis(
|
||||
page: Page,
|
||||
options: { batchStatus?: "draft" | "reviewed"; meOverride?: Partial<typeof me> } = {},
|
||||
options: {
|
||||
batchStatus?: "draft" | "reviewed";
|
||||
hasReceipt?: boolean;
|
||||
receiptQueryError?: boolean;
|
||||
meOverride?: Partial<typeof me>;
|
||||
} = {},
|
||||
) {
|
||||
const currentMe = { ...me, ...options.meOverride };
|
||||
const batchStatus = options.batchStatus ?? "reviewed";
|
||||
let hasReceipt = options.hasReceipt ?? true;
|
||||
const calls = {
|
||||
deleteReimbursement: 0,
|
||||
deleteReimbursementAttachment: 0,
|
||||
exportReimbursements: 0,
|
||||
executePaymentBatch: 0,
|
||||
uploadPaymentReceipt: 0,
|
||||
voidPaymentReceipt: 0,
|
||||
attachmentDeleteReasons: [] as string[],
|
||||
receiptVoidReasons: [] as string[],
|
||||
@@ -327,8 +334,19 @@ async function mockSystemActionApis(
|
||||
}
|
||||
|
||||
if (path === `/api/payment-batches/${paymentBatchId}/receipt-attachments` && request.method() === "GET") {
|
||||
if (options.receiptQueryError) {
|
||||
await route.fulfill({
|
||||
status: 503,
|
||||
contentType: "application/json",
|
||||
body: JSON.stringify({
|
||||
requestId: "mock-system-action-confirm",
|
||||
error: { code: "SYS_001", message: "回单状态暂时不可用" },
|
||||
}),
|
||||
});
|
||||
return;
|
||||
}
|
||||
await fulfillJson(route, {
|
||||
items: [
|
||||
items: hasReceipt ? [
|
||||
{
|
||||
id: paymentReceiptId,
|
||||
originalName: "合成银行回单.pdf",
|
||||
@@ -348,11 +366,18 @@ async function mockSystemActionApis(
|
||||
uploadedBy: { id: me.id, employeeNo: me.employeeNo, name: me.name },
|
||||
createdAt: "2026-05-15T08:20:00.000Z",
|
||||
},
|
||||
],
|
||||
] : [],
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (path === `/api/payment-batches/${paymentBatchId}/receipt-attachments` && request.method() === "POST") {
|
||||
calls.uploadPaymentReceipt += 1;
|
||||
hasReceipt = true;
|
||||
await fulfillJson(route, { items: [{ id: paymentReceiptId }] });
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
path === `/api/payment-batches/${paymentBatchId}/receipt-attachments/${paymentReceiptId}/void` &&
|
||||
request.method() === "POST"
|
||||
@@ -419,18 +444,37 @@ test.describe("R7E 全站高风险操作二次确认", () => {
|
||||
await page.goto(`/payment-batches?id=${paymentBatchId}`);
|
||||
await expect(page.getByText("PAY-ACTION-001").first()).toBeVisible();
|
||||
|
||||
await page.getByRole("button", { name: "执行" }).click();
|
||||
await expect(page.getByTestId("action-confirm-dialog")).toContainText("确认后将执行付款批次");
|
||||
await page.getByRole("button", { name: "登记付款完成" }).click();
|
||||
await expect(page.getByTestId("action-confirm-dialog")).toContainText("登记付款完成");
|
||||
expect(calls.executePaymentBatch).toBe(0);
|
||||
|
||||
await page.getByTestId("action-confirm-cancel").click();
|
||||
expect(calls.executePaymentBatch).toBe(0);
|
||||
|
||||
await page.getByRole("button", { name: "执行" }).click();
|
||||
await page.getByRole("button", { name: "登记付款完成" }).click();
|
||||
await page.getByTestId("action-confirm-submit").click();
|
||||
await expect.poll(() => calls.executePaymentBatch).toBe(1);
|
||||
});
|
||||
|
||||
test("银行回单上传前后只显示一个付款主动作", async ({ page }) => {
|
||||
const calls = await mockSystemActionApis(page, { hasReceipt: false });
|
||||
await login(page, user);
|
||||
await page.goto(`/payment-batches?id=${paymentBatchId}`);
|
||||
|
||||
await expect(page.getByRole("button", { name: "上传银行回单" }).first()).toBeVisible();
|
||||
await expect(page.getByRole("button", { name: "登记付款完成" })).toHaveCount(0);
|
||||
|
||||
await page.getByTestId("payment-batch-receipt-file-input").setInputFiles({
|
||||
name: "合成银行回单.pdf",
|
||||
mimeType: "application/pdf",
|
||||
buffer: Buffer.from("%PDF-1.4\nsynthetic receipt\n%%EOF\n", "utf8"),
|
||||
});
|
||||
|
||||
await expect.poll(() => calls.uploadPaymentReceipt).toBe(1);
|
||||
await expect(page.getByRole("button", { name: "登记付款完成" })).toBeVisible();
|
||||
await expect(page.getByTestId("payment-batch-detail-panel").getByRole("button", { name: "上传银行回单" })).toHaveCount(0);
|
||||
});
|
||||
|
||||
test("高敏附件删除要求对象、后果和理由,取消与理由不足均为零请求", async ({ page }) => {
|
||||
const calls = await mockSystemActionApis(page);
|
||||
await login(page, user);
|
||||
@@ -493,6 +537,33 @@ test.describe("R7E 全站高风险操作二次确认", () => {
|
||||
await login(page, user);
|
||||
await page.goto(`/payment-batches?id=${paymentBatchId}`);
|
||||
await expect(page.getByText("PAY-ACTION-001").first()).toBeVisible();
|
||||
await expect(page.getByRole("button", { name: "复核", exact: true })).toHaveCount(0);
|
||||
await expect(page.getByRole("button", { name: "复核通过", exact: true })).toHaveCount(0);
|
||||
});
|
||||
|
||||
test("兼任付款复核职责的制单人也不显示自审动作", async ({ page }) => {
|
||||
await mockSystemActionApis(page, {
|
||||
batchStatus: "draft",
|
||||
meOverride: {
|
||||
roleCodes: ["manager", "finance"],
|
||||
permissions: [...me.permissions, "payment.batch.review"],
|
||||
},
|
||||
});
|
||||
|
||||
await login(page, user);
|
||||
await page.goto(`/payment-batches?id=${paymentBatchId}`);
|
||||
await expect(page.getByText("制单人不能复核自己的批次")).toBeVisible();
|
||||
await expect(page.getByRole("button", { name: "复核通过", exact: true })).toHaveCount(0);
|
||||
});
|
||||
|
||||
test("回单查询失败时不把未知状态误报为空且不显示付款动作", async ({ page }) => {
|
||||
await mockSystemActionApis(page, { receiptQueryError: true });
|
||||
|
||||
await login(page, user);
|
||||
await page.goto(`/payment-batches?id=${paymentBatchId}`);
|
||||
await expect(page.getByText(/服务暂不可用/)).toBeVisible();
|
||||
await expect(page.getByRole("button", { name: "重新加载" })).toBeVisible();
|
||||
await expect(page.getByText(/暂无银行回单/)).toHaveCount(0);
|
||||
await expect(page.getByRole("button", { name: "上传银行回单" })).toHaveCount(0);
|
||||
await expect(page.getByRole("button", { name: "登记付款完成" })).toHaveCount(0);
|
||||
});
|
||||
});
|
||||
|
||||
在新工单中引用
屏蔽一个用户