From 5d1275d6280b1cd6ba3999bbdf8a754a2bc42956 Mon Sep 17 00:00:00 2001 From: Gitead Date: Sat, 18 Apr 2026 09:25:02 -0400 Subject: [PATCH] fix: UnitedSCO status always inactive and missing patient name --- ...lenium_UnitedSCO_eligibilityCheckWorker.py | 117 +++++++++++++++--- 1 file changed, 100 insertions(+), 17 deletions(-) diff --git a/apps/SeleniumService/selenium_UnitedSCO_eligibilityCheckWorker.py b/apps/SeleniumService/selenium_UnitedSCO_eligibilityCheckWorker.py index 1ed3f1d2..cb68bb72 100644 --- a/apps/SeleniumService/selenium_UnitedSCO_eligibilityCheckWorker.py +++ b/apps/SeleniumService/selenium_UnitedSCO_eligibilityCheckWorker.py @@ -157,7 +157,22 @@ class AutomationUnitedSCOEligibilityCheck: # Step 2: Fill in credentials on B2C login page if "b2clogin.com" in current_url or "login" in current_url.lower(): print("[UnitedSCO login] On B2C login page - filling credentials") - + + # Check if we're already on the phone verification ("Text Me") page + # This happens if the browser session was left on this page + try: + send_code_btn = self.driver.find_element(By.XPATH, + "//button[@id='sendCode'] | //input[@id='sendCode'] | " + "//button[contains(text(),'Text Me') or contains(text(),'Send Code')]" + ) + if send_code_btn.is_displayed(): + print("[UnitedSCO login] Already on phone verification page - clicking 'Text Me'") + self.driver.execute_script("arguments[0].click();", send_code_btn) + time.sleep(3) + return "OTP_REQUIRED" + except Exception: + pass + try: # Find email field by id="signInName" (Azure B2C specific) email_field = WebDriverWait(self.driver, 10).until( @@ -231,7 +246,49 @@ class AutomationUnitedSCOEligibilityCheck: # Click Continue continue_btn.click() print("[UnitedSCO login] Clicked 'Continue' on MFA selection page") - time.sleep(5) # Wait for OTP to be sent + time.sleep(3) # Wait for phone verification page to load + + # Click "Text Me" button on the phone verification page + # Azure B2C uses id="sendCode" for this button + try: + text_me_btn = WebDriverWait(self.driver, 8).until( + EC.element_to_be_clickable((By.XPATH, + "//button[@id='sendCode'] | " + "//input[@id='sendCode'] | " + "//button[contains(text(),'Text Me') or contains(text(),'Send Code') or contains(text(),'Send me')] | " + "//input[@value='Text Me' or @value='Send Code' or @value='Send me']" + )) + ) + self.driver.execute_script("arguments[0].scrollIntoView({block:'center'});", text_me_btn) + time.sleep(0.5) + text_me_btn.click() + print("[UnitedSCO login] Clicked 'Text Me' / 'Send Code' button") + time.sleep(3) # Wait for SMS to be sent + except TimeoutException: + print("[UnitedSCO login] No 'Text Me' button found - trying JS fallback") + try: + clicked = self.driver.execute_script(""" + var btn = document.getElementById('sendCode'); + if (btn) { btn.click(); return 'sendCode clicked'; } + var all = document.querySelectorAll('button, input[type="button"], input[type="submit"]'); + for (var i = 0; i < all.length; i++) { + var t = (all[i].textContent || all[i].value || '').toLowerCase(); + if (t.includes('text me') || t.includes('send code') || t.includes('send me')) { + all[i].click(); + return 'clicked: ' + t; + } + } + return null; + """) + if clicked: + print(f"[UnitedSCO login] JS 'Text Me' click result: {clicked}") + time.sleep(3) + else: + print("[UnitedSCO login] WARNING: Could not find 'Text Me' button via JS either") + except Exception as js_err: + print(f"[UnitedSCO login] JS click error: {js_err}") + except Exception as e: + print(f"[UnitedSCO login] Error clicking 'Text Me': {e}") except Exception: pass # No MFA selection page - proceed normally @@ -784,25 +841,44 @@ class AutomationUnitedSCOEligibilityCheck: patientName = f"{self.firstName} {self.lastName}".strip() foundMemberId = self.memberId # Use provided memberId as default - # Extract eligibility status + # Extract eligibility status — try multiple text patterns try: status_elem = WebDriverWait(self.driver, 10).until( EC.presence_of_element_located((By.XPATH, - "//*[contains(text(),'Member Eligible') or contains(text(),'member eligible')]" + "//*[contains(text(),'Member Eligible') or contains(text(),'member eligible') or " + "contains(text(),'Eligible') or contains(text(),'eligible') or " + "contains(text(),'Ineligible') or contains(text(),'ineligible') or " + "contains(text(),'Not Eligible') or contains(text(),'not eligible')]" )) ) status_text = status_elem.text.strip().lower() - print(f"[UnitedSCO step2] Found status: {status_text}") - - if "eligible" in status_text: - eligibilityText = "active" - elif "ineligible" in status_text or "not eligible" in status_text: + print(f"[UnitedSCO step2] Found status element text: {status_text}") + + if "ineligible" in status_text or "not eligible" in status_text: eligibilityText = "inactive" - + elif "eligible" in status_text: + eligibilityText = "active" + except TimeoutException: - print("[UnitedSCO step2] Eligibility status badge not found") + print("[UnitedSCO step2] Eligibility status element not found via text — trying page text scan") except Exception as e: print(f"[UnitedSCO step2] Error extracting status: {e}") + + # Fallback: scan page text for eligibility keywords + if eligibilityText == "unknown": + try: + body_text = self.driver.find_element(By.TAG_NAME, "body").text.lower() + if "member eligible" in body_text or "member is eligible" in body_text: + eligibilityText = "active" + print("[UnitedSCO step2] Status from page text: active (member eligible)") + elif "not eligible" in body_text or "ineligible" in body_text or "member ineligible" in body_text: + eligibilityText = "inactive" + print("[UnitedSCO step2] Status from page text: inactive") + elif "eligible" in body_text: + eligibilityText = "active" + print("[UnitedSCO step2] Status from page text: active (eligible found)") + except Exception as e: + print(f"[UnitedSCO step2] Page text status scan error: {e}") print(f"[UnitedSCO step2] Eligibility status: {eligibilityText}") @@ -842,6 +918,10 @@ class AutomationUnitedSCOEligibilityCheck: "//div[contains(@class,'patient')]//h3 | //div[contains(@class,'patient')]//h4", "//*[contains(@class,'eligibility__banner')]//h3 | //*[contains(@class,'eligibility__banner')]//h4", "//*[contains(@class,'banner__patient')]", + # Heading elements near "Selected Patient" label + "//*[contains(text(),'Selected Patient')]/following-sibling::*[self::h1 or self::h2 or self::h3 or self::h4 or self::strong or self::p][1]", + "//*[contains(text(),'Selected Patient')]/..//*[self::h1 or self::h2 or self::h3 or self::h4 or self::strong][1]", + "//*[contains(text(),'Selected Patient')]/parent::*/following-sibling::*[1]//*[self::h3 or self::h4 or self::p or self::span][1]", ] for sel in name_selectors: try: @@ -863,13 +943,16 @@ class AutomationUnitedSCOEligibilityCheck: # IMPORTANT: Use [^\n] to avoid matching across newlines (e.g. picking up "Member Eligible") if not name_extracted: name_patterns = [ - # Name on the line right after "Selected Patient" - r'Selected Patient\s*\n\s*([A-Z][A-Za-z\-\']+(?: [A-Z][A-Za-z\-\']+)+)', + # Name on the line right after "Selected Patient" (on same or next line) + r'Selected Patient[:\s]*\n\s*([A-Z][A-Za-z\-\']+(?: [A-Z][A-Za-z\-\']+)+)', + r'Selected Patient[:\s]+([A-Z][A-Za-z\-\']+(?: [A-Z][A-Za-z\-\']+)+)', r'Patient Name\s*[\n:]\s*([A-Z][A-Za-z\-\']+(?: [A-Z][A-Za-z\-\']+)+)', # "LASTNAME, FIRSTNAME" format r'Selected Patient\s*\n\s*([A-Z][A-Za-z\-\']+,\s*[A-Z][A-Za-z\-\']+)', - # Name on the line right before "Member Eligible" or "Member ID" - r'\n([A-Z][A-Za-z\-\']+(?: [A-Z]\.?)? [A-Z][A-Za-z\-\']+)\n(?:Member|Date Of Birth|DOB)', + # Name on the line right before "Member Eligible", "Eligible", "Member ID", or "Date Of Birth" + r'\n([A-Z][A-Za-z\-\']+(?: [A-Z]\.?)? [A-Z][A-Za-z\-\']+)\n(?:Member|Eligible|Date Of Birth|DOB)', + # Name before DOB in any case + r'([A-Z][A-Za-z\-\']+(?:\s+[A-Z][A-Za-z\-\']+)+)\n\d{2}/\d{2}/\d{4}', ] for pattern in name_patterns: try: @@ -877,9 +960,9 @@ class AutomationUnitedSCOEligibilityCheck: if name_match: candidate = name_match.group(1).strip() # Validate: not too long, not a header/label, and doesn't contain "Eligible"/"Member"/"Patient" - skip_words = ("Selected Patient", "Patient Name", "Patient Information", + skip_words = ("Selected Patient", "Patient Name", "Patient Information", "Member Eligible", "Member ID", "Date Of Birth") - if (len(candidate) < 50 and candidate not in skip_words + if (len(candidate) < 50 and candidate not in skip_words and "Eligible" not in candidate and "Member" not in candidate): patientName = candidate name_extracted = True