fix: buffer times in handleNewBooking (#14871)

* get buffer busy time from bookings outside of start and end time

* add test for buffers

* fix typo

---------

Co-authored-by: CarinaWolli <wollencarina@gmail.com>
This commit is contained in:
Carina Wollendorfer
2024-05-09 13:39:32 +00:00
committed by GitHub
co-authored by CarinaWolli
parent b8890c841c
commit 304ef29618
4 changed files with 152 additions and 3 deletions
@@ -8,6 +8,7 @@ import { Controller, useFormContext } from "react-hook-form";
import type { SingleValue } from "react-select";
import useLockedFieldsManager from "@calcom/features/ee/managed-event-types/hooks/useLockedFieldsManager";
import { getDefinedBufferTimes } from "@calcom/features/eventtypes/lib/getDefinedBufferTimes";
import type { FormValues } from "@calcom/features/eventtypes/lib/types";
import { classNames } from "@calcom/lib";
import type { DurationType } from "@calcom/lib/convertToNewDurationType";
@@ -172,7 +173,7 @@ export const EventLimitsTab = ({ eventType }: Pick<EventTypeSetupProps, "eventTy
label: t("event_buffer_default"),
value: 0,
},
...[5, 10, 15, 20, 30, 45, 60, 90, 120].map((minutes) => ({
...getDefinedBufferTimes().map((minutes) => ({
label: `${minutes} ${t("minutes")}`,
value: minutes,
})),
+10 -2
View File
@@ -14,6 +14,8 @@ import { stringToDayjs } from "@calcom/prisma/zod-utils";
import type { EventBusyDetails, IntervalLimit } from "@calcom/types/Calendar";
import type { CredentialPayload } from "@calcom/types/Credential";
import { getDefinedBufferTimes } from "../features/eventtypes/lib/getDefinedBufferTimes";
export async function getBusyTimes(params: {
credentials: CredentialPayload[];
userId: number;
@@ -85,10 +87,16 @@ export async function getBusyTimes(params: {
const endTimeDate =
rescheduleUid && duration ? dayjs(endTime).add(duration, "minute").toDate() : new Date(endTime);
// to also get bookings that are outside of start and end time, but the buffer falls within the start and end time
const definedBufferTimes = getDefinedBufferTimes();
const maxBuffer = definedBufferTimes[definedBufferTimes.length - 1];
const startTimeAdjustedWithMaxBuffer = dayjs(startTimeDate).subtract(maxBuffer, "minute").toDate();
const endTimeAdjustedWithMaxBuffer = dayjs(endTimeDate).add(maxBuffer, "minute").toDate();
// startTime is less than endTimeDate and endTime grater than startTimeDate
const sharedQuery = {
startTime: { lte: endTimeDate },
endTime: { gte: startTimeDate },
startTime: { lte: endTimeAdjustedWithMaxBuffer },
endTime: { gte: startTimeAdjustedWithMaxBuffer },
status: {
in: [BookingStatus.ACCEPTED],
},
@@ -462,4 +462,141 @@ describe("handleNewBooking", () => {
},
timeout
);
describe("Buffers", () => {
test(`should throw error when booking is within a before event buffer of an existing booking
`, async ({}) => {
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],
});
const { dateString: nextDayDateString } = getDate({ dateIncrement: 1 });
await createBookingScenario(
getScenarioData({
eventTypes: [
{
id: 1,
slotInterval: 15,
length: 15,
beforeEventBuffer: 60,
users: [
{
id: 101,
},
],
},
],
bookings: [
{
eventTypeId: 1,
userId: 101,
status: BookingStatus.ACCEPTED,
startTime: `${nextDayDateString}T05:00:00.000Z`,
endTime: `${nextDayDateString}T05:15:00.000Z`,
},
],
organizer,
})
);
const mockBookingData = getMockRequestDataForBooking({
data: {
start: `${nextDayDateString}T04:30:00.000Z`,
end: `${nextDayDateString}T04:45:00.000Z`,
eventTypeId: 1,
responses: {
email: booker.email,
name: booker.name,
location: { optionValue: "", value: "New York" },
},
},
});
const { req } = createMockNextJsRequest({
method: "POST",
body: mockBookingData,
});
await expect(async () => await handleNewBooking(req)).rejects.toThrowError(
"no_available_users_found_error"
);
});
});
test(`should throw error when booking is within a after event buffer of an existing booking
`, async ({}) => {
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],
});
const { dateString: nextDayDateString } = getDate({ dateIncrement: 1 });
await createBookingScenario(
getScenarioData({
eventTypes: [
{
id: 1,
slotInterval: 15,
length: 15,
afterEventBuffer: 60,
users: [
{
id: 101,
},
],
},
],
bookings: [
{
eventTypeId: 1,
userId: 101,
status: BookingStatus.ACCEPTED,
startTime: `${nextDayDateString}T05:00:00.000Z`,
endTime: `${nextDayDateString}T05:15:00.000Z`,
},
],
organizer,
})
);
const mockBookingData = getMockRequestDataForBooking({
data: {
start: `${nextDayDateString}T05:30:00.000Z`,
end: `${nextDayDateString}T05:45:00.000Z`,
eventTypeId: 1,
responses: {
email: booker.email,
name: booker.name,
location: { optionValue: "", value: "New York" },
},
},
});
const { req } = createMockNextJsRequest({
method: "POST",
body: mockBookingData,
});
await expect(async () => await handleNewBooking(req)).rejects.toThrowError(
"no_available_users_found_error"
);
});
});
@@ -0,0 +1,3 @@
export const getDefinedBufferTimes = () => {
return [5, 10, 15, 20, 30, 45, 60, 90, 120];
};