fix: invalid Cancelled / Rescheduled downstream calendar block (#14700)

* fix: invalid Cancelled / Rescheduled downstream calendar block

* Adjust test so no calendar is connected

* Remove the googleCalendar from multiple tests
This commit is contained in:
Alex van Andel authored and GitHub committed 2024-04-22 16:10:39 +01:00
1 parent 20dfc34e70
commit 0306ad737f
4 files changed
+54 -114

No files matched your search

+2 -3
View File
@@ -630,8 +630,7 @@ describe("getSchedule", () => {
...TestData.users.example,
id: 101,
schedules: [TestData.schedules.IstWorkHours],
credentials: [getGoogleCalendarCredential()],
selectedCalendars: [TestData.selectedCalendars.google],
credentials: [],
},
],
bookings: [
@@ -643,7 +642,7 @@ describe("getSchedule", () => {
status: "ACCEPTED" as BookingStatus,
},
],
apps: [TestData.apps.googleCalendar],
// apps: [TestData.apps.googleCalendar],
};
await createBookingScenario(scenarioData);
+44 -37
View File
@@ -144,43 +144,50 @@ export async function getBusyTimes(params: {
});
const bookingSeatCountMap: { [x: string]: number } = {};
const busyTimes = bookings.reduce(
(aggregate: EventBusyDetails[], { id, startTime, endTime, eventType, title, ...rest }) => {
if (rest._count?.seatsReferences) {
const bookedAt = `${dayjs(startTime).utc().format()}<>${dayjs(endTime).utc().format()}`;
bookingSeatCountMap[bookedAt] = bookingSeatCountMap[bookedAt] || 0;
bookingSeatCountMap[bookedAt]++;
// Seat references on the current event are non-blocking until the event is fully booked.
if (
// there are still seats available.
bookingSeatCountMap[bookedAt] < (eventType?.seatsPerTimeSlot || 1) &&
// and this is the seated event, other event types should be blocked.
eventTypeId === eventType?.id
) {
// then we do not add the booking to the busyTimes.
return aggregate;
}
// if it does get blocked at this point; we remove the bookingSeatCountMap entry
// doing this allows using the map later to remove the ranges from calendar busy times.
delete bookingSeatCountMap[bookedAt];
}
if (rest.uid === rescheduleUid) {
return aggregate;
}
aggregate.push({
start: dayjs(startTime)
.subtract((eventType?.beforeEventBuffer || 0) + (afterEventBuffer || 0), "minute")
.toDate(),
end: dayjs(endTime)
.add((eventType?.afterEventBuffer || 0) + (beforeEventBuffer || 0), "minute")
.toDate(),
title,
source: `eventType-${eventType?.id}-booking-${id}`,
});
return aggregate;
},
[]
);
// Only take bookings as source of truth when there are no connected calendars
// this is because cancellations downstream aren't reflected in our Booking database.
// TODO: Reflect downstream cancellations in our Booking database and use Booking as
// source of truth.
const busyTimes =
credentials?.length > 0
? []
: bookings.reduce(
(aggregate: EventBusyDetails[], { id, startTime, endTime, eventType, title, ...rest }) => {
if (rest._count?.seatsReferences) {
const bookedAt = `${dayjs(startTime).utc().format()}<>${dayjs(endTime).utc().format()}`;
bookingSeatCountMap[bookedAt] = bookingSeatCountMap[bookedAt] || 0;
bookingSeatCountMap[bookedAt]++;
// Seat references on the current event are non-blocking until the event is fully booked.
if (
// there are still seats available.
bookingSeatCountMap[bookedAt] < (eventType?.seatsPerTimeSlot || 1) &&
// and this is the seated event, other event types should be blocked.
eventTypeId === eventType?.id
) {
// then we do not add the booking to the busyTimes.
return aggregate;
}
// if it does get blocked at this point; we remove the bookingSeatCountMap entry
// doing this allows using the map later to remove the ranges from calendar busy times.
delete bookingSeatCountMap[bookedAt];
}
if (rest.uid === rescheduleUid) {
return aggregate;
}
aggregate.push({
start: dayjs(startTime)
.subtract((eventType?.beforeEventBuffer || 0) + (afterEventBuffer || 0), "minute")
.toDate(),
end: dayjs(endTime)
.add((eventType?.afterEventBuffer || 0) + (beforeEventBuffer || 0), "minute")
.toDate(),
title,
source: `eventType-${eventType?.id}-booking-${id}`,
});
return aggregate;
},
[]
);
logger.debug(
`Busy Time from Cal Bookings ${JSON.stringify({
@@ -2433,13 +2433,7 @@ describe("handleNewBooking", () => {
email: "organizer@example.com",
id: 101,
schedules: [TestData.schedules.IstWorkHours],
credentials: [getGoogleCalendarCredential()],
selectedCalendars: [TestData.selectedCalendars.google],
destinationCalendar: {
integration: "google_calendar",
externalId: "organizer@google-calendar.com",
primaryEmail: organizerOtherEmail,
},
credentials: [],
});
await createBookingScenario(
@@ -2455,15 +2449,10 @@ describe("handleNewBooking", () => {
id: 101,
},
],
destinationCalendar: {
integration: "google_calendar",
externalId: "event-type-1@google-calendar.com",
primaryEmail: organizerDestinationCalendarEmailOnEventType,
},
},
],
organizer,
apps: [TestData.apps["google-calendar"], TestData.apps["daily-video"]],
apps: [TestData.apps["daily-video"]],
})
);
@@ -2524,36 +2513,10 @@ describe("handleNewBooking", () => {
meetingPassword: "MOCK_PASS",
meetingUrl: "http://mock-dailyvideo.example.com/meeting-1",
},
{
type: appStoreMetadata.googlecalendar.type,
uid: "MOCKED_GOOGLE_CALENDAR_EVENT_ID",
meetingId: "MOCKED_GOOGLE_CALENDAR_EVENT_ID",
meetingPassword: "MOCK_PASSWORD",
meetingUrl: "https://UNUSED_URL",
},
],
iCalUID: createdBooking.iCalUID,
});
expectSuccessfulCalendarEventCreationInCalendar(calendarMock, {
calendarId: "event-type-1@google-calendar.com",
videoCallUrl: "http://mock-dailyvideo.example.com/meeting-1",
});
const iCalUID = expectICalUIDAsString(createdBooking.iCalUID);
expectSuccessfulBookingCreationEmails({
booking: {
uid: createdBooking.uid!,
urlOrigin: WEBSITE_URL,
},
booker,
organizer,
emails,
iCalUID,
destinationEmail: organizerDestinationCalendarEmailOnEventType,
});
await expect(async () => await handleNewBooking(req)).rejects.toThrowError(
ErrorCode.NoAvailableUsersFound
);
@@ -266,12 +266,8 @@ describe("handleNewBooking", () => {
email: "organizer@example.com",
id: 101,
schedules: [TestData.schedules.IstWorkHours],
credentials: [getGoogleCalendarCredential()],
selectedCalendars: [TestData.selectedCalendars.google],
destinationCalendar: {
integration: "google_calendar",
externalId: "organizer@google-calendar.com",
},
credentials: [],
selectedCalendars: [],
});
const recurrence = getRecurrence({
@@ -303,10 +299,6 @@ describe("handleNewBooking", () => {
id: 101,
},
],
destinationCalendar: {
integration: "google_calendar",
externalId: "event-type-1@google-calendar.com",
},
},
],
bookings: [
@@ -320,7 +312,7 @@ describe("handleNewBooking", () => {
},
],
organizer,
apps: [TestData.apps["google-calendar"], TestData.apps["daily-video"]],
apps: [TestData.apps["daily-video"]],
})
);
@@ -837,12 +829,7 @@ describe("handleNewBooking", () => {
],
// Has morning shift with some overlap with morning shift
schedules: [TestData.schedules.IstMorningShift],
credentials: [getGoogleCalendarCredential()],
selectedCalendars: [TestData.selectedCalendars.google],
destinationCalendar: {
integration: TestData.apps["google-calendar"].type,
externalId: "organizer@google-calendar.com",
},
credentials: [],
});
const otherTeamMembers = [
@@ -856,12 +843,7 @@ describe("handleNewBooking", () => {
id: 102,
// Has Evening shift
schedules: [TestData.schedules.IstMorningShift],
credentials: [getGoogleCalendarCredential()],
selectedCalendars: [TestData.selectedCalendars.google],
destinationCalendar: {
integration: TestData.apps["google-calendar"].type,
externalId: "other-team-member-1@google-calendar.com",
},
credentials: [],
},
];
@@ -901,10 +883,6 @@ describe("handleNewBooking", () => {
isFixed: true,
},
],
destinationCalendar: {
integration: "google_calendar",
externalId: "event-type-1@google-calendar.com",
},
},
],
bookings: [
@@ -923,7 +901,7 @@ describe("handleNewBooking", () => {
],
organizer,
usersApartFromOrganizer: otherTeamMembers,
apps: [TestData.apps["google-calendar"], TestData.apps["daily-video"]],
apps: [TestData.apps["daily-video"]],
})
);
@@ -936,13 +914,6 @@ describe("handleNewBooking", () => {
},
});
const calendarMock = mockCalendarToHaveNoBusySlots("googlecalendar", {
create: {
id: "MOCKED_GOOGLE_CALENDAR_EVENT_ID",
iCalUID: "MOCKED_GOOGLE_CALENDAR_ICS_ID",
},
});
const recurringCountInRequest = 4;
const mockBookingData1 = getMockRequestDataForBooking({
data: {