Initial import: eCW Charge Validation bot and results Portal
Snapshot of the working project as of 2026-10-23 (local 2d4d4fc), one commit with no earlier history: the tracked files were de-identified first (synthetic claim ids and patient data only; see Context.md section 7). Credentials, run logs, screenshots, claim reports and client workbooks are gitignored and not included. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
commit
ba15a574ab
205 files changed
+56772
No files matched your search
@@ -0,0 +1,189 @@
|
||||
r"""
|
||||
VERIFY mode writes nothing to eCW (operator, 2026-10-16 — option C).
|
||||
|
||||
Found 2026-10-15, confirmed in eCW's audit log: clicking a CPT line's
|
||||
"Assign To Patient" box runs eCW's updateBillToIns(), which saves on the
|
||||
server at once — closing the form with Cancel did not undo it. So with
|
||||
SAVE_CORRECTIONS=0 (VERIFY) the box is set on SCREEN only (no click event,
|
||||
so updateBillToIns never runs), and no CPT row is added (Add → picker OK
|
||||
runs addClaimFSCPTCode('save')). LIVE-WRITE still clicks for real.
|
||||
|
||||
python tests\test_verify_no_live_writes.py
|
||||
|
||||
Uses tests/fixtures/vaccine_claim.html, reshaped per case with
|
||||
seedCptRows; a capture listener counts real clicks on the bill-to boxes.
|
||||
"""
|
||||
|
||||
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" / "vaccine_claim.html"
|
||||
|
||||
from ecw_bot import settings as cfg # noqa: E402
|
||||
from ecw_bot.conditions import vaccine_admin_codes as vac # noqa: E402
|
||||
from ecw_bot.pages import claim_form # noqa: E402
|
||||
|
||||
CASES = []
|
||||
|
||||
|
||||
def case(fn):
|
||||
CASES.append(fn)
|
||||
return fn
|
||||
|
||||
|
||||
def _quiet(fn, *a, **k):
|
||||
with contextlib.redirect_stdout(io.StringIO()) as out:
|
||||
result = fn(*a, **k)
|
||||
return result, out.getvalue()
|
||||
|
||||
|
||||
def _fresh(page, rows):
|
||||
page.goto(FIXTURE.as_uri())
|
||||
page.evaluate("rows => window.seedCptRows(rows)", rows)
|
||||
page.evaluate("""() => {
|
||||
window.billClicks = 0; window.addClicks = 0;
|
||||
document.addEventListener('click', e => {
|
||||
if (e.target.closest('[ng-click*="updateBillToIns("]'))
|
||||
window.billClicks++;
|
||||
if (e.target.closest('button[ng-click*="addProcedureCode("]'))
|
||||
window.addClicks++;
|
||||
}, true);
|
||||
}""")
|
||||
|
||||
|
||||
def _billed(page):
|
||||
return {r["code"]: r["billed"] for r in claim_form.extract(page)["cpt"]}
|
||||
|
||||
|
||||
def _clicks(page):
|
||||
return page.evaluate("window.billClicks")
|
||||
|
||||
|
||||
ROWS = [
|
||||
{"code": "99213", "title": "OFFICE VISIT EST LEVEL 3", "fee": "120.00"},
|
||||
{"code": "G8510", "title": "SCREENING NEGATIVE", "fee": "0.00"},
|
||||
{"code": "J2001", "title": "LIDOCAINE", "fee": "15.00"},
|
||||
{"code": "90656", "title": "FLU VACC", "fee": "65.00", "checked": False},
|
||||
]
|
||||
|
||||
|
||||
# ── VERIFY: on screen, no click ──────────────────────────────────────────────
|
||||
|
||||
@case
|
||||
def verify_unchecks_a_zero_fee_line_on_screen_without_clicking(page):
|
||||
_fresh(page, ROWS)
|
||||
changes, out = _quiet(claim_form.uncheck_zero_fee_cpt_rows, page)
|
||||
assert [c["code"] for c in changes] == ["G8510"], changes
|
||||
assert _billed(page)["G8510"] is False, "the screen shows it unchecked"
|
||||
assert _clicks(page) == 0, "a real click would run updateBillToIns()"
|
||||
|
||||
|
||||
@case
|
||||
def verify_checks_a_priced_line_on_screen_without_clicking(page):
|
||||
_fresh(page, ROWS)
|
||||
changes, _ = _quiet(claim_form.check_priced_unchecked_cpt_rows, page)
|
||||
assert [c["code"] for c in changes] == ["90656"], changes
|
||||
assert _billed(page)["90656"] is True
|
||||
assert _clicks(page) == 0
|
||||
|
||||
|
||||
@case
|
||||
def verify_unchecks_and_zeroes_a_target_code_without_clicking(page):
|
||||
_fresh(page, ROWS)
|
||||
changes, _ = _quiet(claim_form.zero_and_uncheck_cpt_rows, page, {"J2001"})
|
||||
assert changes and changes[0]["unchecked"] is True, changes
|
||||
row = [r for r in claim_form.extract(page)["cpt"] if r["code"] == "J2001"][0]
|
||||
assert row["billed"] is False and row["billed_fee"] == "0.00", row
|
||||
assert _clicks(page) == 0
|
||||
|
||||
|
||||
@case
|
||||
def verify_re_includes_a_kept_line_without_clicking(page):
|
||||
_fresh(page, [
|
||||
{"code": "99213", "title": "OFFICE VISIT", "fee": "120.00"},
|
||||
{"code": "G8510", "title": "SCREENING", "fee": "65.00",
|
||||
"checked": False}])
|
||||
changes, _ = _quiet(claim_form.ensure_cpt_rows_checked, page, {"G8510"})
|
||||
assert [c["code"] for c in changes] == ["G8510"], changes
|
||||
assert _billed(page)["G8510"] is True
|
||||
assert _clicks(page) == 0
|
||||
|
||||
|
||||
@case
|
||||
def verify_adds_no_cpt_row(page):
|
||||
_fresh(page, ROWS)
|
||||
before = len(claim_form.extract(page)["cpt"])
|
||||
added, out = _quiet(claim_form.add_cpt_row, page, "96372")
|
||||
assert added is False, out
|
||||
assert len(claim_form.extract(page)["cpt"]) == before
|
||||
assert page.evaluate("window.addClicks") == 0, "Add was clicked"
|
||||
assert "VERIFY" in out, out
|
||||
|
||||
|
||||
@case
|
||||
def verify_admin_code_is_not_added_and_says_why(page):
|
||||
_fresh(page, ROWS)
|
||||
change, _ = _quiet(vac._add_admin_code, page, "C1", "96372", 1)
|
||||
assert change["added"] is False and change["grid_changed"] is False, change
|
||||
assert "VERIFY" in (change["error"] or ""), change
|
||||
|
||||
|
||||
# ── LIVE-WRITE: the real click, as before ────────────────────────────────────
|
||||
|
||||
@case
|
||||
def live_write_still_clicks_for_real(page):
|
||||
cfg.SAVE_CORRECTIONS = True
|
||||
_fresh(page, ROWS)
|
||||
_quiet(claim_form.uncheck_zero_fee_cpt_rows, page)
|
||||
assert _billed(page)["G8510"] is False
|
||||
assert _clicks(page) == 1, "LIVE-WRITE keeps eCW's own click"
|
||||
|
||||
|
||||
def _run_cases() -> 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("_", " ")
|
||||
cfg.SAVE_CORRECTIONS = False # VERIFY unless the case says
|
||||
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:
|
||||
"""shot() writes into the operator's Screenshots\\ folder; not here."""
|
||||
import tempfile
|
||||
orig = (cfg.SCREENSHOTS, cfg.SAVE_CORRECTIONS)
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
cfg.SCREENSHOTS = pathlib.Path(tmp)
|
||||
try:
|
||||
return _run_cases()
|
||||
finally:
|
||||
cfg.SCREENSHOTS, cfg.SAVE_CORRECTIONS = orig
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
Reference in new issue
Block a user