feat: Tufts SCO claim automation, Claim All button, fee schedule updates

- 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>
This commit is contained in:
Gitead
2026-05-25 20:22:26 -04:00
parent 1e581c193c
commit 3534ecb3c9
11 changed files with 5188 additions and 88 deletions

View File

@@ -1202,16 +1202,26 @@ export function ClaimForm({
? npiProviders.find((p) => p.npiNumber === npiProvider.npiNumber)?.id ?? null
: null;
const createdClaim = await onSubmit({
...formToCreateClaim,
serviceLines: filteredServiceLines,
staffId: appointmentStaffId ?? Number(staff?.id),
patientId,
insuranceProvider: "Tufts SCO",
appointmentId: appointmentIdToUse!,
claimFiles: claimFilesMeta,
...(selectedNpiProviderId ? { npiProviderId: selectedNpiProviderId } : {}),
});
let createdClaim: any;
try {
createdClaim = await onSubmit({
...formToCreateClaim,
serviceLines: filteredServiceLines,
staffId: appointmentStaffId ?? Number(staff?.id),
patientId,
insuranceProvider: "Tufts SCO",
appointmentId: appointmentIdToUse!,
claimFiles: claimFilesMeta,
...(selectedNpiProviderId ? { npiProviderId: selectedNpiProviderId } : {}),
});
} catch (err: any) {
toast({
title: "Failed to save claim",
description: err?.message || "An error occurred saving the claim.",
variant: "destructive",
});
return;
}
onHandleForTuftsSCOSeleniumClaim({
...form,
@@ -1228,6 +1238,27 @@ export function ClaimForm({
onClose();
};
const handleClaimAll = () => {
const siteKey = (form.insuranceSiteKey || deriveInsuranceSiteKey(form.insuranceProvider || "")).toUpperCase();
if (siteKey === "MH" || siteKey === "MASSHEALTH") {
runWithPriceCheck(() => handleMHSubmit());
} else if (siteKey === "CCA") {
runWithPriceCheck(handleCCAClaim);
} else if (siteKey === "DDMA") {
runWithPriceCheck(handleDDMAClaim);
} else if (siteKey === "TUFTSSCO" || siteKey === "TUFTS_SCO") {
runWithPriceCheck(handleTuftsSCOClaim);
} else if (siteKey === "UNITEDSCO" || siteKey === "UNITEDDH" || siteKey === "UNITED_SCO") {
runWithPriceCheck(handleUnitedDHClaim);
} else {
toast({
title: "No automated claim for this insurance",
description: `Insurance type "${form.insuranceSiteKey || "unknown"}" does not have an automated claim. Please use one of the buttons below.`,
variant: "destructive",
});
}
};
const handleCCAPreAuth = async () => {
const missingFields: string[] = [];
if (!form.memberId?.trim()) missingFields.push("Member ID");
@@ -2146,6 +2177,15 @@ export function ClaimForm({
</Button>
</div>
) : (
<>
<div className="flex justify-center mb-3">
<Button
className="w-36 bg-slate-800 hover:bg-slate-900 text-white font-semibold"
onClick={handleClaimAll}
>
Claim All
</Button>
</div>
<div className="flex flex-wrap gap-2 justify-center">
<Button
className="w-32 bg-blue-600 hover:bg-blue-700 text-white"
@@ -2184,6 +2224,7 @@ export function ClaimForm({
Claim Saved
</Button>
</div>
</>
)}
</div>
</div>