feat: United SCO claim worker rewrite + eligibility/patient-table fixes
- Rewrote UnitedDH claim worker to navigate via eligibility page → Selected Patient → Submit Claim button flow - Updated helpers_uniteddh_claim.py step names to match new 9-step workflow - Changed payer selection in both eligibility and claim workers to type + Enter - Updated patient table column header from 'DOB / Gender' to 'DOB' Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -250,13 +250,14 @@ async def start_uniteddh_claim_run(sid: str, data: dict, url: str):
|
||||
|
||||
# --- Claim steps ---
|
||||
for step_name, step_fn in [
|
||||
("step1_search_patient", bot.step1_search_patient),
|
||||
("step2_open_member_page", bot.step2_open_member_page),
|
||||
("step3_click_create_claim", bot.step3_click_create_claim),
|
||||
("step4_fill_claim_form", bot.step4_fill_claim_form),
|
||||
("step5_attach_files", bot.step5_attach_files),
|
||||
("step6_click_next", bot.step6_click_next),
|
||||
("step7_submit_claim", bot.step7_submit_claim),
|
||||
("step1_search_patient", bot.step1_search_patient),
|
||||
("step2_click_submit_claim", bot.step2_click_submit_claim),
|
||||
("step3_continue_prefilled", bot.step3_continue_prefilled),
|
||||
("step4_select_insurance_ok", bot.step4_select_insurance_ok),
|
||||
("step5_practitioner_continue", bot.step5_practitioner_continue),
|
||||
("step6_fill_claim_form", bot.step6_fill_claim_form),
|
||||
("step7_attach_files", bot.step7_attach_files),
|
||||
("step8_submit_claim", bot.step8_submit_claim),
|
||||
]:
|
||||
result = step_fn()
|
||||
print(f"[UnitedDH Claim] {step_name} result: {result}")
|
||||
@@ -267,14 +268,14 @@ async def start_uniteddh_claim_run(sid: str, data: dict, url: str):
|
||||
asyncio.create_task(_remove_session_later(sid, 30))
|
||||
return {"status": "error", "message": result}
|
||||
|
||||
# --- Step 8: PDF + claim number ---
|
||||
step8_result = bot.step8_save_confirmation_pdf()
|
||||
print(f"[UnitedDH Claim] step8 result: {step8_result}")
|
||||
if isinstance(step8_result, str) and step8_result.startswith("ERROR"):
|
||||
print(f"[UnitedDH Claim] step8 warning (non-fatal): {step8_result}")
|
||||
step8_result = {}
|
||||
# --- Step 9: PDF + claim number ---
|
||||
step9_result = bot.step9_save_confirmation_pdf()
|
||||
print(f"[UnitedDH Claim] step9 result: {step9_result}")
|
||||
if isinstance(step9_result, str) and step9_result.startswith("ERROR"):
|
||||
print(f"[UnitedDH Claim] step9 warning (non-fatal): {step9_result}")
|
||||
step9_result = {}
|
||||
|
||||
pdf_path = step8_result.get("pdf_path") if isinstance(step8_result, dict) else None
|
||||
pdf_path = step9_result.get("pdf_path") if isinstance(step9_result, dict) else None
|
||||
pdf_url = None
|
||||
if pdf_path:
|
||||
import os as _os
|
||||
@@ -284,7 +285,7 @@ async def start_uniteddh_claim_run(sid: str, data: dict, url: str):
|
||||
pdf_url = f"http://{url_host}:{port}/downloads/{filename}"
|
||||
print(f"[UnitedDH Claim] pdf_url: {pdf_url}")
|
||||
|
||||
claim_number = step8_result.get("claimNumber") if isinstance(step8_result, dict) else None
|
||||
claim_number = step9_result.get("claimNumber") if isinstance(step9_result, dict) else None
|
||||
|
||||
result = {
|
||||
"status": "success",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -524,7 +524,7 @@ class AutomationUnitedSCOEligibilityCheck:
|
||||
|
||||
# Step 1.2: Select Payer - UnitedHealthcare Massachusetts
|
||||
print("[UnitedSCO step1] Selecting Payer...")
|
||||
|
||||
|
||||
# First dismiss any blocking dialogs (e.g. Chrome password save)
|
||||
try:
|
||||
self.driver.execute_script("""
|
||||
@@ -534,12 +534,10 @@ class AutomationUnitedSCOEligibilityCheck:
|
||||
""")
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
payer_selected = False
|
||||
|
||||
# Strategy 1: Click the ng-select, type to search, and select the option
|
||||
|
||||
try:
|
||||
# Find the Payer ng-select by multiple selectors
|
||||
payer_selectors = [
|
||||
"//label[contains(text(),'Payer')]/following-sibling::ng-select",
|
||||
"//label[contains(text(),'Payer')]/..//ng-select",
|
||||
@@ -554,101 +552,27 @@ class AutomationUnitedSCOEligibilityCheck:
|
||||
break
|
||||
except Exception:
|
||||
continue
|
||||
|
||||
|
||||
if payer_ng_select:
|
||||
# Scroll to it and click to open
|
||||
self.driver.execute_script("arguments[0].scrollIntoView({block:'center'});", payer_ng_select)
|
||||
time.sleep(0.5)
|
||||
payer_ng_select.click()
|
||||
time.sleep(1)
|
||||
|
||||
# Type into the search input inside ng-select to filter options
|
||||
try:
|
||||
search_input = payer_ng_select.find_element(By.XPATH, ".//input[contains(@type,'text') or contains(@role,'combobox')]")
|
||||
search_input.clear()
|
||||
search_input.send_keys("UnitedHealthcare Massachusetts")
|
||||
print("[UnitedSCO step1] Typed payer search text")
|
||||
time.sleep(2)
|
||||
except Exception:
|
||||
# If no search input, try sending keys directly to ng-select
|
||||
try:
|
||||
ActionChains(self.driver).send_keys("UnitedHealthcare Mass").perform()
|
||||
print("[UnitedSCO step1] Typed payer search via ActionChains")
|
||||
time.sleep(2)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Find and click the matching option
|
||||
payer_options = self.driver.find_elements(By.XPATH,
|
||||
"//ng-dropdown-panel//div[contains(@class,'ng-option')]"
|
||||
)
|
||||
for opt in payer_options:
|
||||
opt_text = opt.text.strip()
|
||||
if "UnitedHealthcare Massachusetts" in opt_text:
|
||||
opt.click()
|
||||
print(f"[UnitedSCO step1] Selected Payer: {opt_text}")
|
||||
payer_selected = True
|
||||
break
|
||||
|
||||
if not payer_selected and payer_options:
|
||||
# Select first visible option if it contains "United"
|
||||
for opt in payer_options:
|
||||
opt_text = opt.text.strip()
|
||||
if "United" in opt_text and opt.is_displayed():
|
||||
opt.click()
|
||||
print(f"[UnitedSCO step1] Selected first matching Payer: {opt_text}")
|
||||
payer_selected = True
|
||||
break
|
||||
|
||||
# Close dropdown
|
||||
ActionChains(self.driver).send_keys(Keys.ESCAPE).perform()
|
||||
search_input = payer_ng_select.find_element(By.XPATH,
|
||||
".//input[contains(@type,'text') or contains(@role,'combobox')]")
|
||||
search_input.clear()
|
||||
search_input.send_keys("UnitedHealthcare Massachusetts")
|
||||
print("[UnitedSCO step1] Typed payer search text")
|
||||
time.sleep(2)
|
||||
search_input.send_keys(Keys.ENTER)
|
||||
print("[UnitedSCO step1] Pressed Enter to select Payer")
|
||||
time.sleep(0.5)
|
||||
payer_selected = True
|
||||
else:
|
||||
print("[UnitedSCO step1] Could not find Payer ng-select element")
|
||||
|
||||
except Exception as e:
|
||||
print(f"[UnitedSCO step1] Payer selection strategy 1 error: {e}")
|
||||
try:
|
||||
ActionChains(self.driver).send_keys(Keys.ESCAPE).perform()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Strategy 2: JavaScript direct selection if strategy 1 failed
|
||||
if not payer_selected:
|
||||
try:
|
||||
# Try clicking via JavaScript
|
||||
clicked = self.driver.execute_script("""
|
||||
// Find ng-select near the Payer label
|
||||
var labels = document.querySelectorAll('label');
|
||||
for (var i = 0; i < labels.length; i++) {
|
||||
if (labels[i].textContent.includes('Payer')) {
|
||||
var parent = labels[i].parentElement;
|
||||
var ngSelect = parent.querySelector('ng-select') || labels[i].nextElementSibling;
|
||||
if (ngSelect) {
|
||||
ngSelect.click();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
""")
|
||||
if clicked:
|
||||
time.sleep(1)
|
||||
ActionChains(self.driver).send_keys("UnitedHealthcare Mass").perform()
|
||||
time.sleep(2)
|
||||
payer_options = self.driver.find_elements(By.XPATH,
|
||||
"//ng-dropdown-panel//div[contains(@class,'ng-option')]"
|
||||
)
|
||||
for opt in payer_options:
|
||||
if "UnitedHealthcare" in opt.text and "Massachusetts" in opt.text:
|
||||
opt.click()
|
||||
print(f"[UnitedSCO step1] Selected Payer via JS: {opt.text.strip()}")
|
||||
payer_selected = True
|
||||
break
|
||||
ActionChains(self.driver).send_keys(Keys.ESCAPE).perform()
|
||||
except Exception as e:
|
||||
print(f"[UnitedSCO step1] Payer selection strategy 2 error: {e}")
|
||||
|
||||
print(f"[UnitedSCO step1] Payer selection error: {e}")
|
||||
|
||||
if not payer_selected:
|
||||
print("[UnitedSCO step1] WARNING: Could not select Payer - form may fail")
|
||||
|
||||
@@ -699,6 +623,10 @@ class AutomationUnitedSCOEligibilityCheck:
|
||||
print("[UnitedSCO step1] Select Insurance modal closed")
|
||||
except TimeoutException:
|
||||
print("[UnitedSCO step1] Modal staleness timeout — continuing anyway")
|
||||
# Wait for the Provider & Location page to begin rendering after modal closes
|
||||
WebDriverWait(self.driver, 5).until(
|
||||
EC.presence_of_element_located((By.XPATH, "//label[@for='treatmentLocation'] | //label[@for='paymentGroupId']"))
|
||||
)
|
||||
except TimeoutException:
|
||||
print("[UnitedSCO step1] Select Insurance popup not found — proceeding")
|
||||
|
||||
@@ -721,17 +649,15 @@ class AutomationUnitedSCOEligibilityCheck:
|
||||
"//label[@for='treatmentLocation']/..//ng-select"
|
||||
))
|
||||
)
|
||||
self.driver.execute_script("arguments[0].scrollIntoView({block:'end'});", location_ng)
|
||||
arrow = location_ng.find_element(By.XPATH, ".//span[contains(@class,'ng-arrow-wrapper')]")
|
||||
ActionChains(self.driver).move_to_element(arrow).click().perform()
|
||||
WebDriverWait(self.driver, 10).until(
|
||||
EC.presence_of_element_located((By.XPATH, "//ng-dropdown-panel"))
|
||||
)
|
||||
first_option = self.driver.find_element(By.XPATH,
|
||||
"//ng-dropdown-panel//div[contains(@class,'ng-option') and not(contains(@class,'disabled'))]"
|
||||
# Center in viewport so panel opens downward instead of upward
|
||||
self.driver.execute_script("arguments[0].scrollIntoView({block:'center'});", location_ng)
|
||||
arrow = location_ng.find_element(By.CSS_SELECTOR, ".ng-arrow-wrapper")
|
||||
arrow.click()
|
||||
first_option = WebDriverWait(self.driver, 5).until(
|
||||
EC.element_to_be_clickable((By.CSS_SELECTOR, ".ng-dropdown-panel .ng-option"))
|
||||
)
|
||||
option_text = first_option.text.strip()
|
||||
ActionChains(self.driver).send_keys(Keys.ARROW_DOWN).send_keys(Keys.ENTER).perform()
|
||||
first_option.click()
|
||||
print(f"[UnitedSCO step1] Selected Treatment Location: {option_text}")
|
||||
location_selected = True
|
||||
except Exception as e:
|
||||
@@ -750,17 +676,15 @@ class AutomationUnitedSCOEligibilityCheck:
|
||||
"//label[@for='paymentGroupId']/..//ng-select"
|
||||
))
|
||||
)
|
||||
self.driver.execute_script("arguments[0].scrollIntoView({block:'end'});", billing_ng)
|
||||
arrow = billing_ng.find_element(By.XPATH, ".//span[contains(@class,'ng-arrow-wrapper')]")
|
||||
ActionChains(self.driver).move_to_element(arrow).click().perform()
|
||||
WebDriverWait(self.driver, 10).until(
|
||||
EC.presence_of_element_located((By.XPATH, "//ng-dropdown-panel"))
|
||||
)
|
||||
first_option = self.driver.find_element(By.XPATH,
|
||||
"//ng-dropdown-panel//div[contains(@class,'ng-option') and not(contains(@class,'disabled'))]"
|
||||
# Center in viewport so panel opens downward instead of upward
|
||||
self.driver.execute_script("arguments[0].scrollIntoView({block:'center'});", billing_ng)
|
||||
arrow = billing_ng.find_element(By.CSS_SELECTOR, ".ng-arrow-wrapper")
|
||||
arrow.click()
|
||||
first_option = WebDriverWait(self.driver, 5).until(
|
||||
EC.element_to_be_clickable((By.CSS_SELECTOR, ".ng-dropdown-panel .ng-option"))
|
||||
)
|
||||
option_text = first_option.text.strip()
|
||||
ActionChains(self.driver).send_keys(Keys.ARROW_DOWN).send_keys(Keys.ENTER).perform()
|
||||
first_option.click()
|
||||
print(f"[UnitedSCO step1] Selected Billing Entity: {option_text}")
|
||||
billing_selected = True
|
||||
except Exception as e:
|
||||
|
||||
Reference in New Issue
Block a user