import time from selenium.webdriver.common.by import By # Cell texts of every row in the Eligible / Ineligible results tables. # innerText (not .text) so cells rendered off-screen still return their text. _ROWS_JS = """ const out = []; for (const label of ['Eligible', 'Ineligible']) { const rows = document.evaluate( `//h4[normalize-space(text())='${label}']/following::table[1]/tbody/tr`, document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); for (let i = 0; i < rows.snapshotLength; i++) { const cells = Array.from(rows.snapshotItem(i).querySelectorAll('td')) .map(td => (td.innerText || td.textContent || '').trim()); out.push([label, cells]); } } return out; """ def _normalize_id(s): return "".join(c for c in str(s) if c.isalnum()).lower() def extract_eligibility_row(driver, member_id, timeout=30): """Wait for the MassHealth results row matching member_id and return {eligibility, firstName, lastName, insurance}. AngularJS adds the rows first and fills the cell text afterwards — the member ID can appear before the name and plan do. Keep polling until the matching row has both a name and a plan, so callers never print the PDF before the data is captured. After the timeout, returns whatever was found ({"eligibility": None} if no row matched). """ norm_self = _normalize_id(member_id) best = {"eligibility": None} deadline = time.time() + timeout attempt = 0 while True: attempt += 1 try: rows = driver.execute_script(_ROWS_JS) or [] except Exception as e: print(f"[extraction] reading rows failed: {e}") rows = [] for label, cells in rows: if len(cells) < 3: continue norm_cell = _normalize_id(cells[2]) if not (norm_self and norm_cell and (norm_self in norm_cell or norm_cell in norm_self)): continue # name in cells[4], plan in cells[6] (fallback to last cell) full_name = cells[4] if len(cells) > 4 else "" plan_name = cells[6] if len(cells) > 6 else (cells[-1] if len(cells) > 4 else "") name_parts = full_name.split() best = { "eligibility": "Y" if label == "Eligible" else "N", "firstName": name_parts[0] if name_parts else "", "lastName": " ".join(name_parts[1:]), "insurance": plan_name, } if full_name and plan_name: print(f"[extraction] MATCHED {label} → name='{full_name}' plan='{plan_name}' (attempt {attempt})") return best break if time.time() >= deadline: break if attempt % 5 == 1: state = "name/plan still empty" if best["eligibility"] else "no matching row yet" print(f"[extraction] {state} for memberId='{member_id}' (attempt {attempt}), waiting...") time.sleep(1) print(f"[extraction] gave up after {timeout}s for memberId='{member_id}' → {best}") return best