diff --git a/apps/Frontend/src/components/claims/claim-form.tsx b/apps/Frontend/src/components/claims/claim-form.tsx index a9e09d08..087b90a7 100755 --- a/apps/Frontend/src/components/claims/claim-form.tsx +++ b/apps/Frontend/src/components/claims/claim-form.tsx @@ -1537,6 +1537,8 @@ export function ClaimForm({ insuranceProvider: "United Ucard", appointmentId: appointmentIdToUse, insuranceSiteKey: "UNITED_UCARD", + firstName: patient?.firstName ?? "", + lastName: patient?.lastName ?? "", claimId: createdClaim.id, claimFiles: claimFilesMeta, }); diff --git a/apps/SeleniumService/selenium_UnitedUcard_claimSubmitWorker.py b/apps/SeleniumService/selenium_UnitedUcard_claimSubmitWorker.py index 2105e1f8..aeeb5941 100644 --- a/apps/SeleniumService/selenium_UnitedUcard_claimSubmitWorker.py +++ b/apps/SeleniumService/selenium_UnitedUcard_claimSubmitWorker.py @@ -16,7 +16,7 @@ service lines / attach files / submit / save confirmation PDF) are left as TODO stubs — fill these in once we know the exact DOM for the claim submission flow on the UHC Dental provider dashboard. """ -from selenium.common.exceptions import WebDriverException, TimeoutException +from selenium.common.exceptions import WebDriverException, TimeoutException, NoSuchElementException from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC @@ -382,12 +382,12 @@ class AutomationUnitedUcardClaimSubmit: def step3_fill_patient_information(self): """ - Fill the Patient Information step: Date of Service, Subscriber ID, - Date of Birth, then click Search to look up the member. + Fill the Patient Information step: Date of Service, choose the + First Name + Last Name + DOB search, then First/Last Name, Date of Birth, then click Search to look up the member. Confirmed against the live site (2026-09-13): - + / """ @@ -402,12 +402,30 @@ class AutomationUnitedUcardClaimSubmit: return "ERROR: Date of Service field not found on Patient Information step" try: - subscriber_id_field = self.driver.find_element(By.CSS_SELECTOR, "input.subscriber-id") - subscriber_id_field.clear() - subscriber_id_field.send_keys(self.memberId) - print(f"[UnitedUcard Claim] Entered Subscriber ID: {self.memberId}") + name_radio = WebDriverWait(self.driver, 10).until( + EC.presence_of_element_located((By.CSS_SELECTOR, "input.searchname[name='member-search'][value='name']")) + ) + self.driver.execute_script("arguments[0].scrollIntoView({block:'center'});", name_radio) + try: + name_radio.click() + except Exception: + self.driver.execute_script("arguments[0].click();", name_radio) + print("[UnitedUcard Claim] Selected 'First Name + Last Name + DOB' search") + except TimeoutException: + return "ERROR: 'First Name + Last Name + DOB' radio not found on Patient Information step" + + try: + fname_field = WebDriverWait(self.driver, 10).until( + EC.element_to_be_clickable((By.CSS_SELECTOR, "input.member-fname")) + ) + fname_field.clear() + fname_field.send_keys(self.firstName) + lname_field = self.driver.find_element(By.CSS_SELECTOR, "input.member-lname") + lname_field.clear() + lname_field.send_keys(self.lastName) + print(f"[UnitedUcard Claim] Entered name: {self.firstName} {self.lastName}") except Exception as e: - return f"ERROR: Subscriber ID field not found on Patient Information step: {e}" + return f"ERROR: First/Last Name fields not found on Patient Information step: {e}" try: dob_field = self.driver.find_element(By.CSS_SELECTOR, "input.date-of-birth") @@ -646,6 +664,16 @@ class AutomationUnitedUcardClaimSubmit: except TimeoutException: return "ERROR: 'Add a Procedure' button not found" + def _wait_visible(self, element_id, timeout=10): + """Return the element once visible, or None if it never appears + (the portal only shows tooth fields for certain procedure codes).""" + try: + return WebDriverWait(self.driver, timeout).until( + lambda d: next((e for e in d.find_elements(By.ID, element_id) if e.is_displayed()), None) + ) + except TimeoutException: + return None + def _fill_and_save_procedure(self, line: dict, idx: int): """ Fill one procedure row (Procedure Code, Date of Service, Procedure @@ -690,6 +718,28 @@ class AutomationUnitedUcardClaimSubmit: except Exception as e: return f"ERROR: Procedure Fee field not found for line {idx + 1}: {e}" + # Tooth Number / Surface are driven by the app's claim data: only wait + # for and fill them when the service line actually has a value. + tooth = str(line.get("toothNumber") or line.get("tooth") or "").strip() + if tooth: + tooth_field = self._wait_visible("toothNum") + if tooth_field: + tooth_field.clear() + tooth_field.send_keys(tooth) + print(f"[UnitedUcard Claim] Entered Tooth Number: {tooth}") + else: + print(f"[UnitedUcard Claim] Tooth Number field did not appear for {procedure_code}; skipped") + + surface = str(line.get("toothSurface") or line.get("surface") or "").strip().upper() + if surface: + surface_field = self._wait_visible("toothSurf") + if surface_field: + surface_field.clear() + surface_field.send_keys(surface) + print(f"[UnitedUcard Claim] Entered Tooth Surface: {surface}") + else: + print(f"[UnitedUcard Claim] Tooth Surface field did not appear for {procedure_code}; skipped") + try: save_btn = WebDriverWait(self.driver, 10).until( EC.element_to_be_clickable((By.XPATH, "//*[@onclick='saveProcCode()']"))