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