232 lines
8.6 KiB
Python
232 lines
8.6 KiB
Python
r"""
|
|
conditions/lab_codes.py — document #3 and #4 (EEWA-38, operator
|
|
2026-10-28): a lab code (5 digits starting with 8) by the claim's primary
|
|
payer —
|
|
|
|
* a Medicare payer (#25's exact eCW names): no lab code at all;
|
|
* Cigna Salud Employee: any lab code;
|
|
* every other payer, blank included: only the 13 in-house codes.
|
|
|
|
A lab code the payer does not take is unchecked and its Billed Fee zeroed.
|
|
36416 and every non-8 code are never touched. Not on Dental claims.
|
|
|
|
python tests\test_conditions_lab_codes.py
|
|
|
|
Uses hcfa_claim.html like the Medicaid uncheck tests: `_inject_cpt_row()`
|
|
adds the lab lines.
|
|
"""
|
|
|
|
import io
|
|
import sys
|
|
import pathlib
|
|
import inspect
|
|
import contextlib
|
|
|
|
ROOT = pathlib.Path(__file__).resolve().parent.parent
|
|
sys.path.insert(0, str(ROOT / "src"))
|
|
sys.path.insert(0, str(ROOT / "tests"))
|
|
|
|
FIXTURE = pathlib.Path(__file__).resolve().parent / "fixtures" / "hcfa_claim.html"
|
|
|
|
from ecw_bot.conditions import lab_codes as cond # noqa: E402
|
|
from ecw_bot.conditions import CONDITIONS # noqa: E402
|
|
from ecw_bot.conditions.base import ConditionResult, run_all # noqa: E402
|
|
from ecw_bot.core import charge_summary as cs # noqa: E402
|
|
from ecw_bot.selectors import claim_form as sel # noqa: E402
|
|
from test_conditions_medicaid_uncheck_cpts import _inject_cpt_row # noqa: E402
|
|
|
|
CASES = []
|
|
|
|
|
|
def case(fn):
|
|
CASES.append(fn)
|
|
return fn
|
|
|
|
|
|
def _claim(payer, *codes, screen=None):
|
|
data = {"insurance": [{"Name": payer}] if payer is not None else [],
|
|
"cpt": [{"code": c, "checked": True, "fee": "45.00"}
|
|
for c in codes]}
|
|
if screen:
|
|
data["screen"] = screen
|
|
return data
|
|
|
|
|
|
# ── detect (no browser) ──────────────────────────────────────────────────────
|
|
|
|
@case
|
|
def a_lab_code_is_five_digits_starting_with_8():
|
|
for code in ("80053", "85025", " 87636 ", "89999", "80000"):
|
|
assert cond.is_lab_code(code), code
|
|
for code in ("36416", "99213", "8005", "800530", "G0466", "8005F",
|
|
"J2001", ""):
|
|
assert not cond.is_lab_code(code), code
|
|
|
|
|
|
@case
|
|
def medicare_payers_take_no_lab_code():
|
|
for payer in ("Medicare", "medicare-novitas", "HCFA Medicare",
|
|
"Humana Medicare", "Devoted MCR UB", "Cigna Healthspring",
|
|
" Cigna Health Spring/ Bravo "):
|
|
assert cond.detect("C1", _claim(payer, "99213", "82948")), payer
|
|
assert cond.detect("C1", _claim(payer, "80053")), payer
|
|
|
|
|
|
@case
|
|
def cigna_salud_takes_any_lab_code():
|
|
assert cond.detect("C1", _claim("Cigna Salud Employee", "80053",
|
|
"85025", "82948")) is False
|
|
assert cond.detect("C1", _claim(" cigna salud employee ",
|
|
"80053")) is False
|
|
|
|
|
|
@case
|
|
def other_payers_take_only_the_13_in_house_codes():
|
|
in_house = ("82948", "81025", "85018", "82270", "82274", "87806",
|
|
"85610", "87880", "80305", "81001", "81003", "87210",
|
|
"87636")
|
|
assert len(set(in_house)) == 13
|
|
for payer in ("Medicaid", "Cigna HealthCare Of Colorado", "AARP", "",
|
|
None):
|
|
assert cond.detect("C1", _claim(payer, "99213", *in_house)) is False, \
|
|
payer
|
|
assert cond.detect("C1", _claim(payer, "82948", "80053")), payer
|
|
|
|
|
|
@case
|
|
def non_lab_codes_never_fire_it():
|
|
assert cond.detect("C1", _claim("Medicare", "99213", "36416",
|
|
"G0467")) is False
|
|
assert cond.detect("C1", {}) is False
|
|
|
|
|
|
@case
|
|
def not_on_a_dental_claim():
|
|
assert cond.detect("C1", _claim("Medicare", "80053",
|
|
screen="dental")) is False
|
|
|
|
|
|
# ── apply (browser) ──────────────────────────────────────────────────────────
|
|
|
|
@case
|
|
def medicare_every_lab_line_unchecked_and_zeroed(page):
|
|
page.goto(FIXTURE.as_uri())
|
|
_inject_cpt_row(page, "82948", row_id="CPTROW_3", fee="15.00")
|
|
_inject_cpt_row(page, "36416", row_id="CPTROW_4", fee="8.00")
|
|
result = cond.apply(page, "C1", _claim("Medicare", "82948", "36416"))
|
|
assert isinstance(result, ConditionResult)
|
|
assert result.condition_name == "lab_codes"
|
|
assert [c["code"] for c in result.changes] == ["82948"], result.changes
|
|
c = result.changes[0]
|
|
assert c["unchecked"] is True and c["fee"] == {"before": "15.00",
|
|
"after": "0.00"}, c
|
|
rows = page.locator(sel.SEL_CPT_ROWS)
|
|
assert rows.nth(3).locator(sel.SEL_CPT_BILLED_FEE).first.input_value() \
|
|
== "0.00"
|
|
assert rows.nth(4).locator(sel.SEL_CPT_BILLED_FEE).first.input_value() \
|
|
== "8.00", "36416 is not a lab code"
|
|
assert rows.nth(0).locator(sel.SEL_CPT_BILLED_FEE).first.input_value() \
|
|
== "210.00", "99213 must be left alone"
|
|
|
|
|
|
@case
|
|
def other_payer_only_the_codes_outside_the_13(page):
|
|
page.goto(FIXTURE.as_uri())
|
|
_inject_cpt_row(page, "87880", row_id="CPTROW_3", fee="30.00")
|
|
_inject_cpt_row(page, "80053", row_id="CPTROW_4", fee="55.00")
|
|
result = cond.apply(page, "C1", _claim("Cigna HealthCare Of Colorado",
|
|
"87880", "80053"))
|
|
assert [c["code"] for c in result.changes] == ["80053"], result.changes
|
|
rows = page.locator(sel.SEL_CPT_ROWS)
|
|
assert rows.nth(3).locator(sel.SEL_CPT_BILLED_FEE).first.input_value() \
|
|
== "30.00", "87880 is in-house"
|
|
|
|
|
|
@case
|
|
def apply_is_a_no_op_once_already_excluded(page):
|
|
page.goto(FIXTURE.as_uri())
|
|
_inject_cpt_row(page, "80053", checked=False, fee="0.00")
|
|
result = cond.apply(page, "C1", _claim("Medicare", "80053"))
|
|
assert result.changed is False and result.changes == []
|
|
|
|
|
|
@case
|
|
def the_comment_names_the_codes_and_the_rule(page):
|
|
page.goto(FIXTURE.as_uri())
|
|
_inject_cpt_row(page, "80053", fee="55.00")
|
|
text = cond.summary_comment(cond.apply(page, "C1",
|
|
_claim("Medicare", "80053")))
|
|
assert "80053" in text and "Medicare" in text, text
|
|
page.goto(FIXTURE.as_uri())
|
|
_inject_cpt_row(page, "80053", fee="55.00")
|
|
text = cond.summary_comment(cond.apply(page, "C1",
|
|
_claim("AARP", "80053")))
|
|
assert "80053" in text and "in-house" in text, text
|
|
|
|
|
|
@case
|
|
def describe_names_the_code_and_the_fee_change(page):
|
|
page.goto(FIXTURE.as_uri())
|
|
_inject_cpt_row(page, "80053", fee="55.00")
|
|
text = cond.describe(cond.apply(page, "C1", _claim("AARP", "80053")))
|
|
assert "80053" in text and "55.00" in text and "0.00" in text, text
|
|
|
|
|
|
# ── wiring ───────────────────────────────────────────────────────────────────
|
|
|
|
@case
|
|
def it_is_registered_before_priced_line_check():
|
|
names = [m.NAME for m in CONDITIONS]
|
|
assert "lab_codes" in names
|
|
assert names.index("lab_codes") < names.index("priced_line_check"), names
|
|
|
|
|
|
@case
|
|
def the_charge_summary_has_a_fallback_comment():
|
|
assert "Lab code" in cs.COMMENTS["lab_codes"]
|
|
|
|
|
|
@case
|
|
def run_all_leaves_the_lab_line_unchecked_at_the_end(page):
|
|
# priced_line_check runs last: the zeroed lab line must stay unchecked.
|
|
page.goto(FIXTURE.as_uri())
|
|
_inject_cpt_row(page, "80053", fee="55.00")
|
|
with contextlib.redirect_stdout(io.StringIO()):
|
|
results = run_all(page, "C1", _claim("Medicare", "80053"))
|
|
assert "lab_codes" in [r.condition_name for r in results], results
|
|
row = page.locator(sel.SEL_CPT_ROWS).nth(3)
|
|
assert row.locator(sel.SEL_CPT_ASSIGN_TO_PATIENT).first.is_checked() \
|
|
is False
|
|
assert row.locator(sel.SEL_CPT_BILLED_FEE).first.input_value() == "0.00"
|
|
|
|
|
|
def main() -> int:
|
|
from playwright.sync_api import sync_playwright
|
|
|
|
failures = 0
|
|
with sync_playwright() as pw:
|
|
browser = pw.chromium.launch(headless=True)
|
|
page = browser.new_page()
|
|
for fn in CASES:
|
|
name = fn.__name__.replace("_", " ")
|
|
try:
|
|
if len(inspect.signature(fn).parameters) == 0:
|
|
fn()
|
|
else:
|
|
fn(page)
|
|
print(f" ok {name}")
|
|
except AssertionError as exc:
|
|
print(f" FAIL {name}: {exc}")
|
|
failures += 1
|
|
except Exception as exc:
|
|
print(f" ERROR {name}: {type(exc).__name__}: {exc}")
|
|
failures += 1
|
|
browser.close()
|
|
|
|
print(f"\n{len(CASES) - failures}/{len(CASES)} passed")
|
|
return 1 if failures else 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|