diff --git a/packages/app-store/_utils/calendars/processExternalId.ts b/packages/app-store/_utils/calendars/processExternalId.ts new file mode 100644 index 0000000000..84f668ac72 --- /dev/null +++ b/packages/app-store/_utils/calendars/processExternalId.ts @@ -0,0 +1,18 @@ +import type { DestinationCalendar } from "@prisma/client"; + +import { metadata as OutlookMetadata } from "../../office365calendar"; + +/** + * When inviting attendees to a calendar event, sometimes the external ID is only used for internal purposes + * Need to process the correct external ID for the calendar service + */ +const processExternalId = (destinationCalendar: DestinationCalendar) => { + if (destinationCalendar.integration === OutlookMetadata.type) { + // Primary email should always be present for Outlook + return destinationCalendar.primaryEmail || destinationCalendar.externalId; + } + + return destinationCalendar.externalId; +}; + +export default processExternalId; diff --git a/packages/core/EventManager.ts b/packages/core/EventManager.ts index 9ec0373680..251b232587 100644 --- a/packages/core/EventManager.ts +++ b/packages/core/EventManager.ts @@ -535,6 +535,7 @@ export default class EventManager { }; if (event.destinationCalendar && event.destinationCalendar.length > 0) { + let eventCreated = false; // Since GCal pushes events to multiple calendars we only want to create one event per booking let gCalAdded = false; const destinationCalendars: DestinationCalendar[] = event.destinationCalendar.reduce( @@ -554,6 +555,7 @@ export default class EventManager { [] as DestinationCalendar[] ); for (const destination of destinationCalendars) { + if (eventCreated) break; log.silly("Creating Calendar event", JSON.stringify({ destination })); if (destination.credentialId) { let credential = this.calendarCredentials.find((c) => c.id === destination.credentialId); @@ -582,6 +584,7 @@ export default class EventManager { const createdEvent = await createEvent(credential, event, destination.externalId); if (createdEvent) { createdEvents.push(createdEvent); + eventCreated = true; } } } else { @@ -607,6 +610,7 @@ export default class EventManager { }) ); createdEvents.push(await createEvent(firstCalendarCredential, event)); + eventCreated = true; } } } diff --git a/packages/features/bookings/lib/handleNewBooking.ts b/packages/features/bookings/lib/handleNewBooking.ts index f97a46cf0e..40bb99b284 100644 --- a/packages/features/bookings/lib/handleNewBooking.ts +++ b/packages/features/bookings/lib/handleNewBooking.ts @@ -11,6 +11,7 @@ import type { Logger } from "tslog"; import { v5 as uuidv5 } from "uuid"; import z from "zod"; +import processExternalId from "@calcom/app-store/_utils/calendars/processExternalId"; import { metadata as GoogleMeetMetadata } from "@calcom/app-store/googlevideo/_metadata"; import type { LocationObject } from "@calcom/app-store/locations"; import { @@ -1405,9 +1406,13 @@ async function handler( // Organizer or user owner of this event type it's not listed as a team member. const teamMemberPromises = users.slice(1).map(async (user) => { + // TODO: Add back once EventManager tests are ready https://github.com/calcom/cal.com/pull/14610#discussion_r1567817120 // push to teamDestinationCalendars if it's a team event but collective only if (isTeamEventType && eventType.schedulingType === "COLLECTIVE" && user.destinationCalendar) { - teamDestinationCalendars.push(user.destinationCalendar); + teamDestinationCalendars.push({ + ...user.destinationCalendar, + externalId: processExternalId(user.destinationCalendar), + }); } return {