fix: 完善动态错误指引与发票日期校验(09-05-error-explainability-payment-readiness)
这个提交包含在:
@@ -13,6 +13,10 @@ const docker = (args, input) => execFileSync("docker", args, { input, encoding:
|
||||
|
||||
async function main() {
|
||||
assert.equal(process.env.RUN_ISOLATED_DB_TEST, "1", "Explicit disposable database opt-in required");
|
||||
if (process.env.RUN_ERROR_GUIDANCE_TEST === "1") {
|
||||
assert.equal(process.env.RUN_BROWSER_TEST, "1", "Error guidance requires browser verification");
|
||||
assert.equal(process.env.RUN_JOB_QUEUE, "1", "Error guidance requires mock OCR provider");
|
||||
}
|
||||
const managerIsCeo = process.env.RUN_MANAGER_IS_CEO_TEST === "1";
|
||||
const ownerApprovalTest = process.env.RUN_OWNER_APPROVAL_TEST === "1";
|
||||
assert.ok(!ownerApprovalTest || managerIsCeo, "Owner approval checks require the small-team fixture");
|
||||
@@ -265,6 +269,37 @@ async function main() {
|
||||
app.config.appOrigin = uiOrigin;
|
||||
const { chromium, expect } = clientRequire("@playwright/test");
|
||||
browser = await chromium.launch({ headless: true });
|
||||
if (process.env.RUN_ERROR_GUIDANCE_TEST === "1") {
|
||||
assert.equal(process.env.RUN_JOB_QUEUE, "1", "Error guidance requires mock OCR provider");
|
||||
const invoice = await makeInvoice({ status: "ocr_failed", ocr_type: "vat", invoice_code: null, seller_name: null });
|
||||
const context = await browser.newContext({ serviceWorkers: "block" });
|
||||
try {
|
||||
const fingerprint = `synthetic-guidance-${randomUUID()}`;
|
||||
await context.addCookies([{ name: "hyb_oa_device_fingerprint", value: fingerprint, url: uiOrigin }]);
|
||||
const login = await context.request.post(`${uiOrigin}/api/auth/login`, { headers: { "x-device-fingerprint": fingerprint }, data: { identifier: employee.email, password: loginPassword } });
|
||||
assert.equal(login.status(), 200);
|
||||
const page = await context.newPage();
|
||||
await page.goto(`${uiOrigin}/invoice-pool?id=${invoice.id}`);
|
||||
await page.getByTestId("invoice-edit-open").click();
|
||||
await page.getByTestId("invoice-edit-set-available").check();
|
||||
const failed = page.waitForResponse((response) => response.request().method() === "PATCH" && response.url().endsWith(`/invoice-pool/${invoice.id}`));
|
||||
await page.getByTestId("invoice-edit-save").click();
|
||||
const failure = await failed;
|
||||
assert.equal(failure.status(), 409);
|
||||
assert.equal((await failure.json()).error.details.reasonCode, "invoice_pool.ocr_fields_missing");
|
||||
await expect(page.locator("main").getByText("票据仍缺少关键字段:发票代码、销售方,补齐后才能标记为可用。", { exact: true })).toBeVisible();
|
||||
assert.equal((await prisma.invoicePool.findUniqueOrThrow({ where: { id: invoice.id } })).status, "ocr_failed");
|
||||
await page.getByTestId("invoice-edit-code").fill("044003204111");
|
||||
await page.getByTestId("invoice-edit-seller-name").fill("synthetic seller");
|
||||
await page.getByTestId("invoice-edit-save").click();
|
||||
await expect(page.getByTestId("invoice-detail-panel")).toContainText("状态:可用");
|
||||
assert.equal((await prisma.invoicePool.findUniqueOrThrow({ where: { id: invoice.id } })).status, "available");
|
||||
console.log(JSON.stringify({ status: "PASS_ERROR_GUIDANCE_REAL_AUTH_DB_BROWSER", missingFieldsShown: true, failureRetainsState: true, correctedSavePersists: true, liveOcr: "NOT_CALLED", fixture: "SEEDED_OCR_FAILED_SYNTHETIC_INVOICE" }));
|
||||
} finally {
|
||||
await context.close();
|
||||
}
|
||||
return;
|
||||
}
|
||||
const runBrowserFlow = async (mobile) => {
|
||||
const context = await browser.newContext({ serviceWorkers: "block", viewport: mobile ? { width: 390, height: 844 } : { width: 1440, height: 960 } });
|
||||
const fingerprint = `synthetic-browser-${mobile ? "mobile" : "desktop"}`;
|
||||
|
||||
在新工单中引用
屏蔽一个用户