diff --git a/packages/core/getUserAvailability.ts b/packages/core/getUserAvailability.ts index 174242dec8..adfaac83a9 100644 --- a/packages/core/getUserAvailability.ts +++ b/packages/core/getUserAvailability.ts @@ -794,3 +794,43 @@ const _getOutOfOfficeDays = async ({ return acc; }, {}); }; + +type GetUserAvailabilityQuery = Parameters[0]; +type GetUserAvailabilityInitialData = NonNullable[1]>; + +const _getUsersAvailability = async ({ + users, + query, + initialData, +}: { + users: (NonNullable & { + currentBookings?: GetUserAvailabilityInitialData["currentBookings"]; + })[]; + query: Omit; + initialData?: Omit; +}) => { + return await Promise.all( + users.map((user) => + _getUserAvailability( + { + ...query, + userId: user.id, + username: user.username || "", + }, + initialData + ? { + ...initialData, + user, + currentBookings: user.currentBookings, + } + : undefined + ) + ) + ); +}; + +export const getUsersAvailability = async ( + ...args: Parameters +): Promise> => { + return monitorCallbackAsync(_getUsersAvailability, ...args); +}; diff --git a/packages/features/bookings/lib/handleNewBooking.ts b/packages/features/bookings/lib/handleNewBooking.ts index 03246cbd9b..be5e70cd47 100644 --- a/packages/features/bookings/lib/handleNewBooking.ts +++ b/packages/features/bookings/lib/handleNewBooking.ts @@ -24,7 +24,7 @@ import { getAppFromSlug } from "@calcom/app-store/utils"; import EventManager from "@calcom/core/EventManager"; import { getEventName } from "@calcom/core/event"; import { getBusyTimesForLimitChecks } from "@calcom/core/getBusyTimes"; -import { getUserAvailability } from "@calcom/core/getUserAvailability"; +import { getUsersAvailability } from "@calcom/core/getUserAvailability"; import dayjs from "@calcom/dayjs"; import { scheduleMandatoryReminder } from "@calcom/ee/workflows/lib/reminders/scheduleMandatoryReminder"; import { @@ -362,24 +362,25 @@ export async function ensureAvailableUsers( }); } - for (const user of eventType.users) { - const { oooExcludedDateRanges: dateRanges, busy: bufferedBusyTimes } = await getUserAvailability( - { + ( + await getUsersAvailability({ + users: eventType.users, + query: { ...input, - userId: user.id, eventTypeId: eventType.id, duration: originalBookingDuration, returnDateOverrides: false, dateFrom: startDateTimeUtc.format(), dateTo: endDateTimeUtc.format(), }, - { - user, + initialData: { eventType, rescheduleUid: input.originalRescheduledBooking?.uid ?? null, busyTimesFromLimitsBookings: busyTimesFromLimitsBookingsAllUsers, - } - ); + }, + }) + ).forEach(({ oooExcludedDateRanges: dateRanges, busy: bufferedBusyTimes }, index) => { + const user = eventType.users[index]; log.debug( "calendarBusyTimes==>>>", @@ -395,7 +396,7 @@ export async function ensureAvailableUsers( input, }) ); - continue; + return; } let foundConflict = false; @@ -422,7 +423,7 @@ export async function ensureAvailableUsers( input, }) ); - continue; + return; } try { @@ -434,7 +435,8 @@ export async function ensureAvailableUsers( if (!foundConflict) { availableUsers.push(user); } - } + }); + if (!availableUsers.length) { loggerWithEventDetails.error( `No available users found.`, diff --git a/packages/trpc/server/routers/viewer/slots/util.ts b/packages/trpc/server/routers/viewer/slots/util.ts index ecb7b54729..9d8ab61273 100644 --- a/packages/trpc/server/routers/viewer/slots/util.ts +++ b/packages/trpc/server/routers/viewer/slots/util.ts @@ -5,7 +5,7 @@ import { v4 as uuid } from "uuid"; import { getAggregatedAvailability } from "@calcom/core/getAggregatedAvailability"; import { getBusyTimesForLimitChecks } from "@calcom/core/getBusyTimes"; import type { CurrentSeats, IFromUser, IToUser } from "@calcom/core/getUserAvailability"; -import { getUserAvailability } from "@calcom/core/getUserAvailability"; +import { getUsersAvailability } from "@calcom/core/getUserAvailability"; import type { Dayjs } from "@calcom/dayjs"; import dayjs from "@calcom/dayjs"; import { getSlugOrRequestedSlug, orgDomainConfig } from "@calcom/ee/organizations/lib/orgDomains"; @@ -456,44 +456,44 @@ export async function getAvailableSlots({ input, ctx }: GetScheduleOptions): Pro }); } + const users = usersWithCredentials.map((currentUser) => { + return { + ...currentUser, + currentBookings: currentBookingsAllUsers + .filter((b) => b.userId === currentUser.id || b.attendees?.some((a) => a.email === currentUser.email)) + .map((bookings) => { + const { attendees: _attendees, ...bookingWithoutAttendees } = bookings; + return bookingWithoutAttendees; + }), + }; + }); + /* We get all users working hours and busy slots */ - const allUsersAvailability = await Promise.all( - usersWithCredentials.map(async (currentUser) => { - const { - busy, - dateRanges, - oooExcludedDateRanges, - currentSeats: _currentSeats, - timeZone, - datesOutOfOffice, - } = await getUserAvailability( - { - userId: currentUser.id, - username: currentUser.username || "", - dateFrom: startTime.format(), - dateTo: endTime.format(), - eventTypeId: eventType.id, - afterEventBuffer: eventType.afterEventBuffer, - beforeEventBuffer: eventType.beforeEventBuffer, - duration: input.duration || 0, - returnDateOverrides: false, - }, - { - user: currentUser, - eventType, - currentSeats, - rescheduleUid: input.rescheduleUid, - currentBookings: currentBookingsAllUsers - .filter( - (b) => b.userId === currentUser.id || b.attendees?.some((a) => a.email === currentUser.email) - ) - .map((bookings) => { - const { attendees: _attendees, ...bookingWithoutAttendees } = bookings; - return bookingWithoutAttendees; - }), - busyTimesFromLimitsBookings: busyTimesFromLimitsBookingsAllUsers, - } - ); + const allUsersAvailability = ( + await getUsersAvailability({ + users, + query: { + dateFrom: startTime.format(), + dateTo: endTime.format(), + eventTypeId: eventType.id, + afterEventBuffer: eventType.afterEventBuffer, + beforeEventBuffer: eventType.beforeEventBuffer, + duration: input.duration || 0, + returnDateOverrides: false, + }, + initialData: { + eventType, + currentSeats, + rescheduleUid: input.rescheduleUid, + busyTimesFromLimitsBookings: busyTimesFromLimitsBookingsAllUsers, + }, + }) + ).map( + ( + { busy, dateRanges, oooExcludedDateRanges, currentSeats: _currentSeats, timeZone, datesOutOfOffice }, + index + ) => { + const currentUser = users[index]; if (!currentSeats && _currentSeats) currentSeats = _currentSeats; return { timeZone, @@ -503,7 +503,7 @@ export async function getAvailableSlots({ input, ctx }: GetScheduleOptions): Pro user: currentUser, datesOutOfOffice, }; - }) + } ); const availabilityCheckProps = {