feat: batch eligibility by patient name + "Check All & Appointment Today" option

- Add batch_eligibility_by_name intent so "check Mary and Sinthia" resolves multiple names
- Add "Check All & Appointment Today" button to batch eligibility UI — creates appointment for each patient after their eligibility check completes

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
ff
2026-06-19 23:32:05 -04:00
parent e081f32648
commit 60689e58f6
4 changed files with 136 additions and 8 deletions

View File

@@ -323,6 +323,10 @@ export async function runInternalChatWorkflow(
return await handleBatchEligibility(classification, storage);
}
if (intent === "batch_eligibility_by_name") {
return await handleBatchEligibilityByName(classification, storage);
}
// ── Check eligibility + claim procedures ──────────────────────────────────
if (intent === "check_and_claim") {
@@ -525,6 +529,95 @@ async function handleBatchEligibility(
};
}
// ─── batch_eligibility_by_name ───────────────────────────────────────────────
async function handleBatchEligibilityByName(
c: ChatClassification,
storage: StorageLike
): Promise<ChatResponse> {
const names = c.patientNames ?? [];
if (names.length < 2) {
return { reply: "Please include at least two patient names to batch-check eligibility." };
}
const resolved: {
memberId: string;
dob: string;
siteKey: string;
autoCheck: string;
patient: ResolvedPatient | null;
}[] = [];
const notFound: string[] = [];
const noInsurance: string[] = [];
for (const name of names) {
const trimmed = name.trim();
if (!trimmed) continue;
const raw = await findPatientByName(trimmed, storage);
if (!raw) {
notFound.push(trimmed);
continue;
}
const patient = patientToResult(raw);
const fullName = `${patient.firstName ?? ""} ${patient.lastName ?? ""}`.trim();
if (!patient.insuranceId) {
noInsurance.push(fullName);
continue;
}
const resolvedDob = patient.dateOfBirth ?? null;
if (!resolvedDob) {
noInsurance.push(fullName);
continue;
}
const siteKey = resolveSiteKey(
patient.insuranceProvider ?? null,
c.insuranceHint ?? null
) ?? "MH";
resolved.push({
memberId: patient.insuranceId,
dob: resolvedDob,
siteKey,
autoCheck: siteKeyToAutoCheck(siteKey, resolvedDob),
patient,
});
}
if (resolved.length === 0) {
if (notFound.length > 0) {
return { reply: `Could not find any patients matching: ${notFound.join(", ")}. Please check the spelling.` };
}
if (noInsurance.length > 0) {
return { reply: `Found ${noInsurance.join(", ")} but they have no Member ID or DOB on file. Please add their insurance info first.` };
}
return { reply: "Could not resolve any patients for eligibility check." };
}
const labels = resolved.map((r) => {
const name = r.patient
? `${r.patient.firstName ?? ""} ${r.patient.lastName ?? ""}`.trim()
: `ID ${r.memberId}`;
return name;
});
let reply = `Ready to check eligibility for ${resolved.length} patients: ${labels.join(", ")}.`;
if (notFound.length > 0) {
reply += ` Could not find: ${notFound.join(", ")}.`;
}
if (noInsurance.length > 0) {
reply += ` Missing insurance info: ${noInsurance.join(", ")}.`;
}
return {
reply,
action: "batch_eligibility_ready",
actionData: { queue: resolved },
};
}
// ─── batch_check_and_claim ────────────────────────────────────────────────────
async function handleBatchCheckAndClaim(