fix: slots rescheduleUid (#21626)

This commit is contained in:
Sarthak Kapila
2025-06-13 17:36:20 +00:00
committed by GitHub
parent 4a53ec0b74
commit ddf5717992
6 changed files with 381 additions and 2 deletions
@@ -0,0 +1,343 @@
import { bootstrap } from "@/app";
import { AppModule } from "@/app.module";
import { SchedulesModule_2024_06_11 } from "@/ee/schedules/schedules_2024_06_11/schedules.module";
import { SchedulesService_2024_06_11 } from "@/ee/schedules/schedules_2024_06_11/services/schedules.service";
import { PermissionsGuard } from "@/modules/auth/guards/permissions/permissions.guard";
import { PrismaModule } from "@/modules/prisma/prisma.module";
import {
expectedSlotsUTC,
expectedSlotsUTCRange,
} from "@/modules/slots/slots-2024-09-04/controllers/e2e/expected-slots";
import { GetSlotsOutput_2024_09_04 } from "@/modules/slots/slots-2024-09-04/outputs/get-slots.output";
import { SlotsModule_2024_09_04 } from "@/modules/slots/slots-2024-09-04/slots.module";
import { TokensModule } from "@/modules/tokens/tokens.module";
import { UsersModule } from "@/modules/users/users.module";
import { INestApplication } from "@nestjs/common";
import { NestExpressApplication } from "@nestjs/platform-express";
import { Test } from "@nestjs/testing";
import { User, Booking } from "@prisma/client";
import * as request from "supertest";
import { BookingsRepositoryFixture } from "test/fixtures/repository/bookings.repository.fixture";
import { EventTypesRepositoryFixture } from "test/fixtures/repository/event-types.repository.fixture";
import { UserRepositoryFixture } from "test/fixtures/repository/users.repository.fixture";
import { randomString } from "test/utils/randomString";
import { CAL_API_VERSION_HEADER, SUCCESS_STATUS, VERSION_2024_09_04 } from "@calcom/platform-constants";
import { CreateScheduleInput_2024_06_11 } from "@calcom/platform-types";
describe("Slots 2024-09-04 Endpoints", () => {
describe("rescheduleUid functionality", () => {
let app: INestApplication;
let userRepositoryFixture: UserRepositoryFixture;
let schedulesService: SchedulesService_2024_06_11;
let eventTypesRepositoryFixture: EventTypesRepositoryFixture;
let bookingsRepositoryFixture: BookingsRepositoryFixture;
const userEmail = `slots-reschedule-uid-${randomString()}@example.com`;
const bookedStartTime = "2050-09-05T11:00:00.000Z";
let user: User;
let eventTypeId: number;
let eventTypeSlug: string;
let existingBooking: Booking;
beforeAll(async () => {
const moduleRef = await Test.createTestingModule({
imports: [
AppModule,
PrismaModule,
UsersModule,
TokensModule,
SchedulesModule_2024_06_11,
SlotsModule_2024_09_04,
],
})
.overrideGuard(PermissionsGuard)
.useValue({
canActivate: () => true,
})
.compile();
userRepositoryFixture = new UserRepositoryFixture(moduleRef);
schedulesService = moduleRef.get<SchedulesService_2024_06_11>(SchedulesService_2024_06_11);
eventTypesRepositoryFixture = new EventTypesRepositoryFixture(moduleRef);
bookingsRepositoryFixture = new BookingsRepositoryFixture(moduleRef);
user = await userRepositoryFixture.create({
email: userEmail,
name: userEmail,
username: userEmail,
});
const userSchedule: CreateScheduleInput_2024_06_11 = {
name: `reschedule-uid-schedule-${randomString()}`,
timeZone: "Europe/Rome",
isDefault: true,
};
// note(Lauris): this creates default schedule monday to friday from 9AM to 5PM in Europe/Rome timezone
await schedulesService.createUserSchedule(user.id, userSchedule);
const event = await eventTypesRepositoryFixture.create(
{
title: "reschedule test meeting",
slug: `reschedule-uid-event-type-${randomString()}`,
length: 60,
},
user.id
);
eventTypeId = event.id;
eventTypeSlug = event.slug;
// Create an existing booking that will be used for reschedule testing
existingBooking = await bookingsRepositoryFixture.create({
uid: `reschedule-booking-uid-${randomString()}`,
title: "existing booking for reschedule",
startTime: bookedStartTime,
endTime: "2050-09-05T12:00:00.000Z",
eventType: {
connect: {
id: eventTypeId,
},
},
metadata: {},
responses: {
name: "reschedule tester",
email: "reschedule@example.com",
guests: [],
},
user: {
connect: {
id: user.id,
},
},
});
app = moduleRef.createNestApplication();
bootstrap(app as NestExpressApplication);
await app.init();
});
describe("bookingUidToReschedule parameter validation", () => {
it("should accept bookingUidToReschedule as optional string parameter", async () => {
const response = await request(app.getHttpServer())
.get(
`/v2/slots?eventTypeId=${eventTypeId}&start=2050-09-05&end=2050-09-09&bookingUidToReschedule=${existingBooking.uid}`
)
.set(CAL_API_VERSION_HEADER, VERSION_2024_09_04)
.expect(200);
const responseBody: GetSlotsOutput_2024_09_04 = response.body;
expect(responseBody.status).toEqual(SUCCESS_STATUS);
expect(responseBody.data).toBeDefined();
});
it("should accept numeric bookingUidToReschedule parameter and convert to string", async () => {
const response = await request(app.getHttpServer())
.get(
`/v2/slots?eventTypeId=${eventTypeId}&start=2050-09-05&end=2050-09-09&bookingUidToReschedule=12345`
)
.set(CAL_API_VERSION_HEADER, VERSION_2024_09_04)
.expect(200);
// Note: The API accepts numeric bookingUidToReschedule and converts it to string
// This is expected behavior for query parameters
const responseBody: GetSlotsOutput_2024_09_04 = response.body;
expect(responseBody.status).toEqual(SUCCESS_STATUS);
});
it("should handle empty bookingUidToReschedule parameter gracefully", async () => {
const response = await request(app.getHttpServer())
.get(`/v2/slots?eventTypeId=${eventTypeId}&start=2050-09-05&end=2050-09-09&bookingUidToReschedule=`)
.set(CAL_API_VERSION_HEADER, VERSION_2024_09_04)
.expect(200);
const responseBody: GetSlotsOutput_2024_09_04 = response.body;
expect(responseBody.status).toEqual(SUCCESS_STATUS);
});
});
describe("bookingUidToReschedule slot availability behavior", () => {
it("should exclude booked slot when bookingUidToReschedule is not provided", async () => {
const response = await request(app.getHttpServer())
.get(`/v2/slots?eventTypeId=${eventTypeId}&start=2050-09-05&end=2050-09-09`)
.set(CAL_API_VERSION_HEADER, VERSION_2024_09_04)
.expect(200);
const responseBody: GetSlotsOutput_2024_09_04 = response.body;
expect(responseBody.status).toEqual(SUCCESS_STATUS);
const slots = responseBody.data;
expect(slots).toBeDefined();
const days = Object.keys(slots);
expect(days.length).toEqual(5);
// Check that the booked slot time is NOT available
const slotsForBookedDay = slots["2050-09-05"];
expect(slotsForBookedDay).toBeDefined();
// Verify the booked slot is excluded
const bookedSlotExists = slotsForBookedDay.some((slot: any) => slot.start === bookedStartTime);
expect(bookedSlotExists).toBe(false);
// Verify we still have slots for that day (just not the booked one)
expect(slotsForBookedDay.length).toBeGreaterThan(0);
});
it("should include booked slot when matching bookingUidToReschedule is provided", async () => {
const response = await request(app.getHttpServer())
.get(
`/v2/slots?eventTypeId=${eventTypeId}&start=2050-09-05&end=2050-09-09&bookingUidToReschedule=${existingBooking.uid}`
)
.set(CAL_API_VERSION_HEADER, VERSION_2024_09_04)
.expect(200);
const responseBody: GetSlotsOutput_2024_09_04 = response.body;
expect(responseBody.status).toEqual(SUCCESS_STATUS);
const slots = responseBody.data;
expect(slots).toBeDefined();
const days = Object.keys(slots);
expect(days.length).toEqual(5);
// Check that the booked slot time IS available when rescheduling
const slotsForBookedDay = slots["2050-09-05"];
expect(slotsForBookedDay).toBeDefined();
// Verify the booked slot is now included due to bookingUidToReschedule
const bookedSlotExists = slotsForBookedDay.some((slot: any) => slot.start === bookedStartTime);
expect(bookedSlotExists).toBe(true);
});
it("should work with non-existent bookingUidToReschedule without errors", async () => {
const nonExistentUid = `non-existent-${randomString()}`;
const response = await request(app.getHttpServer())
.get(
`/v2/slots?eventTypeId=${eventTypeId}&start=2050-09-05&end=2050-09-09&bookingUidToReschedule=${nonExistentUid}`
)
.set(CAL_API_VERSION_HEADER, VERSION_2024_09_04)
.expect(200);
const responseBody: GetSlotsOutput_2024_09_04 = response.body;
expect(responseBody.status).toEqual(SUCCESS_STATUS);
const slots = responseBody.data;
expect(slots).toBeDefined();
// Should behave like normal slots query when bookingUidToReschedule doesn't match any booking
const slotsForBookedDay = slots["2050-09-05"];
expect(slotsForBookedDay).toBeDefined();
// Verify the booked slot is excluded (same as without bookingUidToReschedule)
const bookedSlotExists = slotsForBookedDay.some((slot: any) => slot.start === bookedStartTime);
expect(bookedSlotExists).toBe(false);
});
});
describe("bookingUidToReschedule with different query types", () => {
it("should work with bookingUidToReschedule using event type slug query", async () => {
const response = await request(app.getHttpServer())
.get(
`/v2/slots?eventTypeSlug=${eventTypeSlug}&username=${user.username}&start=2050-09-05&end=2050-09-09&bookingUidToReschedule=${existingBooking.uid}`
)
.set(CAL_API_VERSION_HEADER, VERSION_2024_09_04)
.expect(200);
const responseBody: GetSlotsOutput_2024_09_04 = response.body;
expect(responseBody.status).toEqual(SUCCESS_STATUS);
const slots = responseBody.data;
expect(slots).toBeDefined();
expect(slots).toEqual(expectedSlotsUTC);
});
it("should work with bookingUidToReschedule in range format", async () => {
const response = await request(app.getHttpServer())
.get(
`/v2/slots?eventTypeId=${eventTypeId}&start=2050-09-05&end=2050-09-09&format=range&bookingUidToReschedule=${existingBooking.uid}`
)
.set(CAL_API_VERSION_HEADER, VERSION_2024_09_04)
.expect(200);
const responseBody: GetSlotsOutput_2024_09_04 = response.body;
expect(responseBody.status).toEqual(SUCCESS_STATUS);
const slots = responseBody.data;
expect(slots).toBeDefined();
expect(slots).toEqual(expectedSlotsUTCRange);
// Verify range format structure
const daySlots = slots["2050-09-05"];
if (daySlots && daySlots.length > 0) {
expect(daySlots[0]).toHaveProperty("start");
expect(daySlots[0]).toHaveProperty("end");
}
});
it("should work with bookingUidToReschedule and timezone parameter", async () => {
const response = await request(app.getHttpServer())
.get(
`/v2/slots?eventTypeId=${eventTypeId}&start=2050-09-05&end=2050-09-09&timeZone=Europe/Rome&bookingUidToReschedule=${existingBooking.uid}`
)
.set(CAL_API_VERSION_HEADER, VERSION_2024_09_04)
.expect(200);
const responseBody: GetSlotsOutput_2024_09_04 = response.body;
expect(responseBody.status).toEqual(SUCCESS_STATUS);
const slots = responseBody.data;
expect(slots).toBeDefined();
const days = Object.keys(slots);
expect(days.length).toEqual(5);
// Verify timezone conversion works with bookingUidToReschedule
const daySlots = slots["2050-09-05"];
if (daySlots && daySlots.length > 0) {
// Should contain timezone info (+02:00 for Europe/Rome)
expect(daySlots[0].start).toContain("+02:00");
// Verify rescheduleUid functionality: the booked slot should be available
const bookedSlotTimeRome = "2050-09-05T13:00:00.000+02:00"; // 11:00 UTC = 13:00 Rome
const bookedSlotExists = daySlots.some((slot: any) => slot.start === bookedSlotTimeRome);
expect(bookedSlotExists).toBe(true);
}
});
});
describe("bookingUidToReschedule edge cases", () => {
it("should handle bookingUidToReschedule with special characters", async () => {
const specialUid = `special-uid-${randomString()}-with-dashes`;
const response = await request(app.getHttpServer())
.get(
`/v2/slots?eventTypeId=${eventTypeId}&start=2050-09-05&end=2050-09-09&bookingUidToReschedule=${specialUid}`
)
.set(CAL_API_VERSION_HEADER, VERSION_2024_09_04)
.expect(200);
const responseBody: GetSlotsOutput_2024_09_04 = response.body;
expect(responseBody.status).toEqual(SUCCESS_STATUS);
});
it("should handle very long bookingUidToReschedule", async () => {
const longUid = `very-long-uid-${randomString()}-${"x".repeat(100)}`;
const response = await request(app.getHttpServer())
.get(
`/v2/slots?eventTypeId=${eventTypeId}&start=2050-09-05&end=2050-09-09&bookingUidToReschedule=${longUid}`
)
.set(CAL_API_VERSION_HEADER, VERSION_2024_09_04)
.expect(200);
const responseBody: GetSlotsOutput_2024_09_04 = response.body;
expect(responseBody.status).toEqual(SUCCESS_STATUS);
});
});
afterAll(async () => {
// Clean up test data
await bookingsRepositoryFixture.deleteById(existingBooking.id);
await bookingsRepositoryFixture.deleteAllBookings(user.id, user.email);
await userRepositoryFixture.deleteByEmail(userEmail);
await app.close();
});
});
});
@@ -83,6 +83,7 @@ export class SlotsController_2024_09_04 {
- timeZone: Time zone in which the available slots should be returned. Defaults to UTC.
- duration: Only use for event types that allow multiple durations or for dynamic event types. If not passed for multiple duration event types defaults to default duration. For dynamic event types defaults to 30 aka each returned slot is 30 minutes long. So duration=60 means that returned slots will be each 60 minutes long.
- format: Format of the slots. By default return is an object where each key is date and value is array of slots as string. If you want to get start and end of each slot use "range" as value.
- bookingUidToReschedule: When rescheduling an existing booking, provide the booking's unique identifier to exclude its time slot from busy time calculations. This ensures the original booking time appears as available for rescheduling.
`,
})
@ApiQuery({
@@ -173,6 +174,13 @@ export class SlotsController_2024_09_04 {
2024-08-13 (will have hours 00:00:00 aka at very beginning of the date) or you can specify hours manually like 2024-08-13T09:00:00Z.`,
example: "2050-09-05",
})
@ApiQuery({
name: "bookingUidToReschedule",
required: false,
description:
"The unique identifier of the booking being rescheduled. When provided will ensure that the original booking time appears within the returned available slots when rescheduling.",
example: "abc123def456",
})
@DocsResponse({
status: 200,
description: `A map of available slots indexed by date, where each date is associated with an array of time slots. If format=range is specified, each slot will be an object with start and end properties denoting start and end of the slot.
@@ -46,6 +46,7 @@ export class SlotsInputService_2024_09_04 {
const usernameList = "usernames" in query ? query.usernames : [];
const timeZone = query.timeZone;
const orgSlug = "organizationSlug" in query ? query.organizationSlug : null;
const rescheduleUid = query.bookingUidToReschedule || null;
return {
isTeamEvent,
@@ -57,6 +58,7 @@ export class SlotsInputService_2024_09_04 {
usernameList,
timeZone,
orgSlug,
rescheduleUid,
};
}
+9 -1
View File
@@ -11122,7 +11122,7 @@
"get": {
"operationId": "SlotsController_2024_09_04_getAvailableSlots",
"summary": "Find out when is an event type ready to be booked.",
"description": "\n There are 4 ways to get available slots for event type of an individual user:\n\n 1. By event type id. Event type id can be of user and team event types. Example '/v2/slots?eventTypeId=10&start=2050-09-05&end=2050-09-06&timeZone=Europe/Rome'\n\n 2. By event type slug + username. Example '/v2/slots?eventTypeSlug=intro&username=bob&start=2050-09-05&end=2050-09-06'\n\n 3. By event type slug + username + organization slug when searching within an organization. Example '/v2/slots?organizationSlug=org-slug&eventTypeSlug=intro&username=bob&start=2050-09-05&end=2050-09-06'\n\n 4. By usernames only (used for dynamic event type - there is no specific event but you want to know when 2 or more people are available). Example '/v2/slots?usernames=alice,bob&username=bob&organizationSlug=org-slug&start=2050-09-05&end=2050-09-06'. As you see you also need to provide the slug of the organization to which each user in the 'usernames' array belongs.\n\n And 3 ways to get available slots for team event type:\n\n 1. By team event type id. Example '/v2/slots?eventTypeId=10&start=2050-09-05&end=2050-09-06&timeZone=Europe/Rome'\n\n 2. By team event type slug + team slug. Example '/v2/slots?eventTypeSlug=intro&teamSlug=team-slug&start=2050-09-05&end=2050-09-06'\n\n 3. By team event type slug + team slug + organization slug when searching within an organization. Example '/v2/slots?organizationSlug=org-slug&eventTypeSlug=intro&teamSlug=team-slug&start=2050-09-05&end=2050-09-06'\n\n All of them require \"start\" and \"end\" query parameters which define the time range for which available slots should be checked.\n Optional parameters are:\n - timeZone: Time zone in which the available slots should be returned. Defaults to UTC.\n - duration: Only use for event types that allow multiple durations or for dynamic event types. If not passed for multiple duration event types defaults to default duration. For dynamic event types defaults to 30 aka each returned slot is 30 minutes long. So duration=60 means that returned slots will be each 60 minutes long.\n - format: Format of the slots. By default return is an object where each key is date and value is array of slots as string. If you want to get start and end of each slot use \"range\" as value.\n ",
"description": "\n There are 4 ways to get available slots for event type of an individual user:\n\n 1. By event type id. Event type id can be of user and team event types. Example '/v2/slots?eventTypeId=10&start=2050-09-05&end=2050-09-06&timeZone=Europe/Rome'\n\n 2. By event type slug + username. Example '/v2/slots?eventTypeSlug=intro&username=bob&start=2050-09-05&end=2050-09-06'\n\n 3. By event type slug + username + organization slug when searching within an organization. Example '/v2/slots?organizationSlug=org-slug&eventTypeSlug=intro&username=bob&start=2050-09-05&end=2050-09-06'\n\n 4. By usernames only (used for dynamic event type - there is no specific event but you want to know when 2 or more people are available). Example '/v2/slots?usernames=alice,bob&username=bob&organizationSlug=org-slug&start=2050-09-05&end=2050-09-06'. As you see you also need to provide the slug of the organization to which each user in the 'usernames' array belongs.\n\n And 3 ways to get available slots for team event type:\n\n 1. By team event type id. Example '/v2/slots?eventTypeId=10&start=2050-09-05&end=2050-09-06&timeZone=Europe/Rome'\n\n 2. By team event type slug + team slug. Example '/v2/slots?eventTypeSlug=intro&teamSlug=team-slug&start=2050-09-05&end=2050-09-06'\n\n 3. By team event type slug + team slug + organization slug when searching within an organization. Example '/v2/slots?organizationSlug=org-slug&eventTypeSlug=intro&teamSlug=team-slug&start=2050-09-05&end=2050-09-06'\n\n All of them require \"start\" and \"end\" query parameters which define the time range for which available slots should be checked.\n Optional parameters are:\n - timeZone: Time zone in which the available slots should be returned. Defaults to UTC.\n - duration: Only use for event types that allow multiple durations or for dynamic event types. If not passed for multiple duration event types defaults to default duration. For dynamic event types defaults to 30 aka each returned slot is 30 minutes long. So duration=60 means that returned slots will be each 60 minutes long.\n - format: Format of the slots. By default return is an object where each key is date and value is array of slots as string. If you want to get start and end of each slot use \"range\" as value.\n - bookingUidToReschedule: When rescheduling an existing booking, provide the booking's unique identifier to exclude its time slot from busy time calculations. This ensures the original booking time appears as available for rescheduling.\n ",
"parameters": [
{
"name": "cal-api-version",
@@ -11134,6 +11134,14 @@
"default": "2024-09-04"
}
},
{
"name": "bookingUidToReschedule",
"required": false,
"in": "query",
"description": "The unique identifier of the booking being rescheduled. When provided will ensure that the original booking time appears within the returned available slots when rescheduling.",
"example": "abc123def456",
"schema": {}
},
{
"name": "start",
"required": true,
+9 -1
View File
@@ -10614,7 +10614,7 @@
"get": {
"operationId": "SlotsController_2024_09_04_getAvailableSlots",
"summary": "Find out when is an event type ready to be booked.",
"description": "\n There are 4 ways to get available slots for event type of an individual user:\n\n 1. By event type id. Event type id can be of user and team event types. Example '/v2/slots?eventTypeId=10&start=2050-09-05&end=2050-09-06&timeZone=Europe/Rome'\n\n 2. By event type slug + username. Example '/v2/slots?eventTypeSlug=intro&username=bob&start=2050-09-05&end=2050-09-06'\n\n 3. By event type slug + username + organization slug when searching within an organization. Example '/v2/slots?organizationSlug=org-slug&eventTypeSlug=intro&username=bob&start=2050-09-05&end=2050-09-06'\n\n 4. By usernames only (used for dynamic event type - there is no specific event but you want to know when 2 or more people are available). Example '/v2/slots?usernames=alice,bob&username=bob&organizationSlug=org-slug&start=2050-09-05&end=2050-09-06'. As you see you also need to provide the slug of the organization to which each user in the 'usernames' array belongs.\n\n And 3 ways to get available slots for team event type:\n\n 1. By team event type id. Example '/v2/slots?eventTypeId=10&start=2050-09-05&end=2050-09-06&timeZone=Europe/Rome'\n\n 2. By team event type slug + team slug. Example '/v2/slots?eventTypeSlug=intro&teamSlug=team-slug&start=2050-09-05&end=2050-09-06'\n\n 3. By team event type slug + team slug + organization slug when searching within an organization. Example '/v2/slots?organizationSlug=org-slug&eventTypeSlug=intro&teamSlug=team-slug&start=2050-09-05&end=2050-09-06'\n\n All of them require \"start\" and \"end\" query parameters which define the time range for which available slots should be checked.\n Optional parameters are:\n - timeZone: Time zone in which the available slots should be returned. Defaults to UTC.\n - duration: Only use for event types that allow multiple durations or for dynamic event types. If not passed for multiple duration event types defaults to default duration. For dynamic event types defaults to 30 aka each returned slot is 30 minutes long. So duration=60 means that returned slots will be each 60 minutes long.\n - format: Format of the slots. By default return is an object where each key is date and value is array of slots as string. If you want to get start and end of each slot use \"range\" as value.\n ",
"description": "\n There are 4 ways to get available slots for event type of an individual user:\n\n 1. By event type id. Event type id can be of user and team event types. Example '/v2/slots?eventTypeId=10&start=2050-09-05&end=2050-09-06&timeZone=Europe/Rome'\n\n 2. By event type slug + username. Example '/v2/slots?eventTypeSlug=intro&username=bob&start=2050-09-05&end=2050-09-06'\n\n 3. By event type slug + username + organization slug when searching within an organization. Example '/v2/slots?organizationSlug=org-slug&eventTypeSlug=intro&username=bob&start=2050-09-05&end=2050-09-06'\n\n 4. By usernames only (used for dynamic event type - there is no specific event but you want to know when 2 or more people are available). Example '/v2/slots?usernames=alice,bob&username=bob&organizationSlug=org-slug&start=2050-09-05&end=2050-09-06'. As you see you also need to provide the slug of the organization to which each user in the 'usernames' array belongs.\n\n And 3 ways to get available slots for team event type:\n\n 1. By team event type id. Example '/v2/slots?eventTypeId=10&start=2050-09-05&end=2050-09-06&timeZone=Europe/Rome'\n\n 2. By team event type slug + team slug. Example '/v2/slots?eventTypeSlug=intro&teamSlug=team-slug&start=2050-09-05&end=2050-09-06'\n\n 3. By team event type slug + team slug + organization slug when searching within an organization. Example '/v2/slots?organizationSlug=org-slug&eventTypeSlug=intro&teamSlug=team-slug&start=2050-09-05&end=2050-09-06'\n\n All of them require \"start\" and \"end\" query parameters which define the time range for which available slots should be checked.\n Optional parameters are:\n - timeZone: Time zone in which the available slots should be returned. Defaults to UTC.\n - duration: Only use for event types that allow multiple durations or for dynamic event types. If not passed for multiple duration event types defaults to default duration. For dynamic event types defaults to 30 aka each returned slot is 30 minutes long. So duration=60 means that returned slots will be each 60 minutes long.\n - format: Format of the slots. By default return is an object where each key is date and value is array of slots as string. If you want to get start and end of each slot use \"range\" as value.\n - bookingUidToReschedule: When rescheduling an existing booking, provide the booking's unique identifier to exclude its time slot from busy time calculations. This ensures the original booking time appears as available for rescheduling.\n ",
"parameters": [
{
"name": "cal-api-version",
@@ -10626,6 +10626,14 @@
"default": "2024-09-04"
}
},
{
"name": "bookingUidToReschedule",
"required": false,
"in": "query",
"description": "The unique identifier of the booking being rescheduled. When provided will ensure that the original booking time appears within the returned available slots when rescheduling.",
"example": "abc123def456",
"schema": {}
},
{
"name": "start",
"required": true,
@@ -78,6 +78,16 @@ export class GetAvailableSlotsInput_2024_09_04 {
enum: SlotFormat,
})
format?: SlotFormat;
@IsString()
@IsOptional()
@ApiPropertyOptional({
type: String,
description:
"The unique identifier of the booking being rescheduled. When provided will ensure that the original booking time appears within the returned available slots when rescheduling.",
example: "abc123def456",
})
bookingUidToReschedule?: string;
}
export const ById_2024_09_04_type = "byEventTypeId";