feat: United/DentalHub claim submission automation and patient list sync

- Add full Selenium automation for United/DentalHub claim submission
  (steps 1-8: login, OTP, patient search, practitioner page, code entry,
  other coverage No, attachments, submit, Status & History PDF)
- Consolidate UnitedDH siteKey to UNITED_SCO throughout app
- Fix procedure date overwrite with Ctrl+A+Delete before typing service date
- Fix OTP popup reliability: emit every poll (no throttle)
- Fix Chrome session persistence: only clear cookies on startup
- Add touchPatient() to storage: claim submission now pushes patient to
  top of list across eligibility, claims, and documents pages

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Gitead
2026-05-25 00:29:04 -04:00
parent cd1381e9c6
commit 1e581c193c
14 changed files with 2100 additions and 95 deletions

View File

@@ -43,100 +43,33 @@ class UnitedSCOBrowserManager:
def clear_session_on_startup(self):
"""
Clear session cookies from Chrome profile on startup.
This forces a fresh login after PC restart.
Preserves device trust tokens (LocalStorage, IndexedDB) to avoid OTPs.
On startup, only clear the Cookies file so the login session is reset
but device trust tokens (Local Storage, IndexedDB) are preserved.
Preserving those lets Azure B2C recognise the device and skip OTP.
"""
print("[UnitedSCO BrowserManager] Clearing session on startup...")
print("[UnitedSCO BrowserManager] Clearing cookies on startup (preserving device trust)...")
try:
# Clear the credentials tracking file
# Clear credentials tracking so the next login re-saves the hash
if os.path.exists(self._credentials_file):
os.remove(self._credentials_file)
print("[UnitedSCO BrowserManager] Cleared credentials tracking file")
# Clear session-related files from Chrome profile
# These are the files that store login session cookies
session_files = [
"Cookies",
"Cookies-journal",
"Login Data",
"Login Data-journal",
"Web Data",
"Web Data-journal",
]
for filename in session_files:
filepath = os.path.join(self.profile_dir, "Default", filename)
if os.path.exists(filepath):
try:
os.remove(filepath)
print(f"[UnitedSCO BrowserManager] Removed {filename}")
except Exception as e:
print(f"[UnitedSCO BrowserManager] Could not remove {filename}: {e}")
# Also try root level (some Chrome versions)
for filename in session_files:
filepath = os.path.join(self.profile_dir, filename)
if os.path.exists(filepath):
try:
os.remove(filepath)
print(f"[UnitedSCO BrowserManager] Removed root {filename}")
except Exception as e:
print(f"[UnitedSCO BrowserManager] Could not remove root {filename}: {e}")
# Clear Session Storage (contains login state)
session_storage_dir = os.path.join(self.profile_dir, "Default", "Session Storage")
if os.path.exists(session_storage_dir):
try:
shutil.rmtree(session_storage_dir)
print("[UnitedSCO BrowserManager] Cleared Session Storage")
except Exception as e:
print(f"[UnitedSCO BrowserManager] Could not clear Session Storage: {e}")
# Clear Local Storage (may contain auth tokens)
local_storage_dir = os.path.join(self.profile_dir, "Default", "Local Storage")
if os.path.exists(local_storage_dir):
try:
shutil.rmtree(local_storage_dir)
print("[UnitedSCO BrowserManager] Cleared Local Storage")
except Exception as e:
print(f"[UnitedSCO BrowserManager] Could not clear Local Storage: {e}")
# Clear IndexedDB (may contain auth tokens)
indexeddb_dir = os.path.join(self.profile_dir, "Default", "IndexedDB")
if os.path.exists(indexeddb_dir):
try:
shutil.rmtree(indexeddb_dir)
print("[UnitedSCO BrowserManager] Cleared IndexedDB")
except Exception as e:
print(f"[UnitedSCO BrowserManager] Could not clear IndexedDB: {e}")
# Clear browser cache (prevents corrupted cached responses)
cache_dirs = [
os.path.join(self.profile_dir, "Default", "Cache"),
os.path.join(self.profile_dir, "Default", "Code Cache"),
os.path.join(self.profile_dir, "Default", "GPUCache"),
os.path.join(self.profile_dir, "Default", "Service Worker"),
os.path.join(self.profile_dir, "Cache"),
os.path.join(self.profile_dir, "Code Cache"),
os.path.join(self.profile_dir, "GPUCache"),
os.path.join(self.profile_dir, "Service Worker"),
os.path.join(self.profile_dir, "ShaderCache"),
]
for cache_dir in cache_dirs:
if os.path.exists(cache_dir):
try:
shutil.rmtree(cache_dir)
print(f"[UnitedSCO BrowserManager] Cleared {os.path.basename(cache_dir)}")
except Exception as e:
print(f"[UnitedSCO BrowserManager] Could not clear {os.path.basename(cache_dir)}: {e}")
# Set flag to clear session via JavaScript after browser opens
self._needs_session_clear = True
print("[UnitedSCO BrowserManager] Session cleared - will require fresh login")
# Only remove cookie files — leave everything else intact
cookie_files = ["Cookies", "Cookies-journal"]
for filename in cookie_files:
for base in [os.path.join(self.profile_dir, "Default"), self.profile_dir]:
filepath = os.path.join(base, filename)
if os.path.exists(filepath):
try:
os.remove(filepath)
print(f"[UnitedSCO BrowserManager] Removed {filepath}")
except Exception as e:
print(f"[UnitedSCO BrowserManager] Could not remove {filepath}: {e}")
self._needs_session_clear = False
print("[UnitedSCO BrowserManager] Cookies cleared — device trust tokens preserved")
except Exception as e:
print(f"[UnitedSCO BrowserManager] Error clearing session: {e}")