"""落库后自检:读回页面行数/合计与 info 比对,差值给 warning;读不到就如实说没核对。""" from typing import Any from src.infra.browser.base import BaseBot class _Row: def __init__(self, text: str, cells: int = 4) -> None: self._text = text self._cells = cells def inner_text(self) -> str: return self._text def query_selector_all(self, selector: str) -> list[Any]: return [object()] * self._cells if selector == "td" else [] class _Table: def __init__(self, header: str, rows: list[str]) -> None: self._header = header self._rows = [_Row(r) for r in rows] def inner_text(self) -> str: return self._header def query_selector_all(self, selector: str) -> list[Any]: return list(self._rows) if selector == "tr" else [] class _Page: def __init__(self, tables: list[_Table]) -> None: self.tables = tables def query_selector_all(self, selector: str) -> list[Any]: return list(self.tables) if selector == "table" else [] class _Bot(BaseBot): def __init__(self, tables: list[_Table]) -> None: self.page = _Page(tables) # type: ignore[assignment] def test_travel_details_match_has_no_warning() -> None: bot = _Bot([_Table("费用类别 出行方式 报销金额", ["交通费 火车 233", "¥233.00"])]) info = {"reimbursement_details": {"transport_fee": [{"amount": "233.00"}]}} check = bot.self_check_step("travel", "details", info) assert check["readable"] is True assert check["rows"] == 1 and check["amount"] == 233.0 assert check["notes"] == [] def test_travel_details_mismatch_reports_rows_and_total() -> None: bot = _Bot([_Table("费用类别 出行方式 报销金额", ["交通费 火车 233", "¥233.00"])]) info = { "reimbursement_details": { "transport_fee": [{"amount": "233.00"}, {"amount": "233.00"}], } } notes = bot.self_check_step("travel", "details", info)["notes"] assert notes and "行数 页面 1 / info 2" in notes[0] assert "合计 页面 233.00 / info 466.00" in notes[0] def test_payment_matches() -> None: bot = _Bot([_Table("支付方式 支付金额 开户行", ["工行公务卡 231.00 工商银行", "¥231.00"])]) info = {"payment_methods": [{"amount": "231.00"}]} check = bot.self_check_step("travel", "payment", info) assert check["readable"] is True and check["notes"] == [] def test_missing_table_says_not_checked() -> None: bot = _Bot([]) check = bot.self_check_step("travel", "payment", {"payment_methods": []}) assert check["readable"] is False assert "没有核对过" in check["notes"][0] def test_steps_without_table_are_skipped() -> None: bot = _Bot([]) assert "skipped" in bot.self_check_step("travel", "basic", {}) assert "skipped" in bot.self_check_step("travel", "attachments", {}) def test_subsidy_compares_rows_only() -> None: bot = _Bot([_Table("补助清单 伙食补助", ["张国庆 540"])]) info = {"subsidy_list": [{"person_name": "张国庆"}]} check = bot.self_check_step("travel", "subsidy", info) assert check["readable"] is True and check["notes"] == [] assert check["expected_amount"] is None