from inspect import getsource from app.admin_ui.pages.reconciliation import loose_reconciliation_items from app import reconciliation_service as service def _item(item_id: str, *, customer: str = "same", external_type: str = "jasmin_invoice") -> dict: return {"id": item_id, "customer_name": customer, "external_type": external_type} def test_item_in_displayed_process_is_not_loose_and_unrepresented_item_stays_visible(): items = [_item("invoice-188"), _item("quote-258")] candidates = [{"item_ids": ["invoice-188"]}] assert loose_reconciliation_items(items, candidates) == [items[1]] def test_multiple_documents_for_same_customer_are_separate_by_exact_id(): invoice = _item("invoice-188", customer="ACME") other_invoice = _item("invoice-112", customer="ACME") assert loose_reconciliation_items( [invoice, other_invoice], [{"item_ids": ["invoice-188"]}], ) == [other_invoice] def test_exclusion_is_exact_and_does_not_use_approximate_document_identity(): exact = _item("doc-1") similar = _item("doc-10") same_number_different_id = {**_item("doc-2"), "document_number": "FA.FA2026.188"} exact["document_number"] = "FA.FA2026.188" assert loose_reconciliation_items( [exact, similar, same_number_different_id], [{"item_ids": ["doc-1"]}], ) == [similar, same_number_different_id] def test_item_from_process_not_displayed_remains_loose(): item = _item("hidden-process-item") assert loose_reconciliation_items([item], []) == [item] assert loose_reconciliation_items([item], [{"item_ids": ["different-id"]}]) == [item] def test_process_candidate_query_preserves_status_external_type_and_days(monkeypatch): received = {} def fake_list(**kwargs): received.update(kwargs) return [] monkeypatch.setattr(service, "list_reconciliation_items", fake_list) assert service.list_reconciliation_process_candidates( status="needs_review", external_type="jasmin_invoice", days=7, limit=8, ) == [] assert received == { "status": "needs_review", "external_type": "jasmin_invoice", "days": 7, "limit": 300, } def test_page_uses_current_filters_and_only_visible_candidate_ids(): from app.admin_ui.pages import reconciliation as page source = getsource(page.reconciliation_page) assert "status=status, external_type=item_type, days=recent_days" in source assert "items = loose_reconciliation_items(items, process_candidates)" in source