feat: 增加差旅报销标准测算和财务终审流程

新增差旅报销测算接口及 Spreadsheet 规则解析,审批流程拆分
直属领导审批与财务终审两阶段并细分权限,修复 PDF 文本层
缺失时自动回退 OCR,提交后清理关联会话,前端适配审批流
交互并补充单元测试。
This commit is contained in:
caoxiaozhu
2026-05-21 09:28:33 +08:00
parent 002bf4f756
commit 8f65661809
43 changed files with 4366 additions and 410 deletions

View File

@@ -177,3 +177,80 @@ def test_ocr_service_converts_pdf_to_images_and_returns_image_preview(
assert any(field.label == "车次/航班" and field.value == "G1234" for field in recognized.document_fields)
assert recognized.lines[0].page_index == 0
assert recognized.lines[1].page_index == 1
def test_ocr_service_prefers_pdf_text_layer_when_rendered_ocr_is_placeholder_heavy(
monkeypatch,
tmp_path: Path,
) -> None:
def fake_convert_pdf_to_images(self, *, pdf_path: Path, output_dir: Path) -> list[Path]:
page = output_dir / "page-1.png"
page.write_bytes(b"fake-page")
return [page]
def fake_invoke_worker(
self,
*,
python_bin: str,
worker_path: str,
input_paths: list[Path],
) -> dict:
return {
"engine": "paddleocr_mobile",
"model": "PP-OCRv5_mobile",
"documents": [
{
"input_path": str(input_paths[0]),
"engine": "paddleocr_mobile",
"model": "PP-OCRv5_mobile",
"text": "□□□□□□\n□□□□26319166100006175398\nG456\n□□:□354.00",
"summary": "□□□□□□□□□□26319166100006175398",
"avg_score": 0.88,
"line_count": 4,
"page_count": 1,
"warnings": [],
"lines": [
{
"text": "□□□□□□",
"score": 0.88,
"box": [[1, 2], [10, 2], [10, 8], [1, 8]],
}
],
}
],
}
monkeypatch.setenv("STORAGE_ROOT_DIR", str(tmp_path / "storage"))
monkeypatch.setattr(OcrService, "_resolve_python_bin", lambda self: "python")
monkeypatch.setattr(OcrService, "_resolve_worker_path", lambda self: "worker.py")
monkeypatch.setattr(OcrService, "_convert_pdf_to_images", fake_convert_pdf_to_images)
monkeypatch.setattr(OcrService, "_invoke_worker", fake_invoke_worker)
monkeypatch.setattr(
OcrService,
"_extract_pdf_text_layer",
lambda self, pdf_path: (
"电子发票(铁路电子客票)\n"
"发票号码:26319166100006175398\n"
"上海虹桥站\n"
"武汉站\n"
"G456\n"
"票价:¥354.00"
),
)
get_settings.cache_clear()
try:
result = OcrService().recognize_files(
[
("train-ticket.pdf", b"%PDF-1.4 fake", "application/pdf"),
]
)
finally:
get_settings.cache_clear()
recognized = result.documents[0]
assert "电子发票(铁路电子客票)" in recognized.text
assert "上海虹桥站" in recognized.text
assert "□□□□" not in recognized.summary
assert recognized.document_type == "train_ticket"
assert recognized.preview_kind == ""
assert recognized.preview_data_url == ""