diff --git a/backend/src/main/java/com/magistr/app/controller/ScheduleRuleAdminController.java b/backend/src/main/java/com/magistr/app/controller/ScheduleRuleAdminController.java index b0624b4..e00dddd 100644 --- a/backend/src/main/java/com/magistr/app/controller/ScheduleRuleAdminController.java +++ b/backend/src/main/java/com/magistr/app/controller/ScheduleRuleAdminController.java @@ -6,6 +6,7 @@ import com.magistr.app.dto.ScheduleRuleSlotDto; import com.magistr.app.model.*; import com.magistr.app.repository.*; import com.magistr.app.service.ScheduleGeneratorService; +import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.*; @@ -81,6 +82,13 @@ public class ScheduleRuleAdminController { try { ScheduleRule rule = new ScheduleRule(); applyRule(rule, request); + ScheduleRule conflictRule = findConflictingRule(request, rule.getSlots(), null); + if (conflictRule != null) { + return ResponseEntity.status(HttpStatus.CONFLICT).body(Map.of( + "message", "Невозможно сохранить правило: слот занят", + "conflictRule", toDto(conflictRule) + )); + } ScheduleRule saved = scheduleRuleRepository.save(rule); scheduleGeneratorService.clearCache(); return ResponseEntity.ok(toDto(saved)); @@ -104,6 +112,13 @@ public class ScheduleRuleAdminController { try { applyRule(rule, request); + ScheduleRule conflictRule = findConflictingRule(request, rule.getSlots(), rule.getId()); + if (conflictRule != null) { + return ResponseEntity.status(HttpStatus.CONFLICT).body(Map.of( + "message", "Невозможно сохранить правило: слот занят", + "conflictRule", toDto(conflictRule) + )); + } ScheduleRule saved = scheduleRuleRepository.save(rule); scheduleGeneratorService.clearCache(); return ResponseEntity.ok(toDto(saved)); @@ -181,6 +196,37 @@ public class ScheduleRuleAdminController { rule.getSlots().addAll(slots); } + private ScheduleRule findConflictingRule(ScheduleRuleDto request, Collection newSlots, Long excludeRuleId) { + return scheduleRuleRepository.findAllWithDetails().stream() + .filter(rule -> !Objects.equals(rule.getId(), excludeRuleId)) + .filter(rule -> rule.getSemester() != null && Objects.equals(rule.getSemester().getId(), request.semesterId())) + .filter(rule -> hasSlotConflict(newSlots, rule.getSlots())) + .min(Comparator.comparing(ScheduleRule::getId)) + .orElse(null); + } + + private boolean hasSlotConflict(Collection newSlots, Collection existingSlots) { + for (ScheduleRuleSlot newSlot : newSlots) { + for (ScheduleRuleSlot existingSlot : existingSlots) { + if (sameTimeSlot(newSlot, existingSlot) && sameTeacherOrClassroom(newSlot, existingSlot)) { + return true; + } + } + } + return false; + } + + private boolean sameTimeSlot(ScheduleRuleSlot first, ScheduleRuleSlot second) { + return Objects.equals(first.getDayOfWeek(), second.getDayOfWeek()) + && Objects.equals(first.getParity(), second.getParity()) + && Objects.equals(first.getTimeSlot().getId(), second.getTimeSlot().getId()); + } + + private boolean sameTeacherOrClassroom(ScheduleRuleSlot first, ScheduleRuleSlot second) { + return Objects.equals(first.getTeacher().getId(), second.getTeacher().getId()) + || Objects.equals(first.getClassroom().getId(), second.getClassroom().getId()); + } + private ScheduleRuleSlot buildSlot(ScheduleRule rule, ScheduleRuleSlotDto slotDto) { if (slotDto.dayOfWeek() == null || slotDto.dayOfWeek() < 1 || slotDto.dayOfWeek() > 7) { throw new IllegalArgumentException("День недели должен быть от 1 до 7");