汇总已落盘的借款本金与还款、兼容历史编号的周期化编号、付款责任与回单核验、报销进度和排序、PWA/采购事务、错误原因与日期校验及ERP退役。 统一共享预算池锁序和锁后判断,恢复差旅原预算选择,补原因码固定夹具及反向完整性检查。 纳入配套迁移、测试、受管QA、分层验收合同、规约及任务记录;原始证据留在ignored artifacts。 关联任务:09-17-company-loan-principal-repayment、09-17-erp-exclusive-retirement、09-18-reimbursement-periodic-numbering、09-08-reimbursement-payment-closeout、09-18-local-concurrency-product-fixes、09-19-budget-pool-concurrency、09-05-error-explainability-payment-readiness。 预算补审由Claude定向验证2文件928项通过,原4446/28及r6结果仍仅对应各自历史输入;本轮未重跑测试。 完整新候选门禁、R1真实入口接入与12项公网义务仍开放。生产编号未启用、差旅仍冻结;不推送、不部署,不宣称发布资格。
46 行
2.2 KiB
TypeScript
46 行
2.2 KiB
TypeScript
import { expect, test } from "@playwright/test";
|
|
import { createAuthenticatedApiClient, EMPLOYEE, FINANCE, FINANCE_MGR, login } from "./helpers/auth";
|
|
|
|
// Original travel chains remain byte-for-byte in their specs, owned by G19's
|
|
// frozen obligations. These assertions exercise the current retained boundary.
|
|
test("冻结差旅:员工入口与共享付款边界", async ({ page }) => {
|
|
const employee = await createAuthenticatedApiClient(EMPLOYEE);
|
|
const finance = await createAuthenticatedApiClient(FINANCE_MGR);
|
|
try {
|
|
expect(employee.me.roleCodes).toContain("employee");
|
|
const denied = await employee.api.post("/api/travel-requests", { data: {} });
|
|
expect(denied.status()).toBe(403);
|
|
await login(page, EMPLOYEE);
|
|
await page.goto("/portal");
|
|
await expect(page.getByTestId("portal-work-summary")).toBeVisible();
|
|
await expect(page.getByRole("link", { name: "差旅申请", exact: true })).toHaveCount(0);
|
|
const readiness = await finance.api.post("/api/payment-batches/readiness", {
|
|
data: { entityType: "travel_order", entityIds: ["ffffffff-ffff-4fff-8fff-ffffffffffff"], defaultPaymentChannel: "bank" },
|
|
});
|
|
expect(readiness.status()).toBe(200);
|
|
const payload = await readiness.json();
|
|
expect(payload.data.ready).toBe(false);
|
|
expect(payload.data.blockers).toContainEqual(expect.objectContaining({ reasonCode: "payment_batch.travel_payment_frozen" }));
|
|
} finally {
|
|
await employee.dispose();
|
|
await finance.dispose();
|
|
}
|
|
});
|
|
|
|
test("冻结差旅:财务对账权限与入站导入权限边界", async ({ page }) => {
|
|
const finance = await createAuthenticatedApiClient(FINANCE);
|
|
try {
|
|
expect(finance.me.roleCodes).toContain("finance");
|
|
for (const endpoint of ["/api/travel/reconciliation/batches", "/api/travel/orders/import", "/api/travel/transactions/import", "/api/travel/authorizations/import"]) {
|
|
const denied = await finance.api.post(endpoint, { data: {} });
|
|
expect(denied.status(), endpoint).toBe(403);
|
|
}
|
|
await login(page, FINANCE);
|
|
await page.goto("/portal");
|
|
await expect(page.getByTestId("portal-work-summary")).toBeVisible();
|
|
await expect(page.getByRole("link", { name: "差旅申请", exact: true })).toHaveCount(0);
|
|
} finally {
|
|
await finance.dispose();
|
|
}
|
|
});
|