fix: UnitedSCO status always inactive and missing patient name
This commit is contained in:
@@ -157,7 +157,22 @@ class AutomationUnitedSCOEligibilityCheck:
|
|||||||
# Step 2: Fill in credentials on B2C login page
|
# Step 2: Fill in credentials on B2C login page
|
||||||
if "b2clogin.com" in current_url or "login" in current_url.lower():
|
if "b2clogin.com" in current_url or "login" in current_url.lower():
|
||||||
print("[UnitedSCO login] On B2C login page - filling credentials")
|
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:
|
try:
|
||||||
# Find email field by id="signInName" (Azure B2C specific)
|
# Find email field by id="signInName" (Azure B2C specific)
|
||||||
email_field = WebDriverWait(self.driver, 10).until(
|
email_field = WebDriverWait(self.driver, 10).until(
|
||||||
@@ -231,7 +246,49 @@ class AutomationUnitedSCOEligibilityCheck:
|
|||||||
# Click Continue
|
# Click Continue
|
||||||
continue_btn.click()
|
continue_btn.click()
|
||||||
print("[UnitedSCO login] Clicked 'Continue' on MFA selection page")
|
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:
|
except Exception:
|
||||||
pass # No MFA selection page - proceed normally
|
pass # No MFA selection page - proceed normally
|
||||||
|
|
||||||
@@ -784,25 +841,44 @@ class AutomationUnitedSCOEligibilityCheck:
|
|||||||
patientName = f"{self.firstName} {self.lastName}".strip()
|
patientName = f"{self.firstName} {self.lastName}".strip()
|
||||||
foundMemberId = self.memberId # Use provided memberId as default
|
foundMemberId = self.memberId # Use provided memberId as default
|
||||||
|
|
||||||
# Extract eligibility status
|
# Extract eligibility status — try multiple text patterns
|
||||||
try:
|
try:
|
||||||
status_elem = WebDriverWait(self.driver, 10).until(
|
status_elem = WebDriverWait(self.driver, 10).until(
|
||||||
EC.presence_of_element_located((By.XPATH,
|
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()
|
status_text = status_elem.text.strip().lower()
|
||||||
print(f"[UnitedSCO step2] Found status: {status_text}")
|
print(f"[UnitedSCO step2] Found status element text: {status_text}")
|
||||||
|
|
||||||
if "eligible" in status_text:
|
if "ineligible" in status_text or "not eligible" in status_text:
|
||||||
eligibilityText = "active"
|
|
||||||
elif "ineligible" in status_text or "not eligible" in status_text:
|
|
||||||
eligibilityText = "inactive"
|
eligibilityText = "inactive"
|
||||||
|
elif "eligible" in status_text:
|
||||||
|
eligibilityText = "active"
|
||||||
|
|
||||||
except TimeoutException:
|
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:
|
except Exception as e:
|
||||||
print(f"[UnitedSCO step2] Error extracting status: {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}")
|
print(f"[UnitedSCO step2] Eligibility status: {eligibilityText}")
|
||||||
|
|
||||||
@@ -842,6 +918,10 @@ class AutomationUnitedSCOEligibilityCheck:
|
|||||||
"//div[contains(@class,'patient')]//h3 | //div[contains(@class,'patient')]//h4",
|
"//div[contains(@class,'patient')]//h3 | //div[contains(@class,'patient')]//h4",
|
||||||
"//*[contains(@class,'eligibility__banner')]//h3 | //*[contains(@class,'eligibility__banner')]//h4",
|
"//*[contains(@class,'eligibility__banner')]//h3 | //*[contains(@class,'eligibility__banner')]//h4",
|
||||||
"//*[contains(@class,'banner__patient')]",
|
"//*[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:
|
for sel in name_selectors:
|
||||||
try:
|
try:
|
||||||
@@ -863,13 +943,16 @@ class AutomationUnitedSCOEligibilityCheck:
|
|||||||
# IMPORTANT: Use [^\n] to avoid matching across newlines (e.g. picking up "Member Eligible")
|
# IMPORTANT: Use [^\n] to avoid matching across newlines (e.g. picking up "Member Eligible")
|
||||||
if not name_extracted:
|
if not name_extracted:
|
||||||
name_patterns = [
|
name_patterns = [
|
||||||
# Name on the line right after "Selected Patient"
|
# 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]*\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\-\']+)+)',
|
r'Patient Name\s*[\n:]\s*([A-Z][A-Za-z\-\']+(?: [A-Z][A-Za-z\-\']+)+)',
|
||||||
# "LASTNAME, FIRSTNAME" format
|
# "LASTNAME, FIRSTNAME" format
|
||||||
r'Selected Patient\s*\n\s*([A-Z][A-Za-z\-\']+,\s*[A-Z][A-Za-z\-\']+)',
|
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"
|
# 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|Date Of Birth|DOB)',
|
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:
|
for pattern in name_patterns:
|
||||||
try:
|
try:
|
||||||
@@ -877,9 +960,9 @@ class AutomationUnitedSCOEligibilityCheck:
|
|||||||
if name_match:
|
if name_match:
|
||||||
candidate = name_match.group(1).strip()
|
candidate = name_match.group(1).strip()
|
||||||
# Validate: not too long, not a header/label, and doesn't contain "Eligible"/"Member"/"Patient"
|
# 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")
|
"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):
|
and "Eligible" not in candidate and "Member" not in candidate):
|
||||||
patientName = candidate
|
patientName = candidate
|
||||||
name_extracted = True
|
name_extracted = True
|
||||||
|
|||||||
Reference in New Issue
Block a user