fix: UnitedDH pre-auth number extraction, service lines saved, RCT combo buttons

- Pre-auth step9: scan all table cells alphanumeric-first (A0260616190876 format),
  URL extraction, body scan fallback with debug logging
- Pre-auth route: save service lines (totalBilled) when creating PREAUTH claim record
  so claim page shows correct billed amount after selecting patient
- Pre-auth processor: read pdf_path fallback alongside pdf_url from Selenium result
- UnitedDH/SCO workers: billing entity selection via direct paymentGroupId click,
  Summit Dental Care first with fallback, Escape to close dropdown
- Pre-auth form: remove Other Insurance step (not present on pre-auth page),
  file upload direct to hidden input without button click
- Pre-auth step8: JS click + Submit Authorization in XPath, Continue via [last()] + JS click
- RCT combo buttons added (pre-auth form only): RCT Ant/Post/Crown, PreM/Post/Crown,
  Mol/Post/Crown; claim form excludes these three combos

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
ff
2026-06-16 17:34:45 -04:00
parent a04176538e
commit 43340ab39d
8 changed files with 207 additions and 112 deletions

View File

@@ -610,22 +610,34 @@ class AutomationUnitedDHClaimSubmit:
print("[UnitedDH Claim] step1: Selecting Billing Entity...")
billing_selected = False
try:
billing_ng = WebDriverWait(self.driver, 10).until(
EC.element_to_be_clickable((By.XPATH,
"//label[@for='paymentGroupId']/following-sibling::ng-select | "
"//label[@for='paymentGroupId']/..//ng-select"
))
)
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()
first_option.click()
print(f"[UnitedDH Claim] step1: Selected Billing Entity: {option_text}")
billing_selected = True
taxonomy_input = self.driver.find_element(By.ID, "paymentGroupId")
if taxonomy_input.is_displayed():
self.driver.execute_script("arguments[0].scrollIntoView({block:'center'});", taxonomy_input)
taxonomy_input.click()
print("[UnitedDH Claim] step1: Clicked Billing Entity dropdown")
time.sleep(1)
try:
summit_option = WebDriverWait(self.driver, 5).until(
EC.element_to_be_clickable((By.XPATH,
"//ng-dropdown-panel//div[contains(@class,'ng-option') and contains(.,'Summit Dental Care')]"
))
)
summit_option.click()
print("[UnitedDH Claim] step1: Selected Billing Entity: Summit Dental Care")
billing_selected = True
except TimeoutException:
try:
first_option = self.driver.find_element(By.XPATH,
"//ng-dropdown-panel//div[contains(@class,'ng-option')]"
)
option_text = first_option.text.strip()
first_option.click()
print(f"[UnitedDH Claim] step1: Selected Billing Entity: {option_text}")
billing_selected = True
except Exception:
print("[UnitedDH Claim] step1: No options available in Billing Entity dropdown")
ActionChains(self.driver).send_keys(Keys.ESCAPE).perform()
time.sleep(1)
except Exception as e:
print(f"[UnitedDH Claim] step1: Billing Entity selection failed: {e}")

View File

@@ -566,22 +566,34 @@ class AutomationUnitedDHPreAuth:
print("[UnitedDH PreAuth] step1: Selecting Billing Entity...")
billing_selected = False
try:
billing_ng = WebDriverWait(self.driver, 10).until(
EC.element_to_be_clickable((By.XPATH,
"//label[@for='paymentGroupId']/following-sibling::ng-select | "
"//label[@for='paymentGroupId']/..//ng-select"
))
)
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()
first_option.click()
print(f"[UnitedDH PreAuth] step1: Selected Billing Entity: {option_text}")
billing_selected = True
taxonomy_input = self.driver.find_element(By.ID, "paymentGroupId")
if taxonomy_input.is_displayed():
self.driver.execute_script("arguments[0].scrollIntoView({block:'center'});", taxonomy_input)
taxonomy_input.click()
print("[UnitedDH PreAuth] step1: Clicked Billing Entity dropdown")
time.sleep(1)
try:
summit_option = WebDriverWait(self.driver, 5).until(
EC.element_to_be_clickable((By.XPATH,
"//ng-dropdown-panel//div[contains(@class,'ng-option') and contains(.,'Summit Dental Care')]"
))
)
summit_option.click()
print("[UnitedDH PreAuth] step1: Selected Billing Entity: Summit Dental Care")
billing_selected = True
except TimeoutException:
try:
first_option = self.driver.find_element(By.XPATH,
"//ng-dropdown-panel//div[contains(@class,'ng-option')]"
)
option_text = first_option.text.strip()
first_option.click()
print(f"[UnitedDH PreAuth] step1: Selected Billing Entity: {option_text}")
billing_selected = True
except Exception:
print("[UnitedDH PreAuth] step1: No options available in Billing Entity dropdown")
ActionChains(self.driver).send_keys(Keys.ESCAPE).perform()
time.sleep(1)
except Exception as e:
print(f"[UnitedDH PreAuth] step1: Billing Entity selection failed: {e}")
@@ -589,9 +601,10 @@ class AutomationUnitedDHPreAuth:
print("[UnitedDH PreAuth] step1: WARNING - Could not select Billing Entity")
continue_btn2 = WebDriverWait(self.driver, 10).until(
EC.element_to_be_clickable((By.XPATH, "//button[contains(text(),'Continue')]"))
EC.element_to_be_clickable((By.XPATH, "(//button[contains(normalize-space(.),'Continue')])[last()]"))
)
continue_btn2.click()
self.driver.execute_script("arguments[0].scrollIntoView({block:'center'});", continue_btn2)
self.driver.execute_script("arguments[0].click();", continue_btn2)
print("[UnitedDH PreAuth] step1: Clicked Continue (Provider & Location) → Selected Patient page")
time.sleep(5)
@@ -648,7 +661,7 @@ class AutomationUnitedDHPreAuth:
for by, selector in preauth_selectors:
try:
btn = WebDriverWait(self.driver, 5).until(
btn = WebDriverWait(self.driver, 15).until(
EC.element_to_be_clickable((by, selector))
)
self.driver.execute_script("arguments[0].scrollIntoView({block:'center'});", btn)
@@ -954,23 +967,6 @@ class AutomationUnitedDHPreAuth:
except Exception as e:
print(f"[UnitedDH PreAuth] step6: could not click span Add for row {idx}: {e}")
# Other coverage: click "No" (second radio button)
try:
print("[UnitedDH PreAuth] step6: selecting 'No' for Other coverage")
radio_buttons = WebDriverWait(self.driver, 8).until(
lambda d: d.find_elements(By.XPATH, "//input[@type='radio']")
)
if len(radio_buttons) >= 2:
no_radio = radio_buttons[1]
self.driver.execute_script("arguments[0].scrollIntoView({block:'center'});", no_radio)
no_radio.click()
print("[UnitedDH PreAuth] step6: Clicked 'No' (2nd radio) for Other coverage")
else:
print(f"[UnitedDH PreAuth] step6: Only {len(radio_buttons)} radio button(s) found — skipping")
time.sleep(0.5)
except Exception as e:
print(f"[UnitedDH PreAuth] step6: Could not click 'No' for Other coverage (non-fatal): {e}")
print("[UnitedDH PreAuth] step6: Done filling pre-auth form")
return "OK"
@@ -1018,17 +1014,10 @@ class AutomationUnitedDHPreAuth:
print(f"[UnitedDH PreAuth] step7: Attaching: {abs_path}")
try:
upload_btn = WebDriverWait(self.driver, 10).until(
EC.element_to_be_clickable((By.ID, "upload-document"))
)
self.driver.execute_script("arguments[0].scrollIntoView({block:'center'});", upload_btn)
upload_btn.click()
time.sleep(1)
file_input = WebDriverWait(self.driver, 8).until(
EC.presence_of_element_located((By.XPATH, "//input[@type='file']"))
)
self.driver.execute_script("arguments[0].style.display='block';", file_input)
self.driver.execute_script("arguments[0].removeAttribute('class');", file_input)
file_input.send_keys(abs_path)
time.sleep(1.5)
print(f"[UnitedDH PreAuth] step7: Attached: {os.path.basename(abs_path)}")
@@ -1052,18 +1041,16 @@ class AutomationUnitedDHPreAuth:
submit_btn = WebDriverWait(self.driver, 15).until(
EC.element_to_be_clickable((By.XPATH,
"//button[contains(normalize-space(.),'Submit Pre-Auth') or "
"//button[contains(normalize-space(.),'Submit Authorization') or "
"contains(normalize-space(.),'Submit Pre-Auth') or "
"contains(normalize-space(.),'Submit Pre Authorization') or "
"contains(normalize-space(.),'Submit Pre-Authorization') or "
"contains(normalize-space(.),'Submit Claim')] | "
"//button[contains(@class,'btn-primary') and ("
"contains(normalize-space(text()),'Submit Pre') or "
"contains(normalize-space(text()),'Submit Claim'))]"
"contains(normalize-space(.),'Submit Claim')]"
))
)
self.driver.execute_script("arguments[0].scrollIntoView({block:'center'});", submit_btn)
time.sleep(0.5)
submit_btn.click()
self.driver.execute_script("arguments[0].click();", submit_btn)
print("[UnitedDH PreAuth] step8: Clicked Submit — waiting for post-submit popup")
time.sleep(3)
@@ -1109,33 +1096,68 @@ class AutomationUnitedDHPreAuth:
time.sleep(4)
preauth_number = None
try:
first_ref = WebDriverWait(self.driver, 20).until(
EC.presence_of_element_located((By.XPATH,
"(//table//tr[not(th)]/td[2] | "
"//table//tr[td]/td[contains(normalize-space(.),'2026') or "
" contains(normalize-space(.),'2025')])[1]"
))
)
ref_text = first_ref.text.strip()
match = re.search(r'\b(\d{14})\b', ref_text)
if match:
preauth_number = match.group(1)
else:
match = re.search(r'\b(\d{10,})\b', ref_text)
if match:
preauth_number = match.group(1)
print(f"[UnitedDH PreAuth] step9: Pre-auth number: {preauth_number!r} (cell: {ref_text!r})")
except Exception as e:
print(f"[UnitedDH PreAuth] step9: Could not read first-row reference number: {e}")
# 1. Try URL — pre-auth ID often appears in the URL path
current_url = self.driver.current_url
url_match = re.search(r'/(\d{6,})', current_url)
if url_match:
preauth_number = url_match.group(1)
print(f"[UnitedDH PreAuth] step9: Pre-auth number from URL: {preauth_number!r}")
# 2. Scan all table cells and log them for debugging
if not preauth_number:
try:
all_cells = self.driver.find_elements(By.XPATH, "//table//tr[td]/td")
cell_texts = [c.text.strip() for c in all_cells if c.text.strip()]
print(f"[UnitedDH PreAuth] step9: Table cells: {cell_texts[:20]}")
# Try each cell — alphanumeric first (e.g. A0260616190876), then pure digits
for cell_text in cell_texts:
# Alphanumeric like A0260616190876 or PA12345678
m = re.search(r'\b([A-Z]{1,4}\d{6,})\b', cell_text)
if m:
preauth_number = m.group(1)
print(f"[UnitedDH PreAuth] step9: Pre-auth number (alphanumeric): {preauth_number!r}")
break
# 14-digit pure numeric ref
m = re.search(r'\b(\d{14})\b', cell_text)
if m:
preauth_number = m.group(1)
print(f"[UnitedDH PreAuth] step9: Pre-auth number (14-digit): {preauth_number!r}")
break
# 8-13 digit fallback
m = re.search(r'\b(\d{8,13})\b', cell_text)
if m:
preauth_number = m.group(1)
print(f"[UnitedDH PreAuth] step9: Pre-auth number (8-13 digit): {preauth_number!r}")
break
except Exception as e:
print(f"[UnitedDH PreAuth] step9: Table cell scan failed: {e}")
# 3. Full body scan fallback
if not preauth_number:
try:
body_text = self.driver.find_element(By.TAG_NAME, "body").text
match = re.search(r'\b(\d{14})\b', body_text)
if match:
preauth_number = match.group(1)
print(f"[UnitedDH PreAuth] step9: Pre-auth number (body scan): {preauth_number}")
except Exception:
pass
print(f"[UnitedDH PreAuth] step9: Body text (first 500 chars): {body_text[:500]!r}")
m = re.search(r'\b([A-Z]{1,4}\d{6,})\b', body_text)
if m:
preauth_number = m.group(1)
else:
m = re.search(r'\b(\d{14})\b', body_text)
if m:
preauth_number = m.group(1)
else:
m = re.search(r'\b(\d{8,13})\b', body_text)
if m:
preauth_number = m.group(1)
if preauth_number:
print(f"[UnitedDH PreAuth] step9: Pre-auth number (body scan): {preauth_number!r}")
else:
print("[UnitedDH PreAuth] step9: No pre-auth number found in body")
except Exception as e:
print(f"[UnitedDH PreAuth] step9: Body scan failed: {e}")
print(f"[UnitedDH PreAuth] step9: Final pre-auth number: {preauth_number!r}")
shared_downloads = os.path.join(_SERVICE_DIR, "downloads")
os.makedirs(shared_downloads, exist_ok=True)

View File

@@ -670,23 +670,34 @@ class AutomationUnitedSCOEligibilityCheck:
print("[UnitedSCO step1] Selecting Billing Entity...")
billing_selected = False
try:
billing_ng = WebDriverWait(self.driver, 10).until(
EC.element_to_be_clickable((By.XPATH,
"//label[@for='paymentGroupId']/following-sibling::ng-select | "
"//label[@for='paymentGroupId']/..//ng-select"
))
)
# 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()
first_option.click()
print(f"[UnitedSCO step1] Selected Billing Entity: {option_text}")
billing_selected = True
taxonomy_input = self.driver.find_element(By.ID, "paymentGroupId")
if taxonomy_input.is_displayed():
self.driver.execute_script("arguments[0].scrollIntoView({block:'center'});", taxonomy_input)
taxonomy_input.click()
print("[UnitedSCO step1] Clicked Billing Entity dropdown")
time.sleep(1)
try:
summit_option = WebDriverWait(self.driver, 5).until(
EC.element_to_be_clickable((By.XPATH,
"//ng-dropdown-panel//div[contains(@class,'ng-option') and contains(.,'Summit Dental Care')]"
))
)
summit_option.click()
print("[UnitedSCO step1] Selected Billing Entity: Summit Dental Care")
billing_selected = True
except TimeoutException:
try:
first_option = self.driver.find_element(By.XPATH,
"//ng-dropdown-panel//div[contains(@class,'ng-option')]"
)
option_text = first_option.text.strip()
first_option.click()
print(f"[UnitedSCO step1] Selected Billing Entity: {option_text}")
billing_selected = True
except Exception:
print("[UnitedSCO step1] No options available in Billing Entity dropdown")
ActionChains(self.driver).send_keys(Keys.ESCAPE).perform()
time.sleep(1)
except Exception as e:
print(f"[UnitedSCO step1] Billing Entity selection failed: {e}")