feat: save claim attachments to cloud storage and documents page
- Claim file uploads (chatbot or manual) now save to both the Cloud Storage patient folder and the Documents page via new POST /api/claims/upload-to-cloud endpoint - MH submit flow now calls uploadAttachmentsToLocalFolder (same as DDMA/United/Tufts) so chatbot-attached X-rays are persisted - Removed old /upload-attachments disk route and attachmentDiskStorage multer config; deleted uploads/patients/ folder - uploadAttachmentsToLocalFolder now points to /upload-to-cloud and sends patientId so the backend can create the patient folder Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -11,6 +11,13 @@ import { ChatClassification } from "./internal-chat-graph";
|
||||
import { lookupCdtCodes } from "./cdt-lookup";
|
||||
import insuranceAliases from "../data/insuranceAliases.json";
|
||||
|
||||
// Phrases the user may write to mean "attach the uploaded file" — not CDT procedures
|
||||
const ATTACHMENT_PHRASES = /^(with\s+)?(the\s+)?(x[\s-]?ray[s]?|xray[s]?|radiograph[s]?|image[s]?|film[s]?|attachment[s]?|attach|file[s]?|photo[s]?|picture[s]?|scan[s]?|doc(ument)?[s]?)$/i;
|
||||
|
||||
function stripAttachmentRefs(names: string[]): string[] {
|
||||
return names.filter((n) => !ATTACHMENT_PHRASES.test(n.trim()));
|
||||
}
|
||||
|
||||
// ─── Types ────────────────────────────────────────────────────────────────────
|
||||
|
||||
export interface ResolvedPatient {
|
||||
@@ -358,6 +365,7 @@ async function handleEligibilityById(
|
||||
dob: resolvedDob,
|
||||
siteKey,
|
||||
autoCheck: siteKeyToAutoCheck(siteKey),
|
||||
appointmentDate: c.appointmentDate ?? null,
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -423,7 +431,7 @@ async function handleCheckAndClaim(
|
||||
}
|
||||
|
||||
// 3. Map procedure names → CDT codes (custom aliases take priority)
|
||||
const procedureNames = c.procedureNames ?? [];
|
||||
const procedureNames = stripAttachmentRefs(c.procedureNames ?? []);
|
||||
const cdtResults: CdtResult[] = procedureNames.length > 0
|
||||
? lookupCdtCodes(procedureNames, customAliases)
|
||||
: [];
|
||||
@@ -492,7 +500,7 @@ async function handleClaimOnly(
|
||||
const fullName = `${patient.firstName ?? ""} ${patient.lastName ?? ""}`.trim();
|
||||
|
||||
// Map procedure names → CDT codes
|
||||
const procedureNames = c.procedureNames ?? [];
|
||||
const procedureNames = stripAttachmentRefs(c.procedureNames ?? []);
|
||||
if (procedureNames.length === 0) {
|
||||
return { reply: "Please specify which procedures to claim (e.g. perio exam, adult prophy)." };
|
||||
}
|
||||
@@ -741,15 +749,16 @@ async function handleScheduleAppointment(
|
||||
export async function createAppointmentToday(
|
||||
patientId: number,
|
||||
userId: number,
|
||||
storage: StorageLike
|
||||
storage: StorageLike,
|
||||
targetDate?: string // YYYY-MM-DD; defaults to today
|
||||
): Promise<{ startTime: string; endTime: string; dateStr: string; dateLabel: string; column: string } | { error: string }> {
|
||||
const today = new Date();
|
||||
const dateStr = `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, "0")}-${String(today.getDate()).padStart(2, "0")}`;
|
||||
const dateLabel = today.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" });
|
||||
const localDate = new Date(today.getFullYear(), today.getMonth(), today.getDate());
|
||||
const base = targetDate ? new Date(targetDate + "T00:00:00") : new Date();
|
||||
const dateStr = `${base.getFullYear()}-${String(base.getMonth() + 1).padStart(2, "0")}-${String(base.getDate()).padStart(2, "0")}`;
|
||||
const dateLabel = base.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" });
|
||||
const localDate = new Date(base.getFullYear(), base.getMonth(), base.getDate());
|
||||
|
||||
const dayNames = ["sunday", "monday", "tuesday", "wednesday", "thursday", "friday", "saturday"];
|
||||
const dayName = dayNames[today.getDay()]!;
|
||||
const dayName = dayNames[base.getDay()]!;
|
||||
|
||||
const officeHours = await storage.getOfficeHours(userId);
|
||||
const dayHours = officeHours?.data?.doctors?.[dayName] ?? {
|
||||
@@ -757,7 +766,7 @@ export async function createAppointmentToday(
|
||||
};
|
||||
|
||||
if (!dayHours.enabled) {
|
||||
return { error: `The office is closed today (${dayName}). Cannot create appointment.` };
|
||||
return { error: `The office is closed on ${dayName} (${dateLabel}). Cannot create appointment.` };
|
||||
}
|
||||
|
||||
const allSlots = buildSlots(dayHours);
|
||||
|
||||
Reference in New Issue
Block a user