fix: eventtype null cant be booked error (#18975)

* fix err msg and add more description

* improvements

* fix cause

* add warn logs for when failing to specific limit checks

* typefix

* safestringify log

* improve error

* test fix and log min booking notice

* adds out of bounds error code

* test fix

* fix
This commit is contained in:
Syed Ali Shahbaz
2025-01-29 13:00:51 +00:00
committed by GitHub
parent 8615ccb1aa
commit 92678dc042
5 changed files with 64 additions and 31 deletions
@@ -83,6 +83,7 @@
"payment_not_created_error": "Payment could not be created",
"couldnt_charge_card_error": "Could not charge card for Payment",
"no_available_users_found_error": "No available users found. Could you try another time slot?",
"booking_time_out_of_bounds_error": "The event type cannot be booked at this time. Could you try another time slot?",
"request_body_end_time_internal_error": "Internal Error. Request body does not contain end time",
"create_calendar_event_error": "Unable to create Calendar event in Organizer's calendar",
"update_calendar_event_error": "Unable to update Calendar event.",
@@ -772,7 +772,9 @@ describe("handleNewBooking", () => {
mockCalendarToHaveNoBusySlots("googlecalendar", {});
await createBookingScenario(scenarioData);
await expect(() => handleNewBooking(req)).rejects.toThrowError("book a meeting in the past");
await expect(() => handleNewBooking(req)).rejects.toThrowError(
"Attempting to book a meeting in the past."
);
},
timeout
);
@@ -865,7 +867,7 @@ describe("handleNewBooking", () => {
},
});
expect(() => handleNewBooking(req)).rejects.toThrowError("cannot be booked at this time");
expect(() => handleNewBooking(req)).rejects.toThrowError("booking_time_out_of_bounds_error");
},
timeout
);
@@ -1,6 +1,7 @@
import type { Logger } from "tslog";
import { getUTCOffsetByTimezone } from "@calcom/lib/date-fns";
import { ErrorCode } from "@calcom/lib/errorCodes";
import { HttpError } from "@calcom/lib/http-error";
import isOutOfBounds, { BookingDateInPastError } from "@calcom/lib/isOutOfBounds";
import type { EventType } from "@calcom/prisma/client";
@@ -15,6 +16,7 @@ type ValidateBookingTimeEventType = Pick<
| "minimumBookingNotice"
| "eventName"
| "id"
| "title"
>;
export const validateBookingTimeIsNotOutOfBounds = async <T extends ValidateBookingTimeEventType>(
@@ -41,22 +43,14 @@ export const validateBookingTimeIsNotOutOfBounds = async <T extends ValidateBook
);
} catch (error) {
logger.warn({
message: "NewBooking: Unable set timeOutOfBounds. Using false. ",
message: "NewBooking: Unable to determine timeOutOfBounds status. Defaulting to false.",
});
if (error instanceof BookingDateInPastError) {
logger.info(`Booking eventType ${eventType.id} failed`, JSON.stringify({ error }));
throw new HttpError({ statusCode: 400, message: error.message });
}
}
if (timeOutOfBounds) {
const error = {
errorCode: "BookingTimeOutOfBounds",
message: `EventType '${eventType.eventName}' cannot be booked at this time.`,
};
logger.warn({
message: `NewBooking: EventType '${eventType.eventName}' cannot be booked at this time.`,
});
throw new HttpError({ statusCode: 400, message: error.message });
}
if (timeOutOfBounds) throw new Error(ErrorCode.BookingTimeOutOfBounds);
};
+1
View File
@@ -16,4 +16,5 @@ export enum ErrorCode {
UnableToSubscribeToThePlatform = "unable_to_subscribe_to_the_platform",
UpdatingOauthClientError = "updating_oauth_client_error",
CreatingOauthClientError = "creating_oauth_client_error",
BookingTimeOutOfBounds = "booking_time_out_of_bounds_error",
}
+53 -18
View File
@@ -250,6 +250,15 @@ export function isTimeViolatingFutureLimit({
isAfterRollingEndDay,
endOfRollingPeriodEndDayInBookerTz: periodLimits.endOfRollingPeriodEndDayInBookerTz.format(),
});
if (isAfterRollingEndDay)
log.warn(
"Booking is out of bounds due to rolling period end day.",
safeStringify({
formattedDate: dateInSystemTz.format(),
isAfterRollingEndDay,
endOfRollingPeriodEndDayInBookerTz: periodLimits.endOfRollingPeriodEndDayInBookerTz.format(),
})
);
return isAfterRollingEndDay;
}
@@ -263,6 +272,17 @@ export function isTimeViolatingFutureLimit({
startOfRangeStartDayInEventTz: periodLimits.startOfRangeStartDayInEventTz.format(),
endOfRangeEndDayInEventTz: periodLimits.endOfRangeEndDayInEventTz.format(),
});
if (isBeforeRangeStart || isAfterRangeEnd)
log.warn(
"Booking is out of bounds due to range start and end.",
safeStringify({
formattedDate: dateInSystemTz.format(),
isBeforeRangeStart,
isAfterRangeEnd,
startOfRangeStartDayInEventTz: periodLimits.startOfRangeStartDayInEventTz.format(),
endOfRangeEndDayInEventTz: periodLimits.endOfRangeEndDayInEventTz.format(),
})
);
return isBeforeRangeStart || isAfterRangeEnd;
}
return false;
@@ -287,22 +307,37 @@ export default function isOutOfBounds(
},
minimumBookingNotice?: number
) {
return (
isTimeOutOfBounds({ time, minimumBookingNotice }) ||
isTimeViolatingFutureLimit({
time,
periodLimits: calculatePeriodLimits({
periodType,
periodDays,
periodCountCalendarDays,
periodStartDate,
periodEndDate,
// Temporary till we find a way to provide allDatesWithBookabilityStatus in handleNewBooking without re-computing availability for the booked timeslot
allDatesWithBookabilityStatusInBookerTz: null,
_skipRollingWindowCheck: true,
eventUtcOffset,
bookerUtcOffset,
}),
})
);
const log = logger.getSubLogger({ prefix: ["isOutOfBounds"] });
const isOutOfBoundsByTime = isTimeOutOfBounds({ time, minimumBookingNotice });
const periodLimits = calculatePeriodLimits({
periodType,
periodDays,
periodCountCalendarDays,
periodStartDate,
periodEndDate,
allDatesWithBookabilityStatusInBookerTz: null, // Temporary workaround
_skipRollingWindowCheck: true,
eventUtcOffset,
bookerUtcOffset,
});
const isOutOfBoundsByPeriod = isTimeViolatingFutureLimit({
time,
periodLimits,
});
if (isOutOfBoundsByTime) {
log.warn(
"Booking is out of bounds due to minimum booking notice.",
safeStringify({ minimumBookingNotice })
);
return true;
}
if (isOutOfBoundsByPeriod) {
log.warn("Booking is out of bounds due to period restrictions", safeStringify({ periodLimits }));
return true;
}
return false;
}