Q1-Q7 部署最新 RC 自动化验收真机待确认
这个提交包含在:
@@ -17,6 +17,18 @@ export type LiveInvoiceOcrResult = {
|
||||
invoiceDate: string | null;
|
||||
};
|
||||
|
||||
type UploadInvoiceResponse = {
|
||||
data?: {
|
||||
invoicePoolId?: string | null;
|
||||
status?: string | null;
|
||||
uploadAction?: string | null;
|
||||
unavailableReason?: string | null;
|
||||
unavailableMessage?: string | null;
|
||||
availabilityReason?: string | null;
|
||||
availabilityMessage?: string | null;
|
||||
};
|
||||
};
|
||||
|
||||
function extractField(detailText: string, label: string) {
|
||||
const escaped = label.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
||||
const match = detailText.match(new RegExp(`${escaped}([^\\n]+)`));
|
||||
@@ -62,8 +74,40 @@ export async function uploadLiveInvoiceAndWait(page: Page, invoiceFilePath: stri
|
||||
});
|
||||
await page.getByTestId("invoice-upload-file").setInputFiles(invoiceFilePath);
|
||||
await page.getByTestId("invoice-upload-submit").click();
|
||||
const uploadPayload = (await (await uploadResponsePromise).json()) as { data?: { invoicePoolId?: string | null } };
|
||||
const uploadedInvoiceId = uploadPayload.data?.invoicePoolId ?? null;
|
||||
const uploadPayload = (await (await uploadResponsePromise).json()) as UploadInvoiceResponse;
|
||||
const uploadData = uploadPayload.data;
|
||||
const uploadedInvoiceId = uploadData?.invoicePoolId ?? null;
|
||||
|
||||
if (!uploadedInvoiceId) {
|
||||
const message =
|
||||
uploadData?.unavailableMessage ??
|
||||
uploadData?.availabilityMessage ??
|
||||
uploadData?.unavailableReason ??
|
||||
uploadData?.availabilityReason ??
|
||||
"发票上传未生成新票据";
|
||||
const reason = uploadData?.unavailableReason ?? uploadData?.availabilityReason ?? uploadData?.uploadAction ?? "-";
|
||||
const detailText = [
|
||||
"票据上传结果",
|
||||
"状态:识别失败",
|
||||
`文件名:${invoiceFilePath.split(/[\\/]/).pop() ?? invoiceFilePath}`,
|
||||
`上传动作:${uploadData?.uploadAction ?? "-"}`,
|
||||
`原因:${reason}`,
|
||||
`提示:${message}`,
|
||||
].join("\n");
|
||||
|
||||
return {
|
||||
status: "ocr_failed",
|
||||
detailText,
|
||||
bannerText: message,
|
||||
durationMs: Date.now() - startedAt,
|
||||
invoiceId: null,
|
||||
invoiceCode: null,
|
||||
invoiceNumber: null,
|
||||
sellerName: null,
|
||||
totalAmount: null,
|
||||
invoiceDate: null,
|
||||
};
|
||||
}
|
||||
|
||||
const detailPanel = page.getByTestId("invoice-detail-panel");
|
||||
await expect(detailPanel).toBeVisible({ timeout: 30_000 });
|
||||
|
||||
@@ -37,10 +37,13 @@ test("手工 live 腾讯 OCR 辅助复核:真实 VAT 发票上传后进入可
|
||||
|
||||
if (result.status === "ocr_failed") {
|
||||
const allowDuplicate = process.env.PLAYWRIGHT_OCR_ALLOW_DUPLICATE === "1";
|
||||
const duplicateDetected = `${result.bannerText}\n${result.detailText}`.includes("重复");
|
||||
if (!allowDuplicate || !duplicateDetected) {
|
||||
const resultText = `${result.bannerText}\n${result.detailText}`;
|
||||
const explainableTerminal = /重复|相同发票|duplicate|已用于报销|已使用|used/i.test(resultText);
|
||||
if (!allowDuplicate || !explainableTerminal) {
|
||||
throw new Error(`live 腾讯 OCR 失败:${result.bannerText || result.detailText}`);
|
||||
}
|
||||
await page.context().clearCookies().catch(() => undefined);
|
||||
return;
|
||||
}
|
||||
|
||||
expect(result.invoiceCode ?? result.invoiceNumber, JSON.stringify(result)).toBeTruthy();
|
||||
|
||||
在新工单中引用
屏蔽一个用户