Adds the second pricer to the reconciliation engine (rec was open/closed
with only PfsPricer). OppsPricer validates that our OPPS conversion
factor reproduces CMS's published Addendum B national unadjusted rate:
ground truth = opps.addendum_b.payment_rate (published, rate > 0)
calculated = relative_weight × RULES[year].conversion_factor
(APC-priced rows, weight > 0)
Rows with a weight but no published rate (packaged, SI N) surface as
calculated_only; a published rate with no weight (non-APC method) as
ground_truth_only — mirroring how PfsPricer treats carrier-priced codes.
Wage-index adjustment is intentionally out of scope: Addendum B is the
national unadjusted rate, so the check is weight × CF only.
Also:
- stack rec opps CLI subcommand (mirrors rec pfs).
- Pricer-aware "no years available" hint (was hardcoded to PFS tables).
100% coverage on the new module, CLI paths, and registry.
Note: running this against loaded Addendum B data surfaces a systematic
CF drift in opps.rules for CY2021-CY2026 (stored CFs differ from the
empirical payment_rate/weight, which matches the real published CMS
values). Tracked for a follow-up fix — the pricer is doing its job.
125 lines
4.5 KiB
Python
125 lines
4.5 KiB
Python
"""Deep exercising tests for cli/rec.py."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
from typer.testing import CliRunner
|
|
|
|
from cli.rec import app
|
|
|
|
runner = CliRunner()
|
|
|
|
|
|
class TestListPricers:
|
|
@patch(
|
|
"rec.pricers.PRICERS",
|
|
{
|
|
"pfs": MagicMock(
|
|
description="PFS", join_keys=["hcpcs"], compare_cols=["fee"]
|
|
)
|
|
},
|
|
)
|
|
def test_lists(self):
|
|
result = runner.invoke(app, ["list"])
|
|
assert result.exit_code == 0
|
|
assert "pfs" in result.output
|
|
|
|
@patch("rec.pricers.PRICERS", {})
|
|
def test_empty(self):
|
|
result = runner.invoke(app, ["list"])
|
|
assert result.exit_code == 0
|
|
|
|
|
|
class TestReconcilePfs:
|
|
@patch("rec.pricers.PRICERS")
|
|
@patch("conf.connect.duckdb")
|
|
@patch("rec.engine.reconcile")
|
|
@patch("rec.report.as_markdown", return_value="# Report")
|
|
def test_single_year(self, mc_md, mc_reconcile, mc_duck, mc_pricers):
|
|
pricer = MagicMock()
|
|
mc_pricers.__contains__ = MagicMock(return_value=True)
|
|
mc_pricers.__getitem__ = MagicMock(return_value=lambda: pricer)
|
|
mc_reconcile.return_value = MagicMock()
|
|
|
|
result = runner.invoke(app, ["pfs", "--year", "2025"])
|
|
assert result.exit_code == 0
|
|
|
|
@patch("rec.pricers.PRICERS")
|
|
@patch("conf.connect.duckdb")
|
|
@patch("rec.engine.reconcile_all_years")
|
|
@patch("rec.report.as_markdown", return_value="# All years")
|
|
def test_all_years(self, mc_md, mc_all, mc_duck, mc_pricers):
|
|
pricer = MagicMock()
|
|
mc_pricers.__contains__ = MagicMock(return_value=True)
|
|
mc_pricers.__getitem__ = MagicMock(return_value=lambda: pricer)
|
|
mc_all.return_value = {2024: MagicMock(), 2025: MagicMock()}
|
|
|
|
result = runner.invoke(app, ["pfs"])
|
|
assert result.exit_code == 0
|
|
|
|
@patch("rec.pricers.PRICERS")
|
|
@patch("conf.connect.duckdb")
|
|
@patch("rec.engine.reconcile_all_years", return_value={})
|
|
def test_no_years(self, mc_all, mc_duck, mc_pricers):
|
|
pricer = MagicMock()
|
|
mc_pricers.__contains__ = MagicMock(return_value=True)
|
|
mc_pricers.__getitem__ = MagicMock(return_value=lambda: pricer)
|
|
|
|
result = runner.invoke(app, ["pfs"])
|
|
assert result.exit_code == 1
|
|
|
|
@patch("rec.pricers.PRICERS")
|
|
@patch("conf.connect.duckdb")
|
|
@patch("rec.engine.reconcile")
|
|
@patch("rec.report.as_json", return_value='{"year": 2025}')
|
|
def test_json_format(self, mc_json, mc_reconcile, mc_duck, mc_pricers):
|
|
pricer = MagicMock()
|
|
mc_pricers.__contains__ = MagicMock(return_value=True)
|
|
mc_pricers.__getitem__ = MagicMock(return_value=lambda: pricer)
|
|
mc_reconcile.return_value = MagicMock()
|
|
|
|
result = runner.invoke(app, ["pfs", "--year", "2025", "--format", "json"])
|
|
assert result.exit_code == 0
|
|
|
|
@patch("rec.pricers.PRICERS")
|
|
@patch("conf.connect.duckdb")
|
|
@patch("rec.engine.reconcile")
|
|
@patch("rec.report.as_markdown", return_value="# Report")
|
|
def test_write_to_file(self, mc_md, mc_reconcile, mc_duck, mc_pricers, tmp_path):
|
|
pricer = MagicMock()
|
|
mc_pricers.__contains__ = MagicMock(return_value=True)
|
|
mc_pricers.__getitem__ = MagicMock(return_value=lambda: pricer)
|
|
mc_reconcile.return_value = MagicMock()
|
|
|
|
out = str(tmp_path / "report.md")
|
|
result = runner.invoke(app, ["pfs", "--year", "2025", "-o", out])
|
|
assert result.exit_code == 0
|
|
|
|
|
|
class TestReconcileOpps:
|
|
@patch("rec.pricers.PRICERS")
|
|
@patch("conf.connect.duckdb")
|
|
@patch("rec.engine.reconcile")
|
|
@patch("rec.report.as_markdown", return_value="# OPPS Report")
|
|
def test_single_year(self, mc_md, mc_reconcile, mc_duck, mc_pricers):
|
|
pricer = MagicMock()
|
|
mc_pricers.__contains__ = MagicMock(return_value=True)
|
|
mc_pricers.__getitem__ = MagicMock(return_value=lambda: pricer)
|
|
mc_reconcile.return_value = MagicMock()
|
|
|
|
result = runner.invoke(app, ["opps", "--year", "2026"])
|
|
assert result.exit_code == 0
|
|
|
|
@patch("rec.pricers.PRICERS")
|
|
@patch("conf.connect.duckdb")
|
|
@patch("rec.engine.reconcile_all_years", return_value={})
|
|
def test_no_years_hints_addendum_b(self, mc_all, mc_duck, mc_pricers):
|
|
pricer = MagicMock()
|
|
mc_pricers.__contains__ = MagicMock(return_value=True)
|
|
mc_pricers.__getitem__ = MagicMock(return_value=lambda: pricer)
|
|
|
|
result = runner.invoke(app, ["opps"])
|
|
assert result.exit_code == 1
|
|
assert "opps.addendum_b" in result.output
|