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:
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user