Use appear-then-disappear pattern: briefly wait for spinner to show up
(so we don't pass through before it starts), then wait for it to clear.
Prevents element click interception on Find Provider button in step2.
Also restores element_to_be_clickable for New Eligibility Request (step1).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The exact ng-click='newEligibility();' XPath was failing to match the link.
Replaced with three alternative patterns (partial ng-click, full text, partial
text), added a JS-click fallback for intercepted clicks, and auto-re-opens the
Verification dropdown if it closes before the link is found.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Added getPatientByInsuranceIdAndDob to storage
- Processor uses insuranceId + DOB as unique key instead of insuranceId alone
- Dependent with same subscriber ID but different DOB gets a new patient record
(bypasses createOrUpdatePatientByInsuranceId which would overwrite subscriber)
- Name extraction anchored to "Relationship:" to scope Patient Info column only
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Extract patient first/last name from Patient Information DOM section
(scoped to avoid duplicate Subscriber Information column values)
- Switch to latest tab at start of step2 (Eligibility Identifier opens in new tab)
- DOB: double-click + ActionChains.send_keys (no pyperclip, avoids Chrome crash)
- BCBS MA button changed to variant="default" to match nearby buttons
- Backend processor uses extracted names from selenium result
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- New Selenium worker (fresh Chrome per run, no persistent session)
login → OTP modal → eTools → ConnectCenter → Verification →
New Eligibility Request → fill form (NPI, member ID, DOB) →
Expand All → CDP PDF back to app
- Backend route fetches BCBS_MA credentials + provider NPI from settings
- Frontend OTP modal with 6-digit code entry
- BCBS MA added to insurance credentials dropdown in settings
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Rewrote UnitedDH claim worker to navigate via eligibility page → Selected Patient → Submit Claim button flow
- Updated helpers_uniteddh_claim.py step names to match new 9-step workflow
- Changed payer selection in both eligibility and claim workers to type + Enter
- Updated patient table column header from 'DOB / Gender' to 'DOB'
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Using paymentGroupId label as the page-load wait caused TimeoutException when
the claim flow's page structure differed, returning ERROR and triggering
_minimize_browser (about:blank + minimize). Now waits for the btn-primary
Continue button (original safe indicator) and wraps both dropdown selections
in try/except so the step never fails due to a missed dropdown.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Mirrors the same Provider & Location page pattern from the eligibility worker:
- wait for paymentGroupId label visibility before interacting
- Treatment Location: ng-arrow-wrapper click + ARROW_DOWN/ENTER
- Billing Entity: ng-arrow-wrapper click + ARROW_DOWN/ENTER
- re-find Continue button after selections to avoid stale element
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- United SCO eligibility: add Treatment Location step before Billing Entity
on Provider & Location page; both use ng-arrow-wrapper ActionChains click
+ ARROW_DOWN/ENTER keyboard selection to handle upward-opening panels
- Use visibility_of_element_located for Billing Entity label wait so code
waits for page to fully render after Select Insurance modal closes
- DOB (and all dates) now display as MM/DD/YYYY instead of Mon DD, YYYY
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
DentaQuest stores its MFA trust as a persistent cookie, not in
LocalStorage like DDMA/Azure B2C. Deleting the Cookies file on startup
wiped that trust token, forcing OTP on every app restart. Now only the
credentials tracking file is reset on startup; if credentials change,
_force_logout() still calls delete_all_cookies() for a full reset.
Covers both eligibility and claim flows (both share the same
DentaQuestBrowserManager singleton).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add appointment type categories matching insurance claim form (recall, filling, pedo, dentures, implant, endo, crown, perio, extraction, ortho, consultation, emergency, other)
- Auto-infer appointment type from CDT codes with priority rules (endo > implant > crown > ...)
- typeLocked flag prevents auto-overwrite when user manually sets type
- Show appointment type label and procedure codes on schedule cards
- Background sync on /day route retroactively fixes stale appointment types
- Fix PUT /api/claims/:id to save claimFiles (previously silently dropped)
- Auto-link AppointmentFile records to ClaimFile when claim is created or updated
- Fix D5750 (denture reline) CDT range to map correctly to dentures category
- Fix typeLocked Zod rejection in appointment update route
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Fix Express route ordering in appointments-procedures so /prefill-from-appointment
is matched before /:id (D0140 and other codes now always reach the claim)
- claim-form: always fetch AppointmentProcedure records when an existing claim loads
so post-save procedure edits (e.g. adding D0140) are reflected immediately
- appointments-page: replace sessionStorage with React state (newApptPrefill) for
slot-click prefill so columns B-F correctly carry their staffId into the form
- add-appointment-modal / appointment-form: thread prefillData prop; add
NewAppointmentPrefill interface; useEffect applies values via setValue
- appointments upsert: remove per-patient dedup so the same patient can have
multiple appointments on the same day in the same column
- DentaQuest / TuftsSCO: navigate to about:blank and minimize instead of
quit_driver after each run — session cookie stays in memory so OTP is only
required once per app startup, not on every eligibility or claim check
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Use normalize-space(.) instead of text() to capture button text inside
child elements, add modal-scoped fallback selectors, and prefer JS click
to avoid overlay interception.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- claims.ts: batch-column now routes each patient to the correct portal
(MH/CCA/DDMA/TuftsSCO/UnitedSCO) based on patient.insuranceProvider
- appointments-page.tsx: eligibility badge falls back to patientStatus
for all insurance types, not just MassHealth
- unitedDHClaimProcessor/ddmaClaimProcessor/tuftsSCOClaimProcessor:
auto-save claim PDF when no socketId (batch-column path)
- unitedSCOEligibilityProcessor: unknown eligibility no longer stored as INACTIVE
- queues.ts: add tuftssco-claim-submit and uniteddh-claim-submit to SeleniumJobType
- selenium_UnitedSCO_eligibilityCheckWorker.py:
- step1: add Select Insurance OK click with staleness wait; Provider &
Location page just clicks Continue; skip first/last name input
- step2: extract name from eligibility details tab (ALL CAPS → title case);
skip "not available" guard; fix name regex to match only all-caps words
- .gitignore: ignore all chrome_profile_* directories
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add full Tufts SCO claim Selenium worker (steps 1-8): login with OTP
support, member search, Create Claim, fill form, attach files, submit,
extract claim number and save confirmation PDF
- Fix DentaQuest browser manager to preserve device trust token on startup
(only clear cookies, not LocalStorage/IndexedDB) so OTP is only needed
once for both eligibility and Tufts claim
- Fix Tufts SCO claim route credential lookup key (TUFTS_SCO not TuftsSCO)
- Add Tufts SCO and United/DentalHub entries to fee schedule update route
- Add "Claim All" button that auto-routes to the correct claim handler
based on the Insurance Type dropdown value
- Add fee schedule JSON files for DDMA, Tufts SCO, and United/DentalHub
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- 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>
- Add full DDMA claim Selenium flow (steps 1-8): search patient, open
member page, create claim, fill form, attach files, next, submit,
extract claim number and save confirmation PDF
- Add fee schedule price-mismatch dialog for all claim buttons (MH,
CCA, DDMA, United, Tufts, Save) with optional price update to JSON
- Add OTP modal for DDMA claim when session expires, mirroring
eligibility OTP flow
- Close Chrome after claim submission via quit_driver() (session
preserved in profile)
- Move Map Price button between Direct Submission and procedure table,
right-aligned above Billed Amount column
- Add fee-schedule update-price backend route
- Add DDMA claim processor with claimNumber/pdf_url result handling
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Selenium: bulletproof Wait→Click→Clear→Type→Verify for tooth, billed amt cells
- Selenium: fix billed amt to click td[23] (correct column) to trigger edit mode
- Selenium: skip tentative date (auto-filled by page after tooth entry)
- Frontend: add Implants category with Implant/Abut/Crown, Fixture, Abutment, Crown buttons (D6010/D6057/D6058)
- Frontend: pdf-preview-modal renders PNG screenshots as <img> instead of PDF iframe
- Backend: CCA preauth route creates claim record if none exists
- Backend: CCA preauth processor saves authNumber into claimNumber column after submission
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add CCA claim submit Selenium worker (login, fill form, attach docs, submit, capture dashboard PDF)
- Add CCA fee schedule (procedureCodesMH.json renamed, procedureCodesCCA.json added with D6010)
- Add backend route /api/claims/cca-claim, processor, and Selenium client
- Wire CCA claim handler in claims-page with job tracking and PDF preview popup
- Add insurance type dropdown in claim form (same options as eligibility page)
- Auto-populate insurance type from patient.insuranceProvider in claim form and patient edit form
- Map fee schedule by insurance type in Map Price button and combo buttons
- Fix CCA login speed (remove fixed sleeps, use readyState check)
- Fix CCA claim DOB format bug (was sending MM-DD-YYYY, now sends YYYY-MM-DD)
- Fix npiProviderId not saved for CCA claims
- Change Add Service → CCA Claim button (blue), MH → MH Claim
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
After login, Chrome on some machines opens the portal dashboard in a new
tab and closes the SSO tab. Poll all window handles until the portal URL
is found, then switch to it — works for both same-tab and new-tab redirects.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- MassHealth: detect SSO/portal maintenance page and return clear error
instead of cryptic step1 timeout; wait for SSO redirect to complete
before running step1; add modal dismissal and failure screenshot/logging
- DentaQuest: detect maintenance page in login and step1; search by
member ID + DOB only (remove first/last name to prevent stale data
from previous patient being submitted)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Insurance Forms modal: split into Insurance Claim / PreAuth tabs
- PreAuth tab: same patient info + service lines, no toggle/direct combos
- Excluded Recalls & New Patients, Composite Fillings (Front/Back), Pedo from PreAuth combos
- Extractions: replaced Simple/Surg/Baby Teeth EXT with Full Bony EXT (D7240)
- MH PreAuth button: rewritten selenium worker to use masshealth-dental.org,
selects Dental Prior Authorization (2nd option), skips Date of Service field
- agent.py: convert pdf_path to pdf_url for /claim-pre-auth endpoint
- nginx + Express: raise body size limit to 50mb (fix 413 errors)
- DB schema: appointmentId optional on Claim, add preAuthNumber field, add PREAUTH status
- Backend: create PREAUTH claim record on preauth submit, save preAuthNumber on completion
- Claims table: add PreAuth No column (blue) next to Claim No
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Member info is always present on the accumulator page regardless of
whether dollar amounts exist. Removing the button wait eliminates the
15s freeze for patients with no financial data.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Instead of navigating back and forth, step4 opens the member details URL
in a new tab. Tab A clicks service history and CDP-prints the history PDF.
Tab B clicks View Accumulator and CDP-prints the accumulator PDF (waits
up to 15s for vm.hasResults, then captures whatever is on screen).
Eliminates the Chrome freeze from back-navigation and the empty-accumulator
race condition.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Previously waited up to 60s for vm.hasResults button causing long freeze.
Now caps at 15s then always proceeds — captures data or no-results state.
Extra 5s sleep ensures Angular finishes rendering table rows before CDP print.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
step7 now waits for button[ng-click='vm.printResults()'][ng-if='vm.hasResults']
to become visible before printing — that element only renders once Angular
has loaded the accumulator data, so the CDP capture is no longer racing
against the async data fetch.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
After clicking the member ID link, print the member details page via CDP
before navigating to service history. Adds member details as a panel in
the side-by-side PDF viewer: MH History shows 3 panels (eligibility,
member details, service history); CMSP shows 4 panels (eligibility,
member details, service history, accumulator).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add MH Eligibility & History button: runs full MH eligibility flow then
clicks member ID → service history, prints both PDFs via CDP, opens
dual side-by-side PDF modal (eligibility auto-downloads, history does not)
- Add CMSP Eligibility & History & Remaining button: same flow plus
navigates back to member details, clicks View Accumulator, prints
accumulator PDF via CDP; opens 3-panel side-by-side PDF modal
- Generalize DualPdfPreviewModal to accept panels[] array (works for 2 or 3 PDFs)
- Auto-download eligibility PDF via direct API URL to avoid Chrome Safe
Browsing pause on blob: URL downloads
- New backend processors, job types, and routes for both flows
- New Python Selenium workers with stable CSS selectors (ng-bind, href*)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add selenium_MHPaymentCheckWorker.py: logs into MassHealth portal, navigates to Search Claims, enters claim number, extracts totalPaidAmount from results table
- Register /mh-payment-check endpoint in Selenium agent
- Add mhPaidAmount field to Payment model with migration
- Add PATCH /api/payments/:id/mh-payment-check backend route: fetches MH credentials, calls selenium, stores result
- Add Claim No. column (MassHealth claim number) as first data column in payments table
- Move Payment ID and Claim ID columns to end of table
- Add MH Paid column showing mhPaidAmount in green
- Wire Check MH Payment button to call API for each selected payment and refresh table
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Filter patient list by userId so each user sees only their own patients
- Sort patients by updatedAt DESC so recently checked patients appear first
- Add updatedAt field to Patient model (DB migration via raw SQL + db:generate)
- Fix DDMA name extraction: read from detail page "Name:" label, not search
results row text which included appended dates
- Fix PDF capture: use driver.get() instead of click() to avoid race condition
that was saving the search results page instead of the patient detail page
- Strip trailing bare dates from extracted names (e.g. "Rodriguez 04/27/2026")
- Handle "Last, First" comma format and single-word last names in splitName
- Normalize insuranceId consistently in createOrUpdatePatientByInsuranceId
- Fix OTP persistent session: stop clearing LocalStorage/IndexedDB on startup
(these hold the DDMA device trust token that skips OTP on subsequent logins)
- Increase post-navigation wait time for full page render before PDF generation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Fix Selenium using today's date instead of selected service date; convert YYYY-MM-DD from frontend to MM/DD/YYYY for MassHealth input
- Rename "New Patient (Limited exam+Pano)" → "Patient (Limited exam+Pano)"
- Rename "New Adult Patient (Limited exam+1PA)" → "Patient (Limited exam+1PA)"
- Add "Patient (D9110+1PA)" combo with codes D9110, D0220
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add PLAN_NOT_ACCEPTED to PatientStatus enum (prisma schema + db push)
- Selenium: return "plan not accepted" eligibility text instead of collapsing to inactive
- Backend processor: map "plan not accepted" → PLAN_NOT_ACCEPTED, fix insuranceProvider label
- _shared.ts: save DOB for existing patients when field is currently empty
- Frontend: show amber "Plan Not Accepted" badge in patient table and detail panel
- patient-form.tsx: display "Plan Not Accepted" label in status dropdown
- BullMQ: set attempts=1 (no retry on selenium failure)
- DDMA: remove first/last name from search (member ID + DOB only)
- patient-types.ts: allow alphanumeric insurance IDs
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add /dentaquest-eligibility endpoint in Python agent (Tufts SCO uses providers.dentaquest.com)
- Add backend route, processor, and service client for Tufts SCO (separate from UnitedSCO/DentalHub)
- Fix Tufts SCO button to post to new tuftssco route instead of unitedsco
- Fix credential field names: dentaquestUsername/Password (was tuftsscoUsername/Password)
- Fix socket event: listen for selenium:dentaquest_session_started (was unitedsco)
- Fix error visibility: keep session alive 30s on error so backend reads real message
- Replace free-text Site Key field with dropdown to prevent key mismatches
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Route DDMA eligibility through InProcessQueue (concurrency=1) so it
queues behind other selenium jobs instead of running concurrently
- New ddmaEligibilityProcessor: starts Python session, polls for OTP/
completion via socket events, saves PDF and updates patient DB
- Frontend ddma-buton-modal now uses shared app socket + job:update
pattern (drops private socket connection)
- SeleniumService: upgrade ddma_browser_manager with credential hash
tracking, anti-detection options, and startup session clearing;
upgrade DDMA worker with firstName/lastName support, PDF via
printToPDF, force-logout on credential change; upgrade helpers with
dual OTP strategy (app API + browser polling); add /clear-ddma-session
endpoint; reduce fixed sleeps with smart WebDriverWait
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>