refactor: duplicate member details tab for parallel service history & accumulator

Instead of navigating back and forth, step4 opens the member details URL
in a new tab. Tab A clicks service history and CDP-prints the history PDF.
Tab B clicks View Accumulator and CDP-prints the accumulator PDF (waits
up to 15s for vm.hasResults, then captures whatever is on screen).
Eliminates the Chrome freeze from back-navigation and the empty-accumulator
race condition.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Gitead
2026-05-14 12:06:33 -04:00
parent 33dded1813
commit 65b26610b1

View File

@@ -16,6 +16,8 @@ class AutomationCMSPEligibilityHistoryRemainingCheck:
self.driver = None
self.extracted_data = {}
self.eligibility_tab = None
self.member_details_tab = None
self.accumulator_tab = None
self.data = data.get("data")
@@ -296,12 +298,36 @@ class AutomationCMSPEligibilityHistoryRemainingCheck:
print(f"[step3b_member_details_pdf] failed: {e}")
return None
# ── step 4 — click "VIEW SERVICE HISTORY" → service history page ─────────────
# ── step 4 — duplicate member details tab ───────────────────────────────────
# Opens the same member details URL in a new tab so that Tab A can navigate
# to service history while Tab B navigates to accumulator independently.
def step4_view_service_history(self):
wait = WebDriverWait(self.driver, 30)
substep = "service_history_link"
def step4_open_duplicate_tab(self):
try:
self.member_details_tab = self.driver.current_window_handle
member_details_url = self.driver.current_url
self.driver.execute_script("window.open(arguments[0]);", member_details_url)
time.sleep(3)
all_tabs = self.driver.window_handles
self.accumulator_tab = next(
t for t in all_tabs
if t not in [self.eligibility_tab, self.member_details_tab]
)
print(f"[step4] duplicate tab opened: {self.accumulator_tab}")
return "Success"
except Exception as e:
print(f"[step4] FAILED: {e}")
return f"ERROR:STEP4:open_duplicate_tab"
# ── step 5 — Tab A: service history → CDP print ──────────────────────────────
def step5_service_history_pdf(self):
wait = WebDriverWait(self.driver, 30)
try:
self.driver.switch_to.window(self.member_details_tab)
history_link = wait.until(
EC.element_to_be_clickable(
(By.CSS_SELECTOR, "a.btn.btn-primary[href*='service-history']")
@@ -310,21 +336,7 @@ class AutomationCMSPEligibilityHistoryRemainingCheck:
self.driver.execute_script("arguments[0].scrollIntoView(true);", history_link)
self.driver.execute_script("arguments[0].click();", history_link)
time.sleep(2)
print(f"[step4] navigated to service history, URL: {self.driver.current_url}")
return "Success"
except Exception as e:
print(f"[step4] FAILED at substep='{substep}': {e}")
return f"ERROR:STEP4:{substep}"
# ── step 5 — print history PDF via CDP, navigate back to member details ──────
# We do NOT click the "Printer Friendly Format" button here because on the
# service history page it calls window.print() (native dialog) which freezes
# Chrome. Instead we capture the page directly via CDP and then go back.
def step5_history_pdf(self):
wait = WebDriverWait(self.driver, 30)
try:
# Wait for Angular to finish rendering the service history data
wait.until(lambda d: d.execute_script("return document.readyState") == "complete")
time.sleep(3)
@@ -336,25 +348,23 @@ class AutomationCMSPEligibilityHistoryRemainingCheck:
with open(pdf_path, "wb") as f:
f.write(pdf_bytes)
print("History PDF saved at:", pdf_path)
# Go back to member details page where "View Accumulator" lives
self.driver.back()
time.sleep(2)
wait.until(lambda d: d.execute_script("return document.readyState") == "complete")
print(f"[step5] returned to member details, URL: {self.driver.current_url}")
return pdf_path
except Exception as e:
print(f"[step5_history_pdf] failed: {e}")
print(f"[step5_service_history_pdf] failed: {e}")
return None
# ── step 6 — click "View Accumulator" ───────────────────────────────────────
# ── step 6 — Tab B: accumulator → wait for data → CDP print ─────────────────
def step6_click_view_accumulator(self):
def step6_accumulator_pdf(self):
wait = WebDriverWait(self.driver, 30)
substep = "view_accumulator_link"
try:
# ng-if="vm.showAccumulator" is the stable Angular condition on this link
self.driver.switch_to.window(self.accumulator_tab)
# Wait for the duplicate member details page to fully load
wait.until(lambda d: d.execute_script("return document.readyState") == "complete")
time.sleep(2)
# Click View Accumulator
accumulator_link = wait.until(
EC.element_to_be_clickable(
(By.CSS_SELECTOR, "a.btn.btn-primary[ng-if='vm.showAccumulator']")
@@ -363,36 +373,22 @@ class AutomationCMSPEligibilityHistoryRemainingCheck:
self.driver.execute_script("arguments[0].scrollIntoView(true);", accumulator_link)
self.driver.execute_script("arguments[0].click();", accumulator_link)
time.sleep(2)
print(f"[step6] navigated to accumulator, URL: {self.driver.current_url}")
return "Success"
except Exception as e:
print(f"[step6] FAILED at substep='{substep}': {e}")
return f"ERROR:STEP6:{substep}"
# ── step 7 — print accumulator PDF ──────────────────────────────────────────
# Wait for accumulator page shell
wait.until(lambda d: d.execute_script("return document.readyState") == "complete")
def step7_accumulator_pdf(self):
try:
# Wait for the page shell to load
WebDriverWait(self.driver, 30).until(
lambda d: d.execute_script("return document.readyState") == "complete"
)
# Try to detect when Angular data is ready (button has ng-if="vm.hasResults").
# Cap at 15 s — if the patient has no accumulator data the button never
# appears and we still want to capture whatever the page shows.
# Wait up to 15 s for vm.hasResults — captures data or "no results" state
try:
WebDriverWait(self.driver, 15).until(
EC.visibility_of_element_located(
(By.CSS_SELECTOR, "button.btn.btn-primary[ng-click='vm.printResults()']")
)
)
print("[step7] vm.hasResults is true — data loaded")
print("[step6] accumulator data loaded (vm.hasResults true)")
except TimeoutException:
print("[step7] print button not visible after 15 s — patient may have no accumulator data, printing anyway")
print("[step6] no accumulator data for this patient — printing empty state")
# Extra pause so Angular finishes rendering table rows
time.sleep(5)
time.sleep(3)
safe_member = "".join(c for c in str(self.memberId) if c.isalnum() or c in "-_.")
pdf_filename = f"cmsp_accumulator_{safe_member}.pdf"
@@ -404,7 +400,7 @@ class AutomationCMSPEligibilityHistoryRemainingCheck:
print("Accumulator PDF saved at:", pdf_path)
return pdf_path
except Exception as e:
print(f"[step7_accumulator_pdf] failed: {e}")
print(f"[step6_accumulator_pdf] failed: {e}")
return None
# ── main workflow ────────────────────────────────────────────────────────────
@@ -433,23 +429,20 @@ class AutomationCMSPEligibilityHistoryRemainingCheck:
member_details_pdf_path = self.step3b_member_details_pdf()
step4_result = self.step4_view_service_history()
# Duplicate the member details tab so service history and accumulator
# can be opened independently without back-navigation
step4_result = self.step4_open_duplicate_tab()
if step4_result.startswith("ERROR"):
return {"status": "partial", "message": step4_result,
"pdf_path": eligibility_pdf_path,
"member_details_pdf_path": member_details_pdf_path,
"file_type": "pdf"}
history_pdf_path = self.step5_history_pdf()
# Tab A: service history PDF
history_pdf_path = self.step5_service_history_pdf()
step6_result = self.step6_click_view_accumulator()
if step6_result.startswith("ERROR"):
return {"status": "partial", "message": step6_result,
"pdf_path": eligibility_pdf_path,
"member_details_pdf_path": member_details_pdf_path,
"history_pdf_path": history_pdf_path, "file_type": "pdf"}
accumulator_pdf_path = self.step7_accumulator_pdf()
# Tab B: accumulator PDF
accumulator_pdf_path = self.step6_accumulator_pdf()
result = {
"status": "success",