From 6a3834a7ebdf7301747d06c32b79332fe92e9e88 Mon Sep 17 00:00:00 2001 From: saridsa2 Date: Mon, 20 Apr 2026 15:46:27 +0530 Subject: [PATCH] feat(messaging): conflict check before booking appointment Check for duplicate patient+doctor+date and max 3 slots per time before creating the appointment. Returns actionable message if conflict found. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/messaging/messaging.service.ts | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/messaging/messaging.service.ts b/src/messaging/messaging.service.ts index 9a92a67..ee8e9a6 100644 --- a/src/messaging/messaging.service.ts +++ b/src/messaging/messaging.service.ts @@ -344,6 +344,32 @@ ${callerContext ? `\n${callerContext}` : ''}`; const cleanPhone = phoneNumber.replace(/[^0-9]/g, '').slice(-10); const resolved = await callerService.resolve(cleanPhone, auth).catch(() => null); + // Conflict check: same doctor + same date + const bookingDate = scheduledAt.split('T')[0]; + const existingAppts = await platform.query( + `{ appointments(first: 50, filter: { doctorName: { eq: "${doctorName}" } }, orderBy: [{ scheduledAt: AscNullsLast }]) { edges { node { id scheduledAt status patientName } } } }`, + ).catch(() => ({ appointments: { edges: [] } })); + + const conflicts = existingAppts.appointments.edges + .map((e: any) => e.node) + .filter((a: any) => a.status === 'SCHEDULED' && a.scheduledAt?.startsWith(bookingDate)); + + // Check if this patient already has a booking with this doctor on the same date + const patientConflict = conflicts.find((a: any) => + a.patientName?.toLowerCase().includes(patientName.split(' ')[0].toLowerCase()), + ); + if (patientConflict) { + logger.log(`[WA-BOOK] Conflict: patient already booked with ${doctorName} on ${bookingDate}`); + return { booked: false, message: `You already have an appointment with ${doctorName} on ${bookingDate}. Would you like to choose a different date?` }; + } + + // Check if the doctor has too many appointments at this exact time + const slotConflicts = conflicts.filter((a: any) => a.scheduledAt === scheduledAt); + if (slotConflicts.length >= 3) { + logger.log(`[WA-BOOK] Conflict: ${doctorName} fully booked at ${scheduledAt} (${slotConflicts.length} existing)`); + return { booked: false, message: `${doctorName} is fully booked at this time. Please choose a different slot.` }; + } + if (resolved?.isNew) { const firstName = patientName.split(' ')[0]; const lastName = patientName.split(' ').slice(1).join(' ') || '';