fix: improve schedule overlap validation in ScheduleSchema

- Enhanced the validation logic to check for overlapping schedules by incorporating checks against existing user schedule dates.
- Added comprehensive overlap detection for new schedules, ensuring they do not conflict with any existing schedules for the user.
- This update aims to improve the integrity of scheduling operations and provide clearer error messages for users regarding scheduling conflicts.
This commit is contained in:
2025-01-17 23:08:32 +07:00
parent bd4eaea379
commit 9aec02568d

View File

@@ -437,6 +437,7 @@ d72a864e-2f41-45ab-9c9b-bf0512a31883,e9be51fd-2382-4e43-9988-74e76fde4b56,2024-1
throw new Error("User not found"); throw new Error("User not found");
} }
Logger.log("args.schedule", args.schedule); Logger.log("args.schedule", args.schedule);
// reject schedule if start date is today or in the past // reject schedule if start date is today or in the past
if ( if (
DateTimeUtils.fromDate(args.schedule.scheduleStart as Date).day <= DateTimeUtils.fromDate(args.schedule.scheduleStart as Date).day <=
@@ -444,6 +445,7 @@ d72a864e-2f41-45ab-9c9b-bf0512a31883,e9be51fd-2382-4e43-9988-74e76fde4b56,2024-1
) { ) {
throw new Error("Start date is in the past or today"); throw new Error("Start date is in the past or today");
} }
// generate preview and check if there is any overlapping with other schedules date in same service // generate preview and check if there is any overlapping with other schedules date in same service
const previewSchedule = const previewSchedule =
await this.scheduleService.createSchedulePreviewForCenter({ await this.scheduleService.createSchedulePreviewForCenter({
@@ -452,6 +454,7 @@ d72a864e-2f41-45ab-9c9b-bf0512a31883,e9be51fd-2382-4e43-9988-74e76fde4b56,2024-1
slots: args.schedule.slots as number[], slots: args.schedule.slots as number[],
days: args.schedule.daysOfWeek as number[], days: args.schedule.daysOfWeek as number[],
}); });
const existingScheduleDates = await this.prisma.scheduleDate.findMany( const existingScheduleDates = await this.prisma.scheduleDate.findMany(
{ {
where: { where: {
@@ -471,6 +474,7 @@ d72a864e-2f41-45ab-9c9b-bf0512a31883,e9be51fd-2382-4e43-9988-74e76fde4b56,2024-1
}, },
} }
); );
// check if there is any overlapping with existing schedule dates in same service using DateTimeUtils // check if there is any overlapping with existing schedule dates in same service using DateTimeUtils
const isOverlapping = DateTimeUtils.isOverlaps( const isOverlapping = DateTimeUtils.isOverlaps(
previewSchedule.slots.map((slot) => ({ previewSchedule.slots.map((slot) => ({
@@ -482,55 +486,72 @@ d72a864e-2f41-45ab-9c9b-bf0512a31883,e9be51fd-2382-4e43-9988-74e76fde4b56,2024-1
end: DateTimeUtils.fromDate(date.end), end: DateTimeUtils.fromDate(date.end),
})) }))
); );
if (isOverlapping) { if (isOverlapping) {
Logger.error("Overlapping schedule", "ScheduleSchema"); Logger.error("Overlapping schedule", "ScheduleSchema");
throw new Error("Overlapping schedule"); throw new Error("Overlapping schedule");
} }
const scheduleDatesInSchedule =
// check if scheduleDate have overlap with other scheduleDate of same user
const existingUserScheduleDates =
await this.prisma.scheduleDate.findMany({ await this.prisma.scheduleDate.findMany({
where: { where: {
scheduleId: args.schedule.id, AND: [
{
participantIds: {
has: ctx.me?.id ?? "",
},
},
{
status: {
notIn: [
ScheduleDateStatus.COMPLETED,
ScheduleDateStatus.EXPIRED,
],
},
},
{
end: {
gte: DateTimeUtils.now().toJSDate(),
},
},
],
}, },
}); });
const overlapSchedule = await this.prisma.scheduleDate.findFirst({
where: { // First, generate the preview schedule dates
AND: [ const previewScheduleDates = previewSchedule.slots.map((slot) => ({
{ start: DateTimeUtils.fromIsoString(slot.start),
participantIds: { end: DateTimeUtils.fromIsoString(slot.end),
has: ctx.me?.id ?? "", }));
},
orderId: { // Check if new schedule overlaps with any existing schedule dates for the user
not: null, const hasOverlap = existingUserScheduleDates.some((existingDate) =>
}, previewScheduleDates.some((newScheduleDate) =>
dayOfWeek: { DateTimeUtils.isOverlap(
in: Array.isArray(args.schedule.daysOfWeek) DateTimeUtils.fromDate(existingDate.start),
? args.schedule.daysOfWeek DateTimeUtils.fromDate(existingDate.end),
: [], newScheduleDate.start,
}, newScheduleDate.end
slot: { )
in: Array.isArray(args.schedule.slots) )
? args.schedule.slots );
: [],
}, if (hasOverlap) {
scheduleId: { throw new Error(
notIn: scheduleDatesInSchedule.map( "Schedule date has overlap with existing schedule dates"
(scheduleDate) => scheduleDate.scheduleId );
),
},
},
],
},
});
if (overlapSchedule) {
throw new Error("Overlapping schedule");
} }
const schedule = await this.prisma.schedule.create({ const schedule = await this.prisma.schedule.create({
...query, ...query,
data: args.schedule, data: args.schedule,
}); });
// generate schedule dates based on data and config // generate schedule dates based on data and config
const scheduleDates = const scheduleDates =
await this.scheduleService.generateScheduleDates(schedule); await this.scheduleService.generateScheduleDates(schedule);
// update schedule with schedule dates // update schedule with schedule dates
return await this.prisma.schedule.update({ return await this.prisma.schedule.update({
...query, ...query,