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,259 @@
|
||||
r"""
|
||||
conditions/dental_dummy_codes.py — document #48: DPIMP is a dummy code on
|
||||
Dental payers. On a Dental payer's claim every DPIMP line is unchecked and
|
||||
its Billed Fee zeroed; on any other payer nothing is changed and the claim
|
||||
goes to Review with a note naming the payer group (operator, 2026-10-13).
|
||||
|
||||
python tests\test_conditions_dental_dummy_codes.py
|
||||
|
||||
Uses tests/fixtures/dental_claim.html (D0120 row 0, DCONS row 1) and adds
|
||||
a DPIMP line per case, cloned from row 0.
|
||||
"""
|
||||
|
||||
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" / "dental_claim.html"
|
||||
|
||||
from ecw_bot.conditions import dental_dummy_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.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
|
||||
|
||||
|
||||
def _claim(payer, *codes):
|
||||
return {"insurance": [{"Name": payer}] if payer is not None else [],
|
||||
"cpt": [{"code": c, "checked": True, "fee": "25.00"}
|
||||
for c in codes]}
|
||||
|
||||
|
||||
def _add_row(page, code, fee="25.00", checked=True):
|
||||
"""One more real Dental 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;
|
||||
const box = tr.querySelector('[ng-click*="updateBillToIns("]');
|
||||
box.checked = a.checked;
|
||||
rows[rows.length - 1].after(tr);
|
||||
}""", {"code": code, "fee": fee, "checked": checked})
|
||||
|
||||
|
||||
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())
|
||||
|
||||
|
||||
def _dental_read(page, payer):
|
||||
data = claim_form.extract(page)
|
||||
data["screen"] = "dental"
|
||||
data["insurance"] = [{"Name": payer}]
|
||||
data["progress_notes"] = {"opened": "tab", "text": "Routine dental visit."}
|
||||
return data
|
||||
|
||||
|
||||
# ── detect / needs_review (no browser) ───────────────────────────────────────
|
||||
|
||||
@case
|
||||
def detect_dpimp_on_each_dental_payer_group():
|
||||
for payer in ("Delta Dental", "CHP+ DENTAQUEST", "DentaQuest"):
|
||||
assert cond.detect("C1", _claim(payer, "D0120", "DPIMP")), payer
|
||||
assert cond.needs_review("C1", _claim(payer, "DPIMP")) is None, payer
|
||||
|
||||
|
||||
@case
|
||||
def detect_ignores_case_and_spaces_of_the_code():
|
||||
assert cond.detect("C1", _claim("Delta Dental", " dpimp ")) is True
|
||||
|
||||
|
||||
@case
|
||||
def dfimp_is_the_same_dummy_code():
|
||||
# The live Dental grid carries DFIMP ("FINAL IMPRESSION"); the document
|
||||
# says DPIMP. Both are #48 (operator, 2026-10-20).
|
||||
for payer in ("Delta Dental", "DentaQuest"):
|
||||
assert cond.detect("C1", _claim(payer, "D0120", "DFIMP")), payer
|
||||
assert cond.needs_review("C1", _claim(payer, "DFIMP")) is None, payer
|
||||
assert cond.detect("C1", _claim("DentaQuest", " dfimp ")) is True
|
||||
|
||||
|
||||
@case
|
||||
def dfimp_on_another_payer_is_noted_by_its_own_code():
|
||||
note = cond.needs_review("C1", _claim("Medicaid", "DFIMP"))
|
||||
assert note and "DFIMP" in note and "DPIMP" not in note, note
|
||||
assert "a Medicaid payer claim" in note, note
|
||||
|
||||
|
||||
@case
|
||||
def no_dpimp_means_nothing_at_all():
|
||||
for payer in ("Delta Dental", "Medicaid"):
|
||||
data = _claim(payer, "D0120", "DCONS")
|
||||
assert cond.detect("C1", data) is False, payer
|
||||
assert cond.needs_review("C1", data) is None, payer
|
||||
assert cond.detect("C1", {}) is False
|
||||
assert cond.needs_review("C1", {}) is None
|
||||
|
||||
|
||||
@case
|
||||
def dpimp_on_another_payer_is_not_fired_but_noted_with_its_group():
|
||||
for payer, group in (("Medicaid", "a Medicaid payer claim"),
|
||||
("Medicare", "a Medicare payer claim"),
|
||||
("AARP", "a Commercial Ins payer claim")):
|
||||
data = _claim(payer, "DPIMP")
|
||||
assert cond.detect("C1", data) is False, payer
|
||||
note = cond.needs_review("C1", data)
|
||||
assert note and group in note and "DPIMP" in note, note
|
||||
assert "not changed" in note, note
|
||||
|
||||
|
||||
@case
|
||||
def dpimp_on_an_unmapped_or_unread_payer_is_noted_too():
|
||||
note = cond.needs_review("C1", _claim("NO SUCH PAYER XYZ", "DPIMP"))
|
||||
assert "not in the Claim Status Dashboard" in note, note
|
||||
note = cond.needs_review("C1", _claim("", "DPIMP"))
|
||||
assert "no payer read" in note, note
|
||||
note = cond.needs_review("C1", _claim(None, "DPIMP"))
|
||||
assert "no payer read" in note, note
|
||||
|
||||
|
||||
# ── apply on the Dental screen (browser) ─────────────────────────────────────
|
||||
|
||||
@case
|
||||
def apply_unchecks_and_zeroes_dpimp_only(page):
|
||||
page.goto(FIXTURE.as_uri())
|
||||
_add_row(page, "DPIMP", fee="25.00")
|
||||
data = _dental_read(page, "Delta Dental")
|
||||
result = cond.apply(page, "C1", data)
|
||||
assert isinstance(result, ConditionResult)
|
||||
assert result.condition_name == "dental_dummy_codes"
|
||||
assert result.changes == [{"row": 2, "code": "DPIMP", "unchecked": True,
|
||||
"fee": {"before": "25.00",
|
||||
"after": "0.00"}}], result.changes
|
||||
assert _row(page, 2) == ("DPIMP", False, "0.00")
|
||||
assert _row(page, 0) == ("D0120", True, "45.00"), "D0120 untouched"
|
||||
|
||||
|
||||
@case
|
||||
def apply_is_a_no_op_once_already_excluded(page):
|
||||
page.goto(FIXTURE.as_uri())
|
||||
_add_row(page, "DPIMP", fee="0.00", checked=False)
|
||||
result = cond.apply(page, "C1", _dental_read(page, "Delta Dental"))
|
||||
assert result.changed is False and result.changes == []
|
||||
|
||||
|
||||
@case
|
||||
def apply_unchecks_and_zeroes_dfimp_too(page):
|
||||
page.goto(FIXTURE.as_uri())
|
||||
_add_row(page, "DFIMP", fee="25.00")
|
||||
result = cond.apply(page, "C1", _dental_read(page, "DentaQuest"))
|
||||
assert result.changes == [{"row": 2, "code": "DFIMP", "unchecked": True,
|
||||
"fee": {"before": "25.00",
|
||||
"after": "0.00"}}], result.changes
|
||||
assert _row(page, 2) == ("DFIMP", False, "0.00")
|
||||
text = cond.describe(result)
|
||||
assert "DFIMP" in text and "DPIMP" not in text, text
|
||||
|
||||
|
||||
@case
|
||||
def describe_names_dpimp_and_the_fee_change(page):
|
||||
page.goto(FIXTURE.as_uri())
|
||||
_add_row(page, "DPIMP", fee="25.00")
|
||||
text = cond.describe(cond.apply(page, "C1",
|
||||
_dental_read(page, "Delta Dental")))
|
||||
assert "DPIMP" in text and "25.00" in text and "0.00" in text, text
|
||||
|
||||
|
||||
# ── run_all and the Charge Summary ───────────────────────────────────────────
|
||||
|
||||
@case
|
||||
def it_is_registered_before_priced_line_check():
|
||||
names = [m.NAME for m in CONDITIONS]
|
||||
assert names.index("dental_dummy_codes") < names.index(
|
||||
"priced_line_check"), names
|
||||
|
||||
|
||||
@case
|
||||
def a_dental_payer_claim_is_fixed_and_fails_with_its_comment(page):
|
||||
page.goto(FIXTURE.as_uri())
|
||||
_add_row(page, "DPIMP", fee="25.00")
|
||||
data = _dental_read(page, "Delta Dental")
|
||||
report = {}
|
||||
with contextlib.redirect_stdout(io.StringIO()):
|
||||
results = run_all(page, "C1", data, report=report)
|
||||
assert "dental_dummy_codes" in [r.condition_name for r in results]
|
||||
assert _row(page, 2) == ("DPIMP", False, "0.00")
|
||||
assert not [r for r in report["review"]
|
||||
if r["name"] == "dental_dummy_codes"], report["review"]
|
||||
assert "DPIMP" in cs.COMMENTS["dental_dummy_codes"]
|
||||
|
||||
|
||||
@case
|
||||
def a_medicaid_claim_keeps_dpimp_and_is_review_with_the_note(page):
|
||||
page.goto(FIXTURE.as_uri())
|
||||
_add_row(page, "DPIMP", fee="25.00")
|
||||
data = _dental_read(page, "Medicaid")
|
||||
report = {}
|
||||
with contextlib.redirect_stdout(io.StringIO()):
|
||||
results = run_all(page, "C1", data, report=report)
|
||||
assert "dental_dummy_codes" not in [r.condition_name for r in results]
|
||||
assert _row(page, 2) == ("DPIMP", True, "25.00"), "left as it is"
|
||||
notes = [r["reason"] for r in report["review"]
|
||||
if r["name"] == "dental_dummy_codes"]
|
||||
assert len(notes) == 1 and "Medicaid" in notes[0], report["review"]
|
||||
data["_conditions"] = {"fired": [r.condition_name for r in results],
|
||||
"saved": False, "failed": report["failed"],
|
||||
"review": report["review"],
|
||||
"comments": report["comments"]}
|
||||
outcome = cs.claim_outcome(True, data)
|
||||
assert outcome["Category"] == "Review", outcome
|
||||
assert "DPIMP on a Medicaid payer claim" in outcome["Comments"], outcome
|
||||
|
||||
|
||||
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())
|
||||
Reference in new issue
Block a user