"""SP41 — tests for the `cyclone rebill-from-835` CLI. Three smoke tests: 1. --help renders cleanly and surfaces --window and --override-filing. 2. --status (with no other args) renders cleanly and exits 0 — the option is recognized even when no prior summary.csv exists. 3. End-to-end run against a 2-row visits CSV (one in-window, one ancient) and a zero-SVC 835 fixture produces a summary.csv with the in-window visit classified as REBILLED_B. """ from __future__ import annotations import csv from pathlib import Path from click.testing import CliRunner from cyclone.cli import main def test_rebill_from_835_help(): runner = CliRunner() result = runner.invoke(main, ["rebill-from-835", "--help"]) assert result.exit_code == 0, result.output assert "--window" in result.output assert "--override-filing" in result.output def test_rebill_from_835_status_help(): """Either bare --status or --status --help should exit 0. The spec note: the help-test ensures the option is recognized, so even a "no prior runs" 0-exit path is acceptable. We try both invocations because click short-circuits --help ahead of any required-option check; the bare --status path is the one that proves --status works without --visits / --ingest. """ runner = CliRunner() result_help = runner.invoke(main, ["rebill-from-835", "--status", "--help"]) assert result_help.exit_code == 0, result_help.output result_bare = runner.invoke(main, ["rebill-from-835", "--status"]) assert result_bare.exit_code == 0, result_bare.output def test_rebill_from_835_runs(tmp_path: Path): """End-to-end: 1 in-window visit + 1 ancient visit + zero-SVC 835 → REBILLED_B for the in-window row.""" visits_path = tmp_path / "visits.csv" visits_path.write_text( "Visit Date,Member ID,Procedure Code,Billable Amount\n" "06/27/2026,J813715,T1019,$2.32\n" "01/01/2020,ANCIENT,T1019,$2.32\n" ) ingest_dir = tmp_path / "ingest" ingest_dir.mkdir() (ingest_dir / "x.835").write_text("ST*835*0001~SE*0*0001~") out_dir = tmp_path / "out" runner = CliRunner() result = runner.invoke(main, [ "rebill-from-835", "--visits", str(visits_path), "--ingest", str(ingest_dir), "--out", str(out_dir), "--as-of", "2026-07-07", ]) assert result.exit_code == 0, ( f"CLI exited {result.exit_code}, output={result.output!r}, " f"exception={result.exception!r}" ) summary_path = out_dir / "summary.csv" assert summary_path.exists(), summary_path with summary_path.open(newline="") as f: rows = list(csv.DictReader(f)) # Two visits in, two summary rows out (one REBILLED_B, one # EXCLUDED_TIMELY_FILING). PAID outcomes would be dropped, but # neither of these is PAID — the 835 has no SVCs. assert len(rows) == 2, rows by_member = {r["member_id"]: r for r in rows} in_window = by_member["J813715"] assert in_window["disposition"] == "REBILLED_B", in_window assert in_window["dos"] == "2026-06-27", in_window ancient = by_member["ANCIENT"] assert ancient["disposition"] == "EXCLUDED_TIMELY_FILING", ancient assert ancient["dos"] == "2020-01-01", ancient