From c952f798537381840a496eee1bf67ad10a9d1e12 Mon Sep 17 00:00:00 2001 From: ff Date: Fri, 29 May 2026 18:04:16 -0400 Subject: [PATCH] fix: United SCO provider/location page selection + DOB display format - United SCO eligibility: add Treatment Location step before Billing Entity on Provider & Location page; both use ng-arrow-wrapper ActionChains click + ARROW_DOWN/ENTER keyboard selection to handle upward-opening panels - Use visibility_of_element_located for Billing Entity label wait so code waits for page to fully render after Select Insurance modal closes - DOB (and all dates) now display as MM/DD/YYYY instead of Mon DD, YYYY Co-Authored-By: Claude Sonnet 4.6 --- apps/Frontend/src/utils/dateUtils.ts | 20 +++--- ...lenium_UnitedSCO_eligibilityCheckWorker.py | 72 +++++++++++++------ 2 files changed, 61 insertions(+), 31 deletions(-) diff --git a/apps/Frontend/src/utils/dateUtils.ts b/apps/Frontend/src/utils/dateUtils.ts index e75b4e08..c324f77b 100755 --- a/apps/Frontend/src/utils/dateUtils.ts +++ b/apps/Frontend/src/utils/dateUtils.ts @@ -128,7 +128,7 @@ function isDateOnlyString(s: string): boolean { // ---------- formatDateToHumanReadable ---------- /** - * Frontend-safe human readable formatter. + * Frontend-safe date formatter. Output format: "MM/DD/YYYY" (e.g. "03/01/1980"). * * Rules: * - If input is a date-only string "YYYY-MM-DD", format it directly (no TZ math). @@ -136,26 +136,24 @@ function isDateOnlyString(s: string): boolean { * - If input is any other string (ISO/timestamp), DO NOT call new Date(isoString) directly * for display. Instead, use parseLocalDate(dateInput) to extract the local calendar day * (strip time portion) and render that. This prevents off-by-one day drift. - * - * Output example: "Oct 7, 2025" */ export function formatDateToHumanReadable(dateInput?: string | Date): string { if (!dateInput) return "N/A"; - // date-only string -> show as-is using MONTH_SHORT + // date-only string "YYYY-MM-DD" -> m and d are already zero-padded if (typeof dateInput === "string" && isDateOnlyString(dateInput)) { const [y, m, d] = dateInput.split("-"); if (!y || !m || !d) return "Invalid Date"; - return `${MONTH_SHORT[parseInt(m, 10) - 1]} ${d}, ${y}`; + return `${m}/${d}/${y}`; } // Date object -> use local calendar fields if (dateInput instanceof Date) { if (isNaN(dateInput.getTime())) return "Invalid Date"; - const dd = String(dateInput.getDate()); - const mm = MONTH_SHORT[dateInput.getMonth()]; + const dd = String(dateInput.getDate()).padStart(2, "0"); + const mm = String(dateInput.getMonth() + 1).padStart(2, "0"); const yy = dateInput.getFullYear(); - return `${mm} ${dd}, ${yy}`; + return `${mm}/${dd}/${yy}`; } // Other string (likely ISO/timestamp) -> normalize via parseLocalDate @@ -163,10 +161,10 @@ export function formatDateToHumanReadable(dateInput?: string | Date): string { if (typeof dateInput === "string") { try { const localDate = parseLocalDate(dateInput); - const dd = String(localDate.getDate()); - const mm = MONTH_SHORT[localDate.getMonth()]; + const dd = String(localDate.getDate()).padStart(2, "0"); + const mm = String(localDate.getMonth() + 1).padStart(2, "0"); const yy = localDate.getFullYear(); - return `${mm} ${dd}, ${yy}`; + return `${mm}/${dd}/${yy}`; } catch (err) { console.error("Invalid date input provided:", dateInput, err); return "Invalid Date"; diff --git a/apps/SeleniumService/selenium_UnitedSCO_eligibilityCheckWorker.py b/apps/SeleniumService/selenium_UnitedSCO_eligibilityCheckWorker.py index a69e93ed..a7fcd449 100644 --- a/apps/SeleniumService/selenium_UnitedSCO_eligibilityCheckWorker.py +++ b/apps/SeleniumService/selenium_UnitedSCO_eligibilityCheckWorker.py @@ -702,45 +702,77 @@ class AutomationUnitedSCOEligibilityCheck: except TimeoutException: print("[UnitedSCO step1] Select Insurance popup not found — proceeding") - # Step 1.5: Provider & Location page — select Treatment Location (first dropdown), - # page auto-fills the rest, then click Continue + # Step 1.5: Provider & Location page — select Billing Entity dropdown (paymentGroupId), + # choose the only available option, then click Continue print("[UnitedSCO step1] Waiting for Provider & Location page...") try: - # Wait for the Continue button to confirm the page loaded - continue_btn2 = WebDriverWait(self.driver, 15).until( - EC.element_to_be_clickable((By.XPATH, "//button[contains(text(),'Continue')]")) + # Wait for the Billing Entity label to be visible — ensures page has fully rendered + WebDriverWait(self.driver, 20).until( + EC.visibility_of_element_located((By.XPATH, "//label[@for='paymentGroupId']")) ) - # Select Treatment Location — click the dropdown and pick the first option; - # the page will auto-fill Billing Entity and other fields automatically + # --- Treatment Location --- print("[UnitedSCO step1] Selecting Treatment Location...") location_selected = False try: - location_ng = self.driver.find_element(By.XPATH, - "//label[contains(text(),'Treatment Location') or contains(text(),'treatment location')]" - "/..//ng-select | " - "(//ng-select)[1]" - ) - self.driver.execute_script("arguments[0].scrollIntoView({block:'center'});", location_ng) - time.sleep(0.3) - location_ng.click() - time.sleep(1) - first_option = WebDriverWait(self.driver, 5).until( + location_ng = WebDriverWait(self.driver, 10).until( EC.element_to_be_clickable((By.XPATH, - "//ng-dropdown-panel//div[contains(@class,'ng-option') and not(contains(@class,'disabled'))]" + "//label[@for='treatmentLocation']/following-sibling::ng-select | " + "//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'))]" + ) option_text = first_option.text.strip() - first_option.click() + ActionChains(self.driver).send_keys(Keys.ARROW_DOWN).send_keys(Keys.ENTER).perform() print(f"[UnitedSCO step1] Selected Treatment Location: {option_text}") location_selected = True - time.sleep(1) # wait for page to auto-fill remaining fields except Exception as e: print(f"[UnitedSCO step1] Treatment Location selection failed: {e}") if not location_selected: print("[UnitedSCO step1] WARNING: Could not select Treatment Location — continuing anyway") + # --- Billing Entity --- + 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" + )) + ) + 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'))]" + ) + option_text = first_option.text.strip() + ActionChains(self.driver).send_keys(Keys.ARROW_DOWN).send_keys(Keys.ENTER).perform() + print(f"[UnitedSCO step1] Selected Billing Entity: {option_text}") + billing_selected = True + except Exception as e: + print(f"[UnitedSCO step1] Billing Entity selection failed: {e}") + + if not billing_selected: + print("[UnitedSCO step1] WARNING: Could not select Billing Entity — continuing anyway") + + # Re-find Continue button after location selection to avoid stale element reference + continue_btn2 = WebDriverWait(self.driver, 10).until( + EC.element_to_be_clickable((By.XPATH, "//button[contains(text(),'Continue')]")) + ) continue_btn2.click() print("[UnitedSCO step1] Clicked Continue button (Provider & Location)") time.sleep(5)