fix: MH eligibility - auto-select first provider, fix PDF double-quit bug
This commit is contained in:
@@ -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:
|
||||||
|
|||||||
Reference in New Issue
Block a user