diff --git a/backend/src/services/services.service.ts b/backend/src/services/services.service.ts index 2ddd08b..f96bf11 100644 --- a/backend/src/services/services.service.ts +++ b/backend/src/services/services.service.ts @@ -36,6 +36,50 @@ export class ServicesService { if (!prof) prof = await this.prisma.professionals.findUnique({ where: { user_id: data.professional_id } }); if (!prof || !prof.is_active) throw new BadRequestException('Profesional no disponible'); + if (data.range1_hour1) { + const slotTime = new Date(`1970-01-01T${data.range1_hour1}:00`); + + // Double-booking check: reject if this slot already has a non-cancelled/denied service + const conflict = await this.prisma.services.findFirst({ + where: { + professional_id: prof.id, + day: new Date(data.day), + range1_hour1: slotTime, + status: { notIn: ['denied', 'cancelled'] }, + }, + }); + if (conflict) throw new BadRequestException('Este horario ya está ocupado'); + + // Schedule validation: confirm the slot is within the professional's configured hours + // JS getDay() → 0=Sun…6=Sat; DB convention → 0=Mon…6=Sun, so: (getDay()+6)%7 + const jsDay = new Date(data.day).getDay(); + const dayOfWeek = (jsDay + 6) % 7; + const schedule = await this.prisma.schedules.findFirst({ + where: { professional_id: prof.id, day_of_week: dayOfWeek, enabled: true }, + }); + if (!schedule) throw new BadRequestException('El profesional no atiende ese día'); + + const toMins = (d: Date | null) => d ? d.getUTCHours() * 60 + d.getUTCMinutes() : null; + const [sh, sm] = data.range1_hour1.split(':').map(Number); + const reqMins = sh * 60 + sm; + + let inRange = false; + if (schedule.continuous_day) { + // Full day: range1_hour1 → range2_hour2 + const start = toMins(schedule.range1_hour1); + const end = toMins(schedule.range2_hour2); + if (start !== null && end !== null) inRange = reqMins >= start && reqMins < end; + } else { + // Morning block: range1_hour1 → range1_hour2 + const s1 = toMins(schedule.range1_hour1), e1 = toMins(schedule.range1_hour2); + if (s1 !== null && e1 !== null) inRange = inRange || (reqMins >= s1 && reqMins < e1); + // Afternoon block: range2_hour1 → range2_hour2 + const s2 = toMins(schedule.range2_hour1), e2 = toMins(schedule.range2_hour2); + if (s2 !== null && e2 !== null) inRange = inRange || (reqMins >= s2 && reqMins < e2); + } + if (!inRange) throw new BadRequestException('La hora seleccionada está fuera del horario del profesional'); + } + return this.prisma.services.create({ data: { professional_id: prof.id,