feat(server): 重构报销单服务,优化费用报销流程和数据校验逻辑,包含schema定义和服务实现
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import base64
|
||||
from collections.abc import Generator
|
||||
from datetime import UTC, date, datetime
|
||||
from decimal import Decimal
|
||||
@@ -165,9 +166,18 @@ def test_claim_item_attachment_upload_preview_and_delete(monkeypatch, tmp_path)
|
||||
assert meta_response.status_code == 200
|
||||
meta_payload = meta_response.json()
|
||||
assert meta_payload["media_type"] == "image/png"
|
||||
assert meta_payload["preview_kind"] == "image"
|
||||
assert meta_payload["preview_url"].endswith(f"/reimbursements/claims/{claim_id}/items/{item_id}/attachment/preview")
|
||||
assert meta_payload["analysis"]["headline"]
|
||||
assert meta_payload["document_info"]["fields"][0]["label"] == "金额"
|
||||
|
||||
preview_response = client.get(
|
||||
f"/api/v1/reimbursements/claims/{claim_id}/items/{item_id}/attachment/preview",
|
||||
headers=headers,
|
||||
)
|
||||
assert preview_response.status_code == 200
|
||||
assert preview_response.content == file_bytes
|
||||
|
||||
content_response = client.get(
|
||||
f"/api/v1/reimbursements/claims/{claim_id}/items/{item_id}/attachment",
|
||||
headers=headers,
|
||||
@@ -279,6 +289,67 @@ def test_claim_item_attachment_upload_flags_non_invoice_image_as_high_risk(monke
|
||||
assert any("附件内容" in point for point in analysis["points"])
|
||||
|
||||
|
||||
def test_claim_item_pdf_attachment_preview_returns_generated_image(monkeypatch, tmp_path) -> None:
|
||||
preview_bytes = b"fake-preview-png"
|
||||
preview_data_url = f"data:image/png;base64,{base64.b64encode(preview_bytes).decode('ascii')}"
|
||||
|
||||
def fake_recognize(
|
||||
self,
|
||||
files: list[tuple[str, bytes, str | None]],
|
||||
) -> OcrRecognizeBatchRead:
|
||||
return OcrRecognizeBatchRead(
|
||||
total_file_count=1,
|
||||
success_count=1,
|
||||
documents=[
|
||||
OcrRecognizeDocumentRead(
|
||||
filename="invoice.pdf",
|
||||
media_type="application/pdf",
|
||||
text="滴滴出行电子发票 金额13.4元",
|
||||
summary="识别到交通票据,金额 13.4 元。",
|
||||
avg_score=0.96,
|
||||
line_count=1,
|
||||
page_count=1,
|
||||
document_type="taxi_receipt",
|
||||
document_type_label="出租车/网约车票据",
|
||||
scene_code="transport",
|
||||
scene_label="交通票据",
|
||||
preview_kind="image",
|
||||
preview_data_url=preview_data_url,
|
||||
warnings=[],
|
||||
)
|
||||
],
|
||||
)
|
||||
|
||||
monkeypatch.setattr(OcrService, "recognize_files", fake_recognize)
|
||||
monkeypatch.setattr(ExpenseClaimService, "_get_attachment_storage_root", lambda self: tmp_path)
|
||||
|
||||
client, session_factory = build_client()
|
||||
with session_factory() as db:
|
||||
claim, item = seed_claim(db)
|
||||
claim_id = claim.id
|
||||
item_id = item.id
|
||||
|
||||
headers = {"x-auth-username": "emp-1", "x-auth-name": "Zhang San"}
|
||||
upload_response = client.post(
|
||||
f"/api/v1/reimbursements/claims/{claim_id}/items/{item_id}/attachment",
|
||||
headers=headers,
|
||||
files=[("file", ("invoice.pdf", b"%PDF-1.4 fake", "application/pdf"))],
|
||||
)
|
||||
|
||||
assert upload_response.status_code == 200
|
||||
meta_payload = upload_response.json()["attachment"]
|
||||
assert meta_payload["preview_kind"] == "image"
|
||||
assert meta_payload["preview_url"].endswith(f"/reimbursements/claims/{claim_id}/items/{item_id}/attachment/preview")
|
||||
|
||||
preview_response = client.get(
|
||||
f"/api/v1/reimbursements/claims/{claim_id}/items/{item_id}/attachment/preview",
|
||||
headers=headers,
|
||||
)
|
||||
assert preview_response.status_code == 200
|
||||
assert preview_response.headers["content-type"].startswith("image/png")
|
||||
assert preview_response.content == preview_bytes
|
||||
|
||||
|
||||
def test_claim_item_delete_removes_item_and_attachment(monkeypatch, tmp_path) -> None:
|
||||
def fake_recognize(
|
||||
self,
|
||||
|
||||
Reference in New Issue
Block a user