feat: MetLife Dental eligibility check with persistent session
Mirrors the DDMA flow: persistent Chrome profile + credential-change logout, PingOne login with email MFA selection and OTP from app or browser, Eligibility & Plan Details search (masked Subscriber ID/SSN), family member picked by DOB and re-verified on the plan details page, PDF saved to the patient's Eligibility folder and status set ACTIVE/INACTIVE. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -31,6 +31,7 @@ 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
|
||||
@@ -40,6 +41,7 @@ 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()
|
||||
@@ -55,6 +57,7 @@ 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)
|
||||
@@ -423,6 +426,46 @@ async def ddma_eligibility(request: Request):
|
||||
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
|
||||
@@ -1126,6 +1169,8 @@ async def submit_otp(request: Request):
|
||||
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")
|
||||
|
||||
@@ -1171,6 +1216,8 @@ async def session_status(sid: str):
|
||||
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":
|
||||
@@ -1240,6 +1287,16 @@ async def clear_cca_session_endpoint():
|
||||
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():
|
||||
|
||||
Reference in New Issue
Block a user