fix: AI claims/preauths keep all codes past 10; reuse CCA/DentalHub Chrome

- Claim form: AI claim/preauth prefill adds rows beyond the initial 10
  instead of dropping codes 11+
- CDT lookup: "D6010 #5, 9, 11, 12" expands to one line per tooth, and
  the chat graph rebuilds such lists from the message if the LLM drops items
- Eligibility: match an existing patient by name+DOB when the insurance ID
  changed (e.g. MassHealth → CCA) instead of creating a duplicate patient
- CCA PreAuth: services grid scrolls to reach rows 11+
- CCA and Tufts SCO PreAuth: tentative service date = today + 3 days
- CCA (eligibility/claim/preauth) and DentalHub (claim/preauth): keep Chrome
  open, blank and minimized, after a job so the next job reuses it

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-12 01:27:28 -04:00
co-authored by Claude Opus 5.5
parent 8937a3390c
commit 143319909f
13 changed files with 218 additions and 63 deletions
+16 -5
View File
@@ -50,11 +50,22 @@ def _close_browser(bot):
bm.save_cookies()
except Exception:
pass
try:
bm.quit_driver()
print("[CCA Claim] Browser closed")
except Exception:
pass
# Keep Chrome open (blank + minimized) so the next CCA job reuses it — faster
# than starting a new browser. get_driver() recreates it if it was closed.
if bot and bot.driver:
try:
bot.driver.get("about:blank")
except Exception:
pass
try:
bot.driver.minimize_window()
print("[CCA Claim] Browser kept open (minimized)")
except Exception:
try:
bot.driver.set_window_position(-10000, -10000)
print("[CCA Claim] Browser kept open (moved off-screen)")
except Exception:
pass
except Exception as e:
print(f"[CCA Claim] Could not close browser: {e}")
@@ -51,11 +51,22 @@ def _close_browser(bot):
bm.save_cookies()
except Exception:
pass
try:
bm.quit_driver()
print("[CCA] Browser closed")
except Exception:
pass
# Keep Chrome open (blank + minimized) so the next CCA job reuses it — faster
# than starting a new browser. get_driver() recreates it if it was closed.
if bot and bot.driver:
try:
bot.driver.get("about:blank")
except Exception:
pass
try:
bot.driver.minimize_window()
print("[CCA] Browser kept open (minimized)")
except Exception:
try:
bot.driver.set_window_position(-10000, -10000)
print("[CCA] Browser kept open (moved off-screen)")
except Exception:
pass
except Exception as e:
print(f"[CCA] Could not close browser: {e}")
+16 -5
View File
@@ -50,11 +50,22 @@ def _close_browser(bot):
bm.save_cookies()
except Exception:
pass
try:
bm.quit_driver()
print("[CCA PreAuth] Browser closed")
except Exception:
pass
# Keep Chrome open (blank + minimized) so the next CCA job reuses it — faster
# than starting a new browser. get_driver() recreates it if it was closed.
if bot and bot.driver:
try:
bot.driver.get("about:blank")
except Exception:
pass
try:
bot.driver.minimize_window()
print("[CCA PreAuth] Browser kept open (minimized)")
except Exception:
try:
bot.driver.set_window_position(-10000, -10000)
print("[CCA PreAuth] Browser kept open (moved off-screen)")
except Exception:
pass
except Exception as e:
print(f"[CCA PreAuth] Could not close browser: {e}")
@@ -297,13 +297,14 @@ async def start_uniteddh_claim_run(sid: str, data: dict, url: str):
s["result"] = result
s["message"] = "completed"
# Close browser window (session preserved in profile via UnitedSCO browser manager)
# Keep Chrome open (blank + minimized) so the next job reuses it — faster than
# starting a new browser. The browser manager recreates it if it was closed.
try:
from unitedsco_browser_manager import get_browser_manager as _gbm
_gbm().quit_driver()
print("[UnitedDH Claim] Browser closed - session preserved in profile")
except Exception as close_err:
print(f"[UnitedDH Claim] Could not close browser (non-fatal): {close_err}")
bot.driver.get("about:blank")
bot.driver.minimize_window()
print("[UnitedDH Claim] Browser kept open (minimized)")
except Exception as hide_err:
print(f"[UnitedDH Claim] Could not minimize browser (non-fatal): {hide_err}")
asyncio.create_task(_remove_session_later(sid, 60))
return result
@@ -294,13 +294,14 @@ async def start_uniteddh_preauth_run(sid: str, data: dict, url: str):
s["result"] = result
s["message"] = "completed"
# Close browser window (session preserved in profile via UnitedSCO browser manager)
# Keep Chrome open (blank + minimized) so the next job reuses it — faster than
# starting a new browser. The browser manager recreates it if it was closed.
try:
from unitedsco_browser_manager import get_browser_manager as _gbm
_gbm().quit_driver()
print("[UnitedDH PreAuth] Browser closed - session preserved in profile")
except Exception as close_err:
print(f"[UnitedDH PreAuth] Could not close browser (non-fatal): {close_err}")
bot.driver.get("about:blank")
bot.driver.minimize_window()
print("[UnitedDH PreAuth] Browser kept open (minimized)")
except Exception as hide_err:
print(f"[UnitedDH PreAuth] Could not minimize browser (non-fatal): {hide_err}")
asyncio.create_task(_remove_session_later(sid, 60))
return result
@@ -45,11 +45,14 @@ class AutomationCCAEligibilityCheck:
browser_manager.save_cookies()
except Exception as e:
print(f"[CCA] Failed to save cookies before close: {e}")
# Keep Chrome open (blank + minimized) so the next CCA job reuses it — faster
# than starting a new browser. get_driver() recreates it if it was closed.
try:
browser_manager.quit_driver()
print("[CCA] Browser closed")
self.driver.get("about:blank")
self.driver.minimize_window()
print("[CCA] Browser kept open (minimized)")
except Exception as e:
print(f"[CCA] Could not close browser: {e}")
print(f"[CCA] Could not minimize browser: {e}")
def _force_logout(self):
try:
@@ -9,7 +9,7 @@ import re
import json
import base64
import tempfile
from datetime import date
from datetime import date, timedelta
from cca_browser_manager import get_browser_manager
@@ -34,10 +34,10 @@ class AutomationCCAPreAuth:
self.cca_password = claim.get("cca_password", "") or raw.get("cca_password", "")
self.memberId = claim.get("memberId", "")
self.dateOfBirth = claim.get("dateOfBirth", "")
# PreAuth uses tentative service date; falls back to serviceDate for compatibility
# PreAuth tentative service date: 3 days after today unless one is given explicitly
self.serviceDate = (
claim.get("tentativeServiceDate")
or claim.get("serviceDate", "")
or (date.today() + timedelta(days=3)).isoformat()
)
self.firstName = claim.get("firstName", "") or first_name
self.lastName = claim.get("lastName", "") or last_name
@@ -677,17 +677,35 @@ class AutomationCCAPreAuth:
print(f"[CCA PreAuth step3] Line {idx+1}: code={code}, tooth={tooth}, billed={billed_str}")
# Find the row element scoped to Services grid
# The grid shows 10 rows; rows 11+ sit below its inner scrollbar.
# Scroll the grid's content pane down and retry if the row isn't found yet.
row_el = None
for xpath in [
f"//div[@id='Services']//tr[@aria-rowindex='{row_idx}']",
f"//div[@id='Services']//div[contains(@class,'e-gridcontent')]//tbody/tr[{idx+1}]",
f"//div[@id='Services']//div[contains(@class,'e-content')]//tr[{idx+1}]",
]:
try:
row_el = self.driver.find_element(By.XPATH, xpath)
for _scroll_try in range(4):
for xpath in [
f"//div[@id='Services']//tr[@aria-rowindex='{row_idx}']",
f"//div[@id='Services']//div[contains(@class,'e-gridcontent')]//tbody/tr[{idx+1}]",
f"//div[@id='Services']//div[contains(@class,'e-content')]//tr[{idx+1}]",
]:
try:
row_el = self.driver.find_element(By.XPATH, xpath)
break
except Exception:
continue
if row_el:
break
try:
self.driver.execute_script(
"var c=document.querySelector('#Services .e-content');"
"if(c){c.scrollTop=c.scrollTop+c.clientHeight;}")
time.sleep(0.6)
except Exception:
continue
pass
if row_el:
try:
self.driver.execute_script(
"arguments[0].scrollIntoView({block:'nearest',inline:'nearest'});", row_el)
except Exception:
pass
if not row_el:
print(f"[CCA PreAuth step3] WARNING: row {idx+1} not found — skipping")
@@ -19,6 +19,7 @@ import base64
import re
from dentaquest_browser_manager import get_browser_manager
from datetime import date, timedelta
MEMBERS_URL = "https://providers.dentaquest.com/members"
@@ -37,7 +38,11 @@ class AutomationTuftsSCOPreAuth:
self.dateOfBirth = claim.get("dateOfBirth", "")
self.firstName = claim.get("firstName", "")
self.lastName = claim.get("lastName", "")
self.serviceDate = claim.get("serviceDate", "")
# PreAuth tentative service date: 3 days after today unless one is given explicitly
self.serviceDate = (
claim.get("tentativeServiceDate")
or (date.today() + timedelta(days=3)).isoformat()
)
self.serviceLines = claim.get("serviceLines", [])
self.claimFiles = claim.get("claimFiles", [])
self.patientName = claim.get("patientName", "")