fix: MH eligibility - auto-select first provider, fix PDF double-quit bug

This commit is contained in:
Gitead
2026-04-22 14:33:19 -04:00
parent 5e7f0ceb07
commit 1414ec11fd

View File

@@ -3,13 +3,10 @@ from selenium.common import TimeoutException
from selenium.webdriver.chrome.service import Service from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait, Select from selenium.webdriver.support.ui import WebDriverWait, Select
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support import expected_conditions as EC
from webdriver_manager.chrome import ChromeDriverManager from webdriver_manager.chrome import ChromeDriverManager
import time import time
import os import os
import shutil
import stat
import base64 import base64
class AutomationMassHealthEligibilityCheck: class AutomationMassHealthEligibilityCheck:
@@ -87,80 +84,86 @@ class AutomationMassHealthEligibilityCheck:
def step1(self): def step1(self):
wait = WebDriverWait(self.driver, 30) wait = WebDriverWait(self.driver, 30)
substep = "init"
try: try:
# Skip My Account - go directly to Patient Management print(f"[step1] current URL after login: {self.driver.current_url}")
# Step 1: Click Patient Management directly print(f"[step1] page title: {self.driver.title}")
substep = "patient_management"
patient_mgmt = wait.until( patient_mgmt = wait.until(
EC.presence_of_element_located( EC.presence_of_element_located(
(By.XPATH, "//strong[@translate='Patient Management']") (By.XPATH, "//strong[@translate='Patient Management']")
) )
) )
# Scroll + JS click = fixes most dropdown issues
self.driver.execute_script("arguments[0].scrollIntoView(true);", patient_mgmt) self.driver.execute_script("arguments[0].scrollIntoView(true);", patient_mgmt)
self.driver.execute_script("arguments[0].click();", patient_mgmt) self.driver.execute_script("arguments[0].click();", patient_mgmt)
time.sleep(2) time.sleep(2)
# Step 3: Click Member Eligibility substep = "member_eligibility_link"
eligibility_link = wait.until( eligibility_link = wait.until(
EC.presence_of_element_located( EC.presence_of_element_located(
(By.XPATH, "//a[@translate='Member Eligibility']") (By.XPATH, "//a[@translate='Member Eligibility']")
) )
) )
self.driver.execute_script("arguments[0].click();", eligibility_link) self.driver.execute_script("arguments[0].click();", eligibility_link)
time.sleep(2) time.sleep(2)
# Step 4: Wait for Provider dropdown substep = "provider_dropdown"
provider_dropdown = wait.until( provider_dropdown = wait.until(
EC.presence_of_element_located((By.NAME, "provider")) EC.presence_of_element_located((By.NAME, "provider"))
) )
# Use Select class (important!)
select_provider = Select(provider_dropdown) select_provider = Select(provider_dropdown)
# Step 5: Select correct option # Log available options so we can see if the provider name changed
select_provider.select_by_visible_text( options = [o.text for o in select_provider.options]
"Summit Dental Care - Framingham - Kai Gao" print(f"[step1] provider options: {options}")
substep = "select_provider"
# Select the first non-empty option (index 0 is usually a blank placeholder)
first_option = next(
(o for o in select_provider.options if o.get_attribute("value").strip()),
select_provider.options[0]
) )
print(f"[step1] selecting provider: '{first_option.text}'")
select_provider.select_by_value(first_option.get_attribute("value"))
time.sleep(2) time.sleep(2)
# Step 6: Member Date Of Birth (SECOND dateInput) substep = "member_dob"
member_dob = wait.until( member_dob = wait.until(
EC.presence_of_all_elements_located((By.NAME, "dateInput")) EC.presence_of_all_elements_located((By.NAME, "dateInput"))
)[1] )[1]
member_dob.clear() member_dob.clear()
member_dob.send_keys(self.dateOfBirth) member_dob.send_keys(self.dateOfBirth)
# Step 7: Member Number substep = "member_number"
member_number = wait.until( member_number = wait.until(
EC.presence_of_element_located((By.NAME, "memberNumber")) EC.presence_of_element_located((By.NAME, "memberNumber"))
) )
member_number.clear() member_number.clear()
member_number.send_keys(self.memberId) member_number.send_keys(self.memberId)
# Step 8: Click Search substep = "search_button"
search_button = wait.until( search_button = wait.until(
EC.element_to_be_clickable((By.XPATH, "//button[contains(@class,'btn-primary')]")) EC.element_to_be_clickable((By.XPATH, "//button[contains(@class,'btn-primary')]"))
) )
search_button.click() search_button.click()
# ✅ CRITICAL WAIT FOR RESULTS substep = "wait_results"
wait.until( wait.until(
EC.presence_of_element_located( EC.presence_of_element_located(
(By.XPATH, "//h4[text()='Eligible' or text()='Ineligible']") (By.XPATH, "//h4[text()='Eligible' or text()='Ineligible']")
) )
) )
# ✅ EXTRACT DATA FROM RESULTS PAGE
self.extracted_data = self._extract_data_from_page() self.extracted_data = self._extract_data_from_page()
print(f"Data extracted in step1: {self.extracted_data}") print(f"[step1] data extracted: {self.extracted_data}")
return "Success" return "Success"
except Exception as e: except Exception as e:
print(f"Error while step1: {e}") print(f"[step1] FAILED at substep='{substep}': {e}")
return "ERROR:STEP1" print(f"[step1] URL at failure: {self.driver.current_url}")
return f"ERROR:STEP1:{substep}"
def _cell_text(self, cell): def _cell_text(self, cell):
"""Get text from a cell, falling back to JS innerText if .text is empty.""" """Get text from a cell, falling back to JS innerText if .text is empty."""
@@ -280,11 +283,22 @@ class AutomationMassHealthEligibilityCheck:
print("Extraction error:", e) print("Extraction error:", e)
return {"eligibility": None} return {"eligibility": None}
def _print_current_page_as_pdf(self):
"""Generate PDF from the currently active tab using CDP."""
safe_member = "".join(c for c in str(self.memberId) if c.isalnum() or c in "-_.")
pdf_filename = f"eligibility_{safe_member}.pdf"
pdf_data = self.driver.execute_cdp_cmd("Page.printToPDF", {"printBackground": True})
pdf_bytes = base64.b64decode(pdf_data["data"])
pdf_path = os.path.join(self.download_dir, pdf_filename)
with open(pdf_path, "wb") as f:
f.write(pdf_bytes)
print("PDF saved at:", pdf_path)
return pdf_path
def step2(self): def step2(self):
wait = WebDriverWait(self.driver, 30) wait = WebDriverWait(self.driver, 30)
try: try:
# ✅ USE STORED EXTRACTED DATA
print(f"Using stored extracted data: {self.extracted_data}") print(f"Using stored extracted data: {self.extracted_data}")
# Step 1: Click Printer Friendly Format # Step 1: Click Printer Friendly Format
@@ -296,57 +310,32 @@ class AutomationMassHealthEligibilityCheck:
original_tab = self.driver.current_window_handle original_tab = self.driver.current_window_handle
download_button.click() download_button.click()
# Wait for NEW TAB # Wait up to 10s for a new tab; if none opens, print the current page
wait.until(lambda d: len(d.window_handles) > 1) try:
WebDriverWait(self.driver, 10).until(lambda d: len(d.window_handles) > 1)
new_tabs = [tab for tab in self.driver.window_handles if tab != original_tab]
self.driver.switch_to.window(new_tabs[0])
wait.until(lambda d: d.execute_script("return document.readyState") == "complete")
wait.until(EC.presence_of_element_located((By.TAG_NAME, "body")))
time.sleep(2)
print("Printer-friendly tab opened:", self.driver.current_url)
except TimeoutException:
# Portal did not open a new tab — print the results page directly
print("No new tab opened; printing results page directly as PDF")
# Switch ONLY to new tab pdf_path = self._print_current_page_as_pdf()
new_tabs = [tab for tab in self.driver.window_handles if tab != original_tab]
self.driver.switch_to.window(new_tabs[0])
wait.until(lambda d: d.execute_script("return document.readyState") == "complete")
# Wait for page to render (CRITICAL)
wait.until(EC.presence_of_element_located((By.TAG_NAME, "body")))
time.sleep(2)
print("Capturing PDF from:", self.driver.current_url)
# Extract data from page BEFORE generating PDF
extracted_data = self._extract_data_from_page()
print(f"Extracted data: {extracted_data}")
# Step 2: Save PDF using Chrome DevTools (REAL solution)
safe_member = "".join(c for c in str(self.memberId) if c.isalnum() or c in "-_.")
pdf_filename = f"eligibility_{safe_member}.pdf"
pdf_data = self.driver.execute_cdp_cmd("Page.printToPDF", {
"printBackground": True
})
pdf_bytes = base64.b64decode(pdf_data['data'])
pdf_path = os.path.join(self.download_dir, pdf_filename)
with open(pdf_path, "wb") as f:
f.write(pdf_bytes)
print("PDF saved at:", pdf_path)
# Return PDF path along with extracted data
result = { result = {
"status": "success", "status": "success",
"pdf_path": pdf_path, "pdf_path": pdf_path,
"file_type": "pdf", "file_type": "pdf",
"message": "PDF captured successfully" "message": "PDF captured successfully"
} }
# Add stored extracted data to result
if self.extracted_data: if self.extracted_data:
result.update(self.extracted_data) result.update(self.extracted_data)
return result
except Exception as e:
print("PDF capture failed:", e)
return result
except Exception as e: except Exception as e:
print("PDF capture failed:", e) print("PDF capture failed:", e)
@@ -365,11 +354,11 @@ class AutomationMassHealthEligibilityCheck:
"file_type": "screenshot", "file_type": "screenshot",
"message": "Screenshot captured (PDF failed)" "message": "Screenshot captured (PDF failed)"
} }
# Add stored extracted data to result even for screenshots # Add stored extracted data to result even for screenshots
if self.extracted_data: if self.extracted_data:
result.update(self.extracted_data) result.update(self.extracted_data)
return result return result
except Exception as ss_error: except Exception as ss_error:
@@ -378,10 +367,6 @@ class AutomationMassHealthEligibilityCheck:
"message": f"PDF + Screenshot failed: {ss_error}" "message": f"PDF + Screenshot failed: {ss_error}"
} }
finally:
if self.driver:
self.driver.quit()
def main_workflow(self, url): def main_workflow(self, url):
try: try:
self.config_driver() self.config_driver()
@@ -402,10 +387,10 @@ class AutomationMassHealthEligibilityCheck:
return {"status": "error", "message": step2_result.get("message")} return {"status": "error", "message": step2_result.get("message")}
return step2_result return step2_result
except Exception as e: except Exception as e:
return { return {
"status": "error", "status": "error",
"message": e "message": str(e)
} }
finally: finally: