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.driver = None
self.extracted_data = {} self.extracted_data = {}
self.eligibility_tab = None self.eligibility_tab = None
self.member_details_tab = None
self.accumulator_tab = None
self.data = data.get("data") self.data = data.get("data")
@@ -296,12 +298,36 @@ class AutomationCMSPEligibilityHistoryRemainingCheck:
print(f"[step3b_member_details_pdf] failed: {e}") print(f"[step3b_member_details_pdf] failed: {e}")
return None 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): def step4_open_duplicate_tab(self):
wait = WebDriverWait(self.driver, 30)
substep = "service_history_link"
try: 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( history_link = wait.until(
EC.element_to_be_clickable( EC.element_to_be_clickable(
(By.CSS_SELECTOR, "a.btn.btn-primary[href*='service-history']") (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].scrollIntoView(true);", history_link)
self.driver.execute_script("arguments[0].click();", history_link) self.driver.execute_script("arguments[0].click();", history_link)
time.sleep(2) 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") wait.until(lambda d: d.execute_script("return document.readyState") == "complete")
time.sleep(3) time.sleep(3)
@@ -336,25 +348,23 @@ class AutomationCMSPEligibilityHistoryRemainingCheck:
with open(pdf_path, "wb") as f: with open(pdf_path, "wb") as f:
f.write(pdf_bytes) f.write(pdf_bytes)
print("History PDF saved at:", pdf_path) 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 return pdf_path
except Exception as e: except Exception as e:
print(f"[step5_history_pdf] failed: {e}") print(f"[step5_service_history_pdf] failed: {e}")
return None 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) wait = WebDriverWait(self.driver, 30)
substep = "view_accumulator_link"
try: 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( accumulator_link = wait.until(
EC.element_to_be_clickable( EC.element_to_be_clickable(
(By.CSS_SELECTOR, "a.btn.btn-primary[ng-if='vm.showAccumulator']") (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].scrollIntoView(true);", accumulator_link)
self.driver.execute_script("arguments[0].click();", accumulator_link) self.driver.execute_script("arguments[0].click();", accumulator_link)
time.sleep(2) 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): # Wait up to 15 s for vm.hasResults — captures data or "no results" state
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.
try: try:
WebDriverWait(self.driver, 15).until( WebDriverWait(self.driver, 15).until(
EC.visibility_of_element_located( EC.visibility_of_element_located(
(By.CSS_SELECTOR, "button.btn.btn-primary[ng-click='vm.printResults()']") (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: 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(3)
time.sleep(5)
safe_member = "".join(c for c in str(self.memberId) if c.isalnum() or c in "-_.") safe_member = "".join(c for c in str(self.memberId) if c.isalnum() or c in "-_.")
pdf_filename = f"cmsp_accumulator_{safe_member}.pdf" pdf_filename = f"cmsp_accumulator_{safe_member}.pdf"
@@ -404,7 +400,7 @@ class AutomationCMSPEligibilityHistoryRemainingCheck:
print("Accumulator PDF saved at:", pdf_path) print("Accumulator PDF saved at:", pdf_path)
return pdf_path return pdf_path
except Exception as e: except Exception as e:
print(f"[step7_accumulator_pdf] failed: {e}") print(f"[step6_accumulator_pdf] failed: {e}")
return None return None
# ── main workflow ──────────────────────────────────────────────────────────── # ── main workflow ────────────────────────────────────────────────────────────
@@ -433,23 +429,20 @@ class AutomationCMSPEligibilityHistoryRemainingCheck:
member_details_pdf_path = self.step3b_member_details_pdf() 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"): if step4_result.startswith("ERROR"):
return {"status": "partial", "message": step4_result, return {"status": "partial", "message": step4_result,
"pdf_path": eligibility_pdf_path, "pdf_path": eligibility_pdf_path,
"member_details_pdf_path": member_details_pdf_path, "member_details_pdf_path": member_details_pdf_path,
"file_type": "pdf"} "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() # Tab B: accumulator PDF
if step6_result.startswith("ERROR"): accumulator_pdf_path = self.step6_accumulator_pdf()
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()
result = { result = {
"status": "success", "status": "success",