diff --git a/apps/web/test/utils/bookingScenario/getMockRequestDataForBooking.ts b/apps/web/test/utils/bookingScenario/getMockRequestDataForBooking.ts index ff94043b97..ac0a0e00f9 100644 --- a/apps/web/test/utils/bookingScenario/getMockRequestDataForBooking.ts +++ b/apps/web/test/utils/bookingScenario/getMockRequestDataForBooking.ts @@ -30,7 +30,7 @@ export function getMockRequestDataForBooking({ responses: { email: string; name: string; - location: { optionValue: ""; value: string }; + location?: { optionValue: ""; value: string }; smsReminderNumber?: string; }; }; diff --git a/packages/features/bookings/lib/handleNewBooking.ts b/packages/features/bookings/lib/handleNewBooking.ts index 7507b3fc3a..494b39c42a 100644 --- a/packages/features/bookings/lib/handleNewBooking.ts +++ b/packages/features/bookings/lib/handleNewBooking.ts @@ -1453,15 +1453,26 @@ async function handler( const isManagedEventType = !!eventType.parentId; + // If location passed is empty , use default location of event + // If location of event is not set , use host default + if (locationBodyString.trim().length == 0) { + if (eventType.locations.length > 0) { + locationBodyString = eventType.locations[0].type; + } else { + locationBodyString = OrganizerDefaultConferencingAppType; + } + } // use host default - if ((isManagedEventType || isTeamEventType) && locationBodyString === OrganizerDefaultConferencingAppType) { + if (locationBodyString == OrganizerDefaultConferencingAppType) { const metadataParseResult = userMetadataSchema.safeParse(organizerUser.metadata); const organizerMetadata = metadataParseResult.success ? metadataParseResult.data : undefined; if (organizerMetadata?.defaultConferencingApp?.appSlug) { const app = getAppFromSlug(organizerMetadata?.defaultConferencingApp?.appSlug); locationBodyString = app?.appData?.location?.type || locationBodyString; - organizerOrFirstDynamicGroupMemberDefaultLocationUrl = - organizerMetadata?.defaultConferencingApp?.appLink; + if (isManagedEventType || isTeamEventType) { + organizerOrFirstDynamicGroupMemberDefaultLocationUrl = + organizerMetadata?.defaultConferencingApp?.appLink; + } } else { locationBodyString = "integrations:daily"; } @@ -1601,6 +1612,12 @@ async function handler( organizerEmail = eventType.secondaryEmail.email; } + //udpate cal event responses with latest location value , later used by webhook + if (reqBody.calEventResponses) + reqBody.calEventResponses["location"].value = { + value: platformBookingLocation ?? bookingLocation, + optionValue: "", + }; let evt: CalendarEvent = { bookerUrl, type: eventType.slug, diff --git a/packages/features/bookings/lib/handleNewBooking/test/fresh-booking.test.ts b/packages/features/bookings/lib/handleNewBooking/test/fresh-booking.test.ts index 90c0ce4633..55b1005447 100644 --- a/packages/features/bookings/lib/handleNewBooking/test/fresh-booking.test.ts +++ b/packages/features/bookings/lib/handleNewBooking/test/fresh-booking.test.ts @@ -1010,6 +1010,273 @@ describe("handleNewBooking", () => { ); }); + describe("Event's first location should be used when location is unspecied", () => { + test( + `should create a successful booking with right location app when event has location option as video client`, + async ({ emails }) => { + const handleNewBooking = (await import("@calcom/features/bookings/lib/handleNewBooking")).default; + const booker = getBooker({ + email: "booker@example.com", + name: "Booker", + }); + + const organizer = getOrganizer({ + name: "Organizer", + email: "organizer@example.com", + id: 101, + schedules: [TestData.schedules.IstWorkHours], + credentials: [getZoomAppCredential()], + selectedCalendars: [TestData.selectedCalendars.google], + }); + + const { req } = createMockNextJsRequest({ + method: "POST", + body: getMockRequestDataForBooking({ + data: { + eventTypeId: 1, + responses: { + email: booker.email, + name: booker.name, + }, + }, + }), + }); + + const scenarioData = getScenarioData({ + webhooks: [ + { + userId: organizer.id, + eventTriggers: ["BOOKING_CREATED"], + subscriberUrl: "http://my-webhook.example.com", + active: true, + eventTypeId: 1, + appId: null, + }, + ], + eventTypes: [ + { + id: 1, + slotInterval: 30, + length: 30, + users: [ + { + id: 101, + }, + ], + locations: [ + { + type: BookingLocations.ZoomVideo, + }, + ], + }, + ], + organizer, + apps: [TestData.apps["zoomvideo"]], + }); + mockSuccessfulVideoMeetingCreation({ + metadataLookupKey: "zoomvideo", + }); + await createBookingScenario(scenarioData); + const createdBooking = await handleNewBooking(req); + expect(createdBooking).toContain({ + location: BookingLocations.ZoomVideo, + }); + const iCalUID = expectICalUIDAsString(createdBooking.iCalUID); + expectSuccessfulBookingCreationEmails({ + booking: { + uid: createdBooking.uid!, + }, + booker, + organizer, + emails, + iCalUID, + }); + expectBookingCreatedWebhookToHaveBeenFired({ + booker, + organizer, + location: BookingLocations.ZoomVideo, + subscriberUrl: "http://my-webhook.example.com", + videoCallUrl: "http://mock-zoomvideo.example.com", + }); + }, + timeout + ); + test( + `should create a successful booking with right location when event's location is not a conferencing app + `, + //test with inPerson event type + async ({ emails }) => { + const handleNewBooking = (await import("@calcom/features/bookings/lib/handleNewBooking")).default; + const booker = getBooker({ + email: "booker@example.com", + name: "Booker", + }); + + const organizer = getOrganizer({ + name: "Organizer", + email: "organizer@example.com", + id: 101, + schedules: [TestData.schedules.IstWorkHours], + credentials: [], + selectedCalendars: [TestData.selectedCalendars.google], + }); + + const { req } = createMockNextJsRequest({ + method: "POST", + body: getMockRequestDataForBooking({ + data: { + eventTypeId: 1, + responses: { + email: booker.email, + name: booker.name, + }, + }, + }), + }); + + const scenarioData = getScenarioData({ + webhooks: [ + { + userId: organizer.id, + eventTriggers: ["BOOKING_CREATED"], + subscriberUrl: "http://my-webhook.example.com", + active: true, + eventTypeId: 1, + appId: null, + }, + ], + eventTypes: [ + { + id: 1, + slotInterval: 30, + length: 30, + users: [ + { + id: 101, + }, + ], + locations: [{ type: "inPerson", address: "Seoul" }], + }, + ], + organizer, + apps: [TestData.apps["daily-video"]], + }); + await createBookingScenario(scenarioData); + const createdBooking = await handleNewBooking(req); + expect(createdBooking).toContain({ + location: "Seoul", + }); + const iCalUID = expectICalUIDAsString(createdBooking.iCalUID); + expectSuccessfulBookingCreationEmails({ + booking: { + uid: createdBooking.uid!, + }, + booker, + organizer, + emails, + iCalUID, + }); + expectBookingCreatedWebhookToHaveBeenFired({ + booker, + organizer, + location: "Seoul", + subscriberUrl: "http://my-webhook.example.com", + }); + }, + timeout + ); + test( + `should create a successful booking with organizer default conferencing app when event's location is not set`, + async ({ emails }) => { + const handleNewBooking = (await import("@calcom/features/bookings/lib/handleNewBooking")).default; + const booker = getBooker({ + email: "booker@example.com", + name: "Booker", + }); + + const organizer = getOrganizer({ + name: "Organizer", + email: "organizer@example.com", + id: 101, + schedules: [TestData.schedules.IstWorkHours], + credentials: [getZoomAppCredential()], + selectedCalendars: [TestData.selectedCalendars.google], + metadata: { + defaultConferencingApp: { + appSlug: "zoom", + }, + }, + }); + + const { req } = createMockNextJsRequest({ + method: "POST", + body: getMockRequestDataForBooking({ + data: { + eventTypeId: 1, + responses: { + email: booker.email, + name: booker.name, + }, + }, + }), + }); + + const scenarioData = getScenarioData({ + webhooks: [ + { + userId: organizer.id, + eventTriggers: ["BOOKING_CREATED"], + subscriberUrl: "http://my-webhook.example.com", + active: true, + eventTypeId: 1, + appId: null, + }, + ], + eventTypes: [ + { + id: 1, + slotInterval: 30, + length: 30, + users: [ + { + id: 101, + }, + ], + }, + ], + organizer, + apps: [TestData.apps["zoomvideo"], TestData.apps["daily-video"]], + }); + mockSuccessfulVideoMeetingCreation({ + metadataLookupKey: "zoomvideo", + }); + await createBookingScenario(scenarioData); + const createdBooking = await handleNewBooking(req); + expect(createdBooking).toContain({ + location: BookingLocations.ZoomVideo, + }); + const iCalUID = expectICalUIDAsString(createdBooking.iCalUID); + expectSuccessfulBookingCreationEmails({ + booking: { + uid: createdBooking.uid!, + }, + booker, + organizer, + emails, + iCalUID, + }); + expectBookingCreatedWebhookToHaveBeenFired({ + booker, + organizer, + location: BookingLocations.ZoomVideo, + subscriberUrl: "http://my-webhook.example.com", + videoCallUrl: "http://mock-zoomvideo.example.com", + }); + }, + timeout + ); + }); + describe("Video Meeting Creation", () => { test( `should create a successful booking with Zoom if used`, diff --git a/packages/features/bookings/lib/handleNewBooking/test/team-bookings/collective-scheduling.test.ts b/packages/features/bookings/lib/handleNewBooking/test/team-bookings/collective-scheduling.test.ts index 3c974d3b98..ecb0986394 100644 --- a/packages/features/bookings/lib/handleNewBooking/test/team-bookings/collective-scheduling.test.ts +++ b/packages/features/bookings/lib/handleNewBooking/test/team-bookings/collective-scheduling.test.ts @@ -1287,7 +1287,7 @@ describe("handleNewBooking", () => { expectBookingCreatedWebhookToHaveBeenFired({ booker, organizer, - location: OrganizerDefaultConferencingAppType, + location: BookingLocations.CalVideo, subscriberUrl: "http://my-webhook.example.com", videoCallUrl: `${WEBAPP_URL}/video/${createdBooking.uid}`, });