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:
ff
2026-05-30 14:46:51 -04:00
parent cda00f5f8a
commit 70f36fc13c
4 changed files with 541 additions and 434 deletions

View File

@@ -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

View File

@@ -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: