r""" conditions/zero_fee_uncheck.py — the operator's common rule for every claim (2026-09-30): a CPT line that is checked but billed at zero gets unchecked. Only that direction here — an unchecked line is never touched by this condition; the reverse half (unchecked with a billed fee -> checked) is conditions/priced_line_check.py's, registered last, and tested in test_conditions_priced_line_check.py. python tests\test_conditions_zero_fee_uncheck.py Pure-data cases first (the shared zero-fee predicate, then detect()), then page cases against BOTH claim screens: hcfa_claim.html, whose own rows carry the live-verified "Assign To Patient" checkbox (`ng-click="updateBillToIns( $index)"`), 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 (`id="claimCPTBillToInsChk..." ng-click="updateBillToIns(n)"`), and the fixture's own rows stand in for a row whose checkbox state is unknown. Rows are injected with page.evaluate, the same way test_conditions_depression_dx_pointer.py's `_inject_duplicate_target_row` adds its row, rather than growing either shared fixture and its row-count assumptions (`CPT/HCPCS (3)`, `len(cpt) == 3`, ...). The live evidence this rule was built against: of 39 saved claim snapshots, exactly one checked zero-fee line — 85018 (Hemoglobin) at 0.00 — which is the code the injected rows below use. The last two cases are where this rule meets another condition's own rule — depression's choice of which G8510 to keep, and vaccine_admin_codes' checked-admin test on vaccine_claim.html. Both used to be PINNED as known gaps; the operator ruled on both on 2026-09-30, and they now assert the ruled outcome: the priced G8510 is the one kept, and a checked zero-fee admin line no longer counts as "admin already billed". """ 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 zero_fee_uncheck as zfu # 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, medicaid_uncheck_cpts, medicare_billing_screening, medicare_telehealth, medicare_vaccine_a6, medicare_wellness_history, medicaid_pregnancy_th, priced_line_check, telehealth, vaccine_admin_codes) 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 _HEMOGLOBIN = "85018" def _cpt(code, billed=True, fee="0.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=True, fee="0.00", has_checkbox=True, has_fee=True): """ Adds one real CPT row (a `CPTROW_` id) above the grid's trailing "*" entry row. `screen` picks the row's own markup: * "hcfa" — hcfa_claim.html's shape: `data-fieldname` fields. * "ub" — the UB form's `uBClaim*` id prefixes, with the "Assign To Patient" checkbox vaccine_claim.html's rows carry (ub_claim.html's own rows have none that SEL_CPT_ASSIGN_TO_PATIENT matches). `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, '&').replace(/"/g, '"'); const box = !a.hasCheckbox ? '' : (a.screen === 'ub' ? ''; const codeInput = a.screen === 'ub' ? '' : ''; const feeInput = !a.hasFee ? '' : (a.screen === 'ub' ? '' : ''); const tr = document.createElement('tr'); tr.id = a.rowId; tr.setAttribute('ng-repeat', 'cpt in CPTCodes'); tr.innerHTML = '' + box + '' + codeInput + '' + '' + feeInput + ''; tbody.insertBefore(tr, entryRow); }""", {"code": code, "rowId": row_id, "screen": screen, "checked": checked, "fee": fee, "hasCheckbox": has_checkbox, "hasFee": has_fee}) 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 _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 test_conditions_depression_dx_pointer.py uses. On the live screen that click is what fires eCW's own `updateBillToIns()`, so a row this rule must leave alone should never receive one at all. """ 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` — Playwright's fill() fires both, so a zero here 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) # ============================================================================= # The shared zero-fee predicate # ============================================================================= @case def is_zero_fee_reads_blank_and_every_zero_spelling_as_zero(): for value in ("", " ", None, "0", "0.00", "0.0", ".00", " 0.00 ", "$0.00", "0,000.00"): assert claim_form.is_zero_fee(value) is True, repr(value) @case def is_zero_fee_reads_a_priced_or_non_numeric_fee_as_not_zero(): for value in ("65.00", "0.01", "$1,200.00", "1,200.00", "N/A", "abc", "--", "0.00 USD"): assert claim_form.is_zero_fee(value) is False, repr(value) # ============================================================================= # detect() # ============================================================================= @case def detect_true_for_a_checked_line_billed_at_0_00(): # The one live case: 85018 (Hemoglobin), checked, at 0.00. data = {"cpt": [_cpt("99213", fee="210.00"), _cpt(_HEMOGLOBIN, fee="0.00")]} assert zfu.detect("C1", data) is True @case def detect_true_for_a_checked_line_with_a_blank_fee(): assert zfu.detect("C1", {"cpt": [_cpt(_HEMOGLOBIN, fee="")]}) is True @case def detect_true_for_a_checked_line_billed_at_plain_0(): assert zfu.detect("C1", {"cpt": [_cpt(_HEMOGLOBIN, fee="0")]}) is True @case def detect_false_for_an_unchecked_line_at_0_00(): # Already excluded — this condition never touches an unchecked line; the # reverse half (unchecked AND priced -> checked) is priced_line_check's, # and 0.00 is not priced anyway. data = {"cpt": [_cpt("99213", fee="210.00"), _cpt("G8510", billed=False, fee="0.00")]} assert zfu.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. assert zfu.detect("C1", {"cpt": [_cpt(_HEMOGLOBIN, billed=None, fee="0.00")]}) is False assert zfu.detect("C1", {"cpt": [{"code": _HEMOGLOBIN, "billed_fee": "0.00"}]}) is False @case def detect_false_for_a_checked_line_whose_fee_was_never_read(): # billed_fee None: extract() found no Billed Fee input on the row. # apply() (uncheck_zero_fee_cpt_rows) leaves such a row alone, so # detect() must not fire on it either — unknown is not zero (review # finding, 2026-09-30). assert zfu.detect("C1", {"cpt": [_cpt(_HEMOGLOBIN, fee=None)]}) is False @case def detect_false_for_a_checked_priced_line(): data = {"cpt": [_cpt("99213", fee="210.00"), _cpt("J7298", fee="1200.00")]} assert zfu.detect("C1", data) is False @case def detect_false_for_a_non_numeric_fee(): assert zfu.detect("C1", {"cpt": [_cpt(_HEMOGLOBIN, fee="N/A")]}) is False @case def detect_false_with_no_cpt_lines(): assert zfu.detect("C1", {"cpt": []}) is False assert zfu.detect("C1", {}) is False assert zfu.detect("C1", None) is False # ============================================================================= # apply() — the professional/HCFA screen # ============================================================================= @case def apply_unchecks_a_checked_zero_fee_line_on_the_hcfa_screen(page): page.goto(FIXTURE.as_uri()) _inject_row(page, _HEMOGLOBIN, "CPTROW_3", checked=True, fee="0.00") _count_checkbox_clicks(page, "CPTROW_3") _watch_fee_writes(page) result = zfu.apply(page, "9103000", {}) assert isinstance(result, ConditionResult) assert result.condition_name == "zero_fee_uncheck" assert result.changed is True assert result.changes == [{"row": 3, "code": _HEMOGLOBIN, "fee": "0.00"}], result.changes assert _row_state(page, 3) == (False, "0.00") assert page.evaluate("window.clicksOn['CPTROW_3']") == 1 # Priced lines keep their checkbox and fee; G8510 (unchecked, 65.00) too. assert _row_state(page, 0) == (True, "210.00") assert _row_state(page, 1) == (True, "1200.00") assert _row_state(page, 2) == (False, "65.00") assert page.evaluate("window.feeWrites") == 0, "the Billed Fee was written" # A second pass has nothing left to uncheck. assert zfu.apply(page, "9103000", {}).changed is False @case def apply_leaves_priced_and_unchecked_lines_alone(page): page.goto(FIXTURE.as_uri()) _inject_row(page, "G8510", "CPTROW_3", checked=False, fee="0.00") _count_checkbox_clicks(page, "CPTROW_3") _count_checkbox_clicks(page, "CPTROW_0") _watch_fee_writes(page) result = zfu.apply(page, "9131000", {}) assert result.changed is False, result.changes assert result.changes == [], result.changes assert _row_state(page, 0) == (True, "210.00") assert _row_state(page, 1) == (True, "1200.00") assert _row_state(page, 2) == (False, "65.00") assert _row_state(page, 3) == (False, "0.00") assert page.evaluate("window.clicksOn['CPTROW_3']") == 0, \ "an unchecked line must never be clicked — updateBillToIns() would fire" assert page.evaluate("window.clicksOn['CPTROW_0']") == 0 assert page.evaluate("window.feeWrites") == 0 @case def apply_unchecks_every_zero_spelling_and_never_writes_the_fee(page): """ Blank, "0", ".00" and "0.00" are all zero — each line is unchecked, and its fee is reported and left exactly as read: never normalised to 0.00, never filled, never blurred. """ page.goto(FIXTURE.as_uri()) _inject_row(page, "85018", "CPTROW_3", fee="") _inject_row(page, "85025", "CPTROW_4", fee="0") _inject_row(page, "36415", "CPTROW_5", fee=".00") _inject_row(page, "81002", "CPTROW_6", fee="0.00") _watch_fee_writes(page) result = zfu.apply(page, "9103000", {}) assert result.changes == [ {"row": 3, "code": "85018", "fee": ""}, {"row": 4, "code": "85025", "fee": "0"}, {"row": 5, "code": "36415", "fee": ".00"}, {"row": 6, "code": "81002", "fee": "0.00"}, ], result.changes assert [_row_state(page, i) for i in (3, 4, 5, 6)] == [ (False, ""), (False, "0"), (False, ".00"), (False, "0.00")] assert page.evaluate("window.feeWrites") == 0, "the Billed Fee was written" @case def apply_leaves_a_non_numeric_fee_alone(page): page.goto(FIXTURE.as_uri()) _inject_row(page, _HEMOGLOBIN, "CPTROW_3", checked=True, fee="N/A") _count_checkbox_clicks(page, "CPTROW_3") result = zfu.apply(page, "9103000", {}) assert result.changed is False, result.changes assert _row_state(page, 3) == (True, "N/A") assert page.evaluate("window.clicksOn['CPTROW_3']") == 0 @case def apply_leaves_a_checked_row_with_no_fee_input_alone(page): # No Billed Fee input at all: the fee is unknown, not zero. page.goto(FIXTURE.as_uri()) _inject_row(page, _HEMOGLOBIN, "CPTROW_3", checked=True, has_fee=False) _count_checkbox_clicks(page, "CPTROW_3") result = zfu.apply(page, "9103000", {}) assert result.changed is False, result.changes assert _row_state(page, 3) == (True, None) assert page.evaluate("window.clicksOn['CPTROW_3']") == 0 @case def apply_leaves_a_zero_fee_row_with_no_checkbox_alone(page): # No "Assign To Patient" checkbox: whether it is billed is unknown. page.goto(FIXTURE.as_uri()) _inject_row(page, _HEMOGLOBIN, "CPTROW_3", fee="0.00", has_checkbox=False) _watch_fee_writes(page) result = zfu.apply(page, "9103000", {}) assert result.changed is False, result.changes assert _row_state(page, 3) == (None, "0.00") assert page.evaluate("window.feeWrites") == 0 # ============================================================================= # apply() — the UB Claim form # ============================================================================= @case def apply_unchecks_a_checked_zero_fee_line_on_the_ub_form(page): page.goto(UB_FIXTURE.as_uri()) _inject_row(page, _HEMOGLOBIN, "CPTROW_2", screen="ub", checked=True, fee="0.00") _inject_row(page, "90791", "CPTROW_3", screen="ub", checked=True, fee="150.00") _inject_row(page, "G8510", "CPTROW_4", screen="ub", checked=False, fee="0.00") _count_checkbox_clicks(page, "CPTROW_2") _count_checkbox_clicks(page, "CPTROW_3") _count_checkbox_clicks(page, "CPTROW_4") _watch_fee_writes(page) result = zfu.apply(page, "9104000", {}) assert result.changes == [{"row": 2, "code": _HEMOGLOBIN, "fee": "0.00"}], result.changes assert _row_state(page, 2) == (False, "0.00") assert _row_state(page, 3) == (True, "150.00") assert _row_state(page, 4) == (False, "0.00") assert page.evaluate("window.clicksOn['CPTROW_2']") == 1 assert page.evaluate("window.clicksOn['CPTROW_3']") == 0 assert page.evaluate("window.clicksOn['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, and a 0.00 fee on one of them must not be acted on. """ page.goto(UB_FIXTURE.as_uri()) page.evaluate("() => { document.getElementById('uBClaimBillFee0').value = '0.00'; }") _watch_fee_writes(page) result = zfu.apply(page, "9104000", {}) assert result.changed is False, result.changes assert page.locator("#claimCPTBillToInsChk0").is_checked() is True assert page.locator("#uBClaimBillFee0").input_value() == "0.00" assert page.evaluate("window.feeWrites") == 0 # ============================================================================= # apply() — no change, and a tab that cannot be confirmed # ============================================================================= @case def apply_logs_why_when_there_is_nothing_to_uncheck(page): page.goto(FIXTURE.as_uri()) out = io.StringIO() with contextlib.redirect_stdout(out): result = zfu.apply(page, "9103000", {}) assert result == ConditionResult.none("zero_fee_uncheck"), result logged = out.getvalue() assert "[COND zero_fee_uncheck 9103000]" in logged, logged assert "nothing to uncheck" in logged, logged # Only on that path — not when a line was actually unchecked. page.goto(FIXTURE.as_uri()) _inject_row(page, _HEMOGLOBIN, "CPTROW_3", checked=True, fee="0.00") out = io.StringIO() with contextlib.redirect_stdout(out): result = zfu.apply(page, "9103000", {}) assert result.changed is True, result.changes assert "nothing to uncheck" 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()) _inject_row(page, _HEMOGLOBIN, "CPTROW_3", checked=True, fee="0.00") 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 = zfu.apply(page, "9103000", {}) finally: claim_form.open_cpt_hcpcs_tab = real assert result.changed is False, result.changes assert _row_state(page, 3) == (True, "0.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_unchecked_line_and_its_fee(page): page.goto(FIXTURE.as_uri()) _inject_row(page, _HEMOGLOBIN, "CPTROW_3", checked=True, fee="0.00") result = zfu.apply(page, "9103000", {}) text = zfu.describe(result) lines = text.splitlines() assert lines[0] == "Checked CPT line(s) with a zero billed fee unchecked:", text assert lines[1:] == [" Row 4 (85018): checked with billed fee 0.00 -> unchecked"], text @case def describe_says_blank_rather_than_printing_nothing(): result = ConditionResult(condition_name="zero_fee_uncheck", changed=True, changes=[{"row": 0, "code": _HEMOGLOBIN, "fee": ""}]) text = zfu.describe(result) assert " Row 1 (85018): checked with billed fee (blank) -> unchecked" in text, text # ============================================================================= # The registry # ============================================================================= @case def registered_first_in_conditions(): """ First, so it runs on the untouched claim and every specific condition runs after it on a consistent grid and has the last word — and the specific conditions keep their own order behind it. The one entry after them is this rule's reverse half, priced_line_check, registered LAST (2026-09-30) so it only ever sees a line an exclusion condition has already zeroed — see test_conditions_priced_line_check.py. """ assert conditions.CONDITIONS[0] is zfu, conditions.CONDITIONS assert conditions.CONDITIONS[1:] == [ telehealth, medicare_telehealth, depression_dx_pointer, j2930_j2001_update, dummy_codes, dental_dummy_codes, dental_payer_check, medicaid_uncheck_cpts, medicare_billing_screening, medicare_vaccine_a6, medicare_wellness_history, medicaid_pregnancy_th, bh_h_code_modifier, vaccine_admin_codes, injection_admin_code, medicare_pps_code, priced_line_check, ], conditions.CONDITIONS assert conditions.BY_NAME["zero_fee_uncheck"] is zfu assert zfu.NAME == "zero_fee_uncheck" # ============================================================================= # run_all() against the REAL registry # ============================================================================= @case def run_all_fires_zero_fee_uncheck_alone_on_a_plain_zero_fee_line(page): """ Against the REAL registry, not fakes — proves this condition is wired into conditions.CONDITIONS, and that a plain zero-fee line sets off nothing else. `icd` is left out of the data on purpose: the fixture carries Z13.31, which would fire depression_dx_pointer on its own account (the next case covers the two together). And the fixture's own G8510 is checked first: as served it sits unchecked at 65.00, which priced_line_check (the reverse half, 2026-09-30) would check on its own account too. """ page.goto(FIXTURE.as_uri()) _set_row(page, "CPTROW_2", checked=True) _inject_row(page, _HEMOGLOBIN, "CPTROW_3", checked=True, fee="0.00") data = {"cpt": claim_form.extract(page)["cpt"]} results = run_all(page, "9103000", data) assert [r.condition_name for r in results] == ["zero_fee_uncheck"], results assert results[0].changes == [{"row": 3, "code": _HEMOGLOBIN, "fee": "0.00"}] @case def run_all_unchecks_a_zero_fee_g8510_and_depression_does_not_re_check_it(page): """ The toggle this rule would otherwise start — the same check/uncheck shape fixed for claim 9131000: the first G8510 is checked at 0.00 and the claim carries Z13.31, so both zero_fee_uncheck and depression_dx_pointer fire. zero_fee_uncheck runs first and unchecks it; depression's own "re-include the first G8510" step must then leave it unchecked, because a zero-fee line is never billed. Before, it checked it straight back: two contradictory changes reported for one row, and updateBillToIns() fired twice on a line that must stay out. """ page.goto(FIXTURE.as_uri()) _set_row(page, "CPTROW_2", checked=True, fee="0.00") _count_checkbox_clicks(page, "CPTROW_2") data = claim_form.extract(page) assert zfu.detect("9103000", data) is True assert depression_dx_pointer.detect("9103000", data) is True results = run_all(page, "9103000", data) names = [r.condition_name for r in results] assert names == ["zero_fee_uncheck", "depression_dx_pointer"], names assert results[0].changes == [{"row": 2, "code": "G8510", "fee": "0.00"}], results[0].changes depression_checks = [c for c in results[1].changes if "before" not in c and "unchecked" not in c and "fee" not in c] assert depression_checks == [], ("depression re-checked the zero-fee G8510", results[1].changes) # Its pointer is still retagged — only the check is withheld. retagged = {c["row"] for c in results[1].changes if "before" in c} assert retagged == {0, 2}, results[1].changes assert _row_state(page, 2) == (False, "0.00") assert page.evaluate("window.clicksOn['CPTROW_2']") == 1, \ "the G8510 checkbox was clicked more than once — a check/uncheck toggle" # ============================================================================= # run_all() — where the rule meets another condition's own rule. Both were # PINNED as known gaps until the operator ruled on them (2026-09-30); each # now asserts the ruled outcome. See zero_fee_uncheck.py's module docstring. # ============================================================================= def _inject_full_g8510_row(page, row_id, *, checked, fee): """ A second G8510 on hcfa_claim.html, after the fixture's own (CPTROW_2), carrying all four ICD pointer fields — depression_dx_pointer's retag step reads every one, the same as test_conditions_depression_dx_pointer.py's `_inject_duplicate_target_row`. """ 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 = '' + '' + '' + '' + '' + '' + ''; tbody.insertBefore(tr, entryRow); }""", {"rowId": row_id, "checked": checked, "fee": fee}) @case def run_all_keeps_the_priced_g8510_when_the_first_copy_is_zero_fee(page): """ Operator ruling (2026-09-30), flipped from a PINNED gap. The first G8510 is checked at 0.00 and a later G8510 checked at 65.00 — a shape none of the 39 snapshots shows. zero_fee_uncheck unchecks the 0.00 copy. depression then keeps the first G8510 whose fee is NOT zero — the 65.00 one — so its re-include step has nothing to check (it is already checked) and its duplicate step has nothing to do on the 0.00 copy (already unchecked, already 0.00). The priced G8510 stays billed with its fee; before the ruling it was zeroed, and no G8510 was left billed at all. Without zero_fee_uncheck in the registry, depression reaches the same end state on its own: the 0.00 copy is now the duplicate, and its duplicate step unchecks it. """ def claim(): page.goto(FIXTURE.as_uri()) _set_row(page, "CPTROW_2", checked=True, fee="0.00") _inject_full_g8510_row(page, "CPTROW_3", checked=True, fee="65.00") _count_checkbox_clicks(page, "CPTROW_2") _count_checkbox_clicks(page, "CPTROW_3") return claim_form.extract(page) results = run_all(page, "9103000", claim()) names = [r.condition_name for r in results] assert names == ["zero_fee_uncheck", "depression_dx_pointer"], names assert results[0].changes == [{"row": 2, "code": "G8510", "fee": "0.00"}], \ results[0].changes not_retags = [c for c in results[1].changes if "before" not in c] assert not_retags == [], ("depression checked, unchecked or zeroed a " "G8510", results[1].changes) assert {c["row"] for c in results[1].changes} == {0, 2, 3}, results[1].changes assert (_row_state(page, 2), _row_state(page, 3)) == \ ((False, "0.00"), (True, "65.00")), "the priced G8510 stays billed" assert page.evaluate("window.clicksOn") == {"CPTROW_2": 1, "CPTROW_3": 0} # Without the rule: depression's own duplicate step unchecks the 0.00 # copy, the priced one untouched. results = run_all(page, "9103000", claim(), conditions=[c for c in conditions.CONDITIONS if c is not zfu]) assert [r.condition_name for r in results] == ["depression_dx_pointer"], results assert [c for c in results[0].changes if "before" not in c] == \ [{"row": 2, "code": "G8510", "unchecked": True}], results[0].changes assert (_row_state(page, 2), _row_state(page, 3)) == \ ((False, "0.00"), (True, "65.00")) assert page.evaluate("window.clicksOn") == {"CPTROW_2": 1, "CPTROW_3": 0} _TDAP = "TETANUS DIPHTHERIA TOXOIDS AND ACELLULAR PERTUSSIS VACC" _ADMIN_1ST = "IMMUNIZATION ADMIN SINGLE OR COMBINATION" @case def run_all_adds_the_admin_code_when_the_only_admin_line_is_checked_at_zero(page): """ Operator ruling (2026-09-30), flipped from a PINNED known gap. `run_all` runs every detect() on the claim as read, where the 90471 is CHECKED at 0.00. It used to count as "admin already billed", so vaccine_admin_codes never fired; zero_fee_uncheck then unchecked that 90471 and the claim left with the vaccine billed and no admin code — document #18's own case. Now a checked zero-fee admin line does not count (zero_fee_uncheck, first, will uncheck it before vaccine_admin_codes' apply() runs): both fire, the 0.00 line ends unchecked, and a new 90471 is added. The same claim with the 90471 ALREADY unchecked (live claim 9132000's shape) reaches the same grid, with vaccine_admin_codes alone. """ def claim(admin_checked): 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": "0.00", "checked": admin_checked}, ]) return claim_form.extract(page) def grid(): return [(r["code"], r["billed"], r["billed_fee"]) for r in claim_form.extract(page)["cpt"]] fixed = [("99396", True, "250.00"), ("90734", True, "60.00"), ("90471", False, "0.00"), ("90471", True, "30.00")] data = claim(admin_checked=True) assert vaccine_admin_codes.detect("9113000", data) is True results = run_all(page, "9113000", data) assert [r.condition_name for r in results] == \ ["zero_fee_uncheck", "vaccine_admin_codes"], results assert results[0].changes == [{"row": 2, "code": "90471", "fee": "0.00"}], \ results[0].changes added = [c for c in results[1].changes if c.get("added")] assert [c["code"] for c in added] == ["90471"], results[1].changes assert grid() == fixed, grid() results = run_all(page, "9113000", claim(admin_checked=False)) assert [r.condition_name for r in results] == ["vaccine_admin_codes"], results assert grid() == fixed, grid() @case def run_all_does_not_fire_on_a_checked_row_with_no_fee_input(page): # The page-level shape: extract() reports the row's fee as None, not # "" — so detect() and apply() agree and the log never claims a # zero-fee line that apply() then cannot find. page.goto(FIXTURE.as_uri()) _inject_row(page, _HEMOGLOBIN, "CPTROW_3", checked=True, has_fee=False) data = claim_form.extract(page) row = [r for r in data["cpt"] if r["code"] == _HEMOGLOBIN] assert [(r["billed"], r["billed_fee"]) for r in row] == [(True, None)], row assert zfu.detect("9103000", data) is False # ============================================================================= # PINNED, NEEDS AN OPERATOR RULING — medicare_telehealth on a claim whose # G2025 is checked at 0.00. Today's outcome, not the settled one (review # finding, 2026-09-30). # ============================================================================= _MEDICARE_DATA = { "progress_notes": {"text": "Session Setting (PoS): TeleHealth"}, "insurance": [{"Name": "Humana Medicare"}], } @case def pinned_needs_ruling_a_g2025_checked_at_zero_leaves_no_line_billed(page): """ PINNED, NEEDS A RULING. The claim a G2025 added at 0.00 leaves for the next run (the Fee Schedule priced it at nothing). zero_fee_uncheck, first, unchecks the 0.00 G2025 — the common rule. medicare_telehealth then asks `cpt_code_present("G2025")`, which ignores the checkbox, counts G2025 as confirmed, and unchecks and zeroes every OTHER line: the claim ends with NO billed line, which that step's own gate says it must never do. Requiring a checked, non-zero G2025 there changes document #22's behaviour — beyond rulings A/B/C. """ page.goto(FIXTURE.as_uri()) _inject_row(page, "G2025", "CPTROW_3", checked=True, fee="0.00") data = dict(_MEDICARE_DATA, cpt=claim_form.extract(page)["cpt"]) results = run_all(page, "9103000", data) assert [r.condition_name for r in results] == ["zero_fee_uncheck", "medicare_telehealth"], results assert results[0].changes == [{"row": 3, "code": "G2025", "fee": "0.00"}] billed = [r["code"] for r in claim_form.extract(page)["cpt"] if r["billed"]] assert billed == [], ("today: no line left billed", billed) 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())