* chore: version existing bookings as 2024-04-15 * feat: initialize bookings version 2024-08-13 * feat: Create and reschedule booking inputs logic * feat: create booking * refactor: create booking response * feat: reschedule booking * chore: update language input * feat: recurring booking * refactor: add booking status in response * refactor: recurring bookings * feat: get booking by uid * wip: get event types * feat: fetch by multiple status filters and sort * feat: fetch by teamId, teamIds, eventTypeId, eventTypeIds * wip: filter by attendee email * feat: filter by attendee email * feat: filter by attendee name * feat: date range filter * chore: format get bookings output * chore: finish main merge * feat: handle instant bookings * refactor: separate reschedule endpoint * feat: cancel endpoint * feat: mark absent host or attendees * chore: dont expose metadata for now * chore: add hostId to response * fix: metadata * feat: bill bookings * feat: cancellationReason * feat: rescheduling reason * handle already busy booking error * test: create new booking * fix: handleNewRecurringBooking ignoring noEmail * test: recurring bookings * test: get individual bookings * fix: cancel email sent if arePlatformEmailsEnabled=false but platformClientId is undefined * tests: cancel, reschedule, mark absent * fix: generateIcsFile null pointer exception * cancel test * error msg improve * tests: team event type creation and teamId, teamIds filters * test: cancel recurring booking * refactor: make hosts and attendees an array * sort by asc start * simplify * refactor: absent * fix: make work with api key * test * ts remove any * feat: BookingUidGuard * fix: recurring booking no email * fix: legacy bookings recurring noEmail * add swagger * retrigger build * fix: atom booker work with v2 * docs: exclude old controller from docs * refactor: make eventTypeIds and teamIds getBookings query params comma separated string * docs: swagger for get bookings query * swagger docs * swagger docs * docs: document authorization header * refactor: remove unused attendee variable * refactor: remove unused check * refactor: remove unused attendee variable * refactor: spelling * use published platform libraries * fix: ci * fix: ci * fix: ci * fix: ci * cleanup script platform types * fix: use libraries from npm * chore: set test env vapid keys * fix: event type tests * fix: remove location from system fields * fix legacy event types * Revert "fix legacy event types" This reverts commit e64b473b73f7ef0fe88942cd87277d29a512b946. * Revert "fix: remove location from system fields" This reverts commit bee9a15cb27cd34705f34c427b6b50d51e3b7ee7. * Revert "fix: event type tests" This reverts commit fab1cb0f5eeb65e4f542bfbeb83849ceed7ba428. * update libraries * fix: increase node space for ci runner * fix: increase node space for ci runner * fix: increase node space for ci runner * readd swagger * ci * ci * refactor: increase idle worker memory jest e2e * fixup! refactor: increase idle worker memory jest e2e * fixup! fixup! refactor: increase idle worker memory jest e2e * refactor: split bookings e2e into smaller e2e files * fixup! refactor: split bookings e2e into smaller e2e files * fixup! fixup! refactor: split bookings e2e into smaller e2e files * fixup! fixup! fixup! refactor: split bookings e2e into smaller e2e files * fixup! Merge branch 'main' into v2-refactor-bookings * revert event types service * fix: remove resetModule, maxWorker 2 jest e2e config --------- Co-authored-by: Morgan Vernay <morgan@cal.com> Co-authored-by: Morgan <33722304+ThyMinimalDev@users.noreply.github.com>
135 lines
3.7 KiB
TypeScript
135 lines
3.7 KiB
TypeScript
import type { PrismaClient } from "@calcom/prisma";
|
|
import type { Prisma } from "@calcom/prisma/client";
|
|
import { BookingStatus } from "@calcom/prisma/enums";
|
|
import { getBookings } from "@calcom/trpc/server/routers/viewer/bookings/get.handler";
|
|
|
|
type InputByStatus = "upcoming" | "recurring" | "past" | "cancelled" | "unconfirmed";
|
|
type SortOptions = {
|
|
sortStart?: "asc" | "desc";
|
|
sortEnd?: "asc" | "desc";
|
|
sortCreated?: "asc" | "desc";
|
|
};
|
|
type GetOptions = {
|
|
ctx: {
|
|
user: { id: number; email: string };
|
|
prisma: PrismaClient;
|
|
};
|
|
bookingListingByStatus: InputByStatus[];
|
|
take: number;
|
|
skip: number;
|
|
filters: {
|
|
status?: InputByStatus;
|
|
teamIds?: number[] | undefined;
|
|
userIds?: number[] | undefined;
|
|
eventTypeIds?: number[] | undefined;
|
|
attendeeEmail?: string;
|
|
attendeeName?: string;
|
|
};
|
|
sort?: SortOptions;
|
|
};
|
|
|
|
const getAllUserBookings = async ({ ctx, filters, bookingListingByStatus, take, skip, sort }: GetOptions) => {
|
|
const { prisma, user } = ctx;
|
|
|
|
const bookingListingFilters: Record<InputByStatus, Prisma.BookingWhereInput> = {
|
|
upcoming: {
|
|
endTime: { gte: new Date() },
|
|
// These changes are needed to not show confirmed recurring events,
|
|
// as rescheduling or cancel for recurring event bookings should be
|
|
// handled separately for each occurrence
|
|
OR: [
|
|
{
|
|
recurringEventId: { not: null },
|
|
status: { equals: BookingStatus.ACCEPTED },
|
|
},
|
|
{
|
|
recurringEventId: { equals: null },
|
|
status: { notIn: [BookingStatus.CANCELLED, BookingStatus.REJECTED] },
|
|
},
|
|
],
|
|
},
|
|
recurring: {
|
|
endTime: { gte: new Date() },
|
|
AND: [
|
|
{ NOT: { recurringEventId: { equals: null } } },
|
|
{ status: { notIn: [BookingStatus.CANCELLED, BookingStatus.REJECTED] } },
|
|
],
|
|
},
|
|
past: {
|
|
endTime: { lte: new Date() },
|
|
AND: [
|
|
{ NOT: { status: { equals: BookingStatus.CANCELLED } } },
|
|
{ NOT: { status: { equals: BookingStatus.REJECTED } } },
|
|
],
|
|
},
|
|
cancelled: {
|
|
OR: [{ status: { equals: BookingStatus.CANCELLED } }, { status: { equals: BookingStatus.REJECTED } }],
|
|
},
|
|
unconfirmed: {
|
|
endTime: { gte: new Date() },
|
|
status: { equals: BookingStatus.PENDING },
|
|
},
|
|
};
|
|
|
|
const orderBy = getOrderBy(bookingListingByStatus, sort);
|
|
|
|
const combinedFilters = bookingListingByStatus.map((status) => bookingListingFilters[status]);
|
|
|
|
const { bookings, recurringInfo } = await getBookings({
|
|
user,
|
|
prisma,
|
|
passedBookingsStatusFilter: {
|
|
OR: combinedFilters,
|
|
},
|
|
filters: filters,
|
|
orderBy,
|
|
take,
|
|
skip,
|
|
});
|
|
|
|
const bookingsFetched = bookings.length;
|
|
let nextCursor: typeof skip | null = skip;
|
|
if (bookingsFetched > take) {
|
|
nextCursor += bookingsFetched;
|
|
} else {
|
|
nextCursor = null;
|
|
}
|
|
|
|
return {
|
|
bookings,
|
|
recurringInfo,
|
|
nextCursor,
|
|
};
|
|
};
|
|
|
|
function getOrderBy(
|
|
bookingListingByStatus: InputByStatus[],
|
|
sort?: SortOptions
|
|
): Prisma.BookingOrderByWithAggregationInput {
|
|
const bookingListingOrderby: Record<InputByStatus, Prisma.BookingOrderByWithAggregationInput> = {
|
|
upcoming: { startTime: "asc" },
|
|
recurring: { startTime: "asc" },
|
|
past: { startTime: "desc" },
|
|
cancelled: { startTime: "desc" },
|
|
unconfirmed: { startTime: "asc" },
|
|
};
|
|
|
|
if (bookingListingByStatus?.length === 1 && !sort) {
|
|
return bookingListingOrderby[bookingListingByStatus[0]];
|
|
}
|
|
|
|
if (sort?.sortStart) {
|
|
return { startTime: sort.sortStart };
|
|
}
|
|
if (sort?.sortEnd) {
|
|
return { endTime: sort.sortEnd };
|
|
}
|
|
if (sort?.sortCreated) {
|
|
return { createdAt: sort.sortCreated };
|
|
}
|
|
|
|
return { startTime: "asc" };
|
|
}
|
|
|
|
export default getAllUserBookings;
|