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,253 @@
|
||||
r"""
|
||||
Dental claims run every applicable condition (operator, 2026-10-07 and
|
||||
2026-10-12): every "All payers" condition plus the claim's own payer's —
|
||||
the same rule as UB/HCFA. Spec:
|
||||
docs/superpowers/specs/2026-10-07-dental-claims-run-all-conditions-design.md
|
||||
|
||||
python tests\test_dental_conditions.py
|
||||
|
||||
Uses tests/fixtures/dental_claim.html: D0120 (row 0, checked, 45.00) and
|
||||
DCONS (row 1, checked, 30.00), ICD 1 = Z01.20, payer DentaQuest.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import pathlib
|
||||
import inspect
|
||||
|
||||
ROOT = pathlib.Path(__file__).resolve().parent.parent
|
||||
sys.path.insert(0, str(ROOT / "src"))
|
||||
|
||||
FIXTURE = pathlib.Path(__file__).resolve().parent / "fixtures" / "dental_claim.html"
|
||||
|
||||
from ecw_bot.pages import claim_form # noqa: E402
|
||||
from ecw_bot.selectors import claim_form as sel # noqa: E402
|
||||
from ecw_bot.conditions import (dummy_codes, telehealth, # noqa: E402
|
||||
medicare_telehealth, vaccine_admin_codes,
|
||||
bh_h_code_modifier, j2930_j2001_update)
|
||||
from ecw_bot.conditions.base import run_all # noqa: E402
|
||||
|
||||
CASES = []
|
||||
|
||||
|
||||
def case(fn):
|
||||
CASES.append(fn)
|
||||
return fn
|
||||
|
||||
|
||||
def _add_row(page, code, fee="40.00", checked=True, icd1="1"):
|
||||
"""One more real service line, cloned from row 0."""
|
||||
page.evaluate(
|
||||
"""(a) => {
|
||||
const rows = document.querySelectorAll(
|
||||
'tr[ng-repeat^="CPT in CPTCodes"]');
|
||||
const tr = rows[0].cloneNode(true);
|
||||
tr.querySelector('[data-fieldname="web_cptcode"]').value = a.code;
|
||||
tr.querySelector('[data-fieldname="web_billedFee"]').value = a.fee;
|
||||
tr.querySelector('[data-fieldname="web_icd1"]').value = a.icd1;
|
||||
const box = tr.querySelector('[ng-click*="updateBillToIns("]');
|
||||
box.checked = a.checked;
|
||||
rows[rows.length - 1].after(tr);
|
||||
}""", {"code": code, "fee": fee, "checked": checked, "icd1": icd1})
|
||||
|
||||
|
||||
def _row(page, index):
|
||||
tr = page.locator(sel.SEL_CPT_ROWS).nth(index)
|
||||
return (tr.locator(sel.SEL_CPT_CODE).first.input_value(),
|
||||
tr.locator(sel.SEL_CPT_ASSIGN_TO_PATIENT).first.is_checked(),
|
||||
tr.locator(sel.SEL_CPT_BILLED_FEE).first.input_value())
|
||||
|
||||
|
||||
# ── reading the Dental screen ────────────────────────────────────────────────
|
||||
|
||||
@case
|
||||
def extract_reads_the_dental_grid_in_the_ub_row_shape(page):
|
||||
page.goto(FIXTURE.as_uri())
|
||||
data = claim_form.extract(page)
|
||||
assert data["screen"] == "dental", data.get("screen")
|
||||
assert data["claim_no"] == "5000000", data["claim_no"]
|
||||
cpt = data["cpt"]
|
||||
assert [r["code"] for r in cpt] == ["D0120", "DCONS"], cpt
|
||||
row = cpt[1]
|
||||
assert row["billed"] is True and row["billed_fee"] == "30.00", row
|
||||
assert row["icd1"] == "1" and row["units"] == "1", row
|
||||
assert row["sdos"] == "09/01/2026", row
|
||||
assert row["mod1"] == "" and row["pos"] == "", "no such columns"
|
||||
assert data["insurance"][0]["Name"] == "DentaQuest", data["insurance"]
|
||||
assert data["icd"] == [{"#": "1", "Code": "Z01.20",
|
||||
"Name": "Encounter for dental exam"}], data["icd"]
|
||||
assert data["notes"] == "Routine visit.", data["notes"]
|
||||
|
||||
|
||||
@case
|
||||
def extract_on_ub_and_hcfa_says_which_screen(page):
|
||||
page.goto(FIXTURE.with_name("ub_claim.html").as_uri())
|
||||
assert claim_form.extract(page)["screen"] == "ub"
|
||||
page.goto(FIXTURE.with_name("hcfa_claim.html").as_uri())
|
||||
assert claim_form.extract(page)["screen"] == "hcfa"
|
||||
|
||||
|
||||
@case
|
||||
def a_hidden_dental_form_is_never_read(page):
|
||||
"""eCW leaves closed forms in the DOM; only the one on screen counts."""
|
||||
page.goto(FIXTURE.as_uri())
|
||||
page.evaluate("""() => document.getElementById('dentalClaim7777777777777')
|
||||
.style.display = 'none'""")
|
||||
data = claim_form.extract(page)
|
||||
assert data["screen"] != "dental" and data["cpt"] == [], data
|
||||
|
||||
|
||||
# ── the row helpers work on the Dental grid ──────────────────────────────────
|
||||
|
||||
@case
|
||||
def dcons_is_unchecked_and_zeroed_on_the_dental_screen(page):
|
||||
page.goto(FIXTURE.as_uri())
|
||||
data = claim_form.extract(page)
|
||||
data["insurance"] = [{"Name": "DentaQuest"}]
|
||||
assert dummy_codes.detect("C1", data) is True
|
||||
result = dummy_codes.apply(page, "C1", data)
|
||||
assert result.changed is True, result
|
||||
assert result.changes == [{"row": 1, "code": "DCONS", "unchecked": True,
|
||||
"fee": {"before": "30.00",
|
||||
"after": "0.00"}}], result.changes
|
||||
assert _row(page, 1) == ("DCONS", False, "0.00")
|
||||
assert _row(page, 0) == ("D0120", True, "45.00"), "D0120 untouched"
|
||||
|
||||
|
||||
@case
|
||||
def j2001_is_unchecked_and_zeroed_on_the_dental_screen(page):
|
||||
page.goto(FIXTURE.as_uri())
|
||||
_add_row(page, "J2001", fee="12.00")
|
||||
data = claim_form.extract(page)
|
||||
result = j2930_j2001_update.apply(page, "C1", data)
|
||||
assert result.changed is True, result
|
||||
assert _row(page, 2) == ("J2001", False, "0.00")
|
||||
|
||||
|
||||
# ── run_all on a Dental claim ────────────────────────────────────────────────
|
||||
|
||||
def _dental_data(page, payer="DentaQuest", note="Routine dental visit."):
|
||||
data = claim_form.extract(page)
|
||||
data["insurance"] = [{"Name": payer}]
|
||||
data["progress_notes"] = {"opened": "tab", "text": note}
|
||||
return data
|
||||
|
||||
|
||||
@case
|
||||
def run_all_on_a_dental_claim_runs_the_all_payer_conditions(page):
|
||||
page.goto(FIXTURE.as_uri())
|
||||
_add_row(page, "J2001", fee="12.00")
|
||||
_add_row(page, "D1110", fee="0.00")
|
||||
report = {}
|
||||
results = run_all(page, "C1", _dental_data(page), report=report)
|
||||
names = [r.condition_name for r in results]
|
||||
for name in ("dummy_codes", "j2930_j2001_update", "zero_fee_uncheck"):
|
||||
assert name in names, (name, names, report)
|
||||
assert report["failed"] == [] and report["review"] == [], report
|
||||
assert _row(page, 1)[1:] == (False, "0.00")
|
||||
assert _row(page, 2)[1:] == (False, "0.00")
|
||||
assert _row(page, 3)[1] is False, "zero-fee line unchecked"
|
||||
assert _row(page, 0) == ("D0120", True, "45.00")
|
||||
|
||||
|
||||
@case
|
||||
def a_fix_the_dental_screen_cannot_make_goes_to_review(page):
|
||||
"""
|
||||
Operator, 2026-10-12: the Dental grid has no POS and no modifier
|
||||
columns, so telehealth's POS 2 + modifier cannot be written — the
|
||||
claim is Review with the reason, never a silent skip.
|
||||
"""
|
||||
page.goto(FIXTURE.as_uri())
|
||||
data = _dental_data(page, note="Session Setting (PoS): TeleHealth. "
|
||||
"Audio and video telehealth visit.")
|
||||
report = {}
|
||||
run_all(page, "C1", data, report=report)
|
||||
reasons = {r["name"]: r["reason"] for r in report["review"]}
|
||||
assert "telehealth" in reasons, report
|
||||
assert "Dental" in reasons["telehealth"], reasons
|
||||
assert "telehealth" not in report["changed"], report
|
||||
|
||||
|
||||
@case
|
||||
def depression_pointer_is_retagged_on_the_dental_icd_fields(page):
|
||||
"""#6 on web_icd1-4: Z13.31 only on G8510, taken off D0120."""
|
||||
page.goto(FIXTURE.as_uri())
|
||||
page.evaluate("""() => {
|
||||
const body = document.querySelector('#addTable tbody');
|
||||
const tr = body.rows[0].cloneNode(true);
|
||||
tr.cells[0].textContent = '2';
|
||||
tr.cells[1].querySelector('input').value = 'Z13.31';
|
||||
tr.cells[2].textContent = 'Encounter for screening for depression';
|
||||
body.rows[0].after(tr);
|
||||
document.querySelector('[data-fieldname="web_icd2"]').value = '2';
|
||||
}""")
|
||||
_add_row(page, "G8510", fee="0.00", icd1="1")
|
||||
report = {}
|
||||
run_all(page, "C1", _dental_data(page), report=report)
|
||||
assert "depression_dx_pointer" in report["changed"], report
|
||||
icd = lambda i, n: page.locator(sel.SEL_CPT_ROWS).nth(i).locator(
|
||||
sel.SEL_CPT_ICD[n]).first.input_value()
|
||||
assert [icd(0, n) for n in range(4)] == ["1", "", "", ""], \
|
||||
"Z13.31 (pointer 2) taken off D0120"
|
||||
assert icd(2, 0) == "2", "G8510 carries Z13.31"
|
||||
|
||||
|
||||
@case
|
||||
def every_condition_that_needs_pos_modifiers_or_new_lines_declares_it():
|
||||
for module in (telehealth, medicare_telehealth, vaccine_admin_codes):
|
||||
reason = getattr(module, "DENTAL_UNSUPPORTED", "")
|
||||
assert reason and "Dental" in reason, module.NAME
|
||||
|
||||
|
||||
@case
|
||||
def bh_h_code_modifier_path_is_review_on_dental_but_non_bh_unchecks(page):
|
||||
page.goto(FIXTURE.as_uri())
|
||||
_add_row(page, "H0023", fee="50.00")
|
||||
report = {}
|
||||
run_all(page, "C1", _dental_data(page, payer="APM2 Medicaid"),
|
||||
report=report)
|
||||
assert "bh_h_code_modifier" in report["changed"], report
|
||||
assert _row(page, 2)[1:] == (False, "0.00")
|
||||
|
||||
# A BH payer's H code with a modifier: the Dental grid has no modifier
|
||||
# column, so there is nothing to read and nothing fires.
|
||||
page.goto(FIXTURE.as_uri())
|
||||
_add_row(page, "H0023", fee="50.00")
|
||||
report = {}
|
||||
run_all(page, "C1", _dental_data(page, payer="BH COLORADO ACCESS"),
|
||||
report=report)
|
||||
assert "bh_h_code_modifier" not in report["fired"], report
|
||||
assert _row(page, 2)[1:] == (True, "50.00")
|
||||
|
||||
|
||||
def main() -> int:
|
||||
if not FIXTURE.exists():
|
||||
print(f" FAIL fixture missing: {FIXTURE}")
|
||||
return 1
|
||||
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())
|
||||
Reference in new issue
Block a user