diff --git a/apps/Backend/src/routes/insuranceStatusDDMA.ts b/apps/Backend/src/routes/insuranceStatusDDMA.ts index 1b8afe35..4c0e2214 100755 --- a/apps/Backend/src/routes/insuranceStatusDDMA.ts +++ b/apps/Backend/src/routes/insuranceStatusDDMA.ts @@ -67,10 +67,15 @@ router.post( }); } + // Fetch NPI providers to pick the target provider on the DDMA portal + const npiProviders = await storage.getNpiProvidersByUser(req.user.id); + const primaryProvider = npiProviders[0]; // sorted by sortOrder asc, then id asc + const enrichedData = { ...rawData, massddmaUsername: credentials.username, massddmaPassword: credentials.password, + providerName: primaryProvider?.providerName ?? "", }; const socketId: string | undefined = req.body.socketId; diff --git a/apps/Backend/src/routes/insuranceStatusDDMAClaim.ts b/apps/Backend/src/routes/insuranceStatusDDMAClaim.ts index 8c0dd216..a62b94ff 100644 --- a/apps/Backend/src/routes/insuranceStatusDDMAClaim.ts +++ b/apps/Backend/src/routes/insuranceStatusDDMAClaim.ts @@ -40,11 +40,16 @@ router.post("/ddma-claim", async (req: Request, res: Response): Promise => }); } + // Fetch NPI providers to pick the target provider on the DDMA portal + const npiProviders = await storage.getNpiProvidersByUser(req.user.id); + const primaryProvider = npiProviders[0]; // sorted by sortOrder asc, then id asc + const enrichedPayload = { claim: { ...claimData, massddmaUsername: credentials.username, massddmaPassword: credentials.password, + providerName: primaryProvider?.providerName ?? "", }, }; diff --git a/apps/SeleniumService/selenium_DDMA_claimSubmitWorker.py b/apps/SeleniumService/selenium_DDMA_claimSubmitWorker.py index 931bbce4..08fc2c45 100644 --- a/apps/SeleniumService/selenium_DDMA_claimSubmitWorker.py +++ b/apps/SeleniumService/selenium_DDMA_claimSubmitWorker.py @@ -41,6 +41,7 @@ class AutomationDDMAClaimSubmit: self.lastName = claim.get("lastName", "") or last_name self.serviceLines = claim.get("serviceLines", []) or [] self.claimFiles = claim.get("claimFiles", []) or [] + self.providerName = claim.get("providerName", "") or raw.get("providerName", "") self.download_dir = get_browser_manager().download_dir @@ -247,6 +248,58 @@ class AutomationDDMAClaimSubmit: print(f"[DDMA Claim login] Exception: {e}") return f"ERROR:LOGIN FAILED: {e}" + def _select_provider_dropdown(self): + """ + Click the provider dropdown on the member search page and select the option + matching self.providerName (case-insensitive). Falls back to the first option. + The button data-testid is 'member-search_provider_select-btn'. + """ + try: + short_wait = WebDriverWait(self.driver, 5) + try: + provider_btn = short_wait.until( + EC.element_to_be_clickable( + (By.XPATH, '//button[@data-testid="member-search_provider_select-btn"]') + ) + ) + except TimeoutException: + print("[DDMA Claim step1] No provider dropdown found — skipping") + return + + provider_btn.click() + time.sleep(0.5) + + try: + WebDriverWait(self.driver, 5).until( + EC.presence_of_element_located((By.XPATH, "//*[@role='option']")) + ) + except TimeoutException: + print("[DDMA Claim step1] Provider listbox did not open") + return + + options = self.driver.find_elements(By.XPATH, "//*[@role='option']") + print(f"[DDMA Claim step1] Provider options: {[o.text.strip() for o in options]}") + + target = (self.providerName or "").strip().lower() + selected = False + + if target: + for opt in options: + if target in opt.text.lower(): + opt.click() + print(f"[DDMA Claim step1] Selected provider: '{opt.text.strip()}'") + selected = True + break + + if not selected and options: + options[0].click() + print(f"[DDMA Claim step1] No match for '{self.providerName}', selected first: '{options[0].text.strip()}'") + + time.sleep(0.3) + + except Exception as e: + print(f"[DDMA Claim step1] Provider selection error (non-fatal): {e}") + # ------------------------------------------------------------------ # # Step 1 — Navigate directly to /members then search patient # # (same as eligibility — bypasses onboarding date/location screen) # @@ -266,6 +319,9 @@ class AutomationDDMAClaimSubmit: print(f"[DDMA Claim step1] Current URL: {self.driver.current_url}") print(f"[DDMA Claim step1] Waiting for member search input...") + # Select provider from dropdown based on NPI settings + self._select_provider_dropdown() + # Fill Member ID if self.memberId: try: diff --git a/apps/SeleniumService/selenium_DDMA_eligibilityCheckWorker.py b/apps/SeleniumService/selenium_DDMA_eligibilityCheckWorker.py index 76590d18..c885ad53 100755 --- a/apps/SeleniumService/selenium_DDMA_eligibilityCheckWorker.py +++ b/apps/SeleniumService/selenium_DDMA_eligibilityCheckWorker.py @@ -26,6 +26,7 @@ class AutomationDeltaDentalMAEligibilityCheck: self.lastName = self.data.get("lastName", "") self.massddma_username = self.data.get("massddmaUsername", "") self.massddma_password = self.data.get("massddmaPassword", "") + self.providerName = self.data.get("providerName", "") # Use browser manager's download dir self.download_dir = get_browser_manager().download_dir @@ -273,6 +274,58 @@ class AutomationDeltaDentalMAEligibilityCheck: print("[login] Exception during login:", e) return f"ERROR:LOGIN FAILED: {e}" + def _select_provider_dropdown(self): + """ + Click the provider dropdown on the member search page and select the option + matching self.providerName (case-insensitive). Falls back to the first option. + The button data-testid is 'member-search_provider_select-btn'. + """ + try: + short_wait = WebDriverWait(self.driver, 5) + try: + provider_btn = short_wait.until( + EC.element_to_be_clickable( + (By.XPATH, '//button[@data-testid="member-search_provider_select-btn"]') + ) + ) + except TimeoutException: + print("[DDMA step1] No provider dropdown found — skipping") + return + + provider_btn.click() + time.sleep(0.5) + + try: + WebDriverWait(self.driver, 5).until( + EC.presence_of_element_located((By.XPATH, "//*[@role='option']")) + ) + except TimeoutException: + print("[DDMA step1] Provider listbox did not open") + return + + options = self.driver.find_elements(By.XPATH, "//*[@role='option']") + print(f"[DDMA step1] Provider options: {[o.text.strip() for o in options]}") + + target = (self.providerName or "").strip().lower() + selected = False + + if target: + for opt in options: + if target in opt.text.lower(): + opt.click() + print(f"[DDMA step1] Selected provider: '{opt.text.strip()}'") + selected = True + break + + if not selected and options: + options[0].click() + print(f"[DDMA step1] No match for '{self.providerName}', selected first: '{options[0].text.strip()}'") + + time.sleep(0.3) + + except Exception as e: + print(f"[DDMA step1] Provider selection error (non-fatal): {e}") + def step1(self): """Fill search form with all available fields (flexible search).""" wait = WebDriverWait(self.driver, 30) @@ -289,6 +342,9 @@ class AutomationDeltaDentalMAEligibilityCheck: fields.append(f"DOB: {self.dateOfBirth}") print(f"[DDMA step1] Starting search with: {', '.join(fields)}") + # Select provider from dropdown based on NPI settings + self._select_provider_dropdown() + def replace_with_sendkeys(el, value): el.click() el.send_keys(Keys.CONTROL, "a")