Eligibility (no OTP, fresh browser per run like MH): logs in, opens Benefits & Claims Information, searches by Subscriber ID (or Subscriber Last Name via "Click Here"), First Name and DOB, picks the matching row from the patient list, sets ACTIVE/INACTIVE from the Coverage range, reads Group Number into the patient's Group Number, opens View Details for the last name and plan name, and saves the details page PDF to the patient's Eligibility folder. A patient switching plans is matched by name + DOB so Altus overwrites the old insurance instead of creating a duplicate. Claims: Altus uses the same 2024 ADA form as BCBS with the Altus payer address (P.O. Box 1557, Providence, RI 02901-1557). Adds Altus Claim/PreAuth (ADA Form) buttons, Claim All and AI queue routing, Print ADA Form in the claim viewer, and an Altus fee schedule (copied from BCBS). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1361 lines
45 KiB
Python
Executable File
1361 lines
45 KiB
Python
Executable File
from fastapi import FastAPI, Request, HTTPException
|
|
from fastapi.middleware.cors import CORSMiddleware
|
|
from fastapi.responses import RedirectResponse, JSONResponse
|
|
from fastapi.staticfiles import StaticFiles
|
|
import uvicorn
|
|
import asyncio
|
|
from selenium_claimSubmitWorker import AutomationMassHealthClaimsLogin
|
|
from selenium_eligibilityCheckWorker import AutomationMassHealthEligibilityCheck
|
|
from selenium_MH_eligibilityHistoryCheckWorker import AutomationMassHealthEligibilityHistoryCheck
|
|
from selenium_CMSP_eligibilityHistoryRemainingCheckWorker import AutomationCMSPEligibilityHistoryRemainingCheck
|
|
from selenium_claimStatusCheckWorker import AutomationMassHealthClaimStatusCheck
|
|
from selenium_preAuthWorker import AutomationMassHealthPreAuth
|
|
from selenium_MHSinglePaymentCheckWorker import AutomationMassHealthSinglePaymentCheck
|
|
from selenium_MHBatchPaymentCheckWorker import AutomationMassHealthBatchPaymentCheck
|
|
from selenium_Altus_eligibilityCheckWorker import AutomationAltusEligibilityCheck
|
|
import os
|
|
import time
|
|
import helpers_ddma_eligibility as hddma
|
|
import helpers_deltaindiv_eligibility as hdeltaindiv
|
|
import helpers_deltains_eligibility as hdeltains
|
|
import helpers_unitedsco_eligibility as hunitedsco
|
|
import helpers_uniteducard_eligibility as huniteducard
|
|
import helpers_dentaquest_eligibility as hdentaquest
|
|
import helpers_cca_eligibility as hcca
|
|
import helpers_cca_claim as hcca_claim
|
|
import helpers_cca_preauth as hcca_preauth
|
|
import helpers_ddma_claim as hddma_claim
|
|
import helpers_deltains_claim as hdeltains_claim
|
|
import helpers_uniteddh_claim as huniteddh_claim
|
|
import helpers_uniteddh_preauth as huniteddh_preauth
|
|
import helpers_tuftssco_claim as htuftssco_claim
|
|
import helpers_tuftssco_preauth as htuftssco_preauth
|
|
import helpers_uniteducard_claim as huniteducard_claim
|
|
import helpers_bcbs_ma_eligibility as hbcbs_ma
|
|
import helpers_metlife_eligibility as hmetlife
|
|
|
|
# Import startup session-clear functions
|
|
from ddma_browser_manager import clear_ddma_session_on_startup
|
|
from deltaindiv_browser_manager import clear_deltaindiv_session_on_startup
|
|
from deltains_browser_manager import clear_deltains_session_on_startup
|
|
from unitedsco_browser_manager import clear_unitedsco_session_on_startup
|
|
from uniteducard_browser_manager import clear_uniteducard_session_on_startup
|
|
from dentaquest_browser_manager import clear_dentaquest_session_on_startup
|
|
from cca_browser_manager import clear_cca_session_on_startup
|
|
from metlife_browser_manager import clear_metlife_session_on_startup
|
|
|
|
from dotenv import load_dotenv
|
|
load_dotenv()
|
|
|
|
# Clear sessions on startup so fresh login is required after PC restart.
|
|
print("=" * 50)
|
|
print("SELENIUM AGENT STARTING - CLEARING SESSIONS")
|
|
print("=" * 50)
|
|
clear_ddma_session_on_startup()
|
|
clear_deltaindiv_session_on_startup()
|
|
clear_deltains_session_on_startup()
|
|
clear_unitedsco_session_on_startup()
|
|
clear_uniteducard_session_on_startup()
|
|
clear_dentaquest_session_on_startup()
|
|
clear_cca_session_on_startup()
|
|
clear_metlife_session_on_startup()
|
|
print("=" * 50)
|
|
print("SESSION CLEAR COMPLETE")
|
|
print("=" * 50)
|
|
|
|
app = FastAPI()
|
|
|
|
# Allow 1 selenium session at a time
|
|
semaphore = asyncio.Semaphore(1)
|
|
|
|
# Manual counters to track active & queued jobs
|
|
active_jobs = 0
|
|
waiting_jobs = 0
|
|
lock = asyncio.Lock() # To safely update counters
|
|
|
|
|
|
app.add_middleware(
|
|
CORSMiddleware,
|
|
allow_origins=["*"], # Replace with your frontend domain for security
|
|
allow_methods=["*"],
|
|
allow_headers=["*"],
|
|
)
|
|
|
|
# Mount static files for serving PDFs (must be after middleware)
|
|
DOWNLOAD_DIR = os.path.join(os.path.dirname(__file__), "downloads")
|
|
os.makedirs(DOWNLOAD_DIR, exist_ok=True)
|
|
app.mount("/downloads", StaticFiles(directory=DOWNLOAD_DIR), name="downloads")
|
|
|
|
# Endpoint: 1 — Start the automation of submitting Claim.
|
|
@app.post("/claimsubmit")
|
|
async def start_workflow(request: Request):
|
|
global active_jobs, waiting_jobs
|
|
data = await request.json()
|
|
|
|
async with lock:
|
|
waiting_jobs += 1
|
|
|
|
async with semaphore:
|
|
async with lock:
|
|
waiting_jobs -= 1
|
|
active_jobs += 1
|
|
|
|
try:
|
|
bot = AutomationMassHealthClaimsLogin(data)
|
|
# result = bot.main_workflow("https://provider.masshealth-dental.org/mh_provider_login")
|
|
result = bot.run()
|
|
|
|
if result.get("status") != "success":
|
|
return {"status": "error", "message": result.get("message")}
|
|
|
|
# Convert pdf_path to pdf_url
|
|
if result.get("pdf_path"):
|
|
filename = os.path.basename(result["pdf_path"])
|
|
port = os.getenv("PORT", "5002")
|
|
url_host = os.getenv("HOST", "localhost")
|
|
result["pdf_url"] = f"http://{url_host}:{port}/downloads/{filename}"
|
|
print(f"DEBUG: Generated pdf_url = {result['pdf_url']}")
|
|
|
|
return result
|
|
except Exception as e:
|
|
return {"status": "error", "message": str(e)}
|
|
finally:
|
|
async with lock:
|
|
active_jobs -= 1
|
|
|
|
# Endpoint: 2 — Start the automation of cheking eligibility
|
|
@app.post("/eligibility-check")
|
|
async def start_workflow(request: Request):
|
|
global active_jobs, waiting_jobs
|
|
data = await request.json()
|
|
|
|
async with lock:
|
|
waiting_jobs += 1
|
|
|
|
async with semaphore:
|
|
async with lock:
|
|
waiting_jobs -= 1
|
|
active_jobs += 1
|
|
try:
|
|
bot = AutomationMassHealthEligibilityCheck(data)
|
|
result = bot.main_workflow("https://provider.masshealth-dental.org/mh_provider_login")
|
|
|
|
if result.get("status") != "success":
|
|
return {"status": "error", "message": result.get("message")}
|
|
|
|
# Convert pdf_path to pdf_url
|
|
if result.get("pdf_path"):
|
|
filename = os.path.basename(result["pdf_path"])
|
|
port = os.getenv("PORT", "5002")
|
|
url_host = os.getenv("HOST", "localhost")
|
|
result["pdf_url"] = f"http://{url_host}:{port}/downloads/{filename}"
|
|
print(f"DEBUG: Generated pdf_url = {result['pdf_url']}")
|
|
|
|
return result
|
|
except Exception as e:
|
|
return {"status": "error", "message": str(e)}
|
|
finally:
|
|
async with lock:
|
|
active_jobs -= 1
|
|
|
|
# Endpoint: 2a — MH Eligibility + Service History
|
|
@app.post("/mh-eligibility-history-check")
|
|
async def mh_eligibility_history_check(request: Request):
|
|
global active_jobs, waiting_jobs
|
|
data = await request.json()
|
|
|
|
async with lock:
|
|
waiting_jobs += 1
|
|
|
|
async with semaphore:
|
|
async with lock:
|
|
waiting_jobs -= 1
|
|
active_jobs += 1
|
|
try:
|
|
bot = AutomationMassHealthEligibilityHistoryCheck(data)
|
|
result = bot.main_workflow("https://provider.masshealth-dental.org/mh_provider_login")
|
|
|
|
if result.get("status") == "error":
|
|
return {"status": "error", "message": result.get("message")}
|
|
|
|
port = os.getenv("PORT", "5002")
|
|
url_host = os.getenv("HOST", "localhost")
|
|
|
|
if result.get("pdf_path"):
|
|
filename = os.path.basename(result["pdf_path"])
|
|
result["pdf_url"] = f"http://{url_host}:{port}/downloads/{filename}"
|
|
|
|
if result.get("history_pdf_path"):
|
|
filename = os.path.basename(result["history_pdf_path"])
|
|
result["history_pdf_url"] = f"http://{url_host}:{port}/downloads/{filename}"
|
|
|
|
return result
|
|
except Exception as e:
|
|
return {"status": "error", "message": str(e)}
|
|
finally:
|
|
async with lock:
|
|
active_jobs -= 1
|
|
|
|
# Endpoint: 2c — Altus Dental eligibility (no OTP, fresh browser per run)
|
|
@app.post("/altus-eligibility-check")
|
|
async def altus_eligibility_check(request: Request):
|
|
global active_jobs, waiting_jobs
|
|
data = await request.json()
|
|
|
|
async with lock:
|
|
waiting_jobs += 1
|
|
|
|
async with semaphore:
|
|
async with lock:
|
|
waiting_jobs -= 1
|
|
active_jobs += 1
|
|
try:
|
|
bot = AutomationAltusEligibilityCheck(data)
|
|
# Selenium is blocking — run off the event loop so /status etc. stay responsive
|
|
result = await asyncio.to_thread(
|
|
bot.main_workflow, "https://www.altusdental.com/Provider/Login?timedOut=False"
|
|
)
|
|
|
|
if result.get("status") == "error":
|
|
return {"status": "error", "message": result.get("message")}
|
|
|
|
if result.get("pdf_path"):
|
|
filename = os.path.basename(result["pdf_path"])
|
|
port = os.getenv("PORT", "5002")
|
|
url_host = os.getenv("HOST", "localhost")
|
|
result["pdf_url"] = f"http://{url_host}:{port}/downloads/{filename}"
|
|
|
|
return result
|
|
except Exception as e:
|
|
return {"status": "error", "message": str(e)}
|
|
finally:
|
|
async with lock:
|
|
active_jobs -= 1
|
|
|
|
# Endpoint: 2b — CMSP Eligibility + Service History + Accumulator (Remaining)
|
|
@app.post("/cmsp-eligibility-history-remaining-check")
|
|
async def cmsp_eligibility_history_remaining_check(request: Request):
|
|
global active_jobs, waiting_jobs
|
|
data = await request.json()
|
|
|
|
async with lock:
|
|
waiting_jobs += 1
|
|
|
|
async with semaphore:
|
|
async with lock:
|
|
waiting_jobs -= 1
|
|
active_jobs += 1
|
|
try:
|
|
bot = AutomationCMSPEligibilityHistoryRemainingCheck(data)
|
|
result = bot.main_workflow("https://provider.masshealth-dental.org/mh_provider_login")
|
|
|
|
if result.get("status") == "error":
|
|
return {"status": "error", "message": result.get("message")}
|
|
|
|
port = os.getenv("PORT", "5002")
|
|
url_host = os.getenv("HOST", "localhost")
|
|
|
|
for key, url_key in [
|
|
("pdf_path", "pdf_url"),
|
|
("history_pdf_path", "history_pdf_url"),
|
|
("accumulator_pdf_path", "accumulator_pdf_url"),
|
|
]:
|
|
if result.get(key):
|
|
filename = os.path.basename(result[key])
|
|
result[url_key] = f"http://{url_host}:{port}/downloads/{filename}"
|
|
|
|
return result
|
|
except Exception as e:
|
|
return {"status": "error", "message": str(e)}
|
|
finally:
|
|
async with lock:
|
|
active_jobs -= 1
|
|
|
|
# Endpoint: 2.1 — Start the automation for Claims login (open browser and log in)
|
|
@app.post("/claims-login")
|
|
async def start_claims_login(request: Request):
|
|
global active_jobs, waiting_jobs
|
|
data = await request.json()
|
|
|
|
async with lock:
|
|
waiting_jobs += 1
|
|
|
|
async with semaphore:
|
|
async with lock:
|
|
waiting_jobs -= 1
|
|
active_jobs += 1
|
|
try:
|
|
bot = AutomationMassHealthClaimsLogin(data)
|
|
result = bot.run()
|
|
|
|
if result.get("status") != "success":
|
|
return {"status": "error", "message": result.get("message")}
|
|
|
|
return result
|
|
except Exception as e:
|
|
return {"status": "error", "message": str(e)}
|
|
finally:
|
|
async with lock:
|
|
active_jobs -= 1
|
|
|
|
# Endpoint: 3 — Start the automation of cheking claim status
|
|
@app.post("/claim-status-check")
|
|
async def start_workflow(request: Request):
|
|
global active_jobs, waiting_jobs
|
|
data = await request.json()
|
|
|
|
async with lock:
|
|
waiting_jobs += 1
|
|
|
|
async with semaphore:
|
|
async with lock:
|
|
waiting_jobs -= 1
|
|
active_jobs += 1
|
|
try:
|
|
bot = AutomationMassHealthClaimStatusCheck(data)
|
|
result = bot.main_workflow("https://provider.masshealth-dental.org/mh_provider_login")
|
|
|
|
if result.get("status") != "success":
|
|
return {"status": "error", "message": result.get("message")}
|
|
|
|
return result
|
|
except Exception as e:
|
|
return {"status": "error", "message": str(e)}
|
|
finally:
|
|
async with lock:
|
|
active_jobs -= 1
|
|
|
|
# Endpoint: 5 — Check MassHealth payment for a given claim number
|
|
@app.post("/mh-payment-check")
|
|
async def mh_payment_check(request: Request):
|
|
global active_jobs, waiting_jobs
|
|
data = await request.json()
|
|
|
|
async with lock:
|
|
waiting_jobs += 1
|
|
|
|
async with semaphore:
|
|
async with lock:
|
|
waiting_jobs -= 1
|
|
active_jobs += 1
|
|
try:
|
|
bot = AutomationMassHealthSinglePaymentCheck(data)
|
|
result = bot.main_workflow("https://provider.masshealth-dental.org/mh_provider_login")
|
|
|
|
if result.get("status") != "success":
|
|
return {"status": "error", "message": result.get("message")}
|
|
|
|
return result
|
|
except Exception as e:
|
|
return {"status": "error", "message": str(e)}
|
|
finally:
|
|
async with lock:
|
|
active_jobs -= 1
|
|
|
|
|
|
# Endpoint: 6 — Check MassHealth payments in batch by date range
|
|
@app.post("/mh-batch-payment-check")
|
|
async def mh_batch_payment_check(request: Request):
|
|
global active_jobs, waiting_jobs
|
|
data = await request.json()
|
|
|
|
async with lock:
|
|
waiting_jobs += 1
|
|
|
|
async with semaphore:
|
|
async with lock:
|
|
waiting_jobs -= 1
|
|
active_jobs += 1
|
|
try:
|
|
bot = AutomationMassHealthBatchPaymentCheck(data)
|
|
result = bot.main_workflow("https://provider.masshealth-dental.org/mh_provider_login")
|
|
|
|
if result.get("status") != "success":
|
|
return {"status": "error", "message": result.get("message")}
|
|
|
|
return result
|
|
except Exception as e:
|
|
return {"status": "error", "message": str(e)}
|
|
finally:
|
|
async with lock:
|
|
active_jobs -= 1
|
|
|
|
|
|
# Endpoint: 4 — Start the automation of cheking claim pre auth
|
|
@app.post("/claim-pre-auth")
|
|
async def start_workflow(request: Request):
|
|
global active_jobs, waiting_jobs
|
|
data = await request.json()
|
|
|
|
async with lock:
|
|
waiting_jobs += 1
|
|
|
|
async with semaphore:
|
|
async with lock:
|
|
waiting_jobs -= 1
|
|
active_jobs += 1
|
|
try:
|
|
bot = AutomationMassHealthPreAuth(data)
|
|
result = bot.main_workflow("https://provider.masshealth-dental.org/mh_provider_login")
|
|
|
|
if result.get("status") != "success":
|
|
return {"status": "error", "message": result.get("message")}
|
|
|
|
# Convert pdf_path to pdf_url so the frontend can fetch it
|
|
if result.get("pdf_path"):
|
|
filename = os.path.basename(result["pdf_path"])
|
|
port = os.getenv("PORT", "5002")
|
|
url_host = os.getenv("HOST", "localhost")
|
|
result["pdf_url"] = f"http://{url_host}:{port}/downloads/{filename}"
|
|
print(f"DEBUG: Generated pdf_url = {result['pdf_url']}")
|
|
|
|
return result
|
|
except Exception as e:
|
|
return {"status": "error", "message": str(e)}
|
|
finally:
|
|
async with lock:
|
|
active_jobs -= 1
|
|
|
|
# Endpoint:5 - DDMA eligibility (background, OTP)
|
|
|
|
async def _ddma_worker_wrapper(sid: str, data: dict, url: str):
|
|
"""
|
|
Background worker that:
|
|
- acquires semaphore (to keep 1 selenium at a time),
|
|
- updates active/queued counters,
|
|
- runs the DDMA flow via helpers.start_ddma_run.
|
|
"""
|
|
global active_jobs, waiting_jobs
|
|
async with semaphore:
|
|
async with lock:
|
|
waiting_jobs -= 1
|
|
active_jobs += 1
|
|
try:
|
|
await hddma.start_ddma_run(sid, data, url)
|
|
finally:
|
|
async with lock:
|
|
active_jobs -= 1
|
|
|
|
|
|
@app.post("/ddma-eligibility")
|
|
async def ddma_eligibility(request: Request):
|
|
"""
|
|
Starts a DDMA eligibility session in the background.
|
|
Body: { "data": { ... }, "url"?: string }
|
|
Returns: { status: "started", session_id: "<uuid>" }
|
|
"""
|
|
global waiting_jobs
|
|
|
|
body = await request.json()
|
|
data = body.get("data", {})
|
|
|
|
# create session
|
|
sid = hddma.make_session_entry()
|
|
hddma.sessions[sid]["type"] = "ddma_eligibility"
|
|
hddma.sessions[sid]["last_activity"] = time.time()
|
|
|
|
async with lock:
|
|
waiting_jobs += 1
|
|
|
|
# run in background (queued under semaphore)
|
|
asyncio.create_task(_ddma_worker_wrapper(sid, data, url="https://www.deltadentalma.com/sign-in"))
|
|
|
|
return {"status": "started", "session_id": sid}
|
|
|
|
|
|
# Endpoint: MetLife Dental eligibility (background, OTP, persistent session)
|
|
|
|
async def _metlife_worker_wrapper(sid: str, data: dict, url: str):
|
|
"""Background worker for MetLife eligibility — acquires semaphore, updates counters."""
|
|
global active_jobs, waiting_jobs
|
|
async with semaphore:
|
|
async with lock:
|
|
waiting_jobs -= 1
|
|
active_jobs += 1
|
|
try:
|
|
await hmetlife.start_metlife_run(sid, data, url)
|
|
finally:
|
|
async with lock:
|
|
active_jobs -= 1
|
|
|
|
|
|
@app.post("/metlife-eligibility")
|
|
async def metlife_eligibility(request: Request):
|
|
"""
|
|
Starts a MetLife eligibility session in the background.
|
|
Body: { "data": { ... } }
|
|
Returns: { status: "started", session_id: "<uuid>" }
|
|
"""
|
|
global waiting_jobs
|
|
|
|
body = await request.json()
|
|
data = body.get("data", {})
|
|
|
|
sid = hmetlife.make_session_entry()
|
|
hmetlife.sessions[sid]["type"] = "metlife_eligibility"
|
|
hmetlife.sessions[sid]["last_activity"] = time.time()
|
|
|
|
async with lock:
|
|
waiting_jobs += 1
|
|
|
|
asyncio.create_task(_metlife_worker_wrapper(sid, data, url="https://dentalprovider.metlife.com/home"))
|
|
|
|
return {"status": "started", "session_id": sid}
|
|
|
|
|
|
async def _deltaindiv_worker_wrapper(sid: str, data: dict, url: str):
|
|
"""Background worker for Delta Indiv eligibility — acquires semaphore, updates counters."""
|
|
global active_jobs, waiting_jobs
|
|
async with semaphore:
|
|
async with lock:
|
|
waiting_jobs -= 1
|
|
active_jobs += 1
|
|
try:
|
|
await hdeltaindiv.start_deltaindiv_run(sid, data, url)
|
|
finally:
|
|
async with lock:
|
|
active_jobs -= 1
|
|
|
|
|
|
@app.post("/deltaindiv-eligibility")
|
|
async def deltaindiv_eligibility(request: Request):
|
|
"""
|
|
Starts a Delta Indiv eligibility session in the background.
|
|
Body: { "data": { ... } }
|
|
Returns: { status: "started", session_id: "<uuid>" }
|
|
"""
|
|
global waiting_jobs
|
|
|
|
body = await request.json()
|
|
data = body.get("data", {})
|
|
|
|
sid = hdeltaindiv.make_session_entry()
|
|
hdeltaindiv.sessions[sid]["type"] = "deltaindiv_eligibility"
|
|
hdeltaindiv.sessions[sid]["last_activity"] = time.time()
|
|
|
|
async with lock:
|
|
waiting_jobs += 1
|
|
|
|
# TODO: replace with the real Delta Indiv sign-in URL
|
|
asyncio.create_task(_deltaindiv_worker_wrapper(sid, data, url="https://www.deltadentalma.com/sign-in"))
|
|
|
|
return {"status": "started", "session_id": sid}
|
|
|
|
|
|
async def _deltains_worker_wrapper(sid: str, data: dict, url: str):
|
|
"""Background worker for DeltaIns — acquires semaphore, updates counters."""
|
|
global active_jobs, waiting_jobs
|
|
async with semaphore:
|
|
async with lock:
|
|
waiting_jobs -= 1
|
|
active_jobs += 1
|
|
try:
|
|
await hdeltains.start_deltains_run(sid, data, url)
|
|
finally:
|
|
async with lock:
|
|
active_jobs -= 1
|
|
|
|
|
|
@app.post("/deltains-eligibility")
|
|
async def deltains_eligibility(request: Request):
|
|
"""
|
|
Starts a DeltaIns eligibility session in the background.
|
|
Body: { "data": { ... } }
|
|
Returns: { status: "started", session_id: "<uuid>" }
|
|
"""
|
|
global waiting_jobs
|
|
|
|
body = await request.json()
|
|
data = body.get("data", {})
|
|
|
|
sid = hdeltains.make_session_entry()
|
|
hdeltains.sessions[sid]["type"] = "deltains_eligibility"
|
|
hdeltains.sessions[sid]["last_activity"] = time.time()
|
|
|
|
async with lock:
|
|
waiting_jobs += 1
|
|
|
|
asyncio.create_task(_deltains_worker_wrapper(
|
|
sid, data,
|
|
url="https://www.deltadentalins.com/ciam/login?TARGET=%2Fprovider-tools%2Fv2"
|
|
))
|
|
|
|
return {"status": "started", "session_id": sid}
|
|
|
|
|
|
async def _unitedsco_worker_wrapper(sid: str, data: dict, url: str):
|
|
"""Background worker for UnitedSCO — acquires semaphore, updates counters."""
|
|
global active_jobs, waiting_jobs
|
|
async with semaphore:
|
|
async with lock:
|
|
waiting_jobs -= 1
|
|
active_jobs += 1
|
|
try:
|
|
await hunitedsco.start_unitedsco_run(sid, data, url)
|
|
finally:
|
|
async with lock:
|
|
active_jobs -= 1
|
|
|
|
|
|
@app.post("/unitedsco-eligibility")
|
|
async def unitedsco_eligibility(request: Request):
|
|
"""
|
|
Starts a UnitedSCO eligibility session in the background.
|
|
Body: { "data": { ... } }
|
|
Returns: { status: "started", session_id: "<uuid>" }
|
|
"""
|
|
global waiting_jobs
|
|
|
|
body = await request.json()
|
|
data = body.get("data", {})
|
|
|
|
sid = hunitedsco.make_session_entry()
|
|
hunitedsco.sessions[sid]["type"] = "unitedsco_eligibility"
|
|
hunitedsco.sessions[sid]["last_activity"] = time.time()
|
|
|
|
async with lock:
|
|
waiting_jobs += 1
|
|
|
|
asyncio.create_task(_unitedsco_worker_wrapper(
|
|
sid, data,
|
|
url="https://app.dentalhub.com/app/login"
|
|
))
|
|
|
|
return {"status": "started", "session_id": sid}
|
|
|
|
|
|
async def _uniteducard_worker_wrapper(sid: str, data: dict, url: str):
|
|
"""Background worker for United Ucard — acquires semaphore, updates counters."""
|
|
global active_jobs, waiting_jobs
|
|
async with semaphore:
|
|
async with lock:
|
|
waiting_jobs -= 1
|
|
active_jobs += 1
|
|
try:
|
|
await huniteducard.start_uniteducard_run(sid, data, url)
|
|
finally:
|
|
async with lock:
|
|
active_jobs -= 1
|
|
|
|
|
|
@app.post("/uniteducard-eligibility")
|
|
async def uniteducard_eligibility(request: Request):
|
|
"""
|
|
Starts a United Ucard (OneHealthcareID) eligibility session in the background.
|
|
Body: { "data": { ... } }
|
|
Returns: { status: "started", session_id: "<uuid>" }
|
|
"""
|
|
global waiting_jobs
|
|
|
|
body = await request.json()
|
|
data = body.get("data", {})
|
|
|
|
sid = huniteducard.make_session_entry()
|
|
huniteducard.sessions[sid]["type"] = "uniteducard_eligibility"
|
|
huniteducard.sessions[sid]["last_activity"] = time.time()
|
|
|
|
async with lock:
|
|
waiting_jobs += 1
|
|
|
|
asyncio.create_task(_uniteducard_worker_wrapper(
|
|
sid, data,
|
|
url="https://www.uhcdental.com/content/provider/dental.html?state=abc"
|
|
))
|
|
|
|
return {"status": "started", "session_id": sid}
|
|
|
|
|
|
async def _dentaquest_worker_wrapper(sid: str, data: dict, url: str):
|
|
"""Background worker for DentaQuest (Tufts SCO) — acquires semaphore, updates counters."""
|
|
global active_jobs, waiting_jobs
|
|
async with semaphore:
|
|
async with lock:
|
|
waiting_jobs -= 1
|
|
active_jobs += 1
|
|
try:
|
|
await hdentaquest.start_dentaquest_run(sid, data, url)
|
|
finally:
|
|
async with lock:
|
|
active_jobs -= 1
|
|
|
|
|
|
@app.post("/dentaquest-eligibility")
|
|
async def dentaquest_eligibility(request: Request):
|
|
"""
|
|
Starts a DentaQuest (Tufts SCO) eligibility session in the background.
|
|
Body: { "data": { ... } }
|
|
Returns: { status: "started", session_id: "<uuid>" }
|
|
"""
|
|
global waiting_jobs
|
|
|
|
body = await request.json()
|
|
data = body.get("data", {})
|
|
|
|
sid = hdentaquest.make_session_entry()
|
|
hdentaquest.sessions[sid]["type"] = "dentaquest_eligibility"
|
|
hdentaquest.sessions[sid]["last_activity"] = time.time()
|
|
|
|
async with lock:
|
|
waiting_jobs += 1
|
|
|
|
asyncio.create_task(_dentaquest_worker_wrapper(
|
|
sid, data,
|
|
url="https://providers.dentaquest.com/"
|
|
))
|
|
|
|
return {"status": "started", "session_id": sid}
|
|
|
|
|
|
async def _cca_worker_wrapper(sid: str, data: dict, url: str):
|
|
"""Background worker for CCA — acquires semaphore, updates counters. No OTP."""
|
|
global active_jobs, waiting_jobs
|
|
async with semaphore:
|
|
async with lock:
|
|
waiting_jobs -= 1
|
|
active_jobs += 1
|
|
try:
|
|
await hcca.start_cca_run(sid, data, url)
|
|
finally:
|
|
async with lock:
|
|
active_jobs -= 1
|
|
|
|
|
|
@app.post("/cca-eligibility")
|
|
async def cca_eligibility(request: Request):
|
|
"""
|
|
Starts a CCA eligibility session in the background (no OTP).
|
|
Body: { "data": { ... } }
|
|
Returns: { status: "started", session_id: "<uuid>" }
|
|
"""
|
|
global waiting_jobs
|
|
|
|
body = await request.json()
|
|
data = body.get("data", {})
|
|
|
|
sid = hcca.make_session_entry()
|
|
hcca.sessions[sid]["type"] = "cca_eligibility"
|
|
hcca.sessions[sid]["last_activity"] = time.time()
|
|
|
|
async with lock:
|
|
waiting_jobs += 1
|
|
|
|
asyncio.create_task(_cca_worker_wrapper(
|
|
sid, data,
|
|
url="https://pwp.sciondental.com/PWP/Landing"
|
|
))
|
|
|
|
return {"status": "started", "session_id": sid}
|
|
|
|
|
|
async def _bcbs_ma_worker_wrapper(sid: str, data: dict, url: str):
|
|
"""Background worker for BCBS MA eligibility — fresh browser, always OTP."""
|
|
global active_jobs, waiting_jobs
|
|
async with semaphore:
|
|
async with lock:
|
|
waiting_jobs -= 1
|
|
active_jobs += 1
|
|
try:
|
|
await hbcbs_ma.start_bcbs_ma_run(sid, data, url)
|
|
finally:
|
|
async with lock:
|
|
active_jobs -= 1
|
|
|
|
|
|
@app.post("/bcbs-ma-eligibility")
|
|
async def bcbs_ma_eligibility(request: Request):
|
|
"""
|
|
Starts a BCBS MA eligibility session in the background.
|
|
Fresh Chrome each time — no persistent session (OTP always required).
|
|
Body: { "data": { memberId, dateOfBirth, firstName, lastName, bcbsMaUsername, bcbsMaPassword } }
|
|
Returns: { status: "started", session_id: "<uuid>" }
|
|
"""
|
|
global waiting_jobs
|
|
|
|
body = await request.json()
|
|
data = body.get("data", {})
|
|
|
|
sid = hbcbs_ma.make_session_entry()
|
|
hbcbs_ma.sessions[sid]["type"] = "bcbs_ma_eligibility"
|
|
hbcbs_ma.sessions[sid]["last_activity"] = time.time()
|
|
|
|
async with lock:
|
|
waiting_jobs += 1
|
|
|
|
asyncio.create_task(_bcbs_ma_worker_wrapper(
|
|
sid, data,
|
|
url="https://provider.bluecrossma.com/ProviderHome/portal/"
|
|
))
|
|
|
|
return {"status": "started", "session_id": sid}
|
|
|
|
|
|
async def _cca_claim_worker_wrapper(sid: str, data: dict, url: str):
|
|
"""Background worker for CCA claim submission."""
|
|
global active_jobs, waiting_jobs
|
|
async with semaphore:
|
|
async with lock:
|
|
waiting_jobs -= 1
|
|
active_jobs += 1
|
|
try:
|
|
await hcca_claim.start_cca_claim_run(sid, data, url)
|
|
finally:
|
|
async with lock:
|
|
active_jobs -= 1
|
|
|
|
|
|
@app.post("/cca-claim")
|
|
async def cca_claim(request: Request):
|
|
"""
|
|
Starts a CCA claim submission session in the background.
|
|
Logs in, navigates Claims > Submit Claims, opens claim entry page.
|
|
Body: { "claim": { "cca_username": "...", "cca_password": "...", ... } }
|
|
Returns: { status: "started", session_id: "<uuid>" }
|
|
"""
|
|
global waiting_jobs
|
|
|
|
body = await request.json()
|
|
|
|
sid = hcca_claim.make_session_entry()
|
|
hcca_claim.sessions[sid]["type"] = "cca_claim"
|
|
hcca_claim.sessions[sid]["last_activity"] = time.time()
|
|
|
|
async with lock:
|
|
waiting_jobs += 1
|
|
|
|
asyncio.create_task(_cca_claim_worker_wrapper(
|
|
sid, body,
|
|
url="https://pwp.sciondental.com/PWP/Landing"
|
|
))
|
|
|
|
return {"status": "started", "session_id": sid}
|
|
|
|
|
|
async def _ddma_claim_worker_wrapper(sid: str, data: dict, url: str):
|
|
"""Background worker for DDMA claim submission."""
|
|
global active_jobs, waiting_jobs
|
|
async with semaphore:
|
|
async with lock:
|
|
waiting_jobs -= 1
|
|
active_jobs += 1
|
|
try:
|
|
await hddma_claim.start_ddma_claim_run(sid, data, url)
|
|
finally:
|
|
async with lock:
|
|
active_jobs -= 1
|
|
|
|
|
|
@app.post("/ddma-claim")
|
|
async def ddma_claim(request: Request):
|
|
"""
|
|
Starts a DDMA claim submission session in the background.
|
|
Logs in, searches patient, opens Member Information page, clicks Create claim,
|
|
fills service date and procedure code.
|
|
Body: { "claim": { "massddmaUsername": "...", "massddmaPassword": "...", ... } }
|
|
Returns: { status: "started", session_id: "<uuid>" }
|
|
"""
|
|
global waiting_jobs
|
|
|
|
body = await request.json()
|
|
|
|
sid = hddma_claim.make_session_entry()
|
|
hddma_claim.sessions[sid]["type"] = "ddma_claim"
|
|
hddma_claim.sessions[sid]["last_activity"] = time.time()
|
|
|
|
async with lock:
|
|
waiting_jobs += 1
|
|
|
|
asyncio.create_task(_ddma_claim_worker_wrapper(
|
|
sid, body,
|
|
url="https://www.deltadentalma.com/sign-in"
|
|
))
|
|
|
|
return {"status": "started", "session_id": sid}
|
|
|
|
|
|
async def _deltains_claim_worker_wrapper(sid: str, data: dict, url: str):
|
|
"""Background worker for Deltains claim submission."""
|
|
global active_jobs, waiting_jobs
|
|
async with semaphore:
|
|
async with lock:
|
|
waiting_jobs -= 1
|
|
active_jobs += 1
|
|
try:
|
|
await hdeltains_claim.start_deltains_claim_run(sid, data, url)
|
|
finally:
|
|
async with lock:
|
|
active_jobs -= 1
|
|
|
|
|
|
@app.post("/deltains-claim")
|
|
async def deltains_claim(request: Request):
|
|
"""
|
|
Starts a Deltains claim submission session in the background.
|
|
Logs in, searches patient, opens the member's eligibility/benefits page,
|
|
finds the claim-submission entry point, fills service lines, and submits.
|
|
Body: { "claim": { "deltainsUsername": "...", "deltainsPassword": "...", ... } }
|
|
Returns: { status: "started", session_id: "<uuid>" }
|
|
"""
|
|
global waiting_jobs
|
|
|
|
body = await request.json()
|
|
|
|
sid = hdeltains_claim.make_session_entry()
|
|
hdeltains_claim.sessions[sid]["type"] = "deltains_claim"
|
|
hdeltains_claim.sessions[sid]["last_activity"] = time.time()
|
|
|
|
async with lock:
|
|
waiting_jobs += 1
|
|
|
|
asyncio.create_task(_deltains_claim_worker_wrapper(
|
|
sid, body,
|
|
url="https://www.deltadentalins.com/ciam/login?TARGET=%2Fprovider-tools%2Fv2"
|
|
))
|
|
|
|
return {"status": "started", "session_id": sid}
|
|
|
|
|
|
async def _uniteddh_claim_worker_wrapper(sid: str, data: dict, url: str):
|
|
"""Background worker for United/DentalHub claim submission."""
|
|
global active_jobs, waiting_jobs
|
|
async with semaphore:
|
|
async with lock:
|
|
waiting_jobs -= 1
|
|
active_jobs += 1
|
|
try:
|
|
await huniteddh_claim.start_uniteddh_claim_run(sid, data, url)
|
|
finally:
|
|
async with lock:
|
|
active_jobs -= 1
|
|
|
|
|
|
@app.post("/uniteddh-claim")
|
|
async def uniteddh_claim(request: Request):
|
|
"""
|
|
Starts a United/DentalHub claim submission session in the background.
|
|
Logs in, searches patient, opens Member Information page, clicks Create claim,
|
|
fills service date and procedure codes.
|
|
Body: { "claim": { "uniteddhUsername": "...", "uniteddhPassword": "...", ... } }
|
|
Returns: { status: "started", session_id: "<uuid>" }
|
|
"""
|
|
global waiting_jobs
|
|
|
|
body = await request.json()
|
|
|
|
sid = huniteddh_claim.make_session_entry()
|
|
huniteddh_claim.sessions[sid]["type"] = "uniteddh_claim"
|
|
huniteddh_claim.sessions[sid]["last_activity"] = time.time()
|
|
|
|
async with lock:
|
|
waiting_jobs += 1
|
|
|
|
asyncio.create_task(_uniteddh_claim_worker_wrapper(
|
|
sid, body,
|
|
url="https://app.dentalhub.com/app/login"
|
|
))
|
|
|
|
return {"status": "started", "session_id": sid}
|
|
|
|
|
|
async def _tuftssco_claim_worker_wrapper(sid: str, data: dict, url: str):
|
|
"""Background worker for Tufts SCO (DentaQuest) claim submission."""
|
|
global active_jobs, waiting_jobs
|
|
async with semaphore:
|
|
async with lock:
|
|
waiting_jobs -= 1
|
|
active_jobs += 1
|
|
try:
|
|
await htuftssco_claim.start_tuftssco_claim_run(sid, data, url)
|
|
finally:
|
|
async with lock:
|
|
active_jobs -= 1
|
|
|
|
|
|
@app.post("/tuftssco-claim")
|
|
async def tuftssco_claim(request: Request):
|
|
"""
|
|
Starts a Tufts SCO (DentaQuest) claim submission session in the background.
|
|
Logs in, searches patient, opens Member Information page, clicks Create claim,
|
|
fills service date and procedure codes.
|
|
Body: { "claim": { "dentaquestUsername": "...", "dentaquestPassword": "...", ... } }
|
|
Returns: { status: "started", session_id: "<uuid>" }
|
|
"""
|
|
global waiting_jobs
|
|
|
|
body = await request.json()
|
|
|
|
sid = htuftssco_claim.make_session_entry()
|
|
htuftssco_claim.sessions[sid]["type"] = "tuftssco_claim"
|
|
htuftssco_claim.sessions[sid]["last_activity"] = time.time()
|
|
|
|
async with lock:
|
|
waiting_jobs += 1
|
|
|
|
asyncio.create_task(_tuftssco_claim_worker_wrapper(
|
|
sid, body,
|
|
url="https://providers.dentaquest.com/"
|
|
))
|
|
|
|
return {"status": "started", "session_id": sid}
|
|
|
|
|
|
async def _uniteducard_claim_worker_wrapper(sid: str, data: dict, url: str):
|
|
"""Background worker for United Ucard claim — acquires semaphore, updates counters."""
|
|
global active_jobs, waiting_jobs
|
|
async with semaphore:
|
|
async with lock:
|
|
waiting_jobs -= 1
|
|
active_jobs += 1
|
|
try:
|
|
await huniteducard_claim.start_uniteducard_claim_run(sid, data, url)
|
|
finally:
|
|
async with lock:
|
|
active_jobs -= 1
|
|
|
|
|
|
@app.post("/uniteducard-claim")
|
|
async def uniteducard_claim(request: Request):
|
|
"""
|
|
Starts a United Ucard (UHC Dental) claim submission session in the background.
|
|
Logs in (shares the persistent browser/profile with the eligibility check,
|
|
so a trusted device skips OTP), then runs the claim-form steps.
|
|
Body: { "claim": { "uniteducardUsername": "...", "uniteducardPassword": "...", ... } }
|
|
Returns: { status: "started", session_id: "<uuid>" }
|
|
"""
|
|
global waiting_jobs
|
|
|
|
body = await request.json()
|
|
|
|
sid = huniteducard_claim.make_session_entry()
|
|
huniteducard_claim.sessions[sid]["type"] = "uniteducard_claim"
|
|
huniteducard_claim.sessions[sid]["last_activity"] = time.time()
|
|
|
|
async with lock:
|
|
waiting_jobs += 1
|
|
|
|
asyncio.create_task(_uniteducard_claim_worker_wrapper(
|
|
sid, body,
|
|
url="https://www.uhcdental.com/content/provider/dental.html"
|
|
))
|
|
|
|
return {"status": "started", "session_id": sid}
|
|
|
|
|
|
async def _uniteddh_preauth_worker_wrapper(sid: str, data: dict, url: str):
|
|
"""Background worker for United/DentalHub pre-authorization submission."""
|
|
global active_jobs, waiting_jobs
|
|
async with semaphore:
|
|
async with lock:
|
|
waiting_jobs -= 1
|
|
active_jobs += 1
|
|
try:
|
|
await huniteddh_preauth.start_uniteddh_preauth_run(sid, data, url)
|
|
finally:
|
|
async with lock:
|
|
active_jobs -= 1
|
|
|
|
|
|
@app.post("/uniteddh-preauth")
|
|
async def uniteddh_preauth(request: Request):
|
|
"""
|
|
Starts a United/DentalHub pre-authorization session in the background.
|
|
Logs in (persistent session, OTP on first use), searches patient, clicks Submit
|
|
Pre-Authorization, fills the form and submits.
|
|
Body: { "claim": { "uniteddhUsername": "...", "uniteddhPassword": "...", ... } }
|
|
Returns: { status: "started", session_id: "<uuid>" }
|
|
"""
|
|
global waiting_jobs
|
|
|
|
body = await request.json()
|
|
|
|
sid = huniteddh_preauth.make_session_entry()
|
|
huniteddh_preauth.sessions[sid]["type"] = "uniteddh_preauth"
|
|
huniteddh_preauth.sessions[sid]["last_activity"] = time.time()
|
|
|
|
async with lock:
|
|
waiting_jobs += 1
|
|
|
|
asyncio.create_task(_uniteddh_preauth_worker_wrapper(
|
|
sid, body,
|
|
url="https://app.dentalhub.com/app/login"
|
|
))
|
|
|
|
return {"status": "started", "session_id": sid}
|
|
|
|
|
|
async def _tuftssco_preauth_worker_wrapper(sid: str, data: dict, url: str):
|
|
"""Background worker for Tufts SCO (DentaQuest) pre-authorization submission."""
|
|
global active_jobs, waiting_jobs
|
|
async with semaphore:
|
|
async with lock:
|
|
waiting_jobs -= 1
|
|
active_jobs += 1
|
|
try:
|
|
await htuftssco_preauth.start_tuftssco_preauth_run(sid, data, url)
|
|
finally:
|
|
async with lock:
|
|
active_jobs -= 1
|
|
|
|
|
|
@app.post("/tuftssco-preauth")
|
|
async def tuftssco_preauth(request: Request):
|
|
"""
|
|
Starts a Tufts SCO (DentaQuest) pre-authorization session in the background.
|
|
Logs in (persistent session, OTP on first use), searches patient, clicks
|
|
Create Prior Authorization, fills the form and submits.
|
|
Body: { "claim": { "dentaquestUsername": "...", "dentaquestPassword": "...", ... } }
|
|
Returns: { status: "started", session_id: "<uuid>" }
|
|
"""
|
|
global waiting_jobs
|
|
|
|
body = await request.json()
|
|
|
|
sid = htuftssco_preauth.make_session_entry()
|
|
htuftssco_preauth.sessions[sid]["type"] = "tuftssco_preauth"
|
|
htuftssco_preauth.sessions[sid]["last_activity"] = time.time()
|
|
|
|
async with lock:
|
|
waiting_jobs += 1
|
|
|
|
asyncio.create_task(_tuftssco_preauth_worker_wrapper(
|
|
sid, body,
|
|
url="https://providers.dentaquest.com/"
|
|
))
|
|
|
|
return {"status": "started", "session_id": sid}
|
|
|
|
|
|
async def _cca_preauth_worker_wrapper(sid: str, data: dict, url: str):
|
|
"""Background worker for CCA pre-authorization submission."""
|
|
global active_jobs, waiting_jobs
|
|
async with semaphore:
|
|
async with lock:
|
|
waiting_jobs -= 1
|
|
active_jobs += 1
|
|
try:
|
|
await hcca_preauth.start_cca_preauth_run(sid, data, url)
|
|
finally:
|
|
async with lock:
|
|
active_jobs -= 1
|
|
|
|
|
|
@app.post("/cca-preauth")
|
|
async def cca_preauth(request: Request):
|
|
"""
|
|
Starts a CCA pre-authorization session in the background.
|
|
Logs in, navigates to Authorization Entry, fills the form and submits.
|
|
Body: { "claim": { "cca_username": "...", "cca_password": "...", ... } }
|
|
Returns: { status: "started", session_id: "<uuid>" }
|
|
"""
|
|
global waiting_jobs
|
|
|
|
body = await request.json()
|
|
|
|
sid = hcca_preauth.make_session_entry()
|
|
hcca_preauth.sessions[sid]["type"] = "cca_preauth"
|
|
hcca_preauth.sessions[sid]["last_activity"] = time.time()
|
|
|
|
async with lock:
|
|
waiting_jobs += 1
|
|
|
|
asyncio.create_task(_cca_preauth_worker_wrapper(
|
|
sid, body,
|
|
url="https://pwp.sciondental.com/PWP/Landing"
|
|
))
|
|
|
|
return {"status": "started", "session_id": sid}
|
|
|
|
|
|
@app.post("/submit-otp")
|
|
async def submit_otp(request: Request):
|
|
"""
|
|
Body: { "session_id": "<sid>", "otp": "123456" }
|
|
Tries each session store in order (CCA has no OTP but included for completeness).
|
|
"""
|
|
body = await request.json()
|
|
sid = body.get("session_id")
|
|
otp = body.get("otp")
|
|
if not sid or not otp:
|
|
raise HTTPException(status_code=400, detail="session_id and otp required")
|
|
|
|
# Try each session store in order
|
|
if sid in hddma.sessions:
|
|
res = hddma.submit_otp(sid, otp)
|
|
elif sid in hdeltaindiv.sessions:
|
|
res = hdeltaindiv.submit_otp(sid, otp)
|
|
elif sid in hdeltains.sessions:
|
|
res = hdeltains.submit_otp(sid, otp)
|
|
elif sid in hunitedsco.sessions:
|
|
res = hunitedsco.submit_otp(sid, otp)
|
|
elif sid in huniteducard.sessions:
|
|
res = huniteducard.submit_otp(sid, otp)
|
|
elif sid in hdentaquest.sessions:
|
|
res = hdentaquest.submit_otp(sid, otp)
|
|
elif sid in hddma_claim.sessions:
|
|
res = hddma_claim.submit_otp(sid, otp)
|
|
elif sid in hdeltains_claim.sessions:
|
|
res = hdeltains_claim.submit_otp(sid, otp)
|
|
elif sid in huniteddh_claim.sessions:
|
|
res = huniteddh_claim.submit_otp(sid, otp)
|
|
elif sid in huniteddh_preauth.sessions:
|
|
res = huniteddh_preauth.submit_otp(sid, otp)
|
|
elif sid in htuftssco_claim.sessions:
|
|
res = htuftssco_claim.submit_otp(sid, otp)
|
|
elif sid in htuftssco_preauth.sessions:
|
|
res = htuftssco_preauth.submit_otp(sid, otp)
|
|
elif sid in huniteducard_claim.sessions:
|
|
res = huniteducard_claim.submit_otp(sid, otp)
|
|
elif sid in hbcbs_ma.sessions:
|
|
res = hbcbs_ma.submit_otp(sid, otp)
|
|
elif sid in hmetlife.sessions:
|
|
res = hmetlife.submit_otp(sid, otp)
|
|
else:
|
|
raise HTTPException(status_code=404, detail="session not found")
|
|
|
|
if res.get("status") == "error":
|
|
raise HTTPException(status_code=400, detail=res.get("message"))
|
|
return res
|
|
|
|
|
|
@app.get("/session/{sid}/status")
|
|
async def session_status(sid: str):
|
|
# Try each session store in order
|
|
if sid in hddma.sessions:
|
|
s = hddma.get_session_status(sid)
|
|
elif sid in hdeltaindiv.sessions:
|
|
s = hdeltaindiv.get_session_status(sid)
|
|
elif sid in hdeltains.sessions:
|
|
s = hdeltains.get_session_status(sid)
|
|
elif sid in hunitedsco.sessions:
|
|
s = hunitedsco.get_session_status(sid)
|
|
elif sid in huniteducard.sessions:
|
|
s = huniteducard.get_session_status(sid)
|
|
elif sid in hdentaquest.sessions:
|
|
s = hdentaquest.get_session_status(sid)
|
|
elif sid in hcca.sessions:
|
|
s = hcca.get_session_status(sid)
|
|
elif sid in hcca_claim.sessions:
|
|
s = hcca_claim.get_session_status(sid)
|
|
elif sid in hcca_preauth.sessions:
|
|
s = hcca_preauth.get_session_status(sid)
|
|
elif sid in hddma_claim.sessions:
|
|
s = hddma_claim.get_session_status(sid)
|
|
elif sid in hdeltains_claim.sessions:
|
|
s = hdeltains_claim.get_session_status(sid)
|
|
elif sid in huniteddh_claim.sessions:
|
|
s = huniteddh_claim.get_session_status(sid)
|
|
elif sid in huniteddh_preauth.sessions:
|
|
s = huniteddh_preauth.get_session_status(sid)
|
|
elif sid in htuftssco_claim.sessions:
|
|
s = htuftssco_claim.get_session_status(sid)
|
|
elif sid in htuftssco_preauth.sessions:
|
|
s = htuftssco_preauth.get_session_status(sid)
|
|
elif sid in huniteducard_claim.sessions:
|
|
s = huniteducard_claim.get_session_status(sid)
|
|
elif sid in hbcbs_ma.sessions:
|
|
s = hbcbs_ma.get_session_status(sid)
|
|
elif sid in hmetlife.sessions:
|
|
s = hmetlife.get_session_status(sid)
|
|
else:
|
|
s = {"status": "not_found"}
|
|
if s.get("status") == "not_found":
|
|
raise HTTPException(status_code=404, detail="session not found")
|
|
return s
|
|
|
|
|
|
# ── Session management endpoints ─────────────────────────────────────────────
|
|
|
|
@app.post("/clear-ddma-session")
|
|
async def clear_ddma_session_endpoint():
|
|
"""Clears the DDMA browser session. Call when credentials are deleted or changed."""
|
|
try:
|
|
clear_ddma_session_on_startup()
|
|
return {"status": "success", "message": "DDMA session cleared"}
|
|
except Exception as e:
|
|
return {"status": "error", "message": str(e)}
|
|
|
|
|
|
@app.post("/clear-deltaindiv-session")
|
|
async def clear_deltaindiv_session_endpoint():
|
|
"""Clears the Delta Indiv browser session. Call when credentials are deleted or changed."""
|
|
try:
|
|
clear_deltaindiv_session_on_startup()
|
|
return {"status": "success", "message": "Delta Indiv session cleared"}
|
|
except Exception as e:
|
|
return {"status": "error", "message": str(e)}
|
|
|
|
|
|
@app.post("/clear-deltains-session")
|
|
async def clear_deltains_session_endpoint():
|
|
"""Clears the DeltaIns browser session. Call when credentials are deleted or changed."""
|
|
try:
|
|
clear_deltains_session_on_startup()
|
|
return {"status": "success", "message": "DeltaIns session cleared"}
|
|
except Exception as e:
|
|
return {"status": "error", "message": str(e)}
|
|
|
|
|
|
@app.post("/clear-unitedsco-session")
|
|
async def clear_unitedsco_session_endpoint():
|
|
"""Clears the UnitedSCO browser session. Call when credentials are deleted or changed."""
|
|
try:
|
|
clear_unitedsco_session_on_startup()
|
|
return {"status": "success", "message": "UnitedSCO session cleared"}
|
|
except Exception as e:
|
|
return {"status": "error", "message": str(e)}
|
|
|
|
|
|
@app.post("/clear-uniteducard-session")
|
|
async def clear_uniteducard_session_endpoint():
|
|
"""Clears the United Ucard browser session. Call when credentials are deleted or changed."""
|
|
try:
|
|
clear_uniteducard_session_on_startup()
|
|
return {"status": "success", "message": "United Ucard session cleared"}
|
|
except Exception as e:
|
|
return {"status": "error", "message": str(e)}
|
|
|
|
|
|
@app.post("/clear-cca-session")
|
|
async def clear_cca_session_endpoint():
|
|
"""Clears the CCA browser session. Call when credentials are deleted or changed."""
|
|
try:
|
|
clear_cca_session_on_startup()
|
|
return {"status": "success", "message": "CCA session cleared"}
|
|
except Exception as e:
|
|
return {"status": "error", "message": str(e)}
|
|
|
|
|
|
@app.post("/clear-metlife-session")
|
|
async def clear_metlife_session_endpoint():
|
|
"""Clears the MetLife browser session. Call when credentials are deleted or changed."""
|
|
try:
|
|
clear_metlife_session_on_startup()
|
|
return {"status": "success", "message": "MetLife session cleared"}
|
|
except Exception as e:
|
|
return {"status": "error", "message": str(e)}
|
|
|
|
|
|
# ✅ Health Check Endpoint
|
|
@app.get("/")
|
|
async def health_check():
|
|
return {
|
|
"status": "ok",
|
|
"service": "Selenium Service",
|
|
"message": "Service is running"
|
|
}
|
|
|
|
# ✅ Status Endpoint
|
|
@app.get("/status")
|
|
async def get_status():
|
|
async with lock:
|
|
return {
|
|
"active_jobs": active_jobs,
|
|
"queued_jobs": waiting_jobs,
|
|
"status": "busy" if active_jobs > 0 or waiting_jobs > 0 else "idle"
|
|
}
|
|
|
|
if __name__ == "__main__":
|
|
host = os.getenv("HOST", "0.0.0.0") # Default to 0.0.0.0 to accept connections from all interfaces
|
|
port = int(os.getenv("PORT", "5002")) # Default to 5002
|
|
print(f"Starting Selenium service on {host}:{port}")
|
|
uvicorn.run(app, host=host, port=port)
|