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:
ManikandanandClaude Opus 5.5 committed 2026-10-23 18:38:17 +05:30
commit ba15a574ab
205 files changed
+56772

No files matched your search

+198
View File
@@ -0,0 +1,198 @@
r"""
Progress Note extraction, against a real browser.
python tests\test_progress_note.py
Local headless chromium against `tests\fixtures\progress_note_host.html`. Never
touches eCW: no proxy, no login, no 2FA mail, no attempt against the guard.
The fixture puts the note in an **iframe** with Close on the parent page,
because that is how it actually arrives — the note is a whole printable
document with its own `<html>`. That split is the trap being tested:
* reading the modal's `innerText` finds nothing, since iframe content is not
part of it — which an earlier version of `open_progress_notes` did;
* looking for Close inside the note finds nothing either, since it lives on
the parent.
The rest is about eCW's own labels. Every section carries
`prisma-section="..."`, so the note comes back as a dict keyed by those rather
than as prose — but `"Footer"` repeats four times, and a naive dict build drops
the signature block. That is covered.
"""
import sys
import pathlib
ROOT = pathlib.Path(__file__).resolve().parent.parent
sys.path.insert(0, str(ROOT / "src"))
HOST = pathlib.Path(__file__).resolve().parent / "fixtures" / "progress_note_host.html"
from ecw_bot.pages import progress_note # noqa: E402
from ecw_bot.selectors import claim_form as sel # noqa: E402
CHECKS = []
def check(fn):
CHECKS.append(fn)
return fn
@check
def found_in_the_iframe_not_the_modal(page, note, where):
"""The note is a separate document; the frame walk is what finds it."""
assert where == "frame", where
# And the trap: the hosting modal's own innerText holds none of the note.
modal_text = page.evaluate(
"""() => {
const m = document.querySelector('.modal');
return m ? (m.innerText || '') : '';
}""")
assert "R69" not in modal_text, (
"the modal's innerText contains the note, so this fixture no longer "
"reproduces the iframe case it exists for")
@check
def patient_header_and_dos(page, note, where):
hdr = note["patient_header"]
assert "SAMPLE, Pat Q" in hdr, hdr
assert "900123" in hdr, hdr
assert note["dos"] == "06/29/2026", note["dos"]
@check
def sections_are_keyed_by_ecw_labels(page, note, where):
got = note["sections"]
for want in ("Header", "Past Medical History", "Surgical History",
"Family History", "Social History",
"Hospitalization/Major Diagnostic Procedure",
"Reason for Appointment", "History of Present Illness",
"Assessments", "Labs", "Procedure Codes",
"Care Plan Details", "Footer", "Active Problem List"):
assert want in got, f"{want!r} missing; got {sorted(got)}"
assert "Generalized Anxiety Disorder" in got["Past Medical History"], \
got["Past Medical History"]
assert "BH Outreach" in got["Reason for Appointment"], \
got["Reason for Appointment"]
# Present but empty on this note, exactly as eCW served it.
assert got["Active Problem List"] == "", repr(got["Active Problem List"])
@check
def repeated_footer_sections_are_joined_not_overwritten(page, note, where):
"""
"Footer" appears four times. Overwriting on each would keep only the last —
the facility block — and silently lose the signature and the sign-off.
"""
footer = note["sections"]["Footer"]
assert "Electronically signed by Provider" in footer, footer
assert "Sign off status" in footer, footer
assert "Brighton Womens Clinic" in footer, footer
@check
def assessments_are_parsed_with_their_codes(page, note, where):
a = note["assessments"]
assert len(a) == 2, a
assert a[0]["n"] == "1" and a[0]["code"] == "R69", a[0]
assert a[0]["primary"] is True, a[0]
assert "Illness, unspecified" in a[0]["text"], a[0]
assert a[1]["code"] == "F41.1", a[1]
assert a[1]["primary"] is False, a[1]
@check
def procedure_codes_carry_their_modifiers(page, note, where):
"""
The pair charge entry actually needs: the note's CPT and modifier are the
same H0023 / GT the UB Claim form shows.
"""
pr = note["procedure_codes"]
assert len(pr) == 2, pr
assert pr[0]["code"] == "H0023", pr[0]
assert pr[0]["modifiers"] == ["GT"], pr[0]
assert "Behavioral Health Outreach Service" in pr[0]["description"], pr[0]
# The description must not swallow the "Modifiers: ..." tail.
assert "Modifiers" not in pr[0]["description"], pr[0]
assert pr[1]["code"] == "90791" and pr[1]["modifiers"] == [], pr[1]
@check
def signoff_is_extracted(page, note, where):
assert "Morgan Lee Taylor" in note["signed_by"], note["signed_by"]
assert "07/13/2026" in note["signed_at"], note["signed_at"]
assert note["signoff_status"] == "Completed", note["signoff_status"]
@check
def chart_locked_needs_textcontent(page, note, where):
"""
`#chartLockedId` is `display:none`. innerText returns "" for it, so a
reader using innerText alone reports the chart as unlocked — the opposite
of the truth, on a field that decides whether a claim should be touched.
"""
assert note["chart_locked"] is True, note["chart_locked"]
@check
def summary_names_the_facts_that_matter(page, note, where):
text = progress_note.summary(note)
for want in ("06/29/2026", "R69", "H0023", "GT", "Completed",
"Morgan Lee Taylor"):
assert want in text, f"{want!r} missing from summary:\n{text}"
@check
def close_clicks_the_parent_not_the_note(page, note, where):
"""Close lives on the host page; the ng-click typo is eCW's own."""
assert "closeProgressNoteViwer" in sel.SEL_PN_CLOSE, sel.SEL_PN_CLOSE
assert progress_note.close(page) is True
assert page.locator(".modal").first.is_visible() is False
def main() -> int:
if not HOST.exists():
print(f" FAIL fixture missing: {HOST}")
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) # local only, no proxy
page = browser.new_page()
page.goto(HOST.as_uri())
page.wait_for_timeout(500) # let the iframe load
reader, where = progress_note.find(page)
if reader is None:
print(" FAIL the note document was not found at all")
browser.close()
return 1
note = progress_note.extract(reader)
for fn in CHECKS:
name = fn.__name__.replace("_", " ")
try:
fn(page, note, where)
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(CHECKS) - failures}/{len(CHECKS)} passed")
return 1 if failures else 0
if __name__ == "__main__":
sys.exit(main())