refactor: enforce 800 line source limits

This commit is contained in:
caoxiaozhu
2026-06-22 11:58:53 +08:00
parent 08a4fa3577
commit 6d33ba5742
150 changed files with 27413 additions and 23791 deletions

View File

@@ -0,0 +1,34 @@
from __future__ import annotations
import ast
from pathlib import Path
MAX_CLASS_LINES = 800
SERVER_SOURCE_ROOT = Path(__file__).resolve().parents[1] / "src" / "app"
def iter_python_source_files(root: Path) -> list[Path]:
ignored_parts = {"__pycache__", "x_financial_server.egg-info"}
return sorted(
path
for path in root.rglob("*.py")
if not ignored_parts.intersection(path.parts)
)
def test_python_classes_do_not_exceed_800_lines() -> None:
oversized_classes: list[str] = []
for path in iter_python_source_files(SERVER_SOURCE_ROOT):
tree = ast.parse(path.read_text(encoding="utf-8"))
for node in ast.walk(tree):
if isinstance(node, ast.ClassDef) and node.end_lineno is not None:
line_count = node.end_lineno - node.lineno + 1
if line_count > MAX_CLASS_LINES:
relative_path = path.relative_to(SERVER_SOURCE_ROOT.parents[1])
oversized_classes.append(
f"{relative_path}:{node.lineno} {node.name} ({line_count} lines)"
)
assert oversized_classes == []

View File

@@ -2207,6 +2207,160 @@ def test_upload_train_ticket_attachment_backfills_item_amount(monkeypatch, tmp_p
assert not any("用途字段" in point for point in uploaded_meta["analysis"]["points"])
def test_upload_auto_collected_attachment_uses_source_receipt_ocr_result(
monkeypatch,
tmp_path,
) -> None:
monkeypatch.setenv("STORAGE_ROOT_DIR", str(tmp_path / "storage"))
get_settings.cache_clear()
try:
current_user = CurrentUserContext(
username="auto-collect-travel@example.com",
name="张三",
role_codes=[],
is_admin=False,
)
def fake_recognize(
self,
files: list[tuple[str, bytes, str | None]],
) -> OcrRecognizeBatchRead:
return OcrRecognizeBatchRead(
total_file_count=1,
success_count=1,
documents=[
OcrRecognizeDocumentRead(
filename="2月22 深圳-上海.pdf",
media_type="application/pdf",
text="",
summary="",
avg_score=0.0,
line_count=0,
page_count=1,
document_type="other",
document_type_label="其他单据",
scene_code="other",
scene_label="其他票据",
)
],
)
monkeypatch.setattr(OcrService, "recognize_files", fake_recognize)
monkeypatch.setattr(
ExpenseClaimAttachmentStorage,
"root",
lambda self: tmp_path / "attachments",
)
with build_session() as db:
employee = Employee(
employee_no="E-AUTO-COLLECT",
name="张三",
email=current_user.username,
grade="P4",
)
db.add(employee)
db.flush()
claim = build_claim(expense_type="travel", location="上海")
claim.employee = employee
claim.employee_id = employee.id
claim.employee_name = employee.name
claim.amount = Decimal("0.00")
claim.invoice_count = 0
claim.risk_flags_json = [
{
"source": "attachment_analysis",
"severity": "high",
"message": "票据类型:未识别到发票、票据、电子行程单等关键字。",
}
]
claim.items[0].item_type = "travel"
claim.items[0].item_reason = ""
claim.items[0].item_location = "上海"
claim.items[0].item_amount = Decimal("0.00")
claim.items[0].invoice_id = None
db.add(claim)
db.commit()
receipt = ReceiptFolderService().save_receipt(
filename="2月22 深圳-上海.pdf",
content=b"%PDF-1.4 fake-train-ticket",
media_type="application/pdf",
current_user=current_user,
document=OcrRecognizeDocumentRead(
filename="2月22 深圳-上海.pdf",
media_type="application/pdf",
text="中国铁路电子客票 深圳北-上海虹桥 2026-02-22 票价:¥388.00",
summary="铁路电子客票深圳至上海2026-02-22 出发,票价 388 元。",
avg_score=0.98,
line_count=1,
page_count=1,
document_type="train_ticket",
document_type_label="火车/高铁票",
scene_code="travel",
scene_label="差旅票据",
document_fields=[
{"key": "origin", "label": "出发城市", "value": "深圳"},
{"key": "destination", "label": "到达城市", "value": "上海"},
{"key": "trip_date", "label": "列车出发时间", "value": "2026-02-22"},
{"key": "fare", "label": "票价", "value": "¥388.00"},
],
),
)
service = ExpenseClaimService(db)
updated = service.upload_claim_item_attachment(
claim_id=claim.id,
item_id=claim.items[0].id,
filename="2月22 深圳-上海.pdf",
content=b"%PDF-1.4 fake-train-ticket",
media_type="application/pdf",
current_user=current_user,
source_receipt_id=receipt.id,
)
assert updated is not None
assert updated["item_type"] == "train_ticket"
assert updated["item_amount"] == Decimal("388.00")
assert updated["item_date"] == "2026-02-22"
assert updated["item_reason"] == "深圳北-上海虹桥"
uploaded_meta = service.get_claim_item_attachment_meta(
claim_id=claim.id,
item_id=claim.items[0].id,
current_user=current_user,
)
assert uploaded_meta is not None
assert uploaded_meta["document_info"]["document_type"] == "train_ticket"
assert uploaded_meta["requirement_check"]["matches"] is True
assert not any(
"未识别到发票" in point or "当前识别为其他单据" in point
for point in uploaded_meta["analysis"]["points"]
)
db.refresh(claim)
allowance_item = next(
item for item in claim.items if item.item_type == "travel_allowance"
)
assert allowance_item.item_amount > Decimal("0.00")
assert "1天" in allowance_item.item_reason
assert claim.amount == Decimal("388.00") + allowance_item.item_amount
assert not any(
isinstance(flag, dict)
and str(flag.get("source") or "").strip() == "attachment_analysis"
and "未识别到发票" in str(flag.get("message") or "")
for flag in list(claim.risk_flags_json or [])
)
linked_receipt = ReceiptFolderService().get_receipt(receipt.id, current_user)
assert linked_receipt.status == "linked"
assert linked_receipt.linked_claim_id == claim.id
assert linked_receipt.linked_claim_no == claim.claim_no
finally:
get_settings.cache_clear()
def test_upload_attachment_response_includes_refreshed_rule_center_risk_flags(
monkeypatch,
tmp_path,