Portal Delete run (Super Admin), lab codes #3/#4, Z23 pointer #45, T1017 #46, payer note, login security-image wait

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ManikandanandClaude Opus 5.5 committed 2026-10-29 12:30:38 +05:30
1 parent a8af44e673
commit fafa5285eb
21 files changed
+1509 -63

No files matched your search

+20
View File
@@ -520,6 +520,26 @@ def tracking_columns_fill_only_for_claims_the_run_read():
assert unread[_col(h)] == "", (h, unread)
@case
def a_payer_the_sheet_and_ecw_disagree_on_is_noted_and_ecws_is_used():
# Operator, 2026-10-28: the rules go by eCW's payer; the sheet's is
# compared, and a difference is a note — not a finding (Category kept).
ecw = _ub(insurance=[{"Name": "Medicare"}])
r = _build({"1000001": cs.claim_outcome(True, ecw)})[1]
assert r[_col("Category")] == "Pass", r
assert r[_col("Comments")].endswith(
"; Payer: sheet says Medicaid, eCW says Medicare - eCW used"), r
assert r[_col("PAYER")] == "Medicaid", "the sheet's column stays"
@case
def no_payer_note_when_they_agree_or_ecw_shows_none():
for ecw in ([{"Name": " medicaid "}], [], [{"Name": ""}]):
r = _build({"1000001": cs.claim_outcome(True,
_ub(insurance=ecw))})[1]
assert "Payer:" not in r[_col("Comments")], (ecw, r)
@case
def a_claim_id_only_test_sheet_still_builds():
rows = cs.build_rows([["Claim No"], ["9000002"], ["9000001"]], 0, 0,
+231
View File
@@ -0,0 +1,231 @@
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())
+7 -4
View File
@@ -56,12 +56,13 @@ from ecw_bot.conditions import (bh_h_code_modifier, # noqa: E402
depression_dx_pointer, dummy_codes,
injection_admin_code,
medicare_pps_code,
j2930_j2001_update, medicaid_uncheck_cpts,
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,
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)
@@ -578,10 +579,12 @@ def registered_last_with_zero_fee_uncheck_first():
zero_fee_uncheck,
telehealth, medicare_telehealth, depression_dx_pointer,
j2930_j2001_update, dummy_codes, dental_dummy_codes,
dental_payer_check, medicaid_uncheck_cpts,
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_admin_codes, injection_admin_code,
bh_h_code_modifier, vaccine_z23_pointer, vaccine_admin_codes,
injection_admin_code,
medicare_pps_code,
plc,
], conditions.CONDITIONS
+192
View File
@@ -0,0 +1,192 @@
r"""
conditions/t1017_non_billable.py — document #46 (EEWA-40, operator
2026-10-28): T1017 by the claim's primary payer —
* a Medicare payer (#25's exact eCW names) or Medicaid (the dashboard's
"Medicaid" group only, as #43/#44): unchecked and Billed Fee 0;
* any other payer (RAE, CHP+, blank, unmapped included): nothing
changed, Review.
python tests\test_conditions_t1017_non_billable.py
Uses hcfa_claim.html like the Medicaid uncheck tests.
"""
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 t1017_non_billable 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
def _fee(page, n):
return page.locator(sel.SEL_CPT_ROWS).nth(n).locator(
sel.SEL_CPT_BILLED_FEE).first.input_value()
# ── detect (no browser) ──────────────────────────────────────────────────────
@case
def detect_t1017_on_any_payer():
for payer in ("Medicare", "Medicaid", "AARP", "", None):
assert cond.detect("C1", _claim(payer, "99213", "T1017")), payer
assert cond.detect("C1", _claim("Medicaid", " t1017 "))
@case
def no_t1017_or_dental_never_fires_it():
assert not cond.detect("C1", _claim("Medicaid", "99213", "T1016"))
assert not cond.detect("C1", {})
assert not cond.detect("C1", _claim("Medicaid", "T1017",
screen="dental"))
@case
def which_payers_make_it_non_billable():
for payer in ("Medicare", "HCFA Medicare", "Humana Medicare",
"Devoted MCR UB", "Medicaid", "HCFA Medicaid"):
assert cond.non_billable_for(_claim(payer, "T1017")), payer
for payer in ("BH COLORADO ACCESS", "Child Health Plan Plus", "AARP",
"NO SUCH PAYER XYZ", "", None):
assert not cond.non_billable_for(_claim(payer, "T1017")), payer
# ── apply (browser) ──────────────────────────────────────────────────────────
@case
def medicaid_t1017_unchecked_and_zeroed(page):
page.goto(FIXTURE.as_uri())
_inject_cpt_row(page, "T1017", fee="80.00")
result = cond.apply(page, "C1", _claim("Medicaid", "99213", "T1017"))
assert isinstance(result, ConditionResult)
assert result.changed and not result.review, result
assert [c["code"] for c in result.changes] == ["T1017"], result.changes
assert _fee(page, 3) == "0.00"
row = page.locator(sel.SEL_CPT_ROWS).nth(3)
assert row.locator(sel.SEL_CPT_ASSIGN_TO_PATIENT).first.is_checked() \
is False
assert _fee(page, 0) == "210.00", "99213 must be left alone"
@case
def medicare_t1017_unchecked_and_zeroed(page):
page.goto(FIXTURE.as_uri())
_inject_cpt_row(page, "T1017", fee="80.00")
result = cond.apply(page, "C1", _claim("Humana Medicare", "T1017"))
assert result.changed and _fee(page, 3) == "0.00", result
@case
def any_other_payer_is_review_and_nothing_changes(page):
for payer in ("Cigna HealthCare Of Colorado", "BH COLORADO ACCESS", ""):
page.goto(FIXTURE.as_uri())
_inject_cpt_row(page, "T1017", fee="80.00")
result = cond.apply(page, "C1", _claim(payer, "T1017"))
assert result.changed is False, (payer, result)
assert "T1017" in result.review and "check by hand" in \
result.review, (payer, result)
assert _fee(page, 3) == "80.00", payer
assert "Cigna HealthCare Of Colorado" in cond.apply(
page, "C1", _claim("Cigna HealthCare Of Colorado", "T1017")).review
@case
def the_comment_names_the_payer_group(page):
page.goto(FIXTURE.as_uri())
_inject_cpt_row(page, "T1017", fee="80.00")
text = cond.summary_comment(cond.apply(page, "C1",
_claim("Medicaid", "T1017")))
assert "T1017" in text and "Medicaid" in text, text
page.goto(FIXTURE.as_uri())
_inject_cpt_row(page, "T1017", fee="80.00")
text = cond.describe(cond.apply(page, "C1", _claim("Medicare", "T1017")))
assert "T1017" in text and "80.00" in text, text
# ── wiring ───────────────────────────────────────────────────────────────────
@case
def it_is_registered_before_priced_line_check():
names = [m.NAME for m in CONDITIONS]
assert "t1017_non_billable" in names
assert names.index("t1017_non_billable") < names.index(
"priced_line_check"), names
@case
def the_charge_summary_has_a_fallback_comment():
assert "T1017" in cs.COMMENTS["t1017_non_billable"]
@case
def run_all_leaves_t1017_unchecked_at_the_end(page):
page.goto(FIXTURE.as_uri())
_inject_cpt_row(page, "T1017", fee="80.00")
with contextlib.redirect_stdout(io.StringIO()):
results = run_all(page, "C1", _claim("Medicaid", "T1017"))
assert "t1017_non_billable" 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 _fee(page, 3) == "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())
@@ -0,0 +1,228 @@
r"""
conditions/vaccine_z23_pointer.py — document #45 (EEWA-39, operator
2026-10-28): "Make sure you are assigning the proper diagnosis code (Z23)
for ALL VACCINES".
Every line with one of the client's 19 vaccine codes (#18's list; not the
admin codes) carries Z23's ICD pointer — its number in the ICD list — in
ICD1-4. Missing → the first empty slot, the line's other pointers kept. No
Z23 on the claim, or no free slot → Review. Other lines are never touched.
All payers; not Dental.
python tests\test_conditions_vaccine_z23_pointer.py
Uses hcfa_claim.html; `_inject_vaccine_row()` adds the vaccine 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"))
FIXTURE = pathlib.Path(__file__).resolve().parent / "fixtures" / "hcfa_claim.html"
from ecw_bot.conditions import vaccine_z23_pointer 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
CASES = []
def case(fn):
CASES.append(fn)
return fn
_ICD = [{"#": "1", "Code": "J06.9", "Name": "..."},
{"#": "2", "Code": "Z23", "Name": "Encounter for immunization"}]
def _claim(*codes, icd=_ICD, screen=None):
data = {"insurance": [{"Name": "Medicaid"}], "icd": list(icd),
"cpt": [{"code": c, "checked": True, "fee": "45.00"}
for c in codes]}
if screen:
data["screen"] = screen
return data
def _inject_vaccine_row(page, code, row_id, icd=("1", "", "", "")):
page.evaluate(
"""(args) => {
const tbody = document.querySelector(
'#claimCPTCodesTable8888888888888 tbody');
const addRowTr = tbody.querySelector('tr:last-child');
const tr = document.createElement('tr');
tr.id = args.rowId;
tr.innerHTML =
'<td><input data-fieldname="claimCPTCode" value="' + args.code + '" readonly></td>'
+ '<td><input type="checkbox" ng-click="updateBillToIns(3)" checked></td>'
+ args.icd.map((v, i) => '<td><input data-fieldname="ClaimCPTICD'
+ (i + 1) + '" value="' + v + '"></td>').join('')
+ '<td><input data-fieldname="ClaimCPTBilledFee" value="45.00"></td>';
tbody.insertBefore(tr, addRowTr);
}""", {"code": code, "rowId": row_id, "icd": list(icd)})
def _icd_of(page, n):
row = page.locator(sel.SEL_CPT_ROWS).nth(n)
return [row.locator(s).first.input_value() for s in sel.SEL_CPT_ICD]
# ── detect (no browser) ──────────────────────────────────────────────────────
@case
def detect_a_vaccine_code_on_any_payer():
assert cond.detect("C1", _claim("99213", "90707"))
data = _claim("90656")
data["insurance"] = [{"Name": "Medicare"}]
assert cond.detect("C1", data), "Medicare too"
@case
def detect_even_without_z23_so_the_claim_goes_to_review():
assert cond.detect("C1", _claim("90707", icd=_ICD[:1]))
@case
def admin_codes_alone_or_no_vaccine_never_fire_it():
assert not cond.detect("C1", _claim("99213", "90471", "90460"))
assert not cond.detect("C1", _claim("99213"))
assert not cond.detect("C1", {})
@case
def not_on_a_dental_claim():
assert not cond.detect("C1", _claim("90707", screen="dental"))
@case
def z23_is_found_with_or_without_a_dot():
for code in ("Z23", "z23", " Z23. ", "Z23.0"):
data = _claim("90707", icd=[{"#": "3", "Code": code}])
assert cond.z23_pointer(data) == "3", code
assert cond.z23_pointer(_claim("90707", icd=[{"#": "1",
"Code": "Z23.5"}])) is None
# ── apply (browser) ──────────────────────────────────────────────────────────
@case
def the_pointer_goes_in_the_first_empty_slot_of_each_vaccine_line(page):
page.goto(FIXTURE.as_uri())
_inject_vaccine_row(page, "90707", "CPTROW_3", ("1", "", "", ""))
_inject_vaccine_row(page, "90656", "CPTROW_4", ("", "", "", ""))
first_before = _icd_of(page, 0)
result = cond.apply(page, "C1", _claim("99213", "90707", "90656"))
assert isinstance(result, ConditionResult)
assert result.changed and not result.review, result
assert [c["code"] for c in result.changes] == ["90707", "90656"]
assert _icd_of(page, 3) == ["1", "2", "", ""]
assert _icd_of(page, 4) == ["2", "", "", ""]
assert _icd_of(page, 0) == first_before, "99213 must be left alone"
@case
def a_line_that_already_carries_it_is_left_alone(page):
page.goto(FIXTURE.as_uri())
_inject_vaccine_row(page, "90707", "CPTROW_3", ("1", "2", "", ""))
result = cond.apply(page, "C1", _claim("90707"))
assert result.changed is False and not result.review, result
assert _icd_of(page, 3) == ["1", "2", "", ""]
@case
def no_z23_on_the_claim_is_review_and_nothing_changes(page):
page.goto(FIXTURE.as_uri())
_inject_vaccine_row(page, "90707", "CPTROW_3", ("1", "", "", ""))
result = cond.apply(page, "C1", _claim("90707", icd=_ICD[:1]))
assert result.changed is False
assert "Z23 not on the claim" in result.review, result
assert _icd_of(page, 3) == ["1", "", "", ""]
@case
def a_line_with_no_free_slot_is_review_the_others_still_fixed(page):
page.goto(FIXTURE.as_uri())
_inject_vaccine_row(page, "90707", "CPTROW_3", ("1", "3", "4", "5"))
_inject_vaccine_row(page, "90656", "CPTROW_4", ("1", "", "", ""))
result = cond.apply(page, "C1", _claim("90707", "90656"))
assert [c["code"] for c in result.changes] == ["90656"], result
assert "no free pointer slot" in result.review and "90707" in \
result.review, result
assert _icd_of(page, 3) == ["1", "3", "4", "5"]
@case
def the_comment_names_the_codes(page):
page.goto(FIXTURE.as_uri())
_inject_vaccine_row(page, "90707", "CPTROW_3")
text = cond.summary_comment(cond.apply(page, "C1", _claim("90707")))
assert "Z23" in text and "90707" in text, text
page.goto(FIXTURE.as_uri())
_inject_vaccine_row(page, "90707", "CPTROW_3")
text = cond.describe(cond.apply(page, "C1", _claim("90707")))
assert "90707" in text and "Z23" in text, text
# ── wiring ───────────────────────────────────────────────────────────────────
@case
def it_is_registered_before_priced_line_check():
names = [m.NAME for m in CONDITIONS]
assert "vaccine_z23_pointer" in names
assert names.index("vaccine_z23_pointer") < names.index(
"priced_line_check"), names
@case
def the_charge_summary_has_a_fallback_comment():
assert "Z23" in cs.COMMENTS["vaccine_z23_pointer"]
@case
def run_all_adds_the_pointer(page):
page.goto(FIXTURE.as_uri())
_inject_vaccine_row(page, "90707", "CPTROW_3", ("1", "", "", ""))
with contextlib.redirect_stdout(io.StringIO()):
results = run_all(page, "C1", _claim("90707"))
assert "vaccine_z23_pointer" in [r.condition_name for r in results], \
results
assert _icd_of(page, 3) == ["1", "2", "", ""]
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())
+7 -4
View File
@@ -55,13 +55,14 @@ from ecw_bot.conditions import (bh_h_code_modifier, # noqa: E402
depression_dx_pointer, dummy_codes,
injection_admin_code,
medicare_pps_code,
j2930_j2001_update, medicaid_uncheck_cpts,
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,
priced_line_check, telehealth,
vaccine_admin_codes)
vaccine_admin_codes, vaccine_z23_pointer)
from ecw_bot.conditions.base import ( # noqa: E402
CPT_TAB_NOT_CONFIRMED, ConditionResult, run_all)
from ecw_bot.pages import claim_form # noqa: E402
@@ -520,10 +521,12 @@ def registered_first_in_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,
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_admin_codes, injection_admin_code,
bh_h_code_modifier, vaccine_z23_pointer, vaccine_admin_codes,
injection_admin_code,
medicare_pps_code,
priced_line_check,
], conditions.CONDITIONS
+109
View File
@@ -0,0 +1,109 @@
r"""
auth/login.py `wait_after_username()` — what comes after the username's
Next (live 2026-10-28 17:59: the security image page came late, the old
one-look check missed it, and the bot clicked a password box that stayed
disabled until it timed out).
It waits, up to its timeout, for whichever comes first: eCW's "VERIFY YOUR
SECURITY IMAGE" page or a password box that is visible AND enabled. Neither
→ a screenshot (with the DOM) and an error that says so.
python tests\test_login_username_step.py
Local headless chromium, `page.set_content()` only. No eCW, no login.
"""
import sys
import time
import pathlib
import tempfile
ROOT = pathlib.Path(__file__).resolve().parent.parent
sys.path.insert(0, str(ROOT / "src"))
from ecw_bot import settings as cfg # noqa: E402
from ecw_bot.auth import login # noqa: E402
CASES = []
def case(fn):
CASES.append(fn)
return fn
# The password box is on the page from the start, disabled — the shape
# seen live; eCW enables it once the username step is done.
_PAGE = """
<input id="doctorID" value="someone">
<input disabled type="password" id="passwordField">
<div id="img" style="display:none">VERIFY YOUR SECURITY IMAGE</div>
<script>%s</script>
"""
@case
def a_late_security_image_page_is_seen(page):
page.set_content(_PAGE % "setTimeout(() => document.getElementById("
"'img').style.display = '', 3000);")
assert login.wait_after_username(page, 10_000) == "image"
@case
def a_password_box_enabled_late_is_waited_for(page):
page.set_content(_PAGE % "setTimeout(() => document.getElementById("
"'passwordField').disabled = false, 2500);")
t0 = time.monotonic()
assert login.wait_after_username(page, 10_000) == "password"
assert time.monotonic() - t0 >= 2, "returned before it was enabled"
@case
def after_the_image_only_the_password_box_counts(page):
page.set_content(_PAGE % "document.getElementById('img').style.display"
" = ''; setTimeout(() => document.getElementById("
"'passwordField').disabled = false, 1500);")
assert login.wait_after_username(page, 10_000, image=False) == "password"
@case
def a_password_box_that_stays_disabled_is_an_error_with_a_screenshot(page):
page.set_content(_PAGE % "")
try:
login.wait_after_username(page, 2_000)
except RuntimeError as exc:
assert "password box stayed disabled" in str(exc), exc
else:
raise AssertionError("no error for a box that never enabled")
shots = list(pathlib.Path(cfg.SCREENSHOTS).glob("*_username_step_disabled.*"))
assert {p.suffix for p in shots} == {".png", ".html"}, shots
def main() -> int:
from playwright.sync_api import sync_playwright
failures = 0
with tempfile.TemporaryDirectory() as tmp:
cfg.SCREENSHOTS = pathlib.Path(tmp) # never the real folder
with sync_playwright() as pw:
browser = pw.chromium.launch(headless=True)
page = browser.new_page()
for fn in CASES:
name = fn.__name__.replace("_", " ")
try:
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())
+83
View File
@@ -105,6 +105,16 @@ class FakeRepo:
self._maybe_fail()
return [dict(r) for r in self._rows if claim_no in r["claim_no"]]
delete_fails = None
def delete_run(self, run_at):
self.calls.append(("delete_run", run_at))
if self.delete_fails:
raise self.delete_fails
kept = [r for r in self._rows if r["run_at"] != run_at]
gone, self._rows = len(self._rows) - len(kept), kept
return gone
TESTER_PASSWORD = "tester-password-1"
@@ -581,6 +591,63 @@ def the_error_page_names_what_went_wrong():
assert "Smith" not in r.text, "the driver's message is never shown"
# ── Delete a run (Super Admin only, operator 2026-10-28) ─────────────────────
def _delete_run(client, app, run_at=RUN_PM, token=None):
return client.post("/admin/runs/delete", headers=_GOOD_ORIGIN,
data={"run_at": run_at.isoformat(),
"token": token or app.state.run_token},
follow_redirects=False)
@case
def a_super_admin_deletes_one_run_and_the_delete_is_recorded():
repo = FakeRepo()
client, app = signed_in(repo, FakeRunner(), role="Super Admin")
page = client.get(f"/day/{DAY.isoformat()}").text
assert page.count("Delete run") == 2, "one button per run of the day"
r = _delete_run(client, app)
assert r.status_code == 303, r.status_code
assert r.headers["location"].startswith(f"/day/{DAY.isoformat()}?"), \
r.headers["location"]
assert [x["run_at"] for x in repo._rows] == [RUN_AM], \
"only that run's rows go"
shown = client.get(r.headers["location"]).text
assert "2 claims deleted" in shown, shown
history = client.get("/admin/signins").text
assert "run deleted" in history and "10/16/2026 2:15 PM" in history, \
history
@case
def an_admin_or_viewer_cannot_see_or_use_delete_run():
for role in ("Admin", "Viewer"):
repo = FakeRepo()
client, app = signed_in(repo, FakeRunner(), role=role)
assert "Delete run" not in client.get(f"/day/{DAY.isoformat()}").text
assert _delete_run(client, app).status_code == 403, role
assert len(repo._rows) == 3, (role, "nothing deleted")
repo = FakeRepo()
client, app = signed_in(repo, FakeRunner(), role="Super Admin")
assert _delete_run(client, app, token="wrong").status_code == 403, \
"a page on another site cannot send it"
assert len(repo._rows) == 3
@case
def delete_run_without_the_sql_permission_says_so():
class DbError(Exception):
pass
repo = FakeRepo()
repo.delete_fails = DbError("42000", "The DELETE permission was denied")
client, app = signed_in(repo, FakeRunner(), role="Super Admin")
r = _quiet(_delete_run, client, app)
assert r.status_code == 503, r.status_code
assert "No permission to delete" in r.text, r.text
assert "GRANT DELETE" in r.text, r.text
# ── repo SQL ─────────────────────────────────────────────────────────────────
class FakeCursor:
@@ -590,6 +657,7 @@ class FakeCursor:
def execute(self, sql, params):
self.log.append((sql, list(params)))
self.rowcount = len(self.rows)
return self
def fetchall(self):
@@ -599,10 +667,14 @@ class FakeCursor:
class FakeConn:
def __init__(self, rows=(), cols=()):
self.log, self.rows, self.cols, self.closed = [], list(rows), cols, False
self.committed = False
def cursor(self):
return FakeCursor(self.log, self.rows, self.cols)
def commit(self):
self.committed = True
def close(self):
self.closed = True
@@ -611,6 +683,17 @@ def _repo(conn):
return SqlResultsRepo("DSN=x", connect=lambda cs, timeout: conn)
@case
def repo_deletes_exactly_one_run_and_commits():
conn = FakeConn(rows=[None] * 20) # the driver's rowcount: 20
assert _repo(conn).delete_run(RUN_PM) == 20
(sql, params), = conn.log
assert re.fullmatch(r"DELETE FROM dbo\.CV_ChargeSummary WHERE run_at = \?",
sql), sql
assert params == [RUN_PM], params
assert conn.committed and conn.closed
@case
def repo_turns_a_text_run_at_or_day_into_a_datetime_or_date():
"""The legacy {SQL Server} driver returns DATETIME2 / DATE as text."""