feat: add United Ucard claim worker and fix batch-column site-key routing

Adds a "United Ucard Claim" button (claims/preauth insurance form) that
submits through a full Selenium pipeline mirroring the Tufts SCO claim
worker: frontend handler -> backend route/queue processor -> Python
agent, reusing the persistent login/OTP session from the existing
United Ucard eligibility check. Implements the UHC Dental claim wizard
end-to-end (Provider Information, Patient Information search/select,
Claim Information procedures + questions, Upload Documents, Review and
Sign, Submit); the final confirmation-page PDF/claim-number capture is
still a TODO stub pending that page's DOM.

Also wires United Ucard into the AI chatbot's eligibility flow
(insuranceAliases.json, siteKeyToAutoCheck, clarification options), and
fixes a bug where the AI-column batch claim feature silently defaulted
United Ucard patients to MassHealth because batchColumnDeriveSiteKey
had no matching branch and no job-dispatch case for UNITED_UCARD.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-14 23:27:39 -04:00
co-authored by Claude Sonnet 5
parent f30016e674
commit e570a0aa13
15 changed files with 1695 additions and 2 deletions
+47
View File
@@ -27,6 +27,7 @@ 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 startup session-clear functions
@@ -832,6 +833,48 @@ async def tuftssco_claim(request: Request):
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
@@ -990,6 +1033,8 @@ async def submit_otp(request: Request):
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)
else:
@@ -1029,6 +1074,8 @@ async def session_status(sid: str):
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)
else: