diff --git a/apps/SeleniumService/selenium_DDMA_claimSubmitWorker.py b/apps/SeleniumService/selenium_DDMA_claimSubmitWorker.py index 1eba83f6..68065764 100644 --- a/apps/SeleniumService/selenium_DDMA_claimSubmitWorker.py +++ b/apps/SeleniumService/selenium_DDMA_claimSubmitWorker.py @@ -245,18 +245,58 @@ class AutomationDDMAClaimSubmit: # ID + Birthdate (same search form as the eligibility flow) # # ------------------------------------------------------------------ # def step1_search_patient(self): - """Open the claims-submission page and search for the patient.""" + """From the dashboard, click 'Submit Claims' and search for the patient.""" wait = WebDriverWait(self.driver, 30) try: claims_url = "https://www.deltadentalma.com/private/provider/claims-submission" - print(f"[DDMA Claim step1] Navigating to claims-submission page: {claims_url}") - self.driver.get(claims_url) + + if "dashboard" not in self.driver.current_url.lower(): + print(f"[DDMA Claim step1] Not on dashboard — navigating to {MEMBERS_URL}") + self.driver.get(MEMBERS_URL) + time.sleep(2) + + try: + submit_claims_link = wait.until(EC.element_to_be_clickable( + (By.XPATH, "//a[@href='/private/provider/claims-submission']") + )) + submit_claims_link.click() + print("[DDMA Claim step1] Clicked 'Submit Claims' quick link") + except Exception as e: + print(f"[DDMA Claim step1] Could not click 'Submit Claims' link ({e}) — falling back to direct navigation") + self.driver.get(claims_url) + time.sleep(2) if "claims-submission" not in self.driver.current_url.lower(): print(f"[DDMA Claim step1] Warning: Ended up at {self.driver.current_url} instead of claims-submission page") + # Claims-submission page opens on the "Service Office" step — click the + # "Member Search" sidebar item to get to the birthdate/subscriber search form. + try: + member_search_link = wait.until(EC.element_to_be_clickable( + (By.XPATH, "//span[contains(@class,'mainLabel') and normalize-space(text())='Member Search']") + )) + member_search_link.click() + print("[DDMA Claim step1] Clicked 'Member Search' sidebar link") + time.sleep(1) + except Exception as e: + print(f"[DDMA Claim step1] Warning: Could not click 'Member Search' sidebar link: {e}") + + # Fill Member ID + if self.memberId: + try: + member_id_input = wait.until(EC.element_to_be_clickable( + (By.XPATH, "//input[@data-test-id='memberId']") + )) + member_id_input.click() + member_id_input.send_keys(Keys.CONTROL, "a") + member_id_input.send_keys(Keys.BACKSPACE) + member_id_input.send_keys(self.memberId) + print(f"[DDMA Claim step1] Filled Member ID: {self.memberId}") + except Exception as e: + print(f"[DDMA Claim step1] Warning: Could not fill Member ID: {e}") + # Fill Birthdate (masked mm/dd/yyyy input — send digits only, mask inserts slashes) if self.dateOfBirth: try: @@ -266,7 +306,7 @@ class AutomationDDMAClaimSubmit: day = dob_parts[2].zfill(2) birthdate_input = wait.until(EC.element_to_be_clickable( - (By.XPATH, "//input[@data-test-id='InStateSearchBirthdate']") + (By.XPATH, "//input[@data-test-id='memberBirthDate']") )) birthdate_input.click() birthdate_input.send_keys(Keys.CONTROL, "a") @@ -276,23 +316,11 @@ class AutomationDDMAClaimSubmit: except Exception as e: print(f"[DDMA Claim step1] Warning: Could not fill Birthdate: {e}") - # Fill Subscriber ID (== member ID) - if self.memberId: - try: - subscriber_input = wait.until(EC.element_to_be_clickable( - (By.XPATH, "//input[@data-test-id='InStateSearchSubscriberId']") - )) - subscriber_input.clear() - subscriber_input.send_keys(self.memberId) - print(f"[DDMA Claim step1] Filled Subscriber ID: {self.memberId}") - except Exception as e: - print(f"[DDMA Claim step1] Warning: Could not fill Subscriber ID: {e}") - time.sleep(0.3) # Click Search search_btn = wait.until(EC.element_to_be_clickable( - (By.XPATH, "//button[@data-test-id='InStateSearchButton']") + (By.XPATH, "//button[@data-test-id='memberSearchButton']") )) search_btn.click() print("[DDMA Claim step1] Clicked Search button") @@ -318,7 +346,11 @@ class AutomationDDMAClaimSubmit: # Step 2 — Select the matching family member row → Member detail page # # ------------------------------------------------------------------ # def step2_open_member_page(self): - """Pick the family member row matching this patient and open their detail page.""" + """Pick the family member row matching this patient and check its selection box. + + The results table (columns: checkbox, Member, Member Id, Role, Group Name, + Date Of Birth, Termination Date) stays on the same page — no navigation happens. + """ try: # Wait for the results table to appear, then let it stabilize try: @@ -337,11 +369,15 @@ class AutomationDDMAClaimSubmit: if self.dateOfBirth and rows: try: dob_parts = self.dateOfBirth.split("-") - dob_year, dob_month, dob_day = dob_parts[0], int(dob_parts[1]), int(dob_parts[2]) - expected_dob = f"{calendar.month_abbr[dob_month]} {dob_day}, {dob_year}".lower() + dob_year = dob_parts[0] + dob_month = dob_parts[1].zfill(2) + dob_day = dob_parts[2].zfill(2) + expected_dob = f"{dob_month}/{dob_day}/{dob_year}" for row in rows: cells = row.find_elements(By.XPATH, "./td") - if len(cells) >= 3 and cells[2].text.strip().lower() == expected_dob: + # cells: [0]=checkbox, [1]=Member, [2]=Member Id, [3]=Role, + # [4]=Group Name, [5]=Date Of Birth, [6]=Termination Date + if len(cells) >= 6 and cells[5].text.strip() == expected_dob: target_row = row break except Exception as e: @@ -361,26 +397,27 @@ class AutomationDDMAClaimSubmit: return "ERROR: step2 failed: no family member rows found" try: - name_link = target_row.find_element(By.XPATH, ".//a") - name_link.click() - print("[DDMA Claim step2] Clicked into patient detail page") + checkbox = target_row.find_element(By.XPATH, ".//i[contains(@class,'fa-check-square')]") + checkbox.click() + print("[DDMA Claim step2] Checked the matching family member row") except Exception as e: - print(f"[DDMA Claim step2] Warning: Could not click patient name link: {e}") - return f"ERROR: step2 failed: could not click patient link: {e}" + print(f"[DDMA Claim step2] Warning: Could not click member checkbox: {e}") + return f"ERROR: step2 failed: could not click member checkbox: {e}" - time.sleep(2) # let the detail page navigate/render - print(f"[DDMA Claim step2] Member detail page loaded: {self.driver.current_url}") + time.sleep(1) try: - # Wait until Create claim button is visible AND enabled (not just in the DOM) - WebDriverWait(self.driver, 15).until( - EC.element_to_be_clickable((By.XPATH, "//button[@aria-label='Create claim']")) + claim_detail_link = WebDriverWait(self.driver, 10).until( + EC.element_to_be_clickable( + (By.XPATH, "//span[contains(@class,'mainLabel') and normalize-space(text())='Claim Detail']") + ) ) - print("[DDMA Claim step2] 'Create claim' button is clickable") - time.sleep(3) # let React finish any remaining re-renders - except TimeoutException: - print("[DDMA Claim step2] Warning: 'Create claim' button not clickable in time") + claim_detail_link.click() + print("[DDMA Claim step2] Clicked 'Claim Detail' sidebar link") time.sleep(2) + except Exception as e: + print(f"[DDMA Claim step2] Warning: Could not click 'Claim Detail' sidebar link: {e}") + return f"ERROR: step2 failed: could not click 'Claim Detail' link: {e}" return "SUCCESS" @@ -389,118 +426,23 @@ class AutomationDDMAClaimSubmit: return f"ERROR: step2 failed: {e}" # ------------------------------------------------------------------ # - # Step 3 — Click "Create claim" button # + # Step 3 — No-op: step2 already navigates into the Claim Detail form # + # on the new site (no separate "Create claim" button exists there). # # ------------------------------------------------------------------ # def step3_click_create_claim(self): - """Click the 'Create claim' button on the Member Information page.""" + """Confirm the Claim Detail / Treatment Form is present (navigation already happened in step2).""" try: - print(f"[DDMA Claim step3] Current URL: {self.driver.current_url}") - handles_before = set(self.driver.window_handles) - url_before = self.driver.current_url - - self.driver.execute_script("window.scrollTo(0, 0);") - time.sleep(0.5) - - # Re-find the button fresh each attempt to avoid stale element references. - # The page may re-render after step2, so we do not cache the element. - CLAIM_BTN_XPATHS = [ - "//button[@aria-label='Create claim']", - "//button[contains(normalize-space(text()),'Create claim')]", - "//button[.//span[contains(text(),'Create claim')]]", - ] - - btn = None - for xpath in CLAIM_BTN_XPATHS: - try: - btn = WebDriverWait(self.driver, 8).until( - EC.element_to_be_clickable((By.XPATH, xpath)) - ) - if btn: - print(f"[DDMA Claim step3] Found 'Create claim' via: {xpath}") - break - except Exception: - continue - - if not btn: - all_btns = self.driver.find_elements(By.XPATH, "//button") - print(f"[DDMA Claim step3] Buttons on page: {[b.get_attribute('aria-label') or b.text for b in all_btns]}") - return "ERROR: step3 failed: 'Create claim' button not found" - - self.driver.execute_script("arguments[0].scrollIntoView({block:'center'});", btn) - time.sleep(0.5) - - # Try direct Selenium click first, fall back to JS events - clicked = False - for attempt, method in enumerate(["selenium", "js_events", "js_click"]): - try: - # Re-find fresh on each attempt to avoid stale reference - for xpath in CLAIM_BTN_XPATHS: - try: - btn = WebDriverWait(self.driver, 5).until( - EC.element_to_be_clickable((By.XPATH, xpath)) - ) - if btn: - break - except Exception: - continue - - if method == "selenium": - btn.click() - elif method == "js_events": - self.driver.execute_script(""" - var el = arguments[0]; - el.dispatchEvent(new PointerEvent('pointerover', {bubbles:true, cancelable:true, composed:true})); - el.dispatchEvent(new PointerEvent('pointerdown', {bubbles:true, cancelable:true, composed:true})); - el.dispatchEvent(new PointerEvent('pointerup', {bubbles:true, cancelable:true, composed:true})); - el.dispatchEvent(new MouseEvent('click', {bubbles:true, cancelable:true, composed:true})); - """, btn) - else: - self.driver.execute_script("arguments[0].click();", btn) - - print(f"[DDMA Claim step3] Clicked via {method} (attempt {attempt+1})") - time.sleep(2) - - # Check if navigation happened (URL changed or new tab opened) - handles_after = set(self.driver.window_handles) - new_handles = handles_after - handles_before - if new_handles: - self.driver.switch_to.window(new_handles.pop()) - print(f"[DDMA Claim step3] Switched to new tab: {self.driver.current_url}") - clicked = True - break - if self.driver.current_url != url_before: - print(f"[DDMA Claim step3] URL changed to: {self.driver.current_url}") - clicked = True - break - print(f"[DDMA Claim step3] URL unchanged after {method}, retrying...") - except Exception as e: - print(f"[DDMA Claim step3] {method} click failed: {e}, retrying...") - - if not clicked: - page_text = self.driver.execute_script("return document.body.innerText;")[:300] - print(f"[DDMA Claim step3] No navigation after all click attempts — page: {page_text}") - return "ERROR: step3 failed: button clicked but no navigation occurred" - - # Wait for claim form to load - try: - WebDriverWait(self.driver, 20).until( - EC.any_of( - EC.presence_of_element_located((By.XPATH, "//input[contains(@id,'procedureCode')]")), - EC.presence_of_element_located((By.XPATH, "//span[@data-type='month' and @contenteditable='true']")), - EC.presence_of_element_located((By.XPATH, - "//*[contains(text(),'date of service') or contains(text(),'Date of service') " - "or contains(text(),'Procedure code')]" - )), - ) - ) - print(f"[DDMA Claim step3] Claim form loaded: {self.driver.current_url}") - except TimeoutException: - page_text = self.driver.execute_script("return document.body.innerText;")[:400] - print(f"[DDMA Claim step3] Claim form not detected — page: {page_text}") - - time.sleep(1) + WebDriverWait(self.driver, 15).until( + EC.presence_of_element_located((By.XPATH, + "//*[contains(text(),'Treatment Form')] | //input[@data-test-id='claimRowServiceDate0']" + )) + ) + print("[DDMA Claim step3] Treatment Form is present — no-op (step2 already navigated here)") return "SUCCESS" - + except TimeoutException: + page_text = self.driver.execute_script("return document.body.innerText;")[:400] + print(f"[DDMA Claim step3] Treatment Form not detected — page: {page_text}") + return "ERROR: step3 failed: Treatment Form not found" except Exception as e: print(f"[DDMA Claim step3] Exception: {e}") return f"ERROR: step3 failed: {e}" @@ -591,200 +533,117 @@ class AutomationDDMAClaimSubmit: print(f"[DDMA Claim step4] Warning: could not fill {label}: {e}") def step4_fill_claim_form(self): - """Fill service date then all procedure line fields.""" + """Fill each treatment row: service date, procedure code, tooth number, surface, amount. + + The new Claim Detail Treatment Form has one row per procedure, each with + indexed fields (ServiceDate{i}, Surface{i}, Amount{i} by data-test-id; + procedure code and tooth number have no id, so they're matched positionally). + """ try: month, day, year = self._parse_service_date() - - # ── Service date (once, at the top of the form) ────────────────── - if month and day and year: - print(f"[DDMA Claim step4] Filling service date: {month}/{day}/{year}") - try: - dos_container = WebDriverWait(self.driver, 8).until( - EC.presence_of_element_located((By.XPATH, - "//*[@data-testid and contains(@data-testid,'date-of-service')] | " - "//*[contains(@aria-label,'Select date of service')]/ancestor::div[1]" - )) - ) - month_el = dos_container.find_element(By.XPATH, ".//span[@data-type='month' and @contenteditable='true']") - day_el = dos_container.find_element(By.XPATH, ".//span[@data-type='day' and @contenteditable='true']") - year_el = dos_container.find_element(By.XPATH, ".//span[@data-type='year' and @contenteditable='true']") - for elem, val in [(month_el, month), (day_el, day), (year_el, year)]: - elem.click() - elem.send_keys(Keys.CONTROL, "a") - elem.send_keys(Keys.BACKSPACE) - elem.send_keys(val) - time.sleep(0.05) - print("[DDMA Claim step4] Service date filled") - except Exception: - self._fill_spinbutton("month", month) - self._fill_spinbutton("day", day) - self._fill_spinbutton("year", year) - else: + service_date_str = f"{month}/{day}/{year}" if (month and day and year) else None + if not service_date_str: print(f"[DDMA Claim step4] No valid service date: {self.serviceDate!r}") - time.sleep(0.3) - active_lines = [ln for ln in self.serviceLines if str(ln.get("procedureCode") or "").strip()] print(f"[DDMA Claim step4] {len(active_lines)} service line(s)") for idx, line in enumerate(active_lines): - code = str(line.get("procedureCode") or "").strip().upper() - tooth = str(line.get("toothNumber") or line.get("tooth") or "").strip() - arch = str(line.get("arch") or "").strip() - quad = str(line.get("quad") or line.get("quadrant") or "").strip() - surface = str(line.get("toothSurface") or line.get("surface") or "").strip().upper() - billed = str(line.get("totalBilled") or line.get("billedAmount") or line.get("fee") or "").strip() - billed = billed.replace("$", "").strip() + code = str(line.get("procedureCode") or "").strip().upper() + tooth = str(line.get("toothNumber") or line.get("tooth") or "").strip() + surface = str(line.get("toothSurface") or line.get("surface") or "").strip().upper() + billed = str(line.get("totalBilled") or line.get("billedAmount") or line.get("fee") or "").strip() + billed = billed.replace("$", "").strip() - print(f"[DDMA Claim step4] Line {idx}: code={code} tooth={tooth!r} arch={arch!r} " - f"quad={quad!r} surface={surface!r} billed={billed!r}") + print(f"[DDMA Claim step4] Line {idx}: code={code} tooth={tooth!r} surface={surface!r} billed={billed!r}") - # ── Click "Add a procedure" for lines after the first ───────── + # ── Click "+ Add another treatment" for lines after the first ── if idx > 0: try: - add_btn = WebDriverWait(self.driver, 10).until( - EC.element_to_be_clickable((By.XPATH, - "//button[.//span[contains(text(),'Add a procedure')]] | " - "//button[contains(normalize-space(text()),'Add a procedure')] | " - "//*[contains(text(),'Add a procedure') and @role='button']" - )) + add_link = WebDriverWait(self.driver, 10).until( + EC.element_to_be_clickable((By.XPATH, "//a[@data-test-id='addNewRowButton']")) ) - self.driver.execute_script("arguments[0].scrollIntoView({block:'center'});", add_btn) - add_btn.click() - print(f"[DDMA Claim step4] Clicked 'Add a procedure' for line {idx}") + self.driver.execute_script("arguments[0].scrollIntoView({block:'center'});", add_link) + add_link.click() + print(f"[DDMA Claim step4] Clicked 'Add another treatment' for line {idx}") time.sleep(1) except Exception as e: - print(f"[DDMA Claim step4] Could not click 'Add a procedure': {e}") + print(f"[DDMA Claim step4] Could not click 'Add another treatment': {e}") - # ── Procedure code ──────────────────────────────────────────── + # ── Service date ──────────────────────────────────────────── + if service_date_str: + try: + date_inp = WebDriverWait(self.driver, 8).until( + EC.element_to_be_clickable((By.XPATH, f"//input[@data-test-id='claimRowServiceDate{idx}']")) + ) + date_inp.click() + date_inp.send_keys(Keys.CONTROL, "a") + date_inp.send_keys(Keys.BACKSPACE) + date_inp.send_keys(f"{month}{day}{year}") + print(f"[DDMA Claim step4] serviceDate[{idx}]: filled {service_date_str}") + except Exception as e: + print(f"[DDMA Claim step4] Could not fill service date[{idx}]: {e}") + time.sleep(0.2) + + # ── Procedure code (no id/data-test-id — matched positionally) ─ if code: try: - proc_inputs = self.driver.find_elements(By.XPATH, - "//input[contains(@id,'procedureCode') and contains(@id,'-input')]" - ) - proc_inp = proc_inputs[idx] if idx < len(proc_inputs) else proc_inputs[-1] - self.driver.execute_script("arguments[0].scrollIntoView({block:'center'});", proc_inp) - self._fill_combobox(proc_inp, code, f"procedureCode[{idx}]") - # Wait for the tooth input on the second row to be present AND interactable - if tooth: - try: - WebDriverWait(self.driver, 8).until( - lambda d: ( - len(d.find_elements(By.XPATH, "//input[@aria-label='Tooth']")) > idx and - d.find_elements(By.XPATH, "//input[@aria-label='Tooth']")[idx].is_enabled() and - d.find_elements(By.XPATH, "//input[@aria-label='Tooth']")[idx].is_displayed() - ) - ) - except Exception: - time.sleep(1) # fallback: just wait a second + proc_inputs = self.driver.find_elements(By.XPATH, "//input[@aria-label='e.g. D1234']") + proc_inp = proc_inputs[idx] if idx < len(proc_inputs) else (proc_inputs[-1] if proc_inputs else None) + if proc_inp: + self.driver.execute_script("arguments[0].scrollIntoView({block:'center'});", proc_inp) + self._fill_combobox(proc_inp, code, f"procedureCode[{idx}]") + else: + print(f"[DDMA Claim step4] procedureCode[{idx}]: input not found") except Exception as e: - print(f"[DDMA Claim step4] Could not fill procedure code: {e}") + print(f"[DDMA Claim step4] Could not fill procedure code[{idx}]: {e}") + time.sleep(0.2) - # ── Tooth ───────────────────────────────────────────────────── + # ── Tooth Number (custom scrollable dropdown, no native accepts several paths joined by newlines in one send_keys call. + file_input.send_keys("\n".join(abs_paths)) + time.sleep(1.5) + print(f"[DDMA Claim step5] Attached {len(abs_paths)}/{len(self.claimFiles)} file(s): " + f"{[os.path.basename(p) for p in abs_paths]}") + except Exception as e: + print(f"[DDMA Claim step5] Could not attach files: {e}") + return f"ERROR: step5 failed: {e}" - print(f"[DDMA Claim step5] Attached {attached}/{len(self.claimFiles)} file(s)") return "SUCCESS" # ------------------------------------------------------------------ # # Step 6 — Click Next step # # ------------------------------------------------------------------ # def step6_click_next(self): - """Click the 'Next step' button (React Aria — dispatches pointer events directly).""" + """Click the sidebar 'Submit Claim' navigation button to advance from the Claim Detail form.""" try: print(f"[DDMA Claim step6] Current URL: {self.driver.current_url}") btn = WebDriverWait(self.driver, 15).until( - EC.element_to_be_clickable((By.XPATH, - "//button[@data-testid='next-step-btn'] | " - "//button[@aria-label='Next step']" - )) + EC.element_to_be_clickable((By.XPATH, "//button[@data-test-id='submitClaimNavigationButton']")) ) self.driver.execute_script("arguments[0].scrollIntoView({block:'center'});", btn) time.sleep(0.5) @@ -876,85 +724,40 @@ class AutomationDDMAClaimSubmit: return f"ERROR: step6 failed: {e}" # ------------------------------------------------------------------ # - # Step 7 — Claims summary: check acknowledgement + submit # + # Step 7 — No-op: step6's "Submit Claim" click already finalizes the # + # claim on the new site (no separate acknowledgement/summary page). # # ------------------------------------------------------------------ # def step7_submit_claim(self): - """On the claims summary page, tick the acknowledgement checkbox then click Submit claim.""" + """Confirm the confirmation page is present (submission already happened in step6).""" try: - print(f"[DDMA Claim step7] Current URL: {self.driver.current_url}") - - # Wait for the acknowledgement checkbox to appear - checkbox = WebDriverWait(self.driver, 15).until( - EC.presence_of_element_located((By.XPATH, - "//input[@type='checkbox'] | " - "//*[@role='checkbox'] | " - "//label[contains(.,'submitting this claim')]//input | " - "//*[contains(@aria-label,'submitting this claim')]" - )) + WebDriverWait(self.driver, 20).until( + lambda d: "claim submitted successfully" in d.page_source.lower() ) - self.driver.execute_script("arguments[0].scrollIntoView({block:'center'});", checkbox) - time.sleep(0.3) - self.driver.execute_script(""" - var el = arguments[0]; - el.dispatchEvent(new PointerEvent('pointerover', {bubbles:true, cancelable:true, composed:true})); - el.dispatchEvent(new PointerEvent('pointerdown', {bubbles:true, cancelable:true, composed:true})); - el.dispatchEvent(new PointerEvent('pointerup', {bubbles:true, cancelable:true, composed:true})); - el.dispatchEvent(new MouseEvent('click', {bubbles:true, cancelable:true, composed:true})); - """, checkbox) - print("[DDMA Claim step7] Checked acknowledgement checkbox") - time.sleep(0.5) - - # Click Submit claim button - submit_btn = None - for xpath in [ - "//button[.//span[contains(text(),'Submit claim')]]", - "//button[contains(normalize-space(text()),'Submit claim')]", - "//button[@aria-label='Submit claim']", - ]: - try: - submit_btn = WebDriverWait(self.driver, 8).until( - EC.element_to_be_clickable((By.XPATH, xpath)) - ) - if submit_btn: - break - except Exception: - continue - if not submit_btn: - return "ERROR: step7 failed: Submit claim button not found" - self.driver.execute_script("arguments[0].scrollIntoView({block:'center'});", submit_btn) - time.sleep(0.3) - self.driver.execute_script(""" - var el = arguments[0]; - el.dispatchEvent(new PointerEvent('pointerover', {bubbles:true, cancelable:true, composed:true})); - el.dispatchEvent(new PointerEvent('pointerdown', {bubbles:true, cancelable:true, composed:true})); - el.dispatchEvent(new PointerEvent('pointerup', {bubbles:true, cancelable:true, composed:true})); - el.dispatchEvent(new MouseEvent('click', {bubbles:true, cancelable:true, composed:true})); - """, submit_btn) - print("[DDMA Claim step7] Clicked 'Submit claim'") - time.sleep(2) - print(f"[DDMA Claim step7] URL after submit: {self.driver.current_url}") + print("[DDMA Claim step7] Confirmation page detected — no-op (step6 already submitted)") return "SUCCESS" - + except TimeoutException: + print(f"[DDMA Claim step7] Confirmation page not detected — URL: {self.driver.current_url}") + return "ERROR: step7 failed: confirmation page not detected" except Exception as e: print(f"[DDMA Claim step7] Exception: {e}") return f"ERROR: step7 failed: {e}" def step8_save_confirmation_pdf(self): - """Wait for the Thank-you page, extract the claim number, save page as PDF.""" + """Wait for the confirmation page, extract the claim number, save page as PDF.""" import re try: # Wait for confirmation page WebDriverWait(self.driver, 30).until( - lambda d: "thank" in d.page_source.lower() or "submitted claim" in d.page_source.lower() + lambda d: "claim submitted successfully" in d.page_source.lower() ) time.sleep(2) print(f"[DDMA Claim step8] Confirmation page URL: {self.driver.current_url}") - # Extract claim number from page text + # Extract claim number from page text (row: "Claim Number" label + value, e.g. "202626032473000") claim_number = None try: body_text = self.driver.find_element(By.TAG_NAME, "body").text - match = re.search(r'submitted claim\s+(\d{10,})', body_text, re.IGNORECASE) + match = re.search(r'claim number\s*\n?\s*(\d{6,})', body_text, re.IGNORECASE) if match: claim_number = match.group(1) print(f"[DDMA Claim step8] Extracted claim number: {claim_number}")