Files
ecw-charge-validation/tests/test_conditions_priced_line_check.py

976 lines
42 KiB
Python

r"""
conditions/priced_line_check.py — the reverse half of the operator's common
rule for every claim (2026-09-30): a CPT line that carries a billed fee but
is unchecked gets checked. Only that direction — a checked line is never
touched, and the fee is never written.
python tests\test_conditions_priced_line_check.py
Pure-data cases first (the shared priced-fee predicate, then detect()), then
page cases against BOTH claim screens, with the same injection helpers and
fixtures as test_conditions_zero_fee_uncheck.py: hcfa_claim.html, whose own
rows carry the live-verified "Assign To Patient" checkbox, and ub_claim.html,
whose own rows carry a plain checkbox with no ng-click at all — so on the UB
form a UB-style row is injected with the checkbox vaccine_claim.html's rows
use, and the fixture's own rows stand in for a row whose checkbox state is
unknown.
hcfa_claim.html's own G8510 (CPTROW_2) sits UNCHECKED at 65.00 — the 9103000
shape depression_dx_pointer re-includes, and exactly the line this rule
checks. Cases about some other line call `_neutralise_fixture_g8510()`
first, so that line cannot answer for them.
The run_all() cases are the point of registering this LAST. Each exclusion
condition — j2930_j2001_update (J2001), dummy_codes (DCONS),
medicare_telehealth ("other primary CPT codes") and depression_dx_pointer's
duplicate step — starts from an original grid where the line it excludes is
UNCHECKED but still PRICED. That line must end unchecked at 0.00, its
checkbox never clicked, and no result may report a check on it: the
check/uncheck toggle claim 9131000 showed between two steps of one
condition, here between two conditions. One contrast case runs this
condition FIRST instead, to prove that order is what prevents it.
Live evidence: 0 of the 39 saved claim snapshots had an unchecked priced
line — this is rare — and exactly one had a checked zero-fee line (85018 at
0.00, zero_fee_uncheck's half).
"""
import io
import sys
import pathlib
import inspect
import contextlib
ROOT = pathlib.Path(__file__).resolve().parent.parent
sys.path.insert(0, str(ROOT / "src"))
FIXTURE = pathlib.Path(__file__).resolve().parent / "fixtures" / "hcfa_claim.html"
UB_FIXTURE = pathlib.Path(__file__).resolve().parent / "fixtures" / "ub_claim.html"
VACCINE_FIXTURE = pathlib.Path(__file__).resolve().parent / "fixtures" / "vaccine_claim.html"
from ecw_bot import conditions # noqa: E402
from ecw_bot.conditions import priced_line_check as plc # noqa: E402
from ecw_bot.conditions import (bh_h_code_modifier, # noqa: E402
dental_dummy_codes,
dental_payer_check,
depression_dx_pointer, dummy_codes,
injection_admin_code,
medicare_pps_code,
j2930_j2001_update, lab_codes, medicaid_uncheck_cpts,
t1017_non_billable,
medicare_billing_screening,
medicare_telehealth,
medicare_vaccine_a6, medicare_wellness_history,
medicaid_pregnancy_th,
telehealth, vaccine_admin_codes, vaccine_z23_pointer,
zero_fee_uncheck)
from ecw_bot.conditions.base import ( # noqa: E402
CPT_TAB_NOT_CONFIRMED, ConditionResult, run_all)
from ecw_bot.pages import claim_form # noqa: E402
from ecw_bot.selectors import claim_form as sel # noqa: E402
CASES = []
def case(fn):
CASES.append(fn)
return fn
def _cpt(code, billed=False, fee="150.00"):
"""One `extract()["cpt"]` row, cut down to what detect() reads."""
return {"code": code, "billed": billed, "billed_fee": fee}
def _inject_row(page, code, row_id, *, screen="hcfa", checked=False,
fee="150.00", has_checkbox=True, has_fee=True):
"""
Adds one real CPT row (a `CPTROW_` id) above the grid's trailing "*"
entry row — the same helper as test_conditions_zero_fee_uncheck.py's,
defaulting to this rule's shape (unchecked, priced). `screen` picks the
row's own markup:
* "hcfa" — hcfa_claim.html's shape: `data-fieldname` fields.
* "ub" — the UB form's `uBClaim*<n>` id prefixes, with the
"Assign To Patient" checkbox vaccine_claim.html's rows carry.
`has_checkbox` / `has_fee` drop the checkbox or the Billed Fee input
entirely — the rows whose state is unknown, which must be left alone.
"""
page.evaluate(
"""(a) => {
const n = a.rowId.replace('CPTROW_', '');
const tbody = document.querySelector(a.screen === 'ub'
? '#claimCPTCodesTable9999999999999 tbody'
: '#claimCPTCodesTable8888888888888 tbody');
const entryRow = tbody.querySelector('tr:last-child');
const esc = s => String(s).replace(/&/g, '&amp;').replace(/"/g, '&quot;');
const box = !a.hasCheckbox ? '' : (a.screen === 'ub'
? '<input type="checkbox" id="claimCPTBillToInsChk9999999999999' + n + '"'
+ ' ng-click="updateBillToIns(' + n + ')"'
: '<input type="checkbox" ng-click="updateBillToIns(' + n + ')"')
+ (a.checked ? ' checked' : '') + '>';
const codeInput = a.screen === 'ub'
? '<input id="uBClaimCPTCode' + n + '" type="text" value="' + esc(a.code) + '" readonly>'
: '<input data-fieldname="claimCPTCode" type="text" value="' + esc(a.code) + '" readonly>';
const feeInput = !a.hasFee ? '' : (a.screen === 'ub'
? '<input type="text" id="uBClaimBillFee' + n + '" value="' + esc(a.fee) + '">'
: '<input data-fieldname="ClaimCPTBilledFee" type="text" value="' + esc(a.fee) + '">');
const tr = document.createElement('tr');
tr.id = a.rowId;
tr.setAttribute('ng-repeat', 'cpt in CPTCodes');
tr.innerHTML = '<td>' + box + '</td><td>' + codeInput + '</td>'
+ '<td>' + feeInput + '</td>';
tbody.insertBefore(tr, entryRow);
}""", {"code": code, "rowId": row_id, "screen": screen,
"checked": checked, "fee": fee,
"hasCheckbox": has_checkbox, "hasFee": has_fee})
def _inject_full_g8510_row(page, row_id, *, checked, fee, icd1="1"):
"""
A second G8510 on hcfa_claim.html carrying all four ICD pointer fields
— depression_dx_pointer's retag step reads every one — the same helper
as test_conditions_zero_fee_uncheck.py's, plus `icd1` for a copy that
already carries the Z13.31 pointer ("2") alone.
"""
page.evaluate(
"""(a) => {
const tbody = document.querySelector(
'#claimCPTCodesTable8888888888888 tbody');
const entryRow = tbody.querySelector('tr:last-child');
const n = a.rowId.replace('CPTROW_', '');
const tr = document.createElement('tr');
tr.id = a.rowId;
tr.innerHTML =
'<td><input data-fieldname="claimCPTCode" value="G8510" readonly></td>'
+ '<td><input type="checkbox" ng-click="updateBillToIns(' + n + ')"'
+ (a.checked ? ' checked' : '') + '></td>'
+ '<td><input data-fieldname="ClaimCPTICD1" value="' + a.icd1 + '"></td>'
+ '<td><input data-fieldname="ClaimCPTICD2" value=""></td>'
+ '<td><input data-fieldname="ClaimCPTICD3" value=""></td>'
+ '<td><input data-fieldname="ClaimCPTICD4" value=""></td>'
+ '<td><input data-fieldname="ClaimCPTBilledFee" value="' + a.fee + '"></td>';
tbody.insertBefore(tr, entryRow);
}""", {"rowId": row_id, "checked": checked, "fee": fee, "icd1": icd1})
def _set_row(page, row_id, *, checked=None, fee=None):
"""Sets one existing row's checkbox and/or Billed Fee in place."""
page.evaluate(
"""(a) => {
const tr = document.getElementById(a.rowId);
if (a.checked !== null)
tr.querySelector('[ng-click*="updateBillToIns("]').checked = a.checked;
if (a.fee !== null)
tr.querySelector('[id^="uBClaimBillFee"], [data-fieldname="ClaimCPTBilledFee"]')
.value = a.fee;
}""", {"rowId": row_id, "checked": checked, "fee": fee})
def _neutralise_fixture_g8510(page):
"""
hcfa_claim.html's own G8510 (CPTROW_2) is unchecked at 65.00 — itself
an unchecked priced line. Checked here, so a case about some other line
is not answered by that one.
"""
_set_row(page, "CPTROW_2", checked=True)
def _count_checkbox_clicks(page, row_id):
"""
Counts clicks on one row's "Assign To Patient" checkbox, read back as
`window.clicksOn[row_id]` — the same helper the depression and
zero_fee_uncheck tests use. On the live screen that click is what fires
eCW's own `updateBillToIns()`, so a line that must stay excluded should
never receive one at all — not merely end up unchecked again.
"""
page.evaluate(
"""(rowId) => {
window.clicksOn = window.clicksOn || {};
window.clicksOn[rowId] = 0;
document.querySelector('#' + rowId + ' [ng-click*="updateBillToIns("]')
.addEventListener('click', () => { window.clicksOn[rowId] += 1; });
}""", row_id)
def _watch_fee_writes(page):
"""
Counts `input`/`change` events on every Billed Fee input on the grid as
`window.feeWrites` — a zero proves the fee was never written, not
merely left with the same value. Call after every row has been injected.
"""
page.evaluate(
"""(s) => {
window.feeWrites = 0;
document.querySelectorAll('tr[id^="CPTROW_"]').forEach(tr => {
tr.querySelectorAll(s).forEach(el => {
el.addEventListener('input', () => { window.feeWrites += 1; });
el.addEventListener('change', () => { window.feeWrites += 1; });
});
});
}""", sel.SEL_CPT_BILLED_FEE)
def _row_state(page, index):
"""(checked or None, fee or None) for the index-th real CPT row."""
row = page.locator(sel.SEL_CPT_ROWS).nth(index)
box = row.locator(sel.SEL_CPT_ASSIGN_TO_PATIENT).first
fee = row.locator(sel.SEL_CPT_BILLED_FEE).first
return (box.is_checked() if box.count() else None,
fee.input_value() if fee.count() else None)
def _run_all_logged(page, claim_id, data, **kwargs):
"""run_all(), with everything it printed."""
out = io.StringIO()
with contextlib.redirect_stdout(out):
results = run_all(page, claim_id, data, **kwargs)
return results, out.getvalue()
def _checks_reported_on(results, row):
"""
Every change in `results` that reports CHECKING `row`: any change
priced_line_check makes (it only ever checks), and depression's
re-include step, whose change is `{"row", "code"}` alone.
"""
return [(r.condition_name, c) for r in results for c in r.changes
if c.get("row") == row
and (r.condition_name == plc.NAME
or (r.condition_name == depression_dx_pointer.NAME
and set(c) == {"row", "code"}))]
def _assert_priced_line_check_ran_and_found_nothing(log, claim_id):
"""
The common case this rule is registered last for: detect() saw the
excluded line priced on the claim as read, and by the time apply()
looked, another condition had zeroed it.
"""
assert f"[COND priced_line_check {claim_id}]" in log, log
assert "nothing to check" in log, log
# =============================================================================
# The shared priced-fee predicate
# =============================================================================
@case
def is_priced_fee_reads_a_positive_amount_as_priced():
for value in ("150.00", "65", "0.01", "1,200.00", "$45.00", "$1,200.00",
" 65.00 "):
assert claim_form.is_priced_fee(value) is True, repr(value)
@case
def is_priced_fee_reads_zero_blank_non_numeric_and_negative_as_not_priced():
for value in ("", " ", None, "0", "0.00", ".00", "$0.00", "0,000.00",
"N/A", "abc", "--", "0.00 USD", "-5.00", "nan", "inf"):
assert claim_form.is_priced_fee(value) is False, repr(value)
@case
def is_priced_fee_and_is_zero_fee_never_both_hold():
# The two halves of the common rule can never both claim one line.
for value in ("", None, "0", "0.00", ".00", "$0.00", "65.00", "0.01",
"1,200.00", "$45.00", "N/A", "-5.00", "nan", "inf"):
assert not (claim_form.is_priced_fee(value)
and claim_form.is_zero_fee(value)), repr(value)
# =============================================================================
# detect()
# =============================================================================
@case
def detect_true_for_an_unchecked_priced_line():
data = {"cpt": [_cpt("99213", billed=True, fee="210.00"),
_cpt("90791", billed=False, fee="150.00")]}
assert plc.detect("C1", data) is True
@case
def detect_true_for_a_thousands_separated_fee():
assert plc.detect("C1", {"cpt": [_cpt("J7298", fee="1,200.00")]}) is True
@case
def detect_true_for_a_dollar_fee():
assert plc.detect("C1", {"cpt": [_cpt("J2001", fee="$45.00")]}) is True
@case
def detect_false_for_an_unchecked_zero_fee_line():
# Already excluded, and correctly — the 9131000 duplicate's shape.
for fee in ("0.00", "", "0", ".00", "$0.00"):
assert plc.detect("C1", {"cpt": [_cpt("G8510", fee=fee)]}) is False, fee
@case
def detect_false_for_a_checked_priced_line():
data = {"cpt": [_cpt("99213", billed=True, fee="210.00"),
_cpt("J7298", billed=True, fee="1200.00")]}
assert plc.detect("C1", data) is False
@case
def detect_false_when_the_checkbox_state_is_unknown():
# billed None: extract() found no "Assign To Patient" checkbox on the
# row. Unknown must never read as "unchecked".
assert plc.detect("C1", {"cpt": [_cpt("90791", billed=None)]}) is False
assert plc.detect("C1", {"cpt": [{"code": "90791",
"billed_fee": "150.00"}]}) is False
@case
def detect_false_for_a_non_numeric_or_negative_fee():
for fee in ("N/A", "abc", "0.00 USD", "-5.00"):
assert plc.detect("C1", {"cpt": [_cpt("90791", fee=fee)]}) is False, fee
@case
def detect_false_with_no_cpt_lines_or_no_fee_read():
assert plc.detect("C1", {"cpt": []}) is False
assert plc.detect("C1", {}) is False
assert plc.detect("C1", None) is False
# No billed_fee key at all: nothing was read, so nothing is priced.
assert plc.detect("C1", {"cpt": [{"code": "90791", "billed": False}]}) is False
# =============================================================================
# apply() — the professional/HCFA screen
# =============================================================================
@case
def apply_checks_unchecked_priced_lines_on_the_hcfa_screen(page):
"""
The fixture's own G8510 (unchecked, 65.00) plus two injected lines
priced the ways eCW can print a fee — "$45.00" and "1,200.00". Each is
checked and reported with its fee exactly as read; the fee itself is
never written. The checked 99213 and J7298 are never clicked.
"""
page.goto(FIXTURE.as_uri())
_inject_row(page, "85025", "CPTROW_3", fee="$45.00")
_inject_row(page, "36415", "CPTROW_4", fee="1,200.00")
for row_id in ("CPTROW_0", "CPTROW_1", "CPTROW_2", "CPTROW_3", "CPTROW_4"):
_count_checkbox_clicks(page, row_id)
_watch_fee_writes(page)
result = plc.apply(page, "9103000", {})
assert isinstance(result, ConditionResult)
assert result.condition_name == "priced_line_check"
assert result.changed is True
assert result.changes == [
{"row": 2, "code": "G8510", "fee": "65.00"},
{"row": 3, "code": "85025", "fee": "$45.00"},
{"row": 4, "code": "36415", "fee": "1,200.00"},
], result.changes
assert [_row_state(page, i) for i in range(5)] == [
(True, "210.00"), (True, "1200.00"), (True, "65.00"),
(True, "$45.00"), (True, "1,200.00")]
clicks = page.evaluate("window.clicksOn")
assert clicks == {"CPTROW_0": 0, "CPTROW_1": 0, "CPTROW_2": 1,
"CPTROW_3": 1, "CPTROW_4": 1}, clicks
assert page.evaluate("window.feeWrites") == 0, "the Billed Fee was written"
# A second pass has nothing left to check.
assert plc.apply(page, "9103000", {}).changed is False
@case
def apply_leaves_zero_fee_non_numeric_and_negative_lines_alone(page):
page.goto(FIXTURE.as_uri())
_neutralise_fixture_g8510(page)
_inject_row(page, "85018", "CPTROW_3", fee="0.00")
_inject_row(page, "85025", "CPTROW_4", fee="")
_inject_row(page, "81002", "CPTROW_5", fee="N/A")
_inject_row(page, "36415", "CPTROW_6", fee="-5.00")
for row_id in ("CPTROW_3", "CPTROW_4", "CPTROW_5", "CPTROW_6"):
_count_checkbox_clicks(page, row_id)
_watch_fee_writes(page)
result = plc.apply(page, "9103000", {})
assert result.changed is False, result.changes
assert result.changes == [], result.changes
assert [_row_state(page, i) for i in (3, 4, 5, 6)] == [
(False, "0.00"), (False, ""), (False, "N/A"), (False, "-5.00")]
assert set(page.evaluate("Object.values(window.clicksOn)")) == {0}, \
page.evaluate("window.clicksOn")
assert page.evaluate("window.feeWrites") == 0
@case
def apply_never_touches_a_checked_line_zero_fee_or_priced(page):
# A checked 0.00 line is zero_fee_uncheck's, never this rule's: only
# ever checks, never unchecks.
page.goto(FIXTURE.as_uri())
_neutralise_fixture_g8510(page)
_inject_row(page, "85018", "CPTROW_3", checked=True, fee="0.00")
for row_id in ("CPTROW_0", "CPTROW_1", "CPTROW_2", "CPTROW_3"):
_count_checkbox_clicks(page, row_id)
result = plc.apply(page, "9103000", {})
assert result.changed is False, result.changes
assert [_row_state(page, i) for i in range(4)] == [
(True, "210.00"), (True, "1200.00"), (True, "65.00"), (True, "0.00")]
assert set(page.evaluate("Object.values(window.clicksOn)")) == {0}
@case
def apply_leaves_an_unchecked_row_with_no_fee_input_alone(page):
# No Billed Fee input at all: the fee is unknown, not priced.
page.goto(FIXTURE.as_uri())
_neutralise_fixture_g8510(page)
_inject_row(page, "90791", "CPTROW_3", has_fee=False)
_count_checkbox_clicks(page, "CPTROW_3")
result = plc.apply(page, "9103000", {})
assert result.changed is False, result.changes
assert _row_state(page, 3) == (False, None)
assert page.evaluate("window.clicksOn['CPTROW_3']") == 0
@case
def apply_leaves_a_priced_row_with_no_checkbox_alone(page):
# No "Assign To Patient" checkbox: whether it is billed is unknown.
page.goto(FIXTURE.as_uri())
_neutralise_fixture_g8510(page)
_inject_row(page, "90791", "CPTROW_3", has_checkbox=False)
_watch_fee_writes(page)
result = plc.apply(page, "9103000", {})
assert result.changed is False, result.changes
assert _row_state(page, 3) == (None, "150.00")
assert page.evaluate("window.feeWrites") == 0
# =============================================================================
# apply() — the UB Claim form
# =============================================================================
@case
def apply_checks_an_unchecked_priced_line_on_the_ub_form(page):
page.goto(UB_FIXTURE.as_uri())
_inject_row(page, "90791", "CPTROW_2", screen="ub", fee="150.00")
_inject_row(page, "G8510", "CPTROW_3", screen="ub", fee="0.00")
_inject_row(page, "99213", "CPTROW_4", screen="ub", checked=True, fee="210.00")
for row_id in ("CPTROW_2", "CPTROW_3", "CPTROW_4"):
_count_checkbox_clicks(page, row_id)
_watch_fee_writes(page)
result = plc.apply(page, "9104000", {})
assert result.changes == [{"row": 2, "code": "90791", "fee": "150.00"}], result.changes
assert _row_state(page, 2) == (True, "150.00")
assert _row_state(page, 3) == (False, "0.00")
assert _row_state(page, 4) == (True, "210.00")
assert page.evaluate("window.clicksOn") == {
"CPTROW_2": 1, "CPTROW_3": 0, "CPTROW_4": 0}
assert page.evaluate("window.feeWrites") == 0, "the Billed Fee was written"
@case
def apply_leaves_ub_rows_without_the_assign_to_patient_checkbox_alone(page):
"""
ub_claim.html's own rows carry a plain checkbox with no
`updateBillToIns(` ng-click — not the live-verified "Assign To Patient"
box — so their billed state is unknown: one sitting unchecked at 74.00
must not be acted on.
"""
page.goto(UB_FIXTURE.as_uri())
page.evaluate("() => { document.getElementById('claimCPTBillToInsChk0')"
".checked = false; }")
result = plc.apply(page, "9104000", {})
assert result.changed is False, result.changes
assert page.locator("#claimCPTBillToInsChk0").is_checked() is False
assert page.locator("#uBClaimBillFee0").input_value() == "74.00"
# =============================================================================
# apply() — no change, and a tab that cannot be confirmed
# =============================================================================
@case
def apply_logs_why_when_there_is_nothing_to_check(page):
page.goto(FIXTURE.as_uri())
_neutralise_fixture_g8510(page)
out = io.StringIO()
with contextlib.redirect_stdout(out):
result = plc.apply(page, "9103000", {})
assert result == ConditionResult.none("priced_line_check"), result
_assert_priced_line_check_ran_and_found_nothing(out.getvalue(), "9103000")
# Only on that path — not when a line was actually checked.
page.goto(FIXTURE.as_uri())
out = io.StringIO()
with contextlib.redirect_stdout(out):
result = plc.apply(page, "9103000", {})
assert result.changed is True, result.changes
assert "nothing to check" not in out.getvalue(), out.getvalue()
@case
def apply_leaves_the_claim_as_read_when_the_cpt_tab_cannot_be_confirmed(page):
page.goto(FIXTURE.as_uri())
def tab_that_raises(page_):
raise RuntimeError("No CPT/HCPCS tab matched (simulated)")
real = claim_form.open_cpt_hcpcs_tab
claim_form.open_cpt_hcpcs_tab = tab_that_raises
out = io.StringIO()
try:
with contextlib.redirect_stdout(out):
result = plc.apply(page, "9103000", {})
finally:
claim_form.open_cpt_hcpcs_tab = real
assert result.changed is False, result.changes
assert _row_state(page, 2) == (False, "65.00"), "nothing may be touched"
assert "leaving the claim as read" in out.getvalue(), out.getvalue()
# Declined, not none(): never checked is not clean (review item D2).
assert result.review == CPT_TAB_NOT_CONFIRMED, result
# =============================================================================
# describe()
# =============================================================================
@case
def describe_names_each_checked_line_and_its_fee(page):
page.goto(FIXTURE.as_uri())
_neutralise_fixture_g8510(page)
_inject_row(page, "99213", "CPTROW_3", fee="150.00")
result = plc.apply(page, "9103000", {})
text = plc.describe(result)
lines = text.splitlines()
assert lines[0] == "Unchecked CPT line(s) with a billed fee checked:", text
assert lines[1:] == [" Row 4 (99213): unchecked with billed fee 150.00 -> checked"], text
@case
def describe_lists_every_line_in_grid_order():
result = ConditionResult(condition_name="priced_line_check", changed=True,
changes=[{"row": 0, "code": "99213", "fee": "150.00"},
{"row": 5, "code": "J7298", "fee": "1,200.00"}])
assert plc.describe(result).splitlines()[1:] == [
" Row 1 (99213): unchecked with billed fee 150.00 -> checked",
" Row 6 (J7298): unchecked with billed fee 1,200.00 -> checked",
], plc.describe(result)
# =============================================================================
# The registry
# =============================================================================
@case
def registered_last_with_zero_fee_uncheck_first():
"""
zero_fee_uncheck FIRST, this LAST, every specific condition between
them in its own order: an exclusion condition has always zeroed its
line before this looks at the grid.
"""
assert conditions.CONDITIONS[0] is zero_fee_uncheck, conditions.CONDITIONS
assert conditions.CONDITIONS[-1] is plc, conditions.CONDITIONS
assert conditions.CONDITIONS == [
zero_fee_uncheck,
telehealth, medicare_telehealth, depression_dx_pointer,
j2930_j2001_update, dummy_codes, dental_dummy_codes,
dental_payer_check, medicaid_uncheck_cpts, lab_codes,
t1017_non_billable,
medicare_billing_screening, medicare_vaccine_a6,
medicare_wellness_history, medicaid_pregnancy_th,
bh_h_code_modifier, vaccine_z23_pointer, vaccine_admin_codes,
injection_admin_code,
medicare_pps_code,
plc,
], conditions.CONDITIONS
assert conditions.BY_NAME["priced_line_check"] is plc
assert plc.NAME == "priced_line_check"
# =============================================================================
# run_all() against the REAL registry — the positive cases
# =============================================================================
@case
def run_all_checks_an_unrelated_priced_line_and_reports_it(page):
"""
99213 unchecked at 150.00 on the claim as read, no other condition's
business: priced_line_check alone fires, and the line ends checked with
its fee untouched. `icd` is left out of the data on purpose: the
fixture carries Z13.31, which would fire depression_dx_pointer on its
own account.
"""
page.goto(FIXTURE.as_uri())
_neutralise_fixture_g8510(page)
_set_row(page, "CPTROW_0", checked=False, fee="150.00")
_count_checkbox_clicks(page, "CPTROW_0")
data = {"cpt": claim_form.extract(page)["cpt"]}
results = run_all(page, "9103000", data)
assert [r.condition_name for r in results] == ["priced_line_check"], results
assert results[0].changes == [{"row": 0, "code": "99213", "fee": "150.00"}], \
results[0].changes
assert _row_state(page, 0) == (True, "150.00")
assert page.evaluate("window.clicksOn['CPTROW_0']") == 1
@case
def run_all_fires_both_halves_of_the_common_rule_on_one_claim(page):
# A checked 0.00 line and an unchecked priced one: each half takes its
# own line, and neither touches the other's.
page.goto(FIXTURE.as_uri())
_neutralise_fixture_g8510(page)
_inject_row(page, "85018", "CPTROW_3", checked=True, fee="0.00")
_inject_row(page, "90791", "CPTROW_4", checked=False, fee="150.00")
_count_checkbox_clicks(page, "CPTROW_3")
_count_checkbox_clicks(page, "CPTROW_4")
data = {"cpt": claim_form.extract(page)["cpt"]}
results = run_all(page, "9103000", data)
assert [r.condition_name for r in results] == \
["zero_fee_uncheck", "priced_line_check"], results
assert results[0].changes == [{"row": 3, "code": "85018", "fee": "0.00"}]
assert results[1].changes == [{"row": 4, "code": "90791", "fee": "150.00"}]
assert (_row_state(page, 3), _row_state(page, 4)) == \
((False, "0.00"), (True, "150.00"))
assert page.evaluate("window.clicksOn") == {"CPTROW_3": 1, "CPTROW_4": 1}
@case
def run_all_leaves_claim_9131000_alone(page):
"""
Live claim 9131000 (Logs\\run_20260929_161613.log), already correct:
the first G8510 checked at 65.00 and tagged Z13.31 alone, a later G8510
unchecked at 0.00. Nothing may change — not even with this rule in the
registry: the 0.00 copy is not priced, and nobody clicks it.
"""
page.goto(FIXTURE.as_uri())
page.evaluate("""() => {
const set = (rowId, field, value) => {
document.querySelector(
'#' + rowId + ' [data-fieldname="' + field + '"]').value = value;
};
set('CPTROW_0', 'ClaimCPTICD2', '3');
set('CPTROW_0', 'ClaimCPTICD3', '');
set('CPTROW_2', 'ClaimCPTICD1', '2');
}""")
_neutralise_fixture_g8510(page)
_inject_full_g8510_row(page, "CPTROW_3", checked=False, fee="0.00", icd1="2")
_count_checkbox_clicks(page, "CPTROW_3")
results = run_all(page, "9131000", claim_form.extract(page))
assert results == [], results
assert _row_state(page, 3) == (False, "0.00")
assert page.evaluate("window.clicksOn['CPTROW_3']") == 0
# =============================================================================
# run_all() against the REAL registry — NO TOGGLE on an excluded line
# =============================================================================
@case
def run_all_does_not_toggle_an_unchecked_priced_j2001(page):
"""
J2001 unchecked but still at 45.00 on the claim as read.
priced_line_check's detect() fires on it; j2930_j2001_update zeroes
its fee (no click — it is already unchecked); priced_line_check,
running last, finds it at 0.00 and checks nothing.
"""
page.goto(FIXTURE.as_uri())
_neutralise_fixture_g8510(page)
_inject_row(page, "J2001", "CPTROW_3", checked=False, fee="45.00")
_count_checkbox_clicks(page, "CPTROW_3")
data = {"cpt": claim_form.extract(page)["cpt"]}
assert plc.detect("9103000", data) is True
assert j2930_j2001_update.detect("9103000", data) is True
results, log = _run_all_logged(page, "9103000", data)
assert [r.condition_name for r in results] == ["j2930_j2001_update"], results
assert results[0].changes == [{"row": 3, "code": "J2001",
"fee": {"before": "45.00", "after": "0.00"}}], \
results[0].changes
assert _checks_reported_on(results, 3) == [], results
assert _row_state(page, 3) == (False, "0.00")
assert page.evaluate("window.clicksOn['CPTROW_3']") == 0, \
"J2001's checkbox was clicked — updateBillToIns() would fire"
_assert_priced_line_check_ran_and_found_nothing(log, "9103000")
@case
def run_all_does_not_toggle_an_unchecked_priced_dcons(page):
page.goto(FIXTURE.as_uri())
_neutralise_fixture_g8510(page)
_inject_row(page, "DCONS", "CPTROW_3", checked=False, fee="45.00")
_count_checkbox_clicks(page, "CPTROW_3")
data = {"cpt": claim_form.extract(page)["cpt"]}
assert plc.detect("9121000", data) is True
assert dummy_codes.detect("9121000", data) is True
results, log = _run_all_logged(page, "9121000", data)
assert [r.condition_name for r in results] == ["dummy_codes"], results
assert results[0].changes == [{"row": 3, "code": "DCONS",
"fee": {"before": "45.00", "after": "0.00"}}], \
results[0].changes
assert _checks_reported_on(results, 3) == [], results
assert _row_state(page, 3) == (False, "0.00")
assert page.evaluate("window.clicksOn['CPTROW_3']") == 0, \
"DCONS's checkbox was clicked — updateBillToIns() would fire"
_assert_priced_line_check_ran_and_found_nothing(log, "9121000")
_MEDICARE_DATA = {
"progress_notes": {"text": "Session Setting (PoS): TeleHealth"},
"insurance": [{"Name": "Humana Medicare"}],
}
@case
def run_all_does_not_toggle_a_medicare_telehealth_other_line(page):
"""
Document #22's "Other Primary CPT codes need to be unchecked and change
the fee amount as Zero", on the fixture's own G8510 — already unchecked
but still at 65.00, exactly an excluded-but-priced line. G2025 is added
through the fixture's Fee Schedule picker, every other line is zeroed,
and priced_line_check leaves G8510 excluded. Data shaped the way
test_conditions_medicare_telehealth.py's `_MEDICARE_DATA` is, plus the
CPT grid as read.
"""
page.goto(FIXTURE.as_uri())
_count_checkbox_clicks(page, "CPTROW_2")
data = dict(_MEDICARE_DATA, cpt=claim_form.extract(page)["cpt"])
assert plc.detect("9103000", data) is True
assert medicare_telehealth.detect("9103000", data) is True
results, log = _run_all_logged(page, "9103000", data)
assert [r.condition_name for r in results] == ["medicare_telehealth"], results
g8510 = [c for c in results[0].changes if c.get("row") == 2]
assert g8510 == [{"row": 2, "code": "G8510",
"fee": {"before": "65.00", "after": "0.00"},
# Unit E (2026-10-05): every change also carries the
# audio/video evidence describe() shows.
"signal": "telehealth", "mode": "video",
"mode_phrase": ""}], results[0].changes
assert _checks_reported_on(results, 2) == [], results
assert _row_state(page, 2) == (False, "0.00")
assert page.evaluate("window.clicksOn['CPTROW_2']") == 0, \
"G8510's checkbox was clicked — updateBillToIns() would fire"
_assert_priced_line_check_ran_and_found_nothing(log, "9103000")
# G2025, the one line #22 keeps billed, is still billed.
last = page.locator(sel.SEL_CPT_ROWS).last
assert last.locator(sel.SEL_CPT_CODE).first.input_value() == "G2025"
assert last.locator(sel.SEL_CPT_ASSIGN_TO_PATIENT).first.is_checked() is True
@case
def pinned_needs_ruling_g2025_unconfirmed_other_line_gets_checked(page):
"""
PINNED, NEEDS A RULING (review finding, 2026-09-30) — the one normal,
non-raising path running last does NOT protect. When G2025 cannot be
confirmed (here: ub_claim.html, where the Fee Schedule picker flow has
no evidence), medicare_telehealth deliberately leaves every other CPT
row as read "for review". An "other" line sitting unchecked but priced
is then checked by this rule, last — billing a line document #22 says
must be excluded, against medicare_telehealth's own log line. Leaving
it for review instead is beyond rulings A/B/C.
"""
page.goto(UB_FIXTURE.as_uri())
_inject_row(page, "99214", "CPTROW_7", screen="ub", checked=False,
fee="65.00")
data = dict(_MEDICARE_DATA, cpt=claim_form.extract(page)["cpt"])
results, log = _run_all_logged(page, "9120000", data)
names = [r.condition_name for r in results]
# The fixture's H0023 is billed to Medicare, not a BH payer: #12
# unchecks and zeroes it (operator, 2026-10-12).
assert names == ["medicare_telehealth", "bh_h_code_modifier",
"priced_line_check"], results
assert results[1].changes == [{"row": 0, "code": "H0023",
"fee": {"before": "74.00",
"after": "0.00"}}], \
results[1].changes
assert "Could not confirm G2025" in log, log
assert [c for c in results[0].changes if "fee" in c] == [], results[0].changes
assert [(c["code"], c["fee"]) for c in results[2].changes] == \
[("99214", "65.00")], ("today: the other line is checked",
results[2].changes)
@case
def run_all_does_not_toggle_an_unchecked_priced_duplicate_g8510(page):
"""
depression_dx_pointer's duplicate step: the first G8510 checked at
65.00 is the one kept, and a later G8510 sits unchecked but still at
75.00. The duplicate step zeroes its fee (no click — already
unchecked); priced_line_check, last, finds it at 0.00.
"""
page.goto(FIXTURE.as_uri())
_neutralise_fixture_g8510(page)
_inject_full_g8510_row(page, "CPTROW_3", checked=False, fee="75.00")
_count_checkbox_clicks(page, "CPTROW_3")
data = claim_form.extract(page)
assert plc.detect("9103000", data) is True
assert depression_dx_pointer.detect("9103000", data) is True
results, log = _run_all_logged(page, "9103000", data)
assert [r.condition_name for r in results] == ["depression_dx_pointer"], results
duplicate = [c for c in results[0].changes if "before" not in c]
assert duplicate == [{"row": 3, "code": "G8510",
"fee": {"before": "75.00", "after": "0.00"}}], \
results[0].changes
assert _checks_reported_on(results, 3) == [], results
assert _row_state(page, 2) == (True, "65.00"), "the kept G8510 stays billed"
assert _row_state(page, 3) == (False, "0.00")
assert page.evaluate("window.clicksOn['CPTROW_3']") == 0, \
"the duplicate's checkbox was clicked — updateBillToIns() would fire"
_assert_priced_line_check_ran_and_found_nothing(log, "9103000")
@case
def run_all_checks_the_unrelated_line_but_never_the_excluded_one(page):
# Both on one claim: 99213 unchecked at 150.00 (checked) and J2001
# unchecked at 45.00 (excluded) — the rule tells them apart only by
# running after j2930_j2001_update has zeroed J2001.
page.goto(FIXTURE.as_uri())
_neutralise_fixture_g8510(page)
_set_row(page, "CPTROW_0", checked=False, fee="150.00")
_inject_row(page, "J2001", "CPTROW_3", checked=False, fee="45.00")
_count_checkbox_clicks(page, "CPTROW_0")
_count_checkbox_clicks(page, "CPTROW_3")
data = {"cpt": claim_form.extract(page)["cpt"]}
results = run_all(page, "9103000", data)
assert [r.condition_name for r in results] == \
["j2930_j2001_update", "priced_line_check"], results
assert results[1].changes == [{"row": 0, "code": "99213", "fee": "150.00"}], \
results[1].changes
assert _checks_reported_on(results, 3) == [], results
assert (_row_state(page, 0), _row_state(page, 3)) == \
((True, "150.00"), (False, "0.00"))
assert page.evaluate("window.clicksOn") == {"CPTROW_0": 1, "CPTROW_3": 0}
@case
def run_all_with_this_rule_first_would_toggle_j2001(page):
"""
The contrast that is WHY this is registered last: the same claim as
`run_all_does_not_toggle_an_unchecked_priced_j2001`, with this rule
moved ahead of j2930_j2001_update. It checks J2001, and J2001's own
condition unchecks it straight after — the same end state, reached by
two clicks on a line that must stay out and two contradictory changes
in the review box.
"""
page.goto(FIXTURE.as_uri())
_neutralise_fixture_g8510(page)
_inject_row(page, "J2001", "CPTROW_3", checked=False, fee="45.00")
_count_checkbox_clicks(page, "CPTROW_3")
data = {"cpt": claim_form.extract(page)["cpt"]}
results = run_all(page, "9103000", data,
conditions=[plc, j2930_j2001_update])
assert [r.condition_name for r in results] == \
["priced_line_check", "j2930_j2001_update"], results
assert results[0].changes == [{"row": 3, "code": "J2001", "fee": "45.00"}]
assert results[1].changes == [{"row": 3, "code": "J2001", "unchecked": True,
"fee": {"before": "45.00", "after": "0.00"}}]
assert _row_state(page, 3) == (False, "0.00")
assert page.evaluate("window.clicksOn['CPTROW_3']") == 2, "the toggle"
# =============================================================================
# run_all() — a KNOWN GAP where this rule meets vaccine_admin_codes' own
# pre-read decision, PINNED pending an operator ruling. Not the settled end
# state; see priced_line_check.py's module docstring.
# =============================================================================
_TDAP = "TETANUS DIPHTHERIA TOXOIDS AND ACELLULAR PERTUSSIS VACC"
_ADMIN_1ST = "IMMUNIZATION ADMIN SINGLE OR COMBINATION"
@case
def run_all_pins_the_vaccine_gap_for_an_unchecked_priced_admin_line(page):
"""
PINNED KNOWN GAP, pending an operator ruling — the mirror image of the
checked-zero-fee admin line zero_fee_uncheck used to open (fixed
2026-09-30). vaccine_admin_codes decides on the claim as read, where
the 90471 is UNCHECKED — so "no admin billed", and it adds a new 90471.
This rule then runs last and checks the old 90471, still at 30.00: two
admin lines billed for one vaccine. None of the 39 snapshots has this
shape (none has an unchecked priced line at all). Fixing it means
vaccine_admin_codes counting an unchecked priced admin line as billed —
another condition's behaviour, not ruled on.
"""
page.goto(VACCINE_FIXTURE.as_uri())
page.evaluate("rows => window.seedCptRows(rows)", [
{"code": "99396", "title": "PREVENTIVE VISIT EST AGE 40-64",
"fee": "250.00"},
{"code": "90734", "title": _TDAP, "fee": "60.00", "icd1": "2"},
{"code": "90471", "title": _ADMIN_1ST, "fee": "30.00",
"checked": False},
])
results = run_all(page, "9113000", claim_form.extract(page))
assert [r.condition_name for r in results] == \
["vaccine_admin_codes", "priced_line_check"], results
assert results[1].changes == [{"row": 2, "code": "90471", "fee": "30.00"}]
grid = [(r["code"], r["billed"], r["billed_fee"])
for r in claim_form.extract(page)["cpt"]]
assert grid == [("99396", True, "250.00"), ("90734", True, "60.00"),
("90471", True, "30.00"), ("90471", True, "30.00")], \
("today: two 90471 lines billed", grid)
def _run_cases() -> int:
for fixture in (FIXTURE, UB_FIXTURE, VACCINE_FIXTURE):
if not fixture.exists():
print(f" FAIL fixture missing: {fixture}")
return 1
try:
from playwright.sync_api import sync_playwright
except ImportError:
print(" SKIP playwright is not installed")
return 0
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
def main() -> int:
from ecw_bot import settings as _cfg
# These cases exercise eCW's own click and Add flow, as a LIVE-WRITE run
# does. VERIFY clicks no box and adds no row (eCW saves both at once,
# 2026-10-16): that is tests/test_verify_no_live_writes.py.
orig = _cfg.SAVE_CORRECTIONS
_cfg.SAVE_CORRECTIONS = True
try:
return _run_cases()
finally:
_cfg.SAVE_CORRECTIONS = orig
if __name__ == "__main__":
sys.exit(main())