r""" conditions/vaccine_admin_codes.py — Charge Condition Document row 18: vaccine codes billed without an immunization-admin code get the admin code(s) added — 90460/90461 for age 18 and below, 90471/90472 above 18 — with the "each additional" code's Units = vaccine count - 1. python tests\test_conditions_vaccine_admin_codes.py Pure-data cases first (detection, payer gate, age), then page cases against fixtures/vaccine_claim.html, whose Fee Schedule picker is the same simulation hcfa_claim.html uses for G2025 — `add_cpt_row()` is exercised for real (click Add, search, pick the exact match, OK), never stubbed. The three "no change" data cases at the end mirror live claims the client had already fixed by hand (9131000, 9132000, 9133000): the condition must leave every one of them alone. Every checked vaccine or admin row a page case seeds carries its own fee. The fixture's `seedCptRows` prices a row with no `fee` at 0.00, and since the operator's ruling of 2026-09-30 a CHECKED line billed at zero is not billed at all — zero_fee_uncheck unchecks it first — so it no longer counts as a vaccine, or as "admin already billed". A case that meant a billed line says so with a price; the cases about a zero-fee line say "0.00". """ import contextlib import io 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" / "vaccine_claim.html" UB_FIXTURE = pathlib.Path(__file__).resolve().parent / "fixtures" / "ub_claim.html" HCFA_FIXTURE = pathlib.Path(__file__).resolve().parent / "fixtures" / "hcfa_claim.html" from ecw_bot import conditions # noqa: E402 from ecw_bot.conditions import vaccine_admin_codes as vac # noqa: E402 from ecw_bot.conditions.base import ConditionResult, run_all # 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 # ============================================================================= # Data helpers # ============================================================================= def _row(code, desc="", billed=True, sdos="07/07/2026", units="1"): return {"code": code, "description": desc, "billed": billed, "sdos": sdos, "units": units} def _data(cpt, payer="Medicaid", dob="01/02/1976", age_sex=" 50Y, M", claim_date="07/07/2026"): return { "cpt": cpt, "insurance": [{"Name": payer}] if payer is not None else [], "patient": {"dob": dob, "age_sex": age_sex}, "header": {"claim_date": claim_date}, } def _age(data): return vac.patient_age(data, vac.checked_vaccine_rows(data.get("cpt")))[0] _TDAP = "TETANUS DIPHTHERIA TOXOIDS AND ACELLULAR PERTUSSIS VACC" _ADMIN_1ST = "IMMUNIZATION ADMIN SINGLE OR COMBINATION" _ADMIN_ADD = "IMMUNIZATION ADMIN, EACH ADD" # ============================================================================= # Vaccine / admin row recognition # ============================================================================= _CLIENT_VACCINES = ("90633", "90648", "90651", "90656", "90657", "90660", "90680", "90687", "90698", "90707", "90710", "90713", "90716", "90732", "90734", "90744", "90746", "91321", "91322") @case def every_code_on_the_client_vaccine_list_is_a_vaccine(): """Operator, 2026-10-13: the 19 codes of the client's list, by code.""" assert vac.VACCINE_CODES == frozenset(_CLIENT_VACCINES) for code in _CLIENT_VACCINES: assert vac.is_vaccine_row(_row(code)), code @case def a_listed_code_is_a_vaccine_whatever_its_hover_text(): assert vac.is_vaccine_row(_row("90732", "PCV20")) assert vac.is_vaccine_row(_row("90746", "")) @case def a_code_off_the_list_is_not_a_vaccine_whatever_its_hover_text(): # The earlier rule took "VACC" in the hover text or 90476-90759; both # are gone (operator, 2026-10-13) — the list is the whole rule. for code, hover in (("90715", _TDAP), ("90677", "PCV20"), ("90750", "Shingrix"), ("90686", "FLU VACC"), ("90476", ""), ("90759", ""), ("Q2037", "FLU VACC FLUVIRIN 3 YRS & >"), ("99213", "Office Visit, Est Pt., Level 3")): assert not vac.is_vaccine_row(_row(code, hover)), code @case def only_the_four_admin_codes_are_admin_rows(): for code in ("90460", "90461", "90471", "90472"): assert vac.is_admin_row(_row(code)), code assert not vac.is_vaccine_row(_row(code)), code # Other administration codes, and "ADMIN" in the hover text, are not # this condition's admin codes (operator, 2026-10-13). for code, hover in (("90473", ""), ("90474", ""), ("90480", ""), ("G0008", ""), ("G0009", ""), ("G0010", ""), ("0002A", "IMMUNIZATION ADMIN COVID 2ND")): assert not vac.is_admin_row(_row(code, hover)), code @case def a_covid_vaccine_with_90480_billed_still_gets_its_admin_code(): """90480 is not one of the four admin codes, so it is not "admin already billed": 91321 on an adult gets 90471 added.""" cpt = [_row("99396"), _row("91321"), _row("90480")] assert [r["code"] for r in vac.checked_vaccine_rows(cpt)] == ["91321"] assert vac.checked_admin_present(cpt) is False assert vac.detect("C1", _data(cpt)) is True @case def flu_plus_covid_count_as_two_vaccines(): data = _data([_row("90656"), _row("91322"), _row("90480")]) assert vac._plan("C1", data, data["cpt"])["vaccines"] == ["90656", "91322"] @case def vaccine_count_is_rows_not_units(): # Ruling 4: one vaccine row at Units 3 is ONE vaccine -> 90471 x1 only. data = _data([_row("99396"), _row("90734", _TDAP, units="3")]) assert vac._plan("C1", data, data["cpt"])["vaccines"] == ["90734"] data = _data([_row("90734", _TDAP, units="2"), _row("90732", "PCV20", units="1")]) assert len(vac._plan("C1", data, data["cpt"])["vaccines"]) == 2 @case def unchecked_vaccine_is_not_counted(): cpt = [_row("99396"), _row("90734", _TDAP, billed=False)] assert vac.checked_vaccine_rows(cpt) == [] assert vac.detect("C1", _data(cpt)) is False @case def unknown_checkbox_state_counts_as_checked(): # billed=None: the row has no "Assign To Patient" box at all; an absent # key is a snapshot from before extract() read it. Neither may silently # drop a vaccine. none_row = _row("90734", _TDAP, billed=None) missing = {"code": "90732", "description": "PCV20"} assert vac.checked_vaccine_rows([none_row, missing]) == [none_row, missing] # ============================================================================= # A checked line billed at zero — zero_fee_uncheck unchecks it first # (operator ruling, 2026-09-30) # ============================================================================= def _fee(row, fee): """`row` with a Billed Fee as extract() reads it.""" return dict(row, billed_fee=fee) @case def a_checked_zero_fee_admin_line_is_not_admin_already_billed(): # zero_fee_uncheck, registered first, unchecks it before this # condition's apply() runs — counting it would leave the vaccine billed # with no admin code (document #18's own case). for fee in ("0.00", "", "0", "$0.00"): cpt = [_fee(_row("90734", _TDAP), "60.00"), _fee(_row("90471", _ADMIN_1ST), fee)] assert vac.checked_admin_present(cpt) is False, fee assert vac.detect("C1", _data(cpt)) is True, fee plan = vac._plan("C1", _data(cpt), cpt) assert (plan["first"], plan["vaccines"]) == ("90471", ["90734"]), (fee, plan) @case def a_checked_priced_admin_line_is_still_admin_already_billed(): for fee in ("30.00", "$30.00", "N/A"): # N/A: does not parse, not zero cpt = [_fee(_row("90734", _TDAP), "60.00"), _fee(_row("90471", _ADMIN_1ST), fee)] assert vac.checked_admin_present(cpt) is True, fee assert vac.detect("C1", _data(cpt)) is False, fee @case def a_zero_fee_admin_line_with_an_unknown_checkbox_still_counts(): # billed None keeps today's behaviour: zero_fee_uncheck never touches a # row with no "Assign To Patient" checkbox, so it stays "billed". cpt = [_fee(_row("90734", _TDAP), "60.00"), _fee(_row("90471", _ADMIN_1ST, billed=None), "0.00")] assert vac.checked_admin_present(cpt) is True assert vac.detect("C1", _data(cpt)) is False @case def an_admin_line_whose_fee_was_never_read_still_counts(): # No billed_fee key at all (a snapshot from before extract() read fees, # or a hand-built row): the fee is unknown, not zero — today's behaviour. cpt = [_row("90734", _TDAP), _row("90471", _ADMIN_1ST)] assert "billed_fee" not in cpt[1] assert vac.checked_admin_present(cpt) is True assert vac.detect("C1", _data(cpt)) is False @case def a_checked_zero_fee_vaccine_is_not_counted(): # The same ruling for a vaccine row: zero_fee_uncheck unchecks it, so it # is not billed — one vaccine left, so 90471 alone, no 90472. tdap = _fee(_row("90734", _TDAP), "0.00") pcv = _fee(_row("90732", "PCV20"), "290.00") assert vac.checked_vaccine_rows([tdap, pcv]) == [pcv] plan = vac._plan("C1", _data([tdap, pcv]), [tdap, pcv]) assert plan["vaccines"] == ["90732"], plan assert plan["first"] == "90471", plan @case def a_claim_whose_only_vaccine_is_checked_at_zero_fires_nothing(): cpt = [_fee(_row("99396"), "250.00"), _fee(_row("90734", _TDAP), "0.00")] assert vac.checked_vaccine_rows(cpt) == [] assert vac.detect("C1", _data(cpt)) is False @case def a_zero_fee_vaccine_with_an_unknown_checkbox_still_counts(): none_row = _fee(_row("90734", _TDAP, billed=None), "0.00") assert vac.checked_vaccine_rows([none_row]) == [none_row] assert vac.detect("C1", _data([none_row])) is True @case def a_checked_admin_line_with_no_fee_input_still_counts(): # billed_fee None: extract() found NO Billed Fee input on the row # (review finding, 2026-09-30). zero_fee_uncheck's apply() skips such a # row (`uncheck_zero_fee_cpt_rows`: no fee input -> left alone), so it is # still billed when this condition's apply() runs — it must count. cpt = [_fee(_row("90734", _TDAP), "60.00"), _fee(_row("90471", _ADMIN_1ST), None)] assert vac.unchecked_by_zero_fee_rule(cpt[1]) is False assert vac.checked_admin_present(cpt) is True assert vac.detect("C1", _data(cpt)) is False @case def a_checked_vaccine_with_no_fee_input_still_counts(): tdap = _fee(_row("90734", _TDAP), None) pcv = _fee(_row("90732", "PCV20"), "290.00") assert vac.checked_vaccine_rows([tdap, pcv]) == [tdap, pcv] plan = vac._plan("C1", _data([tdap, pcv]), [tdap, pcv]) assert plan["vaccines"] == ["90734", "90732"], plan # ============================================================================= # detect() # ============================================================================= @case def detect_true_for_checked_vaccines_without_admin(): cpt = [_row("99396"), _row("90732", "PCV20"), _row("90734", _TDAP)] assert vac.detect("C1", _data(cpt)) is True @case def detect_false_when_a_checked_admin_code_is_present(): cpt = [_row("90734", _TDAP), _row("90471", _ADMIN_1ST)] assert vac.detect("C1", _data(cpt)) is False @case def an_admin_by_hover_text_does_not_count_as_admin_billed(): # By code only since 2026-10-13: 0002A is not one of the four. cpt = [_row("90734", _TDAP), _row("0002A", "IMMUNIZATION ADMIN COVID 2ND")] assert vac.detect("C1", _data(cpt)) is True @case def detect_still_true_when_the_only_admin_code_is_unchecked(): # Live claim 9132000's unchecked 90460 at 0.00 is not "present". cpt = [_row("90656", "FLU VACC IIV3 NO PRSV 0.5ML IM"), _row("90460", "IMMUNIZATION ADMIN", billed=False)] assert vac.detect("C1", _data(cpt)) is True @case def detect_false_with_no_vaccine_at_all(): assert vac.detect("C1", _data([_row("99213")])) is False assert vac.detect("C1", {}) is False assert vac.detect("C1", None) is False @case def detect_false_for_medicare(): cpt = [_row("90734", _TDAP)] assert vac.detect("C1", _data(cpt, payer="Humana Medicare")) is False @case def detect_false_for_an_unmapped_payer_or_no_payer(): cpt = [_row("90734", _TDAP)] assert vac.detect("C1", _data(cpt, payer="Some New Carrier Inc")) is False assert vac.detect("C1", _data(cpt, payer=None)) is False @case def detect_true_for_every_known_non_medicare_group(): # The PAYER GATE only, on data shaped like a UB-form read. Commercial # ("United Health Care") claims open on the professional/HCFA screen — # end to end in hcfa_screen_vaccine_claim_fires_on_the_payer_from_the_ # insurances_grid below — and Dental claims never reach run_all at all # (is_dental_claim_form). cpt = [_row("90734", _TDAP)] for payer in ("Medicaid", "BH COLORADO ACCESS", "United Health Care", "DentaQuest", "OUTREACH PROGRAM"): assert vac.detect("C1", _data(cpt, payer=payer)) is True, payer @case def detect_false_when_no_age_can_be_determined(): cpt = [_row("90734", _TDAP)] assert vac.detect("C1", _data(cpt, dob="", age_sex="")) is False # ============================================================================= # needs_review() — "did not fire" that is not "clean" (review item D2) # ============================================================================= @case def needs_review_names_an_unmapped_payer(): cpt = [_row("90734", _TDAP)] why = vac.needs_review("C1", _data(cpt, payer="Some New Carrier Inc")) assert why and "Some New Carrier Inc" in why and "90734" in why, why assert "add the admin code by hand" in why, why @case def needs_review_names_a_claim_with_no_payer_name_read(): why = vac.needs_review("C1", _data([_row("90734", _TDAP)], payer=None)) assert why and "no primary payer name was read" in why, why @case def needs_review_names_a_claim_with_no_usable_age(): why = vac.needs_review("C1", _data([_row("90734", _TDAP)], dob="", age_sex="")) assert why and "no usable DOB or age" in why, why @case def needs_review_is_silent_for_medicare(): """Document #19 is Medicare's own rule: not covered, not unfinished.""" cpt = [_row("90734", _TDAP)] why = vac.needs_review("C1", _data(cpt, payer="Humana Medicare")) assert why is None, why @case def needs_review_is_silent_when_an_admin_code_is_already_billed(): # Even with a payer it could not classify: nothing is missing. cpt = [_row("90734", _TDAP), _row("90471", _ADMIN_1ST)] why = vac.needs_review("C1", _data(cpt, payer="Some New Carrier Inc")) assert why is None, why @case def needs_review_is_silent_with_no_vaccine_or_when_detect_fires(): assert vac.needs_review("C1", _data([_row("99213", "OFFICE VISIT")], payer="Some New Carrier Inc")) is None assert vac.needs_review("C1", {}) is None assert vac.needs_review("C1", _data([_row("90734", _TDAP)])) is None @case def needs_review_does_not_log_the_decision_a_second_time(): data = _data([_row("90734", _TDAP)], payer="Some New Carrier Inc") out = io.StringIO() with contextlib.redirect_stdout(out): vac.detect("C1", data) vac.needs_review("C1", data) logged = out.getvalue() assert logged.count("leaving the claim as read") == 1, logged @case def run_all_reports_the_unmapped_payer_as_review(): report = {} data = _data([_row("90734", _TDAP)], payer="Some New Carrier Inc") with contextlib.redirect_stdout(io.StringIO()): results = run_all(None, "C1", data, conditions=[vac], report=report) assert results == [], results assert report["fired"] == [] and report["failed"] == [], report assert [r["name"] for r in report["review"]] == [vac.NAME], report # ============================================================================= # Age # ============================================================================= @case def age_is_whole_years_on_the_first_vaccine_rows_date_of_service(): cpt = [_row("99396", sdos="01/01/2020"), _row("90734", _TDAP, sdos="07/07/2026")] assert _age(_data(cpt, dob="01/02/1976")) == 50 @case def eighteenth_birthday_on_the_dos_is_still_18_pediatric(): cpt = [_row("90734", _TDAP, sdos="03/15/2026")] assert _age(_data(cpt, dob="03/15/2008")) == 18 assert vac.admin_codes_for_age(18) == ("90460", "90461") @case def nineteenth_birthday_on_the_dos_is_19_adult(): cpt = [_row("90734", _TDAP, sdos="03/15/2026")] assert _age(_data(cpt, dob="03/15/2007")) == 19 assert vac.admin_codes_for_age(19) == ("90471", "90472") @case def day_before_the_nineteenth_birthday_is_still_18(): cpt = [_row("90734", _TDAP, sdos="03/14/2026")] assert _age(_data(cpt, dob="03/15/2007")) == 18 @case def age_falls_back_to_the_claim_date_when_the_row_has_no_sdos(): cpt = [_row("90734", _TDAP, sdos="")] assert _age(_data(cpt, dob="03/15/2007", claim_date="03/15/2026")) == 19 @case def age_falls_back_to_age_sex_when_dob_is_unusable(): cpt = [_row("90734", _TDAP)] assert _age(_data(cpt, dob="", age_sex=" 50Y, M")) == 50 assert _age(_data(cpt, dob="not a date", age_sex="7Y, F")) == 7 # a DOB after the date of service is not a usable DOB either assert _age(_data(cpt, dob="01/01/2030", age_sex=" 50Y, M")) == 50 @case def months_or_days_only_age_sex_is_zero_years(): cpt = [_row("90734", _TDAP)] assert _age(_data(cpt, dob="", age_sex=" 12M 12D, F")) == 0 assert _age(_data(cpt, dob="", age_sex="3D, M")) == 0 assert _age(_data(cpt, dob="", age_sex="")) is None # ============================================================================= # Live samples the client already fixed by hand — must stay untouched # ============================================================================= @case def live_9131000_adult_with_admin_already_billed_no_change(): # The live vaccines (90677, 90750, 90715) are off the client's list # since 2026-10-13; listed codes stand in so the admin rule is tested. cpt = [_row("99396"), _row("90732", "PCV20"), _row("90746", "Shingrix"), _row("90734", _TDAP), _row("90471", _ADMIN_1ST, units="1"), _row("90472", _ADMIN_ADD, units="2")] assert vac.detect("9131000", _data(cpt, age_sex=" 50Y, F")) is False @case def live_9132000_adult_with_checked_90471_and_unchecked_90460_no_change(): # 90673 is off the client's vaccine list (2026-10-13): no vaccine at # all now, as well as an admin code already billed. cpt = [_row("99397"), _row("90673", "FLU VACC RIV3 NO PRESERV"), _row("90471", _ADMIN_1ST), _row("90460", "IMMUNIZATION ADMIN THROUGH 18 YRS", billed=False)] assert vac.detect("9132000", _data(cpt, dob="02/10/1968", age_sex=" 58Y, F")) is False @case def live_9133000_infant_with_pediatric_admin_already_billed_no_change(): cpt = [_row("99392"), _row("90732", "PCV20"), _row("90716", "VARICELLA VIRUS VACCINE LIVE FOR SUBCUTANEOUS USE"), _row("90707", "MMR VIRUS VACCINE LIVE SUBCUTANEOUS"), _row("90633", "HEPA VACCINE PED/ADOL-2 DOSE IM"), _row("90460", "IMMUNIZATION ADMIN THROUGH 18 YRS"), _row("90461", "IMMUNIZATION ADMIN EACH ADD", units="3")] assert vac.detect("9133000", _data(cpt, dob="07/07/2025", age_sex=" 12M, M")) is False # ============================================================================= # Registry # ============================================================================= @case def registered_last_of_the_specific_conditions(): """ After every other specific condition, so it re-reads a grid they have already changed. After it come only injection_admin_code (#20, which adds a line the same way, 2026-10-13), medicare_pps_code (#25, which adds one too, 2026-10-23) and priced_line_check — the common rule's reverse half, registered LAST on 2026-09-30 so it only ever sees lines the exclusion conditions have already zeroed. """ from ecw_bot.conditions import (injection_admin_code, medicare_pps_code, priced_line_check) assert conditions.CONDITIONS[-4] is vac, conditions.CONDITIONS assert conditions.CONDITIONS[-3] is injection_admin_code, conditions.CONDITIONS assert conditions.CONDITIONS[-2] is medicare_pps_code, conditions.CONDITIONS assert conditions.CONDITIONS[-1] is priced_line_check, conditions.CONDITIONS assert conditions.BY_NAME["vaccine_admin_codes"] is vac assert vac.NAME == "vaccine_admin_codes" # ============================================================================= # Page helpers # ============================================================================= def _fresh(page): page.goto(FIXTURE.as_uri()) def _seed(page, rows, dob=None, age_sex=None): page.evaluate("rows => window.seedCptRows(rows)", rows) if dob is not None or age_sex is not None: page.evaluate("([d, a]) => window.setPatient(d, a)", [dob or "", age_sex or ""]) def _live(page): return claim_form.extract(page) def _rows_for(page, code): return [r for r in _live(page)["cpt"] if r["code"] == code] _ADULT_ONE = [ {"code": "99396", "title": "PREVENTIVE VISIT EST AGE 40-64", "fee": "250.00"}, {"code": "90734", "title": _TDAP, "fee": "60.00", "icd1": "2"}, ] _CHILD_FOUR = [ {"code": "99392", "title": "PREV VISIT EST AGE 1-4", "fee": "180.00"}, {"code": "90732", "title": "PCV20", "fee": "290.00", "icd1": "2"}, {"code": "90716", "title": "VARICELLA VIRUS VACCINE LIVE FOR SUBCUTANEOUS USE", "fee": "180.00", "icd1": "2"}, {"code": "90707", "title": "MMR VIRUS VACCINE LIVE SUBCUTANEOUS", "fee": "95.00", "icd1": "2"}, {"code": "90633", "title": "HEPA VACCINE PED/ADOL-2 DOSE IM", "fee": "70.00", "icd1": "2"}, ] # ============================================================================= # Extractor: the additive `billed` field # ============================================================================= @case def extract_reports_billed_from_the_assign_to_patient_checkbox(page): _fresh(page) _seed(page, [{"code": "90734", "title": _TDAP}, {"code": "90460", "title": "IMMUNIZATION ADMIN", "checked": False}, {"code": "90732", "title": "PCV20", "noCheckbox": True}]) cpt = _live(page)["cpt"] assert [r["billed"] for r in cpt] == [True, False, None], cpt assert cpt[0]["description"] == _TDAP, cpt[0] @case def extract_billed_is_none_on_a_ub_form_without_the_checkbox(page): # ub_claim.html's rows carry no updateBillToIns( checkbox — unknown, # which the condition treats as checked, never as "not billed". page.goto(UB_FIXTURE.as_uri()) cpt = _live(page)["cpt"] assert cpt and all(r["billed"] is None for r in cpt), cpt assert cpt[0]["code"] == "H0023", "existing fields must be unchanged" @case def extract_reports_billed_fee_none_for_a_row_with_no_fee_input(page): # None ("never read"), not "" — "" is a blank fee that WAS read, which # is_zero_fee() calls zero. Told apart, zero_fee_uncheck.detect() and # this condition's pre-read agree with uncheck_zero_fee_cpt_rows(), # which leaves a row with no fee input alone (review finding 2026-09-30). _fresh(page) _seed(page, [{"code": "90734", "title": _TDAP, "fee": "60.00"}, {"code": "90471", "title": _ADMIN_1ST, "noFee": True}]) cpt = _live(page)["cpt"] assert [r["billed_fee"] for r in cpt] == ["60.00", None], cpt @case def run_all_counts_a_checked_admin_line_with_no_fee_input_as_billed(page): """ The claim-level shape of the finding: a checked 90471 with no Billed Fee input. zero_fee_uncheck never unchecks it (no fee input -> left alone), so it IS the admin code billed — no second 90471 is added. Before the fix extract() read its fee as "" (zero): vaccine_admin_codes fired and added a 90471 on top, two admin lines billed. """ _fresh(page) _seed(page, _ADULT_ONE + [{"code": "90471", "title": _ADMIN_1ST, "noFee": True}]) data = _live(page) assert vac.detect("9113000", data) is False results = run_all(page, "9113000", data) assert [r.condition_name for r in results] == [], results assert [r["billed"] for r in _rows_for(page, "90471")] == [True] @case def run_all_counts_a_checked_vaccine_with_no_fee_input(page): # The mirror: a checked vaccine with no fee input stays billed, so it is # counted — two vaccines, 90471 AND 90472, not 90471 alone. _fresh(page) _seed(page, _ADULT_ONE + [{"code": "90716", "title": _CHILD_FOUR[2]["title"], "noFee": True, "icd1": "2"}]) results = run_all(page, "9113000", _live(page)) assert [r.condition_name for r in results] == ["vaccine_admin_codes"], results added = [c["code"] for c in results[0].changes if c.get("added")] assert added == ["90471", "90472"], results[0].changes # ============================================================================= # PINNED, NEEDS AN OPERATOR RULING — an admin code the Fee Schedule prices # at 0.00. Today's outcome, not the settled one (review finding 2026-09-30). # ============================================================================= @case def pinned_needs_ruling_an_admin_code_added_at_zero_adds_again_next_run(page): """ PINNED, NEEDS A RULING. Run 1: the picker prices the added 90471 at 0.00 — it lands checked at 0.00 and stays checked (zero_fee_uncheck ran FIRST, before it existed; priced_line_check only ever checks), and describe() reports it with no warning. Run 2 on the same claim, still in the queue: that 90471 is a checked zero-fee admin line, which ruling B says does not count, so zero_fee_uncheck unchecks it and vaccine_admin_codes adds ANOTHER 90471 at 0.00 — one more per run. Whether a line added at 0.00 should be flagged, failed, or left is beyond rulings A/B/C. """ _fresh(page) page.evaluate("([c, f]) => window.setFeeScheduleFee(c, f)", ["90471", "0.00"]) _seed(page, _ADULT_ONE) def grid(): return [(r["code"], r["billed"], r["billed_fee"]) for r in _live(page)["cpt"]] results = run_all(page, "9113000", _live(page)) assert [r.condition_name for r in results] == ["vaccine_admin_codes"], results assert "CHECK" not in vac.describe(results[0]).upper(), vac.describe(results[0]) assert grid()[-1] == ("90471", True, "0.00"), grid() results = run_all(page, "9113000", _live(page)) assert [r.condition_name for r in results] == ["zero_fee_uncheck", "vaccine_admin_codes"], results assert grid()[2:] == [("90471", False, "0.00"), ("90471", True, "0.00")], ("today: a second 90471 added", grid()) @case def default_fixture_is_what_detect_fires_on(page): _fresh(page) data = _live(page) assert data["insurance"][0]["Name"] == "Medicaid", data["insurance"] assert data["patient"]["dob"] == "01/02/1976", data["patient"] assert vac.detect("9113000", data) is True # ============================================================================= # apply() # ============================================================================= @case def apply_adult_one_vaccine_adds_90471_x1_only(page): _fresh(page) _seed(page, _ADULT_ONE) data = _live(page) result = vac.apply(page, "9113000", data) assert isinstance(result, ConditionResult) assert result.condition_name == "vaccine_admin_codes" assert result.changed is True, result assert [c["code"] for c in result.changes] == ["90471"], result.changes assert result.changes[0]["added"] is True assert result.changes[0]["units"] == "1", result.changes added = _rows_for(page, "90471") assert len(added) == 1 and added[0]["units"] == "1", added assert added[0]["billed_fee"] == "30.00", added assert _rows_for(page, "90472") == [], "one vaccine needs no 90472" assert _rows_for(page, "90460") == [], "an adult never gets 90460" @case def apply_adult_three_vaccines_adds_90471_x1_and_90472_x1(page): """ The operator's simplified rule (2026-09-29): more than one vaccine -> the two admin codes, each x1 — NOT 90472 x (vaccines - 1). """ _fresh(page) # the default grid: 90732, 90746, 90734 on a 50-year-old data = _live(page) result = vac.apply(page, "9113000", data) assert result.changed is True by_code = {c["code"]: c for c in result.changes} assert set(by_code) == {"90471", "90472"}, result.changes assert by_code["90471"]["units"] == "1", by_code assert by_code["90472"]["units"] == "1", by_code assert by_code["90472"]["billed_fee"] == "20.00", by_code # Both landed: nothing for a human (control for unit D review finding 3). assert result.review == "", result.review row = _rows_for(page, "90472") assert len(row) == 1 and row[0]["units"] == "1", row assert row[0]["billed_fee"] == "20.00", row @case def apply_adult_two_vaccines_leaves_both_lines_as_ecw_priced_them(page): # Both codes want Units 1 and the picker already gave 1 — so neither # line's Units is touched; each is left exactly as eCW priced it. _fresh(page) _seed(page, _ADULT_ONE + [{"code": "90732", "title": "PCV20", "icd1": "2", "fee": "290.00"}]) result = vac.apply(page, "9113000", _live(page)) by_code = {c["code"]: c for c in result.changes} assert set(by_code) == {"90471", "90472"}, result.changes assert by_code["90472"]["units"] == "1", by_code assert by_code["90472"]["billed_fee"] == "20.00", by_code for i in (3, 4): units = page.locator(sel.SEL_CPT_ROWS).nth(i).locator(sel.SEL_CPT_UNITS).first assert units.input_value() == "1" assert units.get_attribute("data-blurred") is None, \ "a line eCW already gave 1 unit must be left as priced" @case def apply_child_four_vaccines_adds_90460_x1_and_90461_x1(page): _fresh(page) _seed(page, _CHILD_FOUR, dob="07/01/2025", age_sex=" 12M 6D, F") data = _live(page) result = vac.apply(page, "9133000", data) assert result.changed is True by_code = {c["code"]: c for c in result.changes} assert set(by_code) == {"90460", "90461"}, result.changes assert by_code["90460"]["units"] == "1", by_code assert by_code["90461"]["units"] == "1", by_code assert by_code["90461"]["billed_fee"] == "15.00", by_code assert _rows_for(page, "90471") == [] and _rows_for(page, "90472") == [] @case def apply_does_not_hand_fill_pos_or_icd_pointers(page): # eCW fills POS / dates / ICD pointers on the new line itself (the # fixture's picker fakes that by copying the first line). Whatever it # put there must survive apply() untouched. _fresh(page) _seed(page, [{"code": "99396", "title": "PREVENTIVE VISIT", "pos": "22", "icd1": "1", "icd2": "2"}, {"code": "90734", "title": _TDAP, "pos": "22", "icd1": "2", "fee": "60.00"}]) vac.apply(page, "9113000", _live(page)) added = _rows_for(page, "90471")[0] assert added["pos"] == "22" and added["icd1"] == "1" \ and added["icd2"] == "2", added @case def apply_still_adds_when_only_an_unchecked_admin_is_present(page): _fresh(page) _seed(page, [{"code": "99397", "title": "PREVENTIVE VISIT EST 65+"}, {"code": "90656", "title": "FLU VACC IIV3 NO PRSV 0.5ML IM", "fee": "65.00"}, {"code": "90460", "title": "IMMUNIZATION ADMIN", "checked": False, "fee": "0.00"}]) result = vac.apply(page, "9132000", _live(page)) assert result.changed is True assert [c["code"] for c in result.changes] == ["90471"], result.changes assert len(_rows_for(page, "90460")) == 1, "the unchecked 90460 is left alone" @case def apply_child_with_an_unchecked_90460_adds_a_new_90460_row(page): _fresh(page) _seed(page, [{"code": "99392", "title": "PREV VISIT EST AGE 1-4"}, {"code": "90732", "title": "PCV20", "fee": "290.00"}, {"code": "90460", "title": "IMMUNIZATION ADMIN", "checked": False, "fee": "0.00"}], dob="07/01/2020", age_sex=" 6Y, M") result = vac.apply(page, "C1", _live(page)) assert result.changed is True rows = _rows_for(page, "90460") assert [r["billed"] for r in rows] == [False, True], rows @case def apply_add_that_leaves_no_new_row_counts_as_a_failure(page): # add_cpt_row() verifies only that SOME 90460 row exists afterward — # true here from the unchecked one alone. The new-row count is what # tells a real add from a picker that silently did nothing. _fresh(page) _seed(page, [{"code": "90732", "title": "PCV20", "fee": "290.00"}, {"code": "90460", "title": "IMMUNIZATION ADMIN", "checked": False}], dob="07/01/2020", age_sex=" 6Y, M") page.evaluate("() => { window.feeScheduleOkAddsNothing = true; }") result = vac.apply(page, "C1", _live(page)) assert result.changed is False, result assert result.changes == [] assert len(_rows_for(page, "90460")) == 1 @case def apply_first_code_add_failure_adds_nothing(page): _fresh(page) page.evaluate("() => window.removeFromFeeSchedule('90471')") result = vac.apply(page, "9113000", _live(page)) assert result.changed is False, result assert result.changes == [] # Declined, not none(): the claim still lacks its admin code (D2). assert result == ConditionResult.declined( vac.NAME, "90471 could not be added — add it by hand"), result assert _rows_for(page, "90471") == [] assert _rows_for(page, "90472") == [], \ "90472 must not be attempted once 90471 could not be added" assert not page.locator(sel.SEL_FEE_SCHEDULE_CPT_SEARCH).first.is_visible(), \ "the picker must be closed, not left blocking the claim form" @case def apply_additional_code_failure_keeps_the_first_and_reports_it(page): _fresh(page) page.evaluate("() => window.removeFromFeeSchedule('90472')") result = vac.apply(page, "9113000", _live(page)) assert result.changed is True by_code = {c["code"]: c for c in result.changes} assert by_code["90471"]["added"] is True, by_code assert by_code["90472"]["added"] is False, by_code # The first code landed, the second did not: the claim still lacks an # admin code, so it carries a review reason (review of unit D, # 2026-10-05, finding 3 — this asserted review == "" before, which made # the summary a Fail row reading "vaccine admin code added"). The # removed fee-schedule entry means the picker added nothing. assert result.review == "90472 could not be added — add it by hand", \ result.review assert len(_rows_for(page, "90471")) == 1 text = vac.describe(result) assert "90472" in text and "FAILED" in text, text @case def apply_decides_from_the_live_grid_not_the_pre_read_data(page): # The pre-read data says "vaccines, no admin" — but by the time apply() # runs, an admin code is on the live grid (e.g. added by hand or by an # earlier condition). Nothing may be added on top of it. _fresh(page) data = _live(page) _seed(page, [{"code": "90734", "title": _TDAP, "fee": "60.00"}, {"code": "90471", "title": _ADMIN_1ST, "fee": "30.00"}]) result = vac.apply(page, "9113000", data) assert result.changed is False, result assert len(_rows_for(page, "90471")) == 1 @case def apply_live_plan_skips_a_checked_zero_fee_admin_line_the_same_as_detect(page): """ detect() and apply()'s live-grid plan share one rule (2026-09-30): the claim as read has its only 90471 checked at 0.00, detect() fires on it, and apply() — called straight here, zero_fee_uncheck never run — reads the live grid the same way and adds 90471, rather than calling the 0.00 line "admin already billed". In a real run zero_fee_uncheck has unchecked that line first (test_conditions_zero_fee_uncheck.py). """ _fresh(page) _seed(page, _ADULT_ONE + [{"code": "90471", "title": _ADMIN_1ST, "fee": "0.00"}]) data = _live(page) assert vac.detect("9113000", data) is True result = vac.apply(page, "9113000", data) assert result.changed is True, result assert [c["code"] for c in result.changes if c["added"]] == ["90471"], \ result.changes assert [(r["billed"], r["billed_fee"]) for r in _rows_for(page, "90471")] \ == [(True, "0.00"), (True, "30.00")] @case def apply_live_plan_does_not_count_a_checked_zero_fee_vaccine(page): # Two vaccine lines, one of them checked at 0.00: one billed vaccine, # so 90471 alone — detect()'s plan and apply()'s agree. _fresh(page) _seed(page, _ADULT_ONE + [{"code": "90732", "title": "PCV20", "fee": "0.00", "icd1": "2"}]) data = _live(page) assert vac._plan("9113000", data, data["cpt"])["vaccines"] == ["90734"] result = vac.apply(page, "9113000", data) assert [c["code"] for c in result.changes] == ["90471"], result.changes assert _rows_for(page, "90472") == [], "one billed vaccine needs no 90472" @case def apply_leaves_a_medicare_claim_alone(page): _fresh(page) data = _live(page) data["insurance"] = [{"Name": "Humana Medicare"}] result = vac.apply(page, "9113000", data) assert result.changed is False assert _rows_for(page, "90471") == [] @case def describe_names_vaccines_age_codes_and_units(page): _fresh(page) result = vac.apply(page, "9113000", _live(page)) text = vac.describe(result) for bit in ("90732", "90746", "90734", "90471", "90472"): assert bit in text, (bit, text) # The age line itself — a bare "50" is already inside "90746". assert "Patient age used: 50 (" in text and "above 18" in text, text assert "Added 90471 x1" in text and "Added 90472 x1" in text, text @case def describe_names_the_pediatric_band_for_a_child(page): _fresh(page) _seed(page, _CHILD_FOUR, dob="07/01/2025", age_sex=" 12M 6D, F") text = vac.describe(vac.apply(page, "9133000", _live(page))) assert "Patient age used: 1 (" in text and "18 and below" in text, text assert "Added 90460 x1" in text and "Added 90461 x1" in text, text # --- vaccine count: rows, not units (ruling 4) -------------------------------- @case def apply_counts_vaccine_rows_not_their_units(page): _fresh(page) _seed(page, [{"code": "99396", "title": "PREVENTIVE VISIT EST AGE 40-64"}, {"code": "90734", "title": _TDAP, "units": "2", "fee": "120.00"}, {"code": "90732", "title": "PCV20", "units": "1", "fee": "290.00"}]) result = vac.apply(page, "9113000", _live(page)) by_code = {c["code"]: c for c in result.changes} assert set(by_code) == {"90471", "90472"}, result.changes assert by_code["90472"]["units"] == "1", \ "2 vaccine ROWS -> 90472 x1, whatever units the vaccines carry" # --- the new line is the one Units is written to ------------------------------ _CHILD_THREE_WITH_OLD_90461 = [ {"code": "99392", "title": "PREV VISIT EST AGE 1-4"}, {"code": "90732", "title": "PCV20", "fee": "290.00"}, {"code": "90716", "title": "VARICELLA VIRUS VACCINE LIVE FOR SUBCUTANEOUS USE", "fee": "180.00"}, {"code": "90707", "title": "MMR VIRUS VACCINE LIVE SUBCUTANEOUS", "fee": "95.00"}, {"code": "90461", "title": "IMMUNIZATION ADMIN EACH ADD", "checked": False, "fee": "0.00"}, ] def _assert_new_and_old_90461(rows, new_first): assert len(rows) == 2, rows new, old = (rows[0], rows[1]) if new_first else (rows[1], rows[0]) assert new["billed"] is True and new["units"] == "1" \ and new["billed_fee"] == "15.00", ("the NEW line gets Units 1", rows) assert old["billed"] is False and old["units"] == "1" \ and old["billed_fee"] == "0.00", ("the old unchecked line is untouched", rows) @case def apply_sets_units_on_the_new_90461_not_an_old_unchecked_one(page): # The 9132000 shape, pediatric: a leftover UNCHECKED 90461 at 0.00 sits # above where the new one lands. # The picker hands back Units 0, so the Units write actually runs — # it must land on the NEW line, not the old one. _fresh(page) _seed(page, _CHILD_THREE_WITH_OLD_90461, dob="07/01/2020", age_sex=" 6Y, M") page.evaluate("() => { window.feeScheduleNewLineUnits = '0'; }") result = vac.apply(page, "C1", _live(page)) by_code = {c["code"]: c for c in result.changes} assert by_code["90461"]["units"] == "1", by_code assert by_code["90461"]["error"] is None, by_code _assert_new_and_old_90461(_rows_for(page, "90461"), new_first=False) @case def apply_sets_units_on_the_new_line_even_when_it_lands_above_an_old_one(page): # A grid that inserts the new 90461 ABOVE the old one: "the last row # with this code" would be the old unchecked line — the diff finds the # real new one. _fresh(page) _seed(page, _CHILD_THREE_WITH_OLD_90461, dob="07/01/2020", age_sex=" 6Y, M") page.evaluate("() => { window.feeScheduleInsertBeforeCode = '90461'; " "window.feeScheduleNewLineUnits = '0'; }") result = vac.apply(page, "C1", _live(page)) by_code = {c["code"]: c for c in result.changes} assert by_code["90461"]["units"] == "1", by_code assert by_code["90461"]["error"] is None, by_code _assert_new_and_old_90461(_rows_for(page, "90461"), new_first=True) @case def apply_reports_an_extra_line_the_picker_added_alongside(page): # The second picker open keeps the first pick, so OK adds 90471 again # with 90472: the 90472 add itself is fine, the stray line is reported. _fresh(page) _seed(page, _ADULT_ONE + [{"code": "90732", "title": "PCV20", "icd1": "2", "fee": "290.00"}]) page.evaluate("() => { window.feeScheduleOkAlsoAdds = '90471'; }") result = vac.apply(page, "9113000", _live(page)) by_code = {c["code"]: c for c in result.changes} assert by_code["90472"]["added"] is True, by_code unexpected = " ".join(by_code["90472"]["unexpected"]) assert "90471" in unexpected, by_code text = vac.describe(result) assert "CHECK BY HAND" in text and "90471" in text, text # --- a failed first add that still changed the grid --------------------------- @case def apply_first_add_that_rechecks_an_old_line_is_reported_not_hidden(page): # OK re-checks and re-prices the claim's existing UNCHECKED 90460 # instead of appending one: nothing was "added", but the grid is not # what it was — a result of "nothing changed" would let another # condition's Save write it unreviewed. _fresh(page) _seed(page, [{"code": "99392", "title": "PREV VISIT EST AGE 1-4"}, {"code": "90732", "title": "PCV20", "fee": "290.00"}, {"code": "90716", "title": "VARICELLA VIRUS VACCINE LIVE", "fee": "180.00"}, {"code": "90460", "title": "IMMUNIZATION ADMIN", "checked": False, "fee": "0.00"}], dob="07/01/2020", age_sex=" 6Y, M") page.evaluate("() => { window.feeScheduleOkRechecksExisting = true; }") result = vac.apply(page, "C1", _live(page)) assert result.changed is True, result assert [c["code"] for c in result.changes] == ["90460"], result.changes change = result.changes[0] assert change["added"] is False and change["grid_changed"] is True, change # And flagged: a failed add that moved the grid is never "clean" (D2). assert result.review == ("90460 could not be added cleanly — check the " "CPT grid by hand"), result.review assert _rows_for(page, "90461") == [], "90461 must not be attempted" text = vac.describe(result) assert "FAILED to add 90460" in text and "CHECK BY HAND" in text, text # both states of the line, so the operator sees exactly what moved assert "90460 x1 (fee 0.00, unchecked)" in text, text assert "90460 x1 (fee 25.00, checked)" in text, text # --- nothing raised mid-add may lose a line already on the form --------------- @contextlib.contextmanager def _patched(module, name, replacement): real = getattr(module, name) setattr(module, name, replacement) try: yield real finally: setattr(module, name, real) @case def apply_second_add_raising_keeps_the_first_and_reports_both(page): _fresh(page) real_add = claim_form.add_cpt_row def add_that_times_out_on_90472(page_, code): if code != "90472": return real_add(page_, code) # The picker is open when the timeout hits, as it would be live. page_.locator(sel.SEL_CPT_ADD_BTN).first.click() raise TimeoutError("Locator.click: Timeout 10000ms exceeded (simulated)") with _patched(claim_form, "add_cpt_row", add_that_times_out_on_90472): results = run_all(page, "9113000", _live(page)) assert [r.condition_name for r in results] == ["vaccine_admin_codes"], \ "a raise inside the second add must not drop the whole result" by_code = {c["code"]: c for c in results[0].changes} assert by_code["90471"]["added"] is True, by_code assert by_code["90472"]["added"] is False, by_code assert "raised" in by_code["90472"]["error"], by_code # Unit D review, finding 3: the missing 90472 makes it a Review row. assert results[0].review.startswith("90472 could not be added"), \ results[0].review assert len(_rows_for(page, "90471")) == 1 assert not page.locator(sel.SEL_FEE_SCHEDULE_CPT_SEARCH).first.is_visible(), \ "the picker the failed add left open must be closed" text = vac.describe(results[0]) assert "Added 90471 x1" in text and "FAILED to add 90472" in text, text @case def apply_units_write_raising_still_reports_the_line_it_added(page): _fresh(page) page.evaluate("() => { window.feeScheduleNewLineUnits = '0'; }") def units_that_time_out(*args, **kwargs): raise TimeoutError("Locator.fill: Timeout 10000ms exceeded (simulated)") with _patched(claim_form, "set_cpt_units", units_that_time_out): results = run_all(page, "9113000", _live(page)) assert [r.condition_name for r in results] == ["vaccine_admin_codes"], results by_code = {c["code"]: c for c in results[0].changes} assert by_code["90472"]["added"] is True, by_code assert by_code["90472"]["units"] == "0", \ "the report shows what the line really reads — still 0 units" assert "raised" in by_code["90472"]["error"], by_code text = vac.describe(results[0]) assert "Added 90472 x0" in text and "CHECK" in text, text # --- the Fee Schedule picker is never left open -------------------------------- @case def apply_ok_that_keeps_the_picker_open_closes_it_and_adds_nothing(page): # Slow (~15s): add_cpt_row() waits out its own 10s for the picker to # hide before deciding OK did nothing. _fresh(page) _seed(page, _ADULT_ONE) page.evaluate("() => { window.feeScheduleOkKeepsOpen = true; }") result = vac.apply(page, "9113000", _live(page)) assert result.changed is False, result assert _rows_for(page, "90471") == [] assert not page.locator(sel.SEL_FEE_SCHEDULE_CPT_SEARCH).first.is_visible(), \ "a picker left up would block the claim form's own Cancel" @case def add_cpt_row_closes_the_picker_when_a_step_raises(page): # Slow (~10s): a disabled OK makes Playwright's click time out, with # the picker open — it must be closed before the error goes on up. _fresh(page) page.evaluate("() => { document.getElementById('claimFeeSchOkBtn')" ".disabled = true; }") try: claim_form.add_cpt_row(page, "90471") except Exception: pass else: raise AssertionError("the OK click timeout must still be raised") assert not page.locator(sel.SEL_FEE_SCHEDULE_CPT_SEARCH).first.is_visible() # --- the fee read back is the re-priced one ----------------------------------- @case def apply_waits_for_an_async_units_reprice(page): _fresh(page) page.evaluate("() => { window.unitsRepriceDelayMs = 600; " "window.feeScheduleNewLineUnits = '0'; }") result = vac.apply(page, "9113000", _live(page)) by_code = {c["code"]: c for c in result.changes} assert by_code["90472"]["billed_fee"] == "20.00", \ ("the 0.00 fee read straight after the blur is stale", by_code) assert by_code["90472"]["error"] is None, by_code @case def apply_flags_a_fee_that_never_reprices(page): _fresh(page) page.evaluate("() => { window.unitsNoReprice = true; " "window.feeScheduleNewLineUnits = '0'; }") result = vac.apply(page, "9113000", _live(page)) by_code = {c["code"]: c for c in result.changes} assert by_code["90472"]["units"] == "1", by_code assert "re-priced" in (by_code["90472"]["error"] or ""), by_code assert "CHECK" in vac.describe(result) # --- the professional/HCFA screen --------------------------------------------- def _hcfa_with_one_vaccine(page): page.goto(HCFA_FIXTURE.as_uri()) page.evaluate("""(title) => { const row = document.getElementById('CPTROW_1'); row.querySelector('[data-fieldname="claimCPTCode"]').value = '90734'; row.querySelector('[data-fieldname="claimCPTCode"]').closest('td') .setAttribute('title', title); // The live screen's DOB bind (MM/DD/YYYY, read on 9109000 and // 9119000) is not part of the fixture; a made-up adult DOB. const dob = document.createElement('span'); dob.setAttribute('ng-bind', 'PatientInfo.dob'); dob.textContent = '01/15/1980'; document.body.appendChild(dob); }""", _TDAP) @case def hcfa_screen_vaccine_claim_fires_on_the_payer_from_the_insurances_grid(page): # hcfa_claim.html is a United Health Care (Commercial) claim — covered # by document #18. This used to be pinned as a gap: extract() read no # insurance on this screen, so the payer gate always said no. _hcfa_with_one_vaccine(page) data = _live(page) assert [r["code"] for r in vac.checked_vaccine_rows(data["cpt"])] == ["90734"] assert data["insurance"][0]["Name"] == "United Health Care", data["insurance"] assert vac.detect("9103000", data) is True @case def hcfa_screen_with_no_payer_row_still_blames_the_read(page): _hcfa_with_one_vaccine(page) page.evaluate("() => document.querySelector(" "'#billingClaimTbl8 tbody').innerHTML = ''") data = _live(page) assert data["insurance"] == [], data["insurance"] out = io.StringIO() with contextlib.redirect_stdout(out): assert vac.detect("9103000", data) is False assert "no primary payer name was read" in out.getvalue(), \ ("the log must blame the read, not payer_groups.json", out.getvalue()) @case def run_all_fires_only_this_condition_on_the_fixture(page): _fresh(page) data = _live(page) results = run_all(page, "9113000", data) assert [r.condition_name for r in results] == ["vaccine_admin_codes"], results # ============================================================================= # What the Charge Summary says (final review, 2026-10-05) # ============================================================================= def _change(code, added): return {"code": code, "added": added, "units": 1, "wanted_units": 1, "billed_fee": "10.00", "error": "" if added else "not found", "grid_changed": None if added else True} @case def summary_comment_says_which_admin_code_was_added_and_which_was_not(): """ The fixed "( vaccine admin code added )" read "added" next to the review reason saying the code could NOT be added. """ sc = vac.summary_comment mk = lambda *c: ConditionResult("vaccine_admin_codes", True, list(c)) assert sc(mk(_change("90471", True), _change("90472", True))) == \ "CPT Code Missing (vaccine admin code 90471 added; 90472 added)" assert sc(mk(_change("90471", False))) == \ "CPT Code Missing (vaccine admin code 90471 NOT added — add by hand)" assert sc(mk(_change("90471", True), _change("90472", False))) == ( "CPT Code Missing (vaccine admin code 90471 added; 90472 NOT added " "— add by hand)") @case def the_charge_summary_row_no_longer_says_added_for_a_failed_add(): """End to end through charge_summary.claim_outcome, both cases.""" from ecw_bot.core import charge_summary as cs for changes, review in ( ([_change("90471", False)], "90471 could not be added cleanly — check the CPT grid by hand"), ([_change("90471", True), _change("90472", False)], "90472 could not be added cleanly — check the CPT grid by hand")): result = ConditionResult("vaccine_admin_codes", True, changes, review=review) data = {"cpt": [{"code": "90686"}], "icd": [{"code": "Z23"}], "progress_notes": {"opened": "frame", "sections": {}}, "_conditions": { "fired": ["vaccine_admin_codes"], "saved": False, "failed": [], "review": [{"name": "vaccine_admin_codes", "reason": review}], "comments": {"vaccine_admin_codes": vac.summary_comment(result)}}} o = cs.claim_outcome(True, data) assert o["Category"] == "Review", o assert "vaccine admin code added" not in o["Comments"], o assert "NOT added — add by hand" in o["Comments"], o @case def a_live_grid_that_reads_empty_after_a_full_first_read_is_declined(): """ Final review, 2026-10-05: detect() found billed vaccines in the first read, but the live re-read came back empty — declined, not "Nothing to add" (none(), which the summary reads as Pass). """ from ecw_bot.conditions.base import CPT_GRID_NOT_READ orig = (claim_form.open_cpt_hcpcs_tab, claim_form.extract) claim_form.open_cpt_hcpcs_tab = lambda page: True claim_form.extract = lambda page: {"cpt": []} try: with contextlib.redirect_stdout(io.StringIO()): result = vac.apply(None, "9131000", {"cpt": [_row("90686", "Flu vaccine")]}) finally: claim_form.open_cpt_hcpcs_tab, claim_form.extract = orig assert result == ConditionResult.declined("vaccine_admin_codes", CPT_GRID_NOT_READ), result def _run_cases() -> int: if not FIXTURE.exists(): print(f" FAIL fixture missing: {FIXTURE}") 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) 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 def main() -> int: from ecw_bot import settings as _cfg # These cases exercise eCW's own click and Add flow, as a LIVE-WRITE run # does. VERIFY clicks no box and adds no row (eCW saves both at once, # 2026-10-16): that is tests/test_verify_no_live_writes.py. orig = _cfg.SAVE_CORRECTIONS _cfg.SAVE_CORRECTIONS = True try: return _run_cases() finally: _cfg.SAVE_CORRECTIONS = orig if __name__ == "__main__": sys.exit(main())