R92 A2 修复发票 OCR provider 与二进制写库

这个提交包含在:
2026-05-05 22:16:13 +08:00
父节点 fced77a567
当前提交 abba3371dd
共修改 7 个文件,包含 113 行新增和 17 行删除
+52
查看文件
@@ -8,8 +8,10 @@ function buildClaimedInvoice(overrides = {}) {
return {
id: "11111111-1111-4111-8111-111111111111",
file_sha256: "sha256-1",
ocr_provider: "mock",
ocr_type: "vat",
storage_path: "20260428/invoice.txt",
mime_type: "text/plain",
ocr_attempts: 0,
...overrides,
};
@@ -74,10 +76,18 @@ describe("ocrJob quality gate", () => {
where: { id: "11111111-1111-4111-8111-111111111111" },
data: expect.objectContaining({
status: "available",
ocr_provider: "mock",
ocr_last_error: null,
}),
}),
);
expect(prisma.ocrResult.create).toHaveBeenCalledWith(
expect.objectContaining({
data: expect.objectContaining({
ocr_provider: "mock",
}),
}),
);
});
it("marks invoice ocr_failed when required VAT fields are missing", async () => {
@@ -112,6 +122,7 @@ describe("ocrJob quality gate", () => {
where: { id: "11111111-1111-4111-8111-111111111111" },
data: expect.objectContaining({
status: "ocr_failed",
ocr_provider: "mock",
ocr_last_error: "missing_required_fields:invoiceCode,sellerName",
}),
}),
@@ -124,4 +135,45 @@ describe("ocrJob quality gate", () => {
"OCR invoice marked as failed for missing required fields",
);
});
it("stores binary PDF mock OCR metadata without unsafe null marker text", async () => {
const pdfPayload = Buffer.from([0x25, 0x50, 0x44, 0x46, 0x00, 0xff, 0x10, 0x20, 0x41]);
await fs.writeFile(path.join(tempDir, "20260428/invoice.pdf"), pdfPayload);
const prisma = buildPrisma([
buildClaimedInvoice({
storage_path: "20260428/invoice.pdf",
mime_type: "application/pdf",
file_sha256: "sha256-pdf-binary",
}),
]);
const logger = {
warn: vi.fn(),
error: vi.fn(),
};
const result = await runOcrOnce(
prisma,
{
storageDir: tempDir,
ocrBatchSize: 1,
ocrLockTtlSeconds: 300,
ocrMaxAttempts: 3,
ocrProvider: "mock",
},
logger,
"ocr-test-worker",
);
expect(result).toEqual({ claimed: 1, available: 1, duplicate: 0, failed: 0 });
const createdPayload = prisma.ocrResult.create.mock.calls[0][0].data.result_json;
expect(createdPayload.raw).toEqual(
expect.objectContaining({
provider: "mock",
marker: null,
sourceSha256: expect.any(String),
}),
);
expect(JSON.stringify(createdPayload)).not.toContain("\\u0000");
});
});