feat: AI chat claim confirmation, CDT alias learning, and eligibility auto-trigger fixes
- Claim flow: show green confirm card (patient, CDT codes, service date) before Selenium starts - CDT lookup: add DIRECT_CODE_MAP + ALIAS_MAP with 60+ dental abbreviations from office fee schedule (2BW→D0272, 4BW→D0274, PA→D0220, FL→D1208, RCT codes, composite tooth#/surface parser, etc.) - Composite filling parser: auto-map "#29 OB" → D2392 based on tooth# (front/back) and surface count - Ask-and-learn: unknown CDT terms block claim and ask user; answer saved to DB alias map for future use - Cancel on confirm card returns to chat (not full reset) so user can correct and retry - Eligibility auto-trigger fix: reset autoTriggeredRef when autoTrigger resets to false so second chatbot eligibility check on same page visit fires correctly (all 5 provider buttons fixed) - check_eligibility by name now returns eligibility_id_ready with correct siteKey for non-MH patients - DDMA/CCA/United/Tufts fee schedules updated with office prices (single Price field, no age split) - getCodeMap case-insensitive matching fix (ddma/cca/etc. now correctly selected) - Family plan member disambiguation: insuranceId+DOB composite lookup prevents overwriting siblings - AI chat date fix: send clientDate from browser to avoid UTC midnight rollover (EST→wrong day) - AI prompt: appointmentDate extracted for claim_only intent when user says "today" or a date Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -102,8 +102,28 @@ export async function createOrUpdatePatientByInsuranceId(options: {
|
||||
|
||||
console.log(`[createOrUpdatePatient] insuranceId="${normalizedId}" firstName="${incomingFirst}" lastName="${incomingLast}" userId=${userId}`);
|
||||
|
||||
let patient = await storage.getPatientByInsuranceId(normalizedId);
|
||||
console.log(`[createOrUpdatePatient] existing patient lookup: ${patient ? `found id=${patient.id}` : "not found"}`);
|
||||
// Family members often share the same insuranceId (e.g. Delta Dental family plans).
|
||||
// When a DOB is provided, look up by insuranceId+DOB so each family member is a
|
||||
// distinct patient record. If the combo doesn't exist → new patient; never
|
||||
// overwrite a different family member who happens to share the same insuranceId.
|
||||
let dobDate: Date | null = null;
|
||||
if (dob) {
|
||||
const parsed = new Date(dob);
|
||||
if (!isNaN(parsed.getTime())) dobDate = parsed;
|
||||
}
|
||||
|
||||
let patient = null;
|
||||
if (dobDate) {
|
||||
// Primary lookup: exact insuranceId + DOB match
|
||||
patient = await storage.getPatientByInsuranceIdAndDob(normalizedId, dobDate);
|
||||
console.log(`[createOrUpdatePatient] id+DOB lookup: ${patient ? `found id=${patient.id}` : "not found"}`);
|
||||
// Do NOT fall back to insuranceId-only lookup — another record with that ID
|
||||
// is a different family member and must not be overwritten.
|
||||
} else {
|
||||
// No DOB supplied — fall back to insuranceId-only (legacy / non-family plans)
|
||||
patient = await storage.getPatientByInsuranceId(normalizedId);
|
||||
console.log(`[createOrUpdatePatient] id-only lookup: ${patient ? `found id=${patient.id}` : "not found"}`);
|
||||
}
|
||||
|
||||
if (patient && patient.id) {
|
||||
const updates: any = {};
|
||||
@@ -111,14 +131,14 @@ export async function createOrUpdatePatientByInsuranceId(options: {
|
||||
updates.firstName = incomingFirst;
|
||||
if (incomingLast && String(patient.lastName ?? "").trim() !== incomingLast)
|
||||
updates.lastName = incomingLast;
|
||||
if (dob && !patient.dateOfBirth) {
|
||||
const parsed = new Date(dob);
|
||||
if (!isNaN(parsed.getTime())) updates.dateOfBirth = parsed;
|
||||
}
|
||||
// Store DOB if not already set
|
||||
if (dobDate && !patient.dateOfBirth) updates.dateOfBirth = dobDate;
|
||||
if (Object.keys(updates).length > 0) {
|
||||
console.log(`[createOrUpdatePatient] updating patient id=${patient.id} with`, updates);
|
||||
await storage.updatePatient(patient.id, updates);
|
||||
patient = await storage.getPatientByInsuranceId(normalizedId);
|
||||
patient = dobDate
|
||||
? await storage.getPatientByInsuranceIdAndDob(normalizedId, dobDate)
|
||||
: await storage.getPatientByInsuranceId(normalizedId);
|
||||
}
|
||||
return patient;
|
||||
}
|
||||
@@ -126,7 +146,7 @@ export async function createOrUpdatePatientByInsuranceId(options: {
|
||||
const createPayload: any = {
|
||||
firstName: incomingFirst,
|
||||
lastName: incomingLast,
|
||||
dateOfBirth: dob,
|
||||
dateOfBirth: dobDate ?? dob, // use parsed Date; fallback to raw string if dobDate is null
|
||||
gender: "",
|
||||
phone: "",
|
||||
userId,
|
||||
|
||||
Reference in New Issue
Block a user