@@ -15,6 +15,7 @@ import type { CRM, Contact, CrmEvent } from "@calcom/types/CrmService";
15
15
import getAppKeysFromSlug from "../../_utils/getAppKeysFromSlug" ;
16
16
import type { ParseRefreshTokenResponse } from "../../_utils/oauth/parseRefreshTokenResponse" ;
17
17
import parseRefreshTokenResponse from "../../_utils/oauth/parseRefreshTokenResponse" ;
18
+ import { default as appMeta } from "../config.json" ;
18
19
import { SalesforceRecordEnum } from "./recordEnum" ;
19
20
20
21
type ExtendedTokenResponse = TokenResponse & {
@@ -502,6 +503,80 @@ export default class SalesforceCRMService implements CRM {
502
503
return createdContacts ;
503
504
}
504
505
506
+ async handleAttendeeNoShow ( bookingUid : string , attendees : { email : string ; noShow : boolean } [ ] ) {
507
+ const appOptions = this . getAppOptions ( ) ;
508
+ const { sendNoShowAttendeeData, sendNoShowAttendeeDataField } = appOptions ;
509
+ const conn = await this . conn ;
510
+ // Check that no show is enabled
511
+ if ( ! sendNoShowAttendeeData && ! sendNoShowAttendeeDataField ) {
512
+ this . log . warn ( `No show settings not set for bookingUid ${ bookingUid } ` ) ;
513
+ return ;
514
+ }
515
+ // Get all Salesforce events associated with the booking
516
+ const salesforceEvents = await prisma . bookingReference . findMany ( {
517
+ where : {
518
+ type : appMeta . type ,
519
+ booking : {
520
+ uid : bookingUid ,
521
+ } ,
522
+ } ,
523
+ } ) ;
524
+
525
+ const salesforceEntity = await conn . describe ( "Event" ) ;
526
+ const fields = salesforceEntity . fields ;
527
+ const noShowField = fields . find ( ( field ) => field . name === sendNoShowAttendeeDataField ) ;
528
+
529
+ if ( ! noShowField || ( ! noShowField . type as unknown as string ) !== "boolean" ) {
530
+ this . log . warn (
531
+ `No show field on Salesforce doesn't exist or is not of type boolean for bookingUid ${ bookingUid } `
532
+ ) ;
533
+ return ;
534
+ }
535
+
536
+ for ( const event of salesforceEvents ) {
537
+ const salesforceEvent = ( await conn . query ( `SELECT WhoId FROM Event WHERE Id = '${ event . uid } '` ) ) as {
538
+ records : { WhoId : string } [ ] ;
539
+ } ;
540
+
541
+ let salesforceAttendeeEmail : string | undefined = undefined ;
542
+ // Figure out if the attendee is a contact or lead
543
+ const contactQuery = ( await conn . query (
544
+ `SELECT Email FROM Contact WHERE Id = '${ salesforceEvent . records [ 0 ] . WhoId } '`
545
+ ) ) as { records : { Email : string } [ ] } ;
546
+ const leadQuery = ( await conn . query (
547
+ `SELECT Email FROM Lead WHERE Id = '${ salesforceEvent . records [ 0 ] . WhoId } '`
548
+ ) ) as { records : { Email : string } [ ] } ;
549
+
550
+ // Prioritize contacts over leads
551
+ if ( contactQuery . records . length > 0 ) {
552
+ salesforceAttendeeEmail = contactQuery . records [ 0 ] . Email ;
553
+ } else if ( leadQuery . records . length > 0 ) {
554
+ salesforceAttendeeEmail = leadQuery . records [ 0 ] . Email ;
555
+ } else {
556
+ this . log . warn (
557
+ `Could not find attendee for bookingUid ${ bookingUid } and salesforce event id ${ event . uid } `
558
+ ) ;
559
+ }
560
+
561
+ if ( salesforceAttendeeEmail ) {
562
+ // Find the attendee no show data
563
+ const noShowData = attendees . find ( ( attendee ) => attendee . email === salesforceAttendeeEmail ) ;
564
+
565
+ if ( ! noShowData ) {
566
+ this . log . warn (
567
+ `No show data could not be found for ${ salesforceAttendeeEmail } and bookingUid ${ bookingUid } `
568
+ ) ;
569
+ } else {
570
+ // Update the event with the no show data
571
+ await conn . sobject ( "Event" ) . update ( {
572
+ Id : event . uid ,
573
+ [ sendNoShowAttendeeDataField ] : noShowData . noShow ,
574
+ } ) ;
575
+ }
576
+ }
577
+ }
578
+ }
579
+
505
580
private getExistingIdFromDuplicateError ( error : any ) : string | null {
506
581
if ( error . duplicateResult && error . duplicateResult . matchResults ) {
507
582
for ( const matchResult of error . duplicateResult . matchResults ) {
0 commit comments