From 77b3e917dbec24862279b549853dc6dbc889cb52 Mon Sep 17 00:00:00 2001 From: saridsa2 Date: Fri, 17 Apr 2026 16:23:48 +0530 Subject: [PATCH] fix: fetch Lead first to resolve patientId before appointments query The build() method previously fetched Lead and Appointments in parallel. When the input patientId was empty (outbound dial, first-time linkage), the appointments query was skipped even though the Lead record in the DB had a valid patientId. Now fetches Lead first, reads its patientId, then fetches appointments/calls/activities in parallel with the correct ID. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/caller/caller-context.service.ts | 49 ++++++++++++++++------------ 1 file changed, 29 insertions(+), 20 deletions(-) diff --git a/src/caller/caller-context.service.ts b/src/caller/caller-context.service.ts index 7f2ec32..ebc40ee 100644 --- a/src/caller/caller-context.service.ts +++ b/src/caller/caller-context.service.ts @@ -89,19 +89,34 @@ export class CallerContextService { private async build(leadId: string, patientId: string, auth: string): Promise { try { - const [leadData, appointmentsData, callsData, activitiesData] = await Promise.all([ - this.platform.queryWithAuth( - `{ lead(filter: { id: { eq: "${leadId}" } }) { - id contactName { firstName lastName } - contactPhone { primaryPhoneNumber } - source status interestedService - aiSummary contactAttempts lastContacted - utmCampaign patientId - } }`, - undefined, auth, - ), - patientId ? this.platform.queryWithAuth( - `{ appointments(first: 10, filter: { patientId: { eq: "${patientId}" } }, orderBy: [{ scheduledAt: DescNullsLast }]) { edges { node { + // Step 1: Fetch lead first to get the authoritative patientId + const leadData = await this.platform.queryWithAuth( + `{ lead(filter: { id: { eq: "${leadId}" } }) { + id contactName { firstName lastName } + contactPhone { primaryPhoneNumber } + source status interestedService + aiSummary contactAttempts lastContacted + utmCampaign patientId + } }`, + undefined, auth, + ); + + const lead = leadData?.lead; + if (!lead) return null; + + // Use Lead's patientId as authoritative source — the input + // param may be empty if caller resolution just linked them. + const resolvedPatientId = patientId || lead.patientId || ''; + this.logger.log(`[CALLER-CTX] Resolved patientId=${resolvedPatientId} (input=${patientId}, lead=${lead.patientId ?? '∅'})`); + + const firstName = lead.contactName?.firstName ?? ''; + const lastName = lead.contactName?.lastName ?? ''; + + // Step 2: Fetch appointments, calls, activities in parallel + // using the resolved patientId from the Lead record. + const [appointmentsData, callsData, activitiesData] = await Promise.all([ + resolvedPatientId ? this.platform.queryWithAuth( + `{ appointments(first: 10, filter: { patientId: { eq: "${resolvedPatientId}" } }, orderBy: [{ scheduledAt: DescNullsLast }]) { edges { node { scheduledAt status doctorName department reasonForVisit } } } }`, undefined, auth, @@ -120,12 +135,6 @@ export class CallerContextService { ), ]); - const lead = leadData?.lead; - if (!lead) return null; - - const firstName = lead.contactName?.firstName ?? ''; - const lastName = lead.contactName?.lastName ?? ''; - const appointments = (appointmentsData?.appointments?.edges ?? []).map((e: any) => e.node); const calls = (callsData?.calls?.edges ?? []).map((e: any) => ({ startedAt: e.node.startedAt, @@ -148,7 +157,7 @@ export class CallerContextService { return { leadId, - patientId: patientId || lead.patientId || '', + patientId: resolvedPatientId, name: `${firstName} ${lastName}`.trim() || 'Unknown', phone: lead.contactPhone?.primaryPhoneNumber ?? '', isNew: false,