Compare commits

...

5 Commits

Author SHA1 Message Date
CarinaWolli 554b85a600 fix type error 2023-10-31 15:40:33 -04:00
CarinaWolli dae16fa6e9 fix type error 2023-10-31 15:34:14 -04:00
CarinaWolli a5f906b9b6 use regex 2023-10-31 15:30:44 -04:00
CarinaWolli f54c5675d6 add test 2023-10-31 15:17:56 -04:00
CarinaWolli 2882b5f7ca fix booking limits 2023-11-01 03:35:18 +10:00
3 changed files with 132 additions and 1 deletions

View File

@ -4,6 +4,7 @@ import prismock from "../../../../tests/libs/__mocks__/prisma";
import { diff } from "jest-diff"; import { diff } from "jest-diff";
import { describe, expect, vi, beforeEach, afterEach, test } from "vitest"; import { describe, expect, vi, beforeEach, afterEach, test } from "vitest";
import dayjs from "@calcom/dayjs";
import type { BookingStatus } from "@calcom/prisma/enums"; import type { BookingStatus } from "@calcom/prisma/enums";
import type { Slot } from "@calcom/trpc/server/routers/viewer/slots/types"; import type { Slot } from "@calcom/trpc/server/routers/viewer/slots/types";
import { getAvailableSlots as getSchedule } from "@calcom/trpc/server/routers/viewer/slots/util"; import { getAvailableSlots as getSchedule } from "@calcom/trpc/server/routers/viewer/slots/util";
@ -874,6 +875,128 @@ describe("getSchedule", () => {
} }
); );
}); });
test("test that booking limit is working correctly if user is all day available", async () => {
const { dateString: plus1DateString } = getDate({ dateIncrement: 1 });
const { dateString: plus2DateString } = getDate({ dateIncrement: 2 });
const { dateString: plus3DateString } = getDate({ dateIncrement: 3 });
const scenarioData = {
eventTypes: [
{
id: 1,
length: 60,
beforeEventBuffer: 0,
afterEventBuffer: 0,
bookingLimits: {
PER_DAY: 1,
},
users: [
{
id: 101,
},
],
},
{
id: 2,
length: 60,
beforeEventBuffer: 0,
afterEventBuffer: 0,
bookingLimits: {
PER_DAY: 2,
},
users: [
{
id: 101,
},
],
},
],
users: [
{
...TestData.users.example,
id: 101,
schedules: [
{
id: 1,
name: "All Day available",
availability: [
{
userId: null,
eventTypeId: null,
days: [0, 1, 2, 3, 4, 5, 6],
startTime: new Date("1970-01-01T00:00:00.000Z"),
endTime: new Date("1970-01-01T23:59:59.999Z"),
date: null,
},
],
timeZone: Timezones["+5:30"],
},
],
},
],
bookings: [
{
userId: 101,
eventTypeId: 1,
startTime: `${plus2DateString}T08:30:00.000Z`,
endTime: `${plus2DateString}T08:29:59.999Z`,
status: "ACCEPTED" as BookingStatus,
},
{
userId: 101,
eventTypeId: 2,
startTime: `${plus2DateString}T08:30:00.000Z`,
endTime: `${plus2DateString}T08:29:59.999Z`,
status: "ACCEPTED" as BookingStatus,
},
],
};
await createBookingScenario(scenarioData);
const thisUserAvailabilityBookingLimitOne = await getSchedule({
input: {
eventTypeId: 1,
eventTypeSlug: "",
startTime: `${plus1DateString}T00:00:00.000Z`,
endTime: `${plus3DateString}T23:59:59.999Z`,
timeZone: Timezones["+5:30"],
isTeamEvent: false,
},
});
const thisUserAvailabilityBookingLimitTwo = await getSchedule({
input: {
eventTypeId: 2,
eventTypeSlug: "",
startTime: `${plus1DateString}T00:00:00.000Z`,
endTime: `${plus3DateString}T23:59:59.999Z`,
timeZone: Timezones["+5:30"],
isTeamEvent: false,
},
});
let countSlotsOnDayWithBooking = 0;
for (const date in thisUserAvailabilityBookingLimitOne.slots) {
for (const timeObj of thisUserAvailabilityBookingLimitOne.slots[date]) {
if (dayjs(timeObj.time).tz(Timezones["+5:30"]).format().startsWith(plus2DateString)) {
countSlotsOnDayWithBooking++;
}
}
}
expect(countSlotsOnDayWithBooking).toBe(0); // 1 booking per day as limit
countSlotsOnDayWithBooking = 0;
for (const date in thisUserAvailabilityBookingLimitTwo.slots) {
for (const timeObj of thisUserAvailabilityBookingLimitTwo.slots[date]) {
if (dayjs(timeObj.time).tz(Timezones["+5:30"]).format().startsWith(plus2DateString)) {
countSlotsOnDayWithBooking++;
}
}
}
expect(countSlotsOnDayWithBooking).toBe(23); // 2 booking per day as limit
});
}); });
describe("Team Event", () => { describe("Team Event", () => {

View File

@ -101,6 +101,9 @@ export type InputEventType = {
requiresConfirmation?: boolean; requiresConfirmation?: boolean;
destinationCalendar?: Prisma.DestinationCalendarCreateInput; destinationCalendar?: Prisma.DestinationCalendarCreateInput;
schedule?: InputUser["schedules"][number]; schedule?: InputUser["schedules"][number];
bookingLimits?: {
PER_DAY?: number;
};
} & Partial<Omit<Prisma.EventTypeCreateInput, "users" | "schedule">>; } & Partial<Omit<Prisma.EventTypeCreateInput, "users" | "schedule">>;
type WhiteListedBookingProps = { type WhiteListedBookingProps = {
@ -199,6 +202,7 @@ async function addEventTypes(eventTypes: InputEventType[], usersStore: InputUser
timeZone: null, timeZone: null,
beforeEventBuffer: 0, beforeEventBuffer: 0,
afterEventBuffer: 0, afterEventBuffer: 0,
bookingLimits: {},
schedulingType: null, schedulingType: null,
length: 15, length: 15,
//TODO: What is the purpose of periodStartDate and periodEndDate? Test these? //TODO: What is the purpose of periodStartDate and periodEndDate? Test these?

View File

@ -205,7 +205,11 @@ export const stringOrNumber = z.union([
z.number().int(), z.number().int(),
]); ]);
export const stringToDayjs = z.string().transform((val) => dayjs(val)); export const stringToDayjs = z.string().transform((val) => {
const matches = val.match(/([+-]\d{2}:\d{2})$/)[1];
const timezone = matches ? matches[1] : "+00:00";
return dayjs(val).utcOffset(timezone);
});
export const bookingCreateBodySchema = z.object({ export const bookingCreateBodySchema = z.object({
end: z.string().optional(), end: z.string().optional(),