Check for working hours + rename isAvailable (#5342)
* Check for working hours + rename isAvailable * Return did not make it all the way back to callee * Removed redundant break clause * Fixes forEach returnpull/5365/head^2
parent
eb14c1b796
commit
328a354f4d
|
@ -21,7 +21,7 @@ import { cancelScheduledJobs, scheduleTrigger } from "@calcom/app-store/zapier/l
|
|||
import EventManager from "@calcom/core/EventManager";
|
||||
import { getEventName } from "@calcom/core/event";
|
||||
import { getUserAvailability } from "@calcom/core/getUserAvailability";
|
||||
import dayjs from "@calcom/dayjs";
|
||||
import dayjs, { ConfigType } from "@calcom/dayjs";
|
||||
import {
|
||||
sendAttendeeRequestEmail,
|
||||
sendOrganizerRequestEmail,
|
||||
|
@ -46,6 +46,7 @@ import { EventTypeMetaDataSchema, extendedBookingCreateBody } from "@calcom/pris
|
|||
import type { BufferedBusyTime } from "@calcom/types/BufferedBusyTime";
|
||||
import type { AdditionalInformation, AppsStatus, CalendarEvent } from "@calcom/types/Calendar";
|
||||
import type { EventResult, PartialReference } from "@calcom/types/EventManager";
|
||||
import { WorkingHours } from "@calcom/types/schedule";
|
||||
|
||||
import sendPayload, { EventTypeInfo } from "../../webhooks/lib/sendPayload";
|
||||
|
||||
|
@ -83,40 +84,56 @@ async function refreshCredentials(credentials: Array<Credential>): Promise<Array
|
|||
return await async.mapLimit(credentials, 5, refreshCredential);
|
||||
}
|
||||
|
||||
function isAvailable(busyTimes: BufferedBusyTimes, time: dayjs.ConfigType, length: number): boolean {
|
||||
// Check for conflicts
|
||||
let t = true;
|
||||
const isWithinAvailableHours = (
|
||||
timeSlot: { start: ConfigType; end: ConfigType },
|
||||
{
|
||||
workingHours,
|
||||
}: {
|
||||
workingHours: WorkingHours[];
|
||||
}
|
||||
) => {
|
||||
const timeSlotStart = dayjs(timeSlot.start).utc();
|
||||
const timeSlotEnd = dayjs(timeSlot.end).utc();
|
||||
for (const workingHour of workingHours) {
|
||||
// TODO: Double check & possibly fix timezone conversions.
|
||||
const startTime = timeSlotStart.startOf("day").add(workingHour.startTime, "minute");
|
||||
const endTime = timeSlotEnd.startOf("day").add(workingHour.endTime, "minute");
|
||||
if (
|
||||
workingHour.days.includes(timeSlotStart.day()) &&
|
||||
// UTC mode, should be performant.
|
||||
timeSlotStart.isBetween(startTime, endTime, null, "[)") &&
|
||||
timeSlotEnd.isBetween(startTime, endTime, null, "(]")
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
// if true, there are conflicts.
|
||||
function checkForConflicts(busyTimes: BufferedBusyTimes, time: dayjs.ConfigType, length: number) {
|
||||
// Early return
|
||||
if (!Array.isArray(busyTimes) || busyTimes.length < 1) return t;
|
||||
if (!Array.isArray(busyTimes) || busyTimes.length < 1) {
|
||||
return false; // guaranteed no conflicts when there is no busy times.
|
||||
}
|
||||
|
||||
let i = 0;
|
||||
while (t === true && i < busyTimes.length) {
|
||||
const busyTime = busyTimes[i];
|
||||
i++;
|
||||
for (const busyTime of busyTimes) {
|
||||
const startTime = dayjs(busyTime.start);
|
||||
const endTime = dayjs(busyTime.end);
|
||||
|
||||
// Check if time is between start and end times
|
||||
if (dayjs(time).isBetween(startTime, endTime, null, "[)")) {
|
||||
t = false;
|
||||
break;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if slot end time is between start and end time
|
||||
if (dayjs(time).add(length, "minutes").isBetween(startTime, endTime)) {
|
||||
t = false;
|
||||
break;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if startTime is between slot
|
||||
if (startTime.isBetween(dayjs(time), dayjs(time).add(length, "minutes"))) {
|
||||
t = false;
|
||||
break;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return t;
|
||||
return false;
|
||||
}
|
||||
|
||||
const getEventTypesFromDB = async (eventTypeId: number) => {
|
||||
|
@ -199,7 +216,7 @@ async function ensureAvailableUsers(
|
|||
const availableUsers: typeof eventType.users = [];
|
||||
/** Let's start checking for availability */
|
||||
for (const user of eventType.users) {
|
||||
const { busy: bufferedBusyTimes } = await getUserAvailability(
|
||||
const { busy: bufferedBusyTimes, workingHours } = await getUserAvailability(
|
||||
{
|
||||
userId: user.id,
|
||||
eventTypeId: eventType.id,
|
||||
|
@ -208,9 +225,22 @@ async function ensureAvailableUsers(
|
|||
{ user, eventType }
|
||||
);
|
||||
|
||||
// check if time slot is outside of schedule.
|
||||
if (
|
||||
!isWithinAvailableHours(
|
||||
{ start: input.dateFrom, end: input.dateTo },
|
||||
{
|
||||
workingHours,
|
||||
}
|
||||
)
|
||||
) {
|
||||
// user does not have availability at this time, skip user.
|
||||
continue;
|
||||
}
|
||||
|
||||
console.log("calendarBusyTimes==>>>", bufferedBusyTimes);
|
||||
|
||||
let isAvailableToBeBooked = true;
|
||||
let foundConflict = true;
|
||||
try {
|
||||
if (eventType.recurringEvent) {
|
||||
const recurringEvent = parseRecurringEvent(eventType.recurringEvent);
|
||||
|
@ -219,23 +249,19 @@ async function ensureAvailableUsers(
|
|||
// DONE: Decreased computational complexity from O(2^n) to O(n) by refactoring this loop to stop
|
||||
// running at the first unavailable time.
|
||||
let i = 0;
|
||||
while (isAvailableToBeBooked === true && i < allBookingDates.length) {
|
||||
const aDate = allBookingDates[i];
|
||||
i++;
|
||||
isAvailableToBeBooked = isAvailable(bufferedBusyTimes, aDate, eventType.length);
|
||||
// We bail at the first false, we don't need to keep checking
|
||||
if (!isAvailableToBeBooked) break;
|
||||
while (!foundConflict && i < allBookingDates.length) {
|
||||
foundConflict = checkForConflicts(bufferedBusyTimes, allBookingDates[i++], eventType.length);
|
||||
}
|
||||
} else {
|
||||
isAvailableToBeBooked = isAvailable(bufferedBusyTimes, input.dateFrom, eventType.length);
|
||||
foundConflict = checkForConflicts(bufferedBusyTimes, input.dateFrom, eventType.length);
|
||||
}
|
||||
} catch {
|
||||
log.debug({
|
||||
message: "Unable set isAvailableToBeBooked. Using true. ",
|
||||
});
|
||||
}
|
||||
|
||||
if (isAvailableToBeBooked) {
|
||||
// no conflicts found, add to available users.
|
||||
if (!foundConflict) {
|
||||
availableUsers.push(user);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue