File size: 3,733 Bytes
a612609
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# tests/integration_v2.py
"""
Integration sanity check for AI E-Consult V2 core layers.
Run with: python -m tests.integration_v2
"""

import sys
import json
from pathlib import Path
from typing import Dict, Any

# Ensure repo root on path
REPO_ROOT = Path(__file__).resolve().parents[1]
if str(REPO_ROOT) not in sys.path:
    sys.path.insert(0, str(REPO_ROOT))

from src import config, billing, modal_templates, store  # noqa: E402

RESULTS = {"passed": 0, "failed": 0}

def _ok(name: str):
    RESULTS["passed"] += 1
    print(f"[PASS] {name}")

def _fail(name: str, e: Exception):
    RESULTS["failed"] += 1
    print(f"[FAIL] {name}: {e}")

def check(name: str):
    def deco(fn):
        def wrapper():
            try:
                fn()
                _ok(name)
            except Exception as e:
                _fail(name, e)
        return wrapper
    return deco

@check("seed_cases_and_v2_schema")
def test_seed_cases_and_v2_schema():
    created = store.seed_cases(reset=True)
    assert len(created) == 4
    for cid in created:
        case = store.read_case(cid)
        assert case and case["schema_version"] == config.SCHEMA_VERSION
        for k in ["status", "created_at", "updated_at", "billing", "explainability"]:
            assert k in case

@check("load_sample_case")
def test_load_sample_case():
    items = store.list_cases()
    assert items, "No cases after seeding"
    case = store.read_case(items[0]["case_id"])
    assert case is not None
    print("  case_id:", case["case_id"], "status:", case["status"])

@check("billing_autosuggest_representative")
def test_billing_autosuggest_representative():
    combos = [(5, False), (12, True), (35, True)]
    for minutes, spoke in combos:
        sugg = billing.autosuggest_cpt(minutes=minutes, spoke=spoke)
        assert isinstance(sugg, list) and len(sugg) >= 1
        codes = [s.code for s in sugg]
        print(f"  minutes={minutes} spoke={spoke} -> {codes} (eligible={[s.code for s in sugg if s.eligible]})")

@check("modal_previews_safe_without_streamlit")
def test_modal_previews_safe_without_streamlit():
    # Build a simple note and claim, then render via modal helpers.
    cases = store.list_cases()
    case = store.read_case(cases[0]["case_id"])
    assert case
    note_md = f"# Consult Note for {case['patient']['name']}\n\nGenerated for integration preview."
    pick = billing.autosuggest_cpt(minutes=12, spoke=True)
    code = next((s.code for s in pick if s.eligible), "99447")
    rate = next((s.rate for s in pick if s.code == code), 55.0)
    claim = billing.build_837_claim(case, code=code, rate=rate, minutes=12, spoke=True, attested=True)
    # These calls are safe even if Streamlit is missing—helpers no-op or use fallbacks
    modal_templates.show_consult_note_preview(note_md)
    modal_templates.show_837_claim_preview(claim)

@check("export_filename_determinism")
def test_export_filename_determinism():
    p1 = config.make_export_path("INTEG", "consult_note.md")
    p2 = config.make_export_path("INTEG", "claim_837.json")
    assert p1.parent.exists() and p2.parent.exists()
    assert p1.name.startswith("EC-INTEG_") and p1.name.endswith("_consult_note.md")
    assert p2.name.startswith("EC-INTEG_") and p2.name.endswith("_claim_837.json")

def main():
    test_seed_cases_and_v2_schema()
    test_load_sample_case()
    test_billing_autosuggest_representative()
    test_modal_previews_safe_without_streamlit()
    test_export_filename_determinism()

    total = RESULTS["passed"] + RESULTS["failed"]
    print(f"\n=== Integration Summary: {RESULTS['passed']} passed, {RESULTS['failed']} failed, {total} total ===")
    if RESULTS["failed"]:
        raise SystemExit(1)

if __name__ == "__main__":
    main()