new_codes_in judges a family member code new in Y only when pfs.code_exposure has a becomes-payable row for it in Y; link targets stay new only at their link since (R84a). The round-3 row-count heuristic and the payability scan over ValuationRows are gone, so a truncated valuation(years=N) window can neither invent nor hide a new code. money_by_specialty takes exposures=; read_becomes_payable reads them for a family's member codes.
572 lines
20 KiB
Python
572 lines
20 KiB
Python
"""pfs.stakes - CMS specialty impact tables and money by specialty (T10)."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import datetime as dt
|
|
from pathlib import Path
|
|
|
|
import duckdb
|
|
import pytest
|
|
|
|
from bib.item import Source
|
|
from bib.store import Store
|
|
from pfs import stakes
|
|
from pfs.codetables import (
|
|
ExposureRow,
|
|
ImpactRow,
|
|
PspsRow,
|
|
ensure_tables,
|
|
write_exposures,
|
|
)
|
|
from pfs.stakes import (
|
|
billing_share,
|
|
discover_508,
|
|
discover_fr,
|
|
fr_table_year,
|
|
money_by_specialty,
|
|
parse_impact_508,
|
|
parse_impact_fr_text,
|
|
read_impacts,
|
|
write_impacts,
|
|
)
|
|
from pfs.valuation import ValuationRow
|
|
|
|
FIX = Path(__file__).parent / "fixtures"
|
|
|
|
|
|
def test_parse_impact_508():
|
|
rows = parse_impact_508(
|
|
FIX / "impact_cy2027_508.txt", rule_year=2027, vintage="final", item_key="K"
|
|
)
|
|
assert len(rows) == 6
|
|
a = rows[0]
|
|
assert (a.specialty, a.setting, a.allowed_mil) == (
|
|
"ALLERGY/IMMUNOLOGY",
|
|
"TOTAL",
|
|
240.0,
|
|
)
|
|
assert (a.impact_work, a.impact_pe, a.impact_mp, a.impact_combined) == (
|
|
0.0,
|
|
-0.02,
|
|
0.0,
|
|
-0.02,
|
|
)
|
|
assert (a.rule_year, a.vintage, a.source, a.item_key, a.page) == (
|
|
2027,
|
|
"final",
|
|
"508",
|
|
"K",
|
|
0,
|
|
)
|
|
assert [r.setting for r in rows[:3]] == ["TOTAL", "Non-Facility", "Facility"]
|
|
anes = rows[3]
|
|
assert (anes.specialty, anes.setting, anes.allowed_mil) == (
|
|
"ANESTHESIOLOGY",
|
|
"TOTAL",
|
|
1672.0,
|
|
)
|
|
|
|
|
|
def test_parse_impact_fr_text():
|
|
rows = parse_impact_fr_text(
|
|
(FIX / "impact_cy2017_fr.txt").read_text(),
|
|
rule_year=2017,
|
|
vintage="final",
|
|
item_key="FR",
|
|
)
|
|
assert [r.specialty for r in rows] == [
|
|
"TOTAL",
|
|
"ALLERGY/IMMUNOLOGY",
|
|
"ANESTHESIOLOGY",
|
|
"AUDIOLOGIST",
|
|
]
|
|
tot, allergy = rows[0], rows[1]
|
|
assert tot.allowed_mil == 89866.0
|
|
assert (allergy.allowed_mil, allergy.impact_pe, allergy.impact_combined) == (
|
|
231.0,
|
|
0.01,
|
|
0.01,
|
|
)
|
|
assert (allergy.setting, allergy.source, allergy.page) == ("TOTAL", "fr", 80544)
|
|
|
|
|
|
def test_fr_text_other_table_titles_and_wrapped_names_and_page_changes():
|
|
text = "\n".join(
|
|
[
|
|
"[[Page 10]]",
|
|
"Table 72--CY 2014 PFS Estimated Impact on Total Allowed Charges by Specialty by Selected Proposal*",
|
|
"-----",
|
|
"ALLERGY..... 1 0 0 0 0",
|
|
"Table 7--CY 2014 PFS Estimated Impact on Total Allowed Charges by Specialty *",
|
|
"-----",
|
|
"(A) Specialty (B)",
|
|
"MULTISPECIALTY CLINIC/OTHER PHYS 129 -1.5 0 0 1",
|
|
"[[Page 11]]",
|
|
"",
|
|
"OTHER........... 27 0 0 0 -1",
|
|
"A footnote line",
|
|
"NOT A ROW..... 1 0 0 0 0",
|
|
]
|
|
)
|
|
rows = parse_impact_fr_text(text, rule_year=2014, vintage="proposed", item_key="X")
|
|
assert [(r.specialty, r.page) for r in rows] == [
|
|
("MULTISPECIALTY CLINIC/OTHER PHYS", 10),
|
|
("OTHER", 11),
|
|
]
|
|
assert rows[0].impact_work == -0.015
|
|
assert rows[1].impact_combined == -0.01
|
|
|
|
|
|
def test_fr_text_older_layouts():
|
|
text = "\n".join(
|
|
[
|
|
"[[Page 5]]",
|
|
"Table 134--CY 2013 PFS Final Rule With Comment Period Estimated Impact on Total Allowed Charges by Specialty *",
|
|
"-----",
|
|
"TOTAL........................................... $ 86,588 0 0 0",
|
|
"02-ANESTHESIOLOGY **............................ 1,923 0 1 1",
|
|
" TOTAL................ $89,020 0% 0% 0% -1%",
|
|
"ANESTHESIOLOGY....... $1,970 0% 1% -2% 0%",
|
|
]
|
|
)
|
|
rows = parse_impact_fr_text(text, rule_year=2013, vintage="final", item_key="X")
|
|
assert [r.specialty for r in rows] == [
|
|
"TOTAL",
|
|
"ANESTHESIOLOGY",
|
|
"TOTAL",
|
|
"ANESTHESIOLOGY",
|
|
]
|
|
tot, anes, tot16, anes16 = rows
|
|
assert tot.allowed_mil == 86588.0
|
|
assert (anes.impact_work, anes.impact_pe, anes.impact_mp, anes.impact_combined) == (
|
|
0.0,
|
|
0.01,
|
|
None,
|
|
0.01,
|
|
)
|
|
assert (tot16.allowed_mil, tot16.impact_combined) == (89020.0, -0.01)
|
|
assert (anes16.impact_pe, anes16.impact_mp) == (0.01, -0.02)
|
|
|
|
|
|
def test_percent_and_money_helpers():
|
|
assert stakes._pct("-2%") == -0.02
|
|
assert stakes._pct("3 %") == 0.03
|
|
assert stakes._pct("") is None
|
|
assert stakes._pct("1") is None # a bare number is not a 508 percent
|
|
assert stakes._pct("1", bare_points=True) == 0.01
|
|
assert stakes._pct("x%") is None
|
|
assert stakes._pct("x", bare_points=True) is None
|
|
assert stakes._money("$1,672") == 1672.0
|
|
assert stakes._money("n/a") is None
|
|
|
|
|
|
def test_508_skips_short_and_unknown_setting_lines(tmp_path):
|
|
p = tmp_path / "x_508.txt"
|
|
p.write_text('title\nA\tB\tC\n"* note"\tx\nFOO\tTOTAL\t$5\t0%\t0%\t0%\t1%\t\n')
|
|
rows = parse_impact_508(p, rule_year=2027, vintage="final")
|
|
assert [
|
|
(r.specialty, r.allowed_mil, r.impact_combined, r.item_key) for r in rows
|
|
] == [("FOO", 5.0, 0.01, "")]
|
|
|
|
|
|
@pytest.fixture
|
|
def con():
|
|
c = duckdb.connect(":memory:")
|
|
ensure_tables(c)
|
|
yield c
|
|
c.close()
|
|
|
|
|
|
def test_write_and_read_impacts(con):
|
|
rows = parse_impact_508(
|
|
FIX / "impact_cy2027_508.txt", rule_year=2027, vintage="final"
|
|
)
|
|
fr = parse_impact_fr_text(
|
|
(FIX / "impact_cy2017_fr.txt").read_text(),
|
|
rule_year=2017,
|
|
vintage="final",
|
|
item_key="FR",
|
|
)
|
|
assert write_impacts(con, 2027, "final", rows, source="508") == 6
|
|
assert write_impacts(con, 2017, "final", fr, source="fr") == 4
|
|
assert write_impacts(con, 2027, "final", rows[:3], source="508") == 3 # replaces
|
|
got = read_impacts(con)
|
|
assert [(r.rule_year, r.source) for r in got].count((2027, "508")) == 3
|
|
assert [r.rule_year for r in read_impacts(con, [2017])] == [2017] * 4
|
|
assert isinstance(got[0], ImpactRow)
|
|
assert write_impacts(con, 2020, "final", [], source="508") == 0
|
|
|
|
|
|
def test_fr_table_year():
|
|
t = "x\nTable 52--CY 2017 PFS Estimated Impact on Total Allowed Charges by Specialty *\n"
|
|
assert fr_table_year(t) == 2017
|
|
assert (
|
|
fr_table_year("Table 5 Estimated Impact on Total Allowed Charges by Specialty")
|
|
is None
|
|
)
|
|
assert fr_table_year("nothing here") is None
|
|
|
|
|
|
def test_impacts_scan_finds_508(tmp_path):
|
|
name = "CY 2027 PFS Final Rule Estimated Impact on Total Allowed Charges by Specialty_508.txt"
|
|
src = tmp_path / "src"
|
|
src.mkdir()
|
|
f = src / name
|
|
f.write_text((FIX / "impact_cy2027_508.txt").read_text())
|
|
other = src / "other_508.txt"
|
|
other.write_text("x")
|
|
store = Store(":memory:", storage_dir=tmp_path / "storage")
|
|
try:
|
|
key = store.upsert(Source(title="Impacts", url="https://x/y"))
|
|
store.attach_file(key, f)
|
|
store.attach_file(key, other)
|
|
# an older year that lives only under the pfs_final directory tree
|
|
root = tmp_path / "pfs_final"
|
|
d = root / "2026" / "files" / "d"
|
|
d.mkdir(parents=True)
|
|
(d / name.replace("2027", "2026")).write_text("x")
|
|
(d / "unrelated_508.txt").write_text("x")
|
|
(d / "CY 2026 Impact on Total Allowed Charges by Specialty_508.txt").write_text(
|
|
"x"
|
|
)
|
|
# the 2027 tree copy must not duplicate the bib one
|
|
d27 = root / "2027" / "files" / "d"
|
|
d27.mkdir(parents=True)
|
|
(d27 / name).write_text("x")
|
|
found = discover_508(store, root)
|
|
finally:
|
|
store.close()
|
|
got = {(s.rule_year, s.vintage): s for s in found}
|
|
assert set(got) == {(2027, "final"), (2026, "final")}
|
|
assert got[(2027, "final")].item_key == key and got[(2027, "final")].kind == "508"
|
|
assert got[(2026, "final")].item_key == ""
|
|
|
|
|
|
def test_discover_fr(tmp_path, monkeypatch):
|
|
import pfs.rounds as rounds
|
|
|
|
t = tmp_path / "a.txt"
|
|
t.write_text((FIX / "impact_cy2017_fr.txt").read_text())
|
|
n = tmp_path / "n.txt"
|
|
n.write_text("no table")
|
|
items = [
|
|
{"item_key": "A", "kind": "final"},
|
|
{"item_key": "B", "kind": "rule"},
|
|
{"item_key": "C", "kind": "proposed"}, # no text on disk
|
|
{"item_key": "D", "kind": "final"}, # text without the table
|
|
]
|
|
paths = {"A": t, "B": t, "C": None, "D": n}
|
|
monkeypatch.setattr(rounds, "rule_items", lambda store, anchors: items)
|
|
monkeypatch.setattr(rounds, "fr_text_path", lambda store, k: paths[k])
|
|
found = discover_fr(object())
|
|
assert [(s.rule_year, s.vintage, s.item_key, s.kind) for s in found] == [
|
|
(2017, "final", "A", "fr")
|
|
]
|
|
|
|
|
|
# ── money by specialty ───────────────────────────────────────────────
|
|
|
|
|
|
def val(code, year, pay, *, proposed=False, status="A"):
|
|
return ValuationRow(
|
|
code=code,
|
|
description="",
|
|
vintage=f"CY{year} {'proposed' if proposed else 'final'}",
|
|
year=year,
|
|
proposed=proposed,
|
|
status=status,
|
|
work=None,
|
|
pe_nf=None,
|
|
pe_f=None,
|
|
mp=None,
|
|
total_nf=None,
|
|
total_f=None,
|
|
cf=1.0,
|
|
pay_nf=pay,
|
|
pay_f=None,
|
|
label="",
|
|
citation="",
|
|
url="",
|
|
)
|
|
|
|
|
|
def ps(year, code, spec, n):
|
|
return PspsRow(year, code, "00", spec, n, None, None, "d", "K")
|
|
|
|
|
|
def exp(code, year, kind="becomes-payable"):
|
|
"""An exposure-calendar row (pfs.code_exposure, #693)."""
|
|
return ExposureRow(
|
|
code=code,
|
|
family="",
|
|
effective_date=dt.date(year, 1, 1),
|
|
year=year,
|
|
kind=kind,
|
|
status="A",
|
|
prior_status="",
|
|
rvu_band=0,
|
|
non_fac_total=0.0,
|
|
delta_pct=0.0,
|
|
item_key="",
|
|
p_id=0,
|
|
page=0,
|
|
anchor_kind="",
|
|
correction=False,
|
|
note="",
|
|
)
|
|
|
|
|
|
def test_money_by_specialty_exact():
|
|
payment = [val("99350", 2022, 100.0), val("99350", 2023, 90.0)]
|
|
psps = [
|
|
ps(2022, "99350", "Family Practice", 10.0),
|
|
ps(2022, "99350", "Nurse Practitioner", 30.0),
|
|
]
|
|
out = money_by_specialty(payment, psps, year=2023)
|
|
by = {m.specialty: m for m in out}
|
|
fp, np_ = by["FAMILY PRACTICE"], by["NURSE PRACTITIONER"]
|
|
assert (fp.delta_per_service, fp.delta_total, fp.share) == (-10.0, -100.0, 0.25)
|
|
assert (np_.delta_per_service, np_.delta_total, np_.share) == (-10.0, -300.0, 0.75)
|
|
assert fp.delta_pct == pytest.approx(-0.10)
|
|
assert fp.new_payment is False
|
|
assert fp.proposed_delta_total is None and fp.proposed_delta_pct is None
|
|
assert [m.specialty for m in out] == ["NURSE PRACTITIONER", "FAMILY PRACTICE"]
|
|
|
|
|
|
def test_missing_year_gives_none_delta_but_counts_in_share():
|
|
payment = [
|
|
val("A", 2022, 100.0),
|
|
val("A", 2023, 50.0),
|
|
val("B", 2023, 10.0), # no prior-year payment
|
|
val("C", 2022, 5.0),
|
|
val("C", 2023, None, status="B"), # no longer paid
|
|
]
|
|
psps = [
|
|
ps(2021, "A", "Family Practice", 5.0), # superseded by the 2022 row
|
|
ps(2022, "A", "Family Practice", 10.0),
|
|
ps(2022, "B", "Family Practice", 10.0),
|
|
ps(2022, "B", "Cardiology", 20.0),
|
|
ps(2022, "C", "Cardiology", 5.0),
|
|
ps(2022, "A", "Cardiology", None), # suppressed, skipped
|
|
ps(2024, "A", "Family Practice", 999.0), # after year-1, ignored
|
|
]
|
|
by = {
|
|
m.specialty: m
|
|
for m in money_by_specialty(
|
|
payment, psps, year=2023, exposures=[exp("B", 2023)]
|
|
)
|
|
}
|
|
fp, ca = by["FAMILY PRACTICE"], by["CARDIOLOGY"]
|
|
assert fp.services == 20.0 and fp.share == pytest.approx(20 / 45)
|
|
assert fp.delta_total == -500.0 # only code A carries a delta
|
|
assert fp.delta_per_service == -50.0 # per service of A, not of B
|
|
assert fp.delta_pct == pytest.approx(-0.5)
|
|
assert fp.new_payment is True # the calendar: B becomes payable in 2023
|
|
assert ca.services == 25.0
|
|
assert (
|
|
ca.delta_total is None and ca.delta_per_service is None and ca.delta_pct is None
|
|
)
|
|
assert ca.new_payment is True
|
|
|
|
|
|
def test_proposed_vs_final_delta_kept_apart():
|
|
payment = [
|
|
val("A", 2026, 100.0),
|
|
val("A", 2027, 90.0),
|
|
val("A", 2027, 80.0, proposed=True),
|
|
val("A", 2028, 1.0, proposed=True), # another year's NPRM, ignored
|
|
val("B", 2027, 40.0, proposed=True), # proposed but no prior final
|
|
]
|
|
psps = [
|
|
ps(2026, "A", "Family Practice", 10.0),
|
|
ps(2026, "B", "Family Practice", 1.0),
|
|
]
|
|
(m,) = money_by_specialty(payment, psps, year=2027)
|
|
assert m.delta_total == -100.0
|
|
assert m.proposed_delta_total == -200.0
|
|
assert m.proposed_delta_per_service == -20.0
|
|
assert m.proposed_delta_pct == pytest.approx(-0.2)
|
|
|
|
|
|
def test_suppressed_lines_make_a_lower_bound_not_a_none():
|
|
payment = [val("A", 2022, 100.0), val("A", 2023, 90.0)]
|
|
psps = [
|
|
PspsRow(2022, "A", "08", "Family Practice", None, None, 5.0, "d", "K", 12.0, 3),
|
|
PspsRow(2022, "A", "50", "Nurse Practitioner", 8.0, 1.0, 5.0, "d", "K", 8.0, 0),
|
|
PspsRow(2022, "A", "06", "Cardiology", None, None, 5.0, "d", "K", None, 2),
|
|
]
|
|
by = {m.specialty: m for m in money_by_specialty(payment, psps, year=2023)}
|
|
assert set(by) == {"FAMILY PRACTICE", "NURSE PRACTITIONER"}
|
|
assert by["FAMILY PRACTICE"].services == 12.0
|
|
assert by["FAMILY PRACTICE"].lower_bound is True
|
|
assert by["FAMILY PRACTICE"].delta_total == -120.0
|
|
assert by["NURSE PRACTITIONER"].lower_bound is False
|
|
assert billing_share(psps, year=2023) == {
|
|
"FAMILY PRACTICE": 0.6,
|
|
"NURSE PRACTITIONER": 0.4,
|
|
}
|
|
|
|
|
|
def test_unnamed_specialty_falls_back_to_code_and_empty_inputs():
|
|
(m,) = money_by_specialty(
|
|
[val("A", 2022, 1.0), val("A", 2023, 2.0)],
|
|
[PspsRow(2022, "A", "99", "", 4.0, None, None, "d", "K")],
|
|
year=2023,
|
|
)
|
|
assert m.specialty == "CODE 99" and m.delta_total == 4.0
|
|
assert money_by_specialty([], [], year=2023) == []
|
|
# zero services: share is 0, never a division error
|
|
(z,) = money_by_specialty([], [ps(2022, "A", "Family Practice", 0.0)], year=2023)
|
|
assert z.share == 0.0 and z.delta_total is None
|
|
|
|
|
|
def test_billing_share():
|
|
psps = [
|
|
ps(2022, "A", "Family Practice", 10.0),
|
|
ps(2022, "A", "Cardiology", 30.0),
|
|
ps(2023, "B", "Family Practice", 60.0),
|
|
]
|
|
got = billing_share(psps, year=2024)
|
|
assert got == {"FAMILY PRACTICE": 0.7, "CARDIOLOGY": 0.3}
|
|
assert billing_share(psps, year=2023) == {
|
|
"FAMILY PRACTICE": 0.25,
|
|
"CARDIOLOGY": 0.75,
|
|
}
|
|
assert billing_share([], year=2023) == {}
|
|
|
|
|
|
class Link:
|
|
def __init__(self, target, since):
|
|
self.target, self.since = target, since
|
|
|
|
|
|
class FamLink: # a pfs.code_family-shaped row
|
|
def __init__(self, code, since):
|
|
self.code, self.since = code, since
|
|
|
|
|
|
def test_new_code_with_no_psps_rows_flips_new_payment_for_every_specialty():
|
|
# G0318-shaped: payable in 2023, absent in 2022, never billed in PSPS
|
|
payment = [
|
|
val("99350", 2022, 100.0),
|
|
val("99350", 2023, 90.0),
|
|
val("G0318", 2023, 15.0),
|
|
]
|
|
psps = [
|
|
ps(2022, "99350", "Family Practice", 10.0),
|
|
ps(2022, "99350", "Cardiology", 5.0),
|
|
]
|
|
out = money_by_specialty(payment, psps, year=2023, exposures=[exp("G0318", 2023)])
|
|
assert [m.new_payment for m in out] == [True, True]
|
|
assert all(m.new_codes == ("G0318",) for m in out)
|
|
assert all(m.delta_note == "new, amount n/a" for m in out)
|
|
assert out[0].delta_total == -100.0 # the existing code's delta is untouched
|
|
|
|
|
|
def test_curated_link_since_year_is_a_new_payment_event():
|
|
payment = [val("99350", 2026, 100.0), val("99350", 2027, 100.0)]
|
|
psps = [ps(2026, "99350", "Family Practice", 10.0)]
|
|
links = [Link("B1", 2027), Link("B2", 2027), Link("G2211", 2026)]
|
|
(m,) = money_by_specialty(payment, psps, year=2027, links=links)
|
|
assert m.new_payment and m.new_codes == ("B1", "B2")
|
|
(m,) = money_by_specialty(payment, psps, year=2027, links=[FamLink("B1", 2027)])
|
|
assert m.new_codes == ("B1",)
|
|
(m,) = money_by_specialty(payment, psps, year=2027)
|
|
assert not m.new_payment and m.new_codes == () and m.delta_note == ""
|
|
|
|
|
|
def test_payment_rows_alone_never_flag_a_member_code():
|
|
# R84c: D absent in 2022 and X non-payable in 2022 looked "new" in 2023
|
|
# from the payment rows; newness now comes only from the calendar
|
|
payment = [
|
|
val("B", 2022, 5.0),
|
|
val("B", 2023, 5.0),
|
|
val("D", 2023, 5.0),
|
|
val("X", 2022, 5.0, status="B"),
|
|
val("X", 2023, 5.0),
|
|
]
|
|
psps = [ps(2022, "B", "Family Practice", 1.0)]
|
|
(m,) = money_by_specialty(payment, psps, year=2023)
|
|
assert m.new_codes == () and not m.new_payment and m.delta_note == ""
|
|
|
|
|
|
def test_member_code_is_new_in_its_becomes_payable_year_only():
|
|
payment = [val("B", 2022, 5.0), val("B", 2023, 5.0), val("B", 2024, 5.0)]
|
|
psps = [ps(2022, "B", "Family Practice", 1.0)]
|
|
exposures = [
|
|
exp("X", 2023),
|
|
exp("D", 2024), # another year
|
|
exp("B", 2023, "revalued"), # other calendar kinds never flag
|
|
exp("B", 2023, "status-change"),
|
|
exp("E", 2023, "ends"),
|
|
exp("T", 2023, "telehealth-listed"),
|
|
]
|
|
flags = {
|
|
y: money_by_specialty(payment, psps, year=y, exposures=exposures)[0]
|
|
for y in (2023, 2024, 2025)
|
|
}
|
|
assert {y: m.new_codes for y, m in flags.items()} == {
|
|
2023: ("X",),
|
|
2024: ("D",),
|
|
2025: (),
|
|
}
|
|
assert flags[2023].new_payment and flags[2023].delta_note == "new, amount n/a"
|
|
assert not flags[2025].new_payment
|
|
|
|
|
|
def test_link_target_flags_only_in_its_since_year_not_when_first_payable():
|
|
# G2211-shaped: the calendar has it becoming payable in 2024, link since 2026
|
|
payment = [val("99350", y, 100.0) for y in (2023, 2024, 2025, 2026)]
|
|
payment += [val("G2211", y, 15.0) for y in (2024, 2025, 2026)]
|
|
psps = [ps(2022, "99350", "Family Practice", 10.0)]
|
|
links = [Link("G2211", 2026)]
|
|
exposures = [exp("G2211", 2024)]
|
|
flags = {
|
|
y: money_by_specialty(payment, psps, year=y, links=links, exposures=exposures)[
|
|
0
|
|
].new_codes
|
|
for y in (2024, 2025, 2026)
|
|
}
|
|
assert flags == {2024: (), 2025: (), 2026: ("G2211",)}
|
|
# a member code (not a link target) still flags by its calendar row
|
|
exposures.append(exp("G0318", 2024))
|
|
(m,) = money_by_specialty(
|
|
payment, psps, year=2024, links=links, exposures=exposures
|
|
)
|
|
assert m.new_codes == ("G0318",)
|
|
|
|
|
|
def test_truncated_payment_window_neither_flags_nor_hides_a_code():
|
|
# valuation(years=7) shape: predecessors 2016-2022, current codes cut to
|
|
# 2021-2027. NEWC is genuinely new in 2021 with the same row count as the
|
|
# longest history (the round-3 heuristic hid it); 99350 is not new
|
|
payment = [val("99324", y, 50.0) for y in range(2016, 2023)]
|
|
payment += [val("99350", y, 100.0) for y in range(2021, 2028)]
|
|
payment += [val("NEWC", y, 20.0) for y in range(2021, 2028)]
|
|
payment += [val("G0318", y, 15.0) for y in range(2023, 2028)]
|
|
psps = [ps(2015, "99350", "Family Practice", 10.0)]
|
|
exposures = [exp("NEWC", 2021), exp("G0318", 2023), exp("99324", 2023, "ends")]
|
|
new = {
|
|
y: money_by_specialty(payment, psps, year=y, exposures=exposures)[0].new_codes
|
|
for y in range(2016, 2028)
|
|
}
|
|
assert {y: c for y, c in new.items() if c} == {2021: ("NEWC",), 2023: ("G0318",)}
|
|
|
|
|
|
def test_read_becomes_payable(con):
|
|
write_exposures(
|
|
con,
|
|
[
|
|
exp("G0318", 2023),
|
|
exp("G0318", 2023, "telehealth-listed"),
|
|
exp("99350", 2027, "telehealth-listed"),
|
|
exp("99343", 2023, "ends"),
|
|
exp("OTHER", 2020),
|
|
],
|
|
)
|
|
got = stakes.read_becomes_payable(con, ["g0318", "99350", "99343"])
|
|
assert [(r.code, r.year, r.kind) for r in got] == [
|
|
("G0318", 2023, "becomes-payable")
|
|
]
|
|
assert stakes.read_becomes_payable(con, []) == []
|