fix(claim): align risk advice with expense rows

This commit is contained in:
caoxiaozhu
2026-06-15 20:53:48 +08:00
parent 5747e85acf
commit 792741709a
7 changed files with 596 additions and 178 deletions

View File

@@ -2283,6 +2283,13 @@ def test_upload_attachment_runs_rule_center_city_risk_from_origin_destination_fi
and flag.get("rule_code") == "risk.travel.high.city_mismatch"
for flag in flags
)
city_flag = next(
flag
for flag in flags
if isinstance(flag, dict)
and flag.get("rule_code") == "risk.travel.high.city_mismatch"
)
assert city_flag.get("item_ids") == [claim.items[0].id]
def test_upload_attachment_uses_linked_application_business_time_for_date_risk(
@@ -2545,6 +2552,104 @@ def test_upload_hotel_attachment_flags_amount_over_travel_policy(monkeypatch, tm
)
def test_upload_hotel_attachment_does_not_add_generic_auto_review_summary(
monkeypatch,
tmp_path,
) -> None:
current_user = CurrentUserContext(
username="emp-hotel-summary@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="hotel-summary-risk.png",
media_type="image/png",
text="北京全季酒店 住宿 1晚 金额800元 2026-05-13",
summary="北京全季酒店住宿发票,住宿 1 晚,金额 800 元。",
avg_score=0.98,
line_count=1,
page_count=1,
document_type="hotel_invoice",
document_type_label="酒店住宿票据",
scene_code="hotel",
scene_label="住宿票据",
document_fields=[
{"key": "merchant_name", "label": "商户", "value": "北京全季酒店"},
{"key": "amount", "label": "金额", "value": "800元"},
{"key": "date", "label": "日期", "value": "2026-05-13"},
],
)
],
)
monkeypatch.setattr(OcrService, "recognize_files", fake_recognize)
monkeypatch.setattr(ExpenseClaimAttachmentStorage, "root", lambda self: tmp_path)
with build_session() as db:
manager = Employee(
employee_no="E7410",
name="李经理",
email="manager-hotel-summary@example.com",
)
employee = Employee(
employee_no="E7411",
name="张三",
email="emp-hotel-summary@example.com",
grade="P4",
manager=manager,
)
db.add_all([manager, employee])
db.flush()
claim = build_claim(expense_type="travel", location="北京")
claim.employee = employee
claim.employee_id = employee.id
claim.reason = "北京客户现场出差"
claim.amount = Decimal("0.00")
claim.invoice_count = 0
claim.items[0].item_type = "hotel"
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()
ExpenseClaimService(db).upload_claim_item_attachment(
claim_id=claim.id,
item_id=claim.items[0].id,
filename="hotel-summary-risk.png",
content=b"fake-image-bytes",
media_type="image/png",
current_user=current_user,
)
db.refresh(claim)
labels = [
str(flag.get("label") or "").strip()
for flag in list(claim.risk_flags_json or [])
if isinstance(flag, dict)
]
assert "自动检测重点复核" not in labels
assert "自动检测提醒" not in labels
assert any(
isinstance(flag, dict)
and str(flag.get("source") or "").strip() == "attachment_analysis"
and str(flag.get("severity") or "").strip() == "high"
for flag in list(claim.risk_flags_json or [])
)
def test_delete_claim_item_attachment_removes_attachment_analysis_risk(monkeypatch, tmp_path) -> None:
current_user = CurrentUserContext(
username="emp-hotel-risk@example.com",
@@ -3533,6 +3638,16 @@ def test_submit_claim_routes_travel_route_mismatch_to_approval_with_review_flag(
)
for flag in list(submitted.risk_flags_json or [])
)
route_flags = [
flag
for flag in list(submitted.risk_flags_json or [])
if isinstance(flag, dict)
and str(flag.get("source") or "").strip() == "submission_review"
and str(flag.get("label") or "").strip() in {"行程终点异常", "多城市行程待说明"}
]
assert route_flags
assert all(flag.get("item_ids") for flag in route_flags)
assert any("travel-item-2" in flag.get("item_ids", []) for flag in route_flags)
def test_submit_claim_allows_round_trip_ticket_origin_inferred_from_route(