создал систему календарного учебного графика
This commit is contained in:
@@ -5,7 +5,6 @@ import com.magistr.app.model.*;
|
||||
import com.magistr.app.repository.*;
|
||||
import com.magistr.app.service.ScheduleGeneratorService;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.Comparator;
|
||||
@@ -18,19 +17,19 @@ public class AcademicCalendarAdminController {
|
||||
|
||||
private final AcademicYearRepository academicYearRepository;
|
||||
private final SemesterRepository semesterRepository;
|
||||
private final HolidayRepository holidayRepository;
|
||||
private final AcademicCalendarMatrixRepository calendarMatrixRepository;
|
||||
private final AcademicCalendarActivityTypeRepository activityTypeRepository;
|
||||
private final AcademicCalendarDayRepository calendarDayRepository;
|
||||
private final ScheduleGeneratorService scheduleGeneratorService;
|
||||
|
||||
public AcademicCalendarAdminController(AcademicYearRepository academicYearRepository,
|
||||
SemesterRepository semesterRepository,
|
||||
HolidayRepository holidayRepository,
|
||||
AcademicCalendarMatrixRepository calendarMatrixRepository,
|
||||
AcademicCalendarActivityTypeRepository activityTypeRepository,
|
||||
AcademicCalendarDayRepository calendarDayRepository,
|
||||
ScheduleGeneratorService scheduleGeneratorService) {
|
||||
this.academicYearRepository = academicYearRepository;
|
||||
this.semesterRepository = semesterRepository;
|
||||
this.holidayRepository = holidayRepository;
|
||||
this.calendarMatrixRepository = calendarMatrixRepository;
|
||||
this.activityTypeRepository = activityTypeRepository;
|
||||
this.calendarDayRepository = calendarDayRepository;
|
||||
this.scheduleGeneratorService = scheduleGeneratorService;
|
||||
}
|
||||
|
||||
@@ -128,113 +127,60 @@ public class AcademicCalendarAdminController {
|
||||
return ResponseEntity.ok(toSemesterDto(semesterRepository.save(semester)));
|
||||
}
|
||||
|
||||
@GetMapping("/holidays")
|
||||
public ResponseEntity<?> getHolidays(@RequestParam Long academicYearId) {
|
||||
if (!academicYearRepository.existsById(academicYearId)) {
|
||||
return ResponseEntity.badRequest().body(Map.of("message", "Учебный год не найден"));
|
||||
}
|
||||
return ResponseEntity.ok(holidayRepository.findByAcademicYearIdOrderByDateAsc(academicYearId).stream()
|
||||
.map(this::toHolidayDto)
|
||||
.toList());
|
||||
@GetMapping("/activity-types")
|
||||
public List<AcademicCalendarActivityTypeDto> getActivityTypes() {
|
||||
return activityTypeRepository.findAllByOrderByDisplayOrderAscCodeAsc().stream()
|
||||
.map(this::toActivityTypeDto)
|
||||
.toList();
|
||||
}
|
||||
|
||||
@PostMapping("/holidays")
|
||||
public ResponseEntity<?> createHoliday(@RequestBody HolidayDto request) {
|
||||
AcademicYear year = academicYearRepository.findById(request.academicYearId()).orElse(null);
|
||||
if (year == null) {
|
||||
return ResponseEntity.badRequest().body(Map.of("message", "Учебный год не найден"));
|
||||
@PostMapping("/activity-types")
|
||||
public ResponseEntity<?> createActivityType(@RequestBody AcademicCalendarActivityTypeDto request) {
|
||||
String validationError = validateActivityType(request);
|
||||
if (validationError != null) {
|
||||
return ResponseEntity.badRequest().body(Map.of("message", validationError));
|
||||
}
|
||||
if (request.date() == null) {
|
||||
return ResponseEntity.badRequest().body(Map.of("message", "Дата праздника обязательна"));
|
||||
if (activityTypeRepository.findByCode(request.code().trim()).isPresent()) {
|
||||
return ResponseEntity.badRequest().body(Map.of("message", "Код активности уже существует"));
|
||||
}
|
||||
if (holidayRepository.existsByAcademicYearIdAndDate(year.getId(), request.date())) {
|
||||
return ResponseEntity.badRequest().body(Map.of("message", "Эта дата уже добавлена в исключения"));
|
||||
}
|
||||
|
||||
Holiday holiday = new Holiday();
|
||||
holiday.setAcademicYear(year);
|
||||
holiday.setDate(request.date());
|
||||
holiday.setDescription(request.description());
|
||||
AcademicCalendarActivityType activityType = new AcademicCalendarActivityType();
|
||||
applyActivityType(activityType, request);
|
||||
scheduleGeneratorService.clearCache();
|
||||
return ResponseEntity.ok(toHolidayDto(holidayRepository.save(holiday)));
|
||||
return ResponseEntity.ok(toActivityTypeDto(activityTypeRepository.save(activityType)));
|
||||
}
|
||||
|
||||
@PutMapping("/holidays/{id}")
|
||||
public ResponseEntity<?> updateHoliday(@PathVariable Long id, @RequestBody HolidayDto request) {
|
||||
Holiday holiday = holidayRepository.findById(id).orElse(null);
|
||||
if (holiday == null) {
|
||||
@PutMapping("/activity-types/{id}")
|
||||
public ResponseEntity<?> updateActivityType(@PathVariable Long id,
|
||||
@RequestBody AcademicCalendarActivityTypeDto request) {
|
||||
AcademicCalendarActivityType activityType = activityTypeRepository.findById(id).orElse(null);
|
||||
if (activityType == null) {
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
if (request.date() == null) {
|
||||
return ResponseEntity.badRequest().body(Map.of("message", "Дата праздника обязательна"));
|
||||
String validationError = validateActivityType(request);
|
||||
if (validationError != null) {
|
||||
return ResponseEntity.badRequest().body(Map.of("message", validationError));
|
||||
}
|
||||
holiday.setDate(request.date());
|
||||
holiday.setDescription(request.description());
|
||||
if (activityTypeRepository.findByCode(request.code().trim())
|
||||
.filter(existing -> !existing.getId().equals(id))
|
||||
.isPresent()) {
|
||||
return ResponseEntity.badRequest().body(Map.of("message", "Код активности уже существует"));
|
||||
}
|
||||
applyActivityType(activityType, request);
|
||||
scheduleGeneratorService.clearCache();
|
||||
return ResponseEntity.ok(toHolidayDto(holidayRepository.save(holiday)));
|
||||
return ResponseEntity.ok(toActivityTypeDto(activityTypeRepository.save(activityType)));
|
||||
}
|
||||
|
||||
@DeleteMapping("/holidays/{id}")
|
||||
public ResponseEntity<?> deleteHoliday(@PathVariable Long id) {
|
||||
if (!holidayRepository.existsById(id)) {
|
||||
@DeleteMapping("/activity-types/{id}")
|
||||
public ResponseEntity<?> deleteActivityType(@PathVariable Long id) {
|
||||
if (!activityTypeRepository.existsById(id)) {
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
holidayRepository.deleteById(id);
|
||||
if (calendarDayRepository.existsByActivityTypeId(id)) {
|
||||
return ResponseEntity.badRequest().body(Map.of("message", "Код активности используется в календарных графиках"));
|
||||
}
|
||||
activityTypeRepository.deleteById(id);
|
||||
scheduleGeneratorService.clearCache();
|
||||
return ResponseEntity.ok(Map.of("message", "Праздник удалён"));
|
||||
}
|
||||
|
||||
@GetMapping("/matrix")
|
||||
public ResponseEntity<?> getMatrix(@RequestParam Long semesterId,
|
||||
@RequestParam Integer courseNumber,
|
||||
@RequestParam Long specialtyId) {
|
||||
if (!semesterRepository.existsById(semesterId)) {
|
||||
return ResponseEntity.badRequest().body(Map.of("message", "Семестр не найден"));
|
||||
}
|
||||
return ResponseEntity.ok(calendarMatrixRepository
|
||||
.findBySemesterIdAndCourseNumberAndSpecialtyIdOrderByWeekNumberAsc(semesterId, courseNumber, specialtyId)
|
||||
.stream()
|
||||
.map(this::toMatrixDto)
|
||||
.toList());
|
||||
}
|
||||
|
||||
@PutMapping("/matrix")
|
||||
@Transactional
|
||||
public ResponseEntity<?> saveMatrix(@RequestBody List<AcademicCalendarMatrixDto> rows) {
|
||||
if (rows == null || rows.isEmpty()) {
|
||||
return ResponseEntity.badRequest().body(Map.of("message", "Передайте хотя бы одну строку матрицы"));
|
||||
}
|
||||
|
||||
try {
|
||||
for (AcademicCalendarMatrixDto row : rows) {
|
||||
Semester semester = semesterRepository.findById(row.semesterId())
|
||||
.orElseThrow(() -> new IllegalArgumentException("Семестр не найден"));
|
||||
if (row.courseNumber() == null || row.courseNumber() <= 0
|
||||
|| row.specialtyId() == null
|
||||
|| row.weekNumber() == null || row.weekNumber() <= 0) {
|
||||
throw new IllegalArgumentException("Курс, специальность и номер недели обязательны");
|
||||
}
|
||||
AcademicCalendarMatrix matrix = calendarMatrixRepository
|
||||
.findBySemesterIdAndCourseNumberAndSpecialtyIdAndWeekNumber(
|
||||
row.semesterId(),
|
||||
row.courseNumber(),
|
||||
row.specialtyId(),
|
||||
row.weekNumber()
|
||||
)
|
||||
.orElseGet(AcademicCalendarMatrix::new);
|
||||
matrix.setSemester(semester);
|
||||
matrix.setCourseNumber(row.courseNumber());
|
||||
matrix.setSpecialtyId(row.specialtyId());
|
||||
matrix.setWeekNumber(row.weekNumber());
|
||||
matrix.setActivityType(row.activityType() == null ? AcademicActivityType.THEORY : row.activityType());
|
||||
calendarMatrixRepository.save(matrix);
|
||||
}
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.badRequest().body(Map.of("message", e.getMessage()));
|
||||
}
|
||||
|
||||
scheduleGeneratorService.clearCache();
|
||||
return ResponseEntity.ok(Map.of("message", "Матрица учебного графика сохранена"));
|
||||
return ResponseEntity.ok(Map.of("message", "Код активности удалён"));
|
||||
}
|
||||
|
||||
private String validateYear(AcademicYearDto request) {
|
||||
@@ -263,6 +209,19 @@ public class AcademicCalendarAdminController {
|
||||
return null;
|
||||
}
|
||||
|
||||
private String validateActivityType(AcademicCalendarActivityTypeDto request) {
|
||||
if (request == null) {
|
||||
return "Передайте код активности";
|
||||
}
|
||||
if (request.code() == null || request.code().isBlank()) {
|
||||
return "Код активности обязателен";
|
||||
}
|
||||
if (request.name() == null || request.name().isBlank()) {
|
||||
return "Название активности обязательно";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void applyYear(AcademicYear year, AcademicYearDto request) {
|
||||
year.setTitle(request.title().trim());
|
||||
year.setStartDate(request.startDate());
|
||||
@@ -275,6 +234,19 @@ public class AcademicCalendarAdminController {
|
||||
semester.setEndDate(request.endDate());
|
||||
}
|
||||
|
||||
private void applyActivityType(AcademicCalendarActivityType activityType, AcademicCalendarActivityTypeDto request) {
|
||||
activityType.setCode(request.code().trim());
|
||||
activityType.setName(request.name().trim());
|
||||
activityType.setAllowSchedule(Boolean.TRUE.equals(request.allowSchedule()));
|
||||
activityType.setColorCode(request.colorCode() == null || request.colorCode().isBlank()
|
||||
? "#64748b"
|
||||
: request.colorCode().trim());
|
||||
activityType.setDisplayOrder(request.displayOrder() == null ? 100 : request.displayOrder());
|
||||
activityType.setDescription(request.description() == null || request.description().isBlank()
|
||||
? null
|
||||
: request.description().trim());
|
||||
}
|
||||
|
||||
private AcademicYearDto toAcademicYearDto(AcademicYear year) {
|
||||
List<SemesterDto> semesters = semesterRepository.findByAcademicYearIdOrderByStartDateAsc(year.getId())
|
||||
.stream()
|
||||
@@ -294,24 +266,15 @@ public class AcademicCalendarAdminController {
|
||||
);
|
||||
}
|
||||
|
||||
private HolidayDto toHolidayDto(Holiday holiday) {
|
||||
return new HolidayDto(
|
||||
holiday.getId(),
|
||||
holiday.getDate(),
|
||||
holiday.getAcademicYear().getId(),
|
||||
holiday.getAcademicYear().getTitle(),
|
||||
holiday.getDescription()
|
||||
);
|
||||
}
|
||||
|
||||
private AcademicCalendarMatrixDto toMatrixDto(AcademicCalendarMatrix matrix) {
|
||||
return new AcademicCalendarMatrixDto(
|
||||
matrix.getId(),
|
||||
matrix.getSemester().getId(),
|
||||
matrix.getCourseNumber(),
|
||||
matrix.getSpecialtyId(),
|
||||
matrix.getWeekNumber(),
|
||||
matrix.getActivityType()
|
||||
private AcademicCalendarActivityTypeDto toActivityTypeDto(AcademicCalendarActivityType activityType) {
|
||||
return new AcademicCalendarActivityTypeDto(
|
||||
activityType.getId(),
|
||||
activityType.getCode(),
|
||||
activityType.getName(),
|
||||
activityType.getAllowSchedule(),
|
||||
activityType.getColorCode(),
|
||||
activityType.getDisplayOrder(),
|
||||
activityType.getDescription()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,255 @@
|
||||
package com.magistr.app.controller;
|
||||
|
||||
import com.magistr.app.dto.*;
|
||||
import com.magistr.app.model.*;
|
||||
import com.magistr.app.repository.*;
|
||||
import com.magistr.app.service.ScheduleGeneratorService;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/api/admin/academic-calendars")
|
||||
public class AcademicCalendarController {
|
||||
|
||||
private final AcademicCalendarRepository calendarRepository;
|
||||
private final AcademicCalendarDayRepository calendarDayRepository;
|
||||
private final AcademicCalendarActivityTypeRepository activityTypeRepository;
|
||||
private final AcademicYearRepository academicYearRepository;
|
||||
private final SpecialtiesRepository specialtiesRepository;
|
||||
private final SpecialtyProfileRepository profileRepository;
|
||||
private final CalendarStudyFormRepository studyFormRepository;
|
||||
private final ScheduleGeneratorService scheduleGeneratorService;
|
||||
|
||||
public AcademicCalendarController(AcademicCalendarRepository calendarRepository,
|
||||
AcademicCalendarDayRepository calendarDayRepository,
|
||||
AcademicCalendarActivityTypeRepository activityTypeRepository,
|
||||
AcademicYearRepository academicYearRepository,
|
||||
SpecialtiesRepository specialtiesRepository,
|
||||
SpecialtyProfileRepository profileRepository,
|
||||
CalendarStudyFormRepository studyFormRepository,
|
||||
ScheduleGeneratorService scheduleGeneratorService) {
|
||||
this.calendarRepository = calendarRepository;
|
||||
this.calendarDayRepository = calendarDayRepository;
|
||||
this.activityTypeRepository = activityTypeRepository;
|
||||
this.academicYearRepository = academicYearRepository;
|
||||
this.specialtiesRepository = specialtiesRepository;
|
||||
this.profileRepository = profileRepository;
|
||||
this.studyFormRepository = studyFormRepository;
|
||||
this.scheduleGeneratorService = scheduleGeneratorService;
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public List<AcademicCalendarDto> getCalendars(@RequestParam(required = false) Long academicYearId,
|
||||
@RequestParam(required = false) Long specialtyId,
|
||||
@RequestParam(required = false) Long profileId) {
|
||||
return calendarRepository.findAllWithDetails(academicYearId, specialtyId, profileId).stream()
|
||||
.map(this::toCalendarDto)
|
||||
.toList();
|
||||
}
|
||||
|
||||
@GetMapping("/study-forms")
|
||||
public List<CalendarStudyFormDto> getStudyForms() {
|
||||
return studyFormRepository.findAllByOrderByNameAsc().stream()
|
||||
.map(form -> new CalendarStudyFormDto(form.getId(), form.getName(), form.getDescription()))
|
||||
.toList();
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public ResponseEntity<?> getCalendar(@PathVariable Long id) {
|
||||
return calendarRepository.findByIdWithDetails(id)
|
||||
.<ResponseEntity<?>>map(calendar -> ResponseEntity.ok(toCalendarDto(calendar)))
|
||||
.orElseGet(() -> ResponseEntity.notFound().build());
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<?> createCalendar(@RequestBody AcademicCalendarDto request) {
|
||||
try {
|
||||
AcademicCalendar calendar = new AcademicCalendar();
|
||||
applyCalendar(calendar, request);
|
||||
scheduleGeneratorService.clearCache();
|
||||
return ResponseEntity.ok(toCalendarDto(calendarRepository.save(calendar)));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.badRequest().body(Map.of("message", e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@PutMapping("/{id}")
|
||||
public ResponseEntity<?> updateCalendar(@PathVariable Long id, @RequestBody AcademicCalendarDto request) {
|
||||
AcademicCalendar calendar = calendarRepository.findById(id).orElse(null);
|
||||
if (calendar == null) {
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
try {
|
||||
applyCalendar(calendar, request);
|
||||
scheduleGeneratorService.clearCache();
|
||||
return ResponseEntity.ok(toCalendarDto(calendarRepository.save(calendar)));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.badRequest().body(Map.of("message", e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
public ResponseEntity<?> deleteCalendar(@PathVariable Long id) {
|
||||
if (!calendarRepository.existsById(id)) {
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
try {
|
||||
calendarRepository.deleteById(id);
|
||||
scheduleGeneratorService.clearCache();
|
||||
return ResponseEntity.ok(Map.of("message", "Календарный график удалён"));
|
||||
} catch (Exception e) {
|
||||
return ResponseEntity.badRequest()
|
||||
.body(Map.of("message", "Нельзя удалить график, который назначен учебным группам"));
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping("/{id}/grid")
|
||||
public ResponseEntity<?> getGrid(@PathVariable Long id) {
|
||||
if (!calendarRepository.existsById(id)) {
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
return ResponseEntity.ok(calendarDayRepository.findByCalendarIdWithActivity(id).stream()
|
||||
.map(this::toGridDayDto)
|
||||
.toList());
|
||||
}
|
||||
|
||||
@PutMapping("/{id}/grid")
|
||||
@Transactional
|
||||
public ResponseEntity<?> saveGrid(@PathVariable Long id, @RequestBody List<AcademicCalendarGridDayDto> rows) {
|
||||
AcademicCalendar calendar = calendarRepository.findByIdWithDetails(id).orElse(null);
|
||||
if (calendar == null) {
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
if (rows == null || rows.isEmpty()) {
|
||||
return ResponseEntity.badRequest().body(Map.of("message", "Передайте хотя бы одну ячейку графика"));
|
||||
}
|
||||
|
||||
try {
|
||||
calendarDayRepository.deleteByCalendarId(id);
|
||||
for (AcademicCalendarGridDayDto row : rows) {
|
||||
AcademicCalendarDay day = buildGridDay(calendar, row);
|
||||
calendarDayRepository.save(day);
|
||||
}
|
||||
scheduleGeneratorService.clearCache();
|
||||
return ResponseEntity.ok(Map.of("message", "Календарный учебный график сохранён"));
|
||||
} catch (IllegalArgumentException e) {
|
||||
return ResponseEntity.badRequest().body(Map.of("message", e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
private void applyCalendar(AcademicCalendar calendar, AcademicCalendarDto request) {
|
||||
if (request == null) {
|
||||
throw new IllegalArgumentException("Передайте данные календарного графика");
|
||||
}
|
||||
if (request.title() == null || request.title().isBlank()) {
|
||||
throw new IllegalArgumentException("Название графика обязательно");
|
||||
}
|
||||
if (request.courseCount() == null || request.courseCount() <= 0) {
|
||||
throw new IllegalArgumentException("Количество курсов должно быть больше нуля");
|
||||
}
|
||||
if (request.academicYearId() == null || request.specialtyId() == null
|
||||
|| request.specialtyProfileId() == null || request.studyFormId() == null) {
|
||||
throw new IllegalArgumentException("Учебный год, специальность, профиль и форма обучения обязательны");
|
||||
}
|
||||
|
||||
AcademicYear year = academicYearRepository.findById(request.academicYearId())
|
||||
.orElseThrow(() -> new IllegalArgumentException("Учебный год не найден"));
|
||||
Speciality speciality = specialtiesRepository.findById(request.specialtyId())
|
||||
.orElseThrow(() -> new IllegalArgumentException("Специальность не найдена"));
|
||||
SpecialtyProfile profile = profileRepository.findById(request.specialtyProfileId())
|
||||
.orElseThrow(() -> new IllegalArgumentException("Профиль обучения не найден"));
|
||||
if (!profile.getSpeciality().getId().equals(speciality.getId())) {
|
||||
throw new IllegalArgumentException("Профиль не относится к выбранной специальности");
|
||||
}
|
||||
CalendarStudyForm studyForm = studyFormRepository.findById(request.studyFormId())
|
||||
.orElseThrow(() -> new IllegalArgumentException("Форма обучения графика не найдена"));
|
||||
|
||||
calendar.setTitle(request.title().trim());
|
||||
calendar.setAcademicYear(year);
|
||||
calendar.setSpeciality(speciality);
|
||||
calendar.setSpecialtyProfile(profile);
|
||||
calendar.setStudyForm(studyForm);
|
||||
calendar.setCourseCount(request.courseCount());
|
||||
}
|
||||
|
||||
private AcademicCalendarDay buildGridDay(AcademicCalendar calendar, AcademicCalendarGridDayDto row) {
|
||||
if (row.courseNumber() == null || row.courseNumber() <= 0
|
||||
|| row.date() == null
|
||||
|| row.weekNumber() == null || row.weekNumber() <= 0
|
||||
|| row.dayOfWeek() == null || row.dayOfWeek() < 1 || row.dayOfWeek() > 7) {
|
||||
throw new IllegalArgumentException("Курс, дата, неделя и день недели обязательны");
|
||||
}
|
||||
if (row.date().isBefore(calendar.getAcademicYear().getStartDate())
|
||||
|| row.date().isAfter(calendar.getAcademicYear().getEndDate())) {
|
||||
throw new IllegalArgumentException("Дата выходит за пределы учебного года");
|
||||
}
|
||||
if (row.courseNumber() > calendar.getCourseCount()) {
|
||||
throw new IllegalArgumentException("Номер курса выходит за пределы графика");
|
||||
}
|
||||
|
||||
AcademicCalendarActivityType activityType = resolveActivityType(row);
|
||||
AcademicCalendarDay day = new AcademicCalendarDay();
|
||||
day.setAcademicCalendar(calendar);
|
||||
day.setCourseNumber(row.courseNumber());
|
||||
day.setDate(row.date());
|
||||
day.setWeekNumber(row.weekNumber());
|
||||
day.setDayOfWeek(row.dayOfWeek());
|
||||
day.setActivityType(activityType);
|
||||
return day;
|
||||
}
|
||||
|
||||
private AcademicCalendarActivityType resolveActivityType(AcademicCalendarGridDayDto row) {
|
||||
if (row.activityTypeId() != null) {
|
||||
return activityTypeRepository.findById(row.activityTypeId())
|
||||
.orElseThrow(() -> new IllegalArgumentException("Код активности не найден"));
|
||||
}
|
||||
if (row.activityCode() != null && !row.activityCode().isBlank()) {
|
||||
return activityTypeRepository.findByCode(row.activityCode().trim())
|
||||
.orElseThrow(() -> new IllegalArgumentException("Код активности не найден"));
|
||||
}
|
||||
throw new IllegalArgumentException("Код активности обязателен");
|
||||
}
|
||||
|
||||
private AcademicCalendarDto toCalendarDto(AcademicCalendar calendar) {
|
||||
AcademicYear year = calendar.getAcademicYear();
|
||||
Speciality speciality = calendar.getSpeciality();
|
||||
SpecialtyProfile profile = calendar.getSpecialtyProfile();
|
||||
CalendarStudyForm studyForm = calendar.getStudyForm();
|
||||
return new AcademicCalendarDto(
|
||||
calendar.getId(),
|
||||
calendar.getTitle(),
|
||||
year.getId(),
|
||||
year.getTitle(),
|
||||
year.getStartDate(),
|
||||
year.getEndDate(),
|
||||
speciality.getId(),
|
||||
speciality.getSpecialityCode(),
|
||||
speciality.getSpecialityName(),
|
||||
profile.getId(),
|
||||
profile.getName(),
|
||||
studyForm.getId(),
|
||||
studyForm.getName(),
|
||||
calendar.getCourseCount()
|
||||
);
|
||||
}
|
||||
|
||||
private AcademicCalendarGridDayDto toGridDayDto(AcademicCalendarDay day) {
|
||||
AcademicCalendarActivityType activityType = day.getActivityType();
|
||||
return new AcademicCalendarGridDayDto(
|
||||
day.getId(),
|
||||
day.getAcademicCalendar().getId(),
|
||||
day.getCourseNumber(),
|
||||
day.getDate(),
|
||||
day.getWeekNumber(),
|
||||
day.getDayOfWeek(),
|
||||
activityType.getId(),
|
||||
activityType.getCode(),
|
||||
activityType.getName(),
|
||||
activityType.getAllowSchedule()
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,17 @@
|
||||
package com.magistr.app.controller;
|
||||
|
||||
import com.magistr.app.dto.CreateGroupRequest;
|
||||
import com.magistr.app.dto.GroupCalendarAssignmentDto;
|
||||
import com.magistr.app.dto.GroupResponse;
|
||||
import com.magistr.app.model.AcademicCalendar;
|
||||
import com.magistr.app.model.AcademicYear;
|
||||
import com.magistr.app.model.EducationForm;
|
||||
import com.magistr.app.model.Speciality;
|
||||
import com.magistr.app.model.SpecialtyProfile;
|
||||
import com.magistr.app.model.StudentGroup;
|
||||
import com.magistr.app.repository.EducationFormRepository;
|
||||
import com.magistr.app.repository.GroupRepository;
|
||||
import com.magistr.app.model.StudentGroupCalendarAssignment;
|
||||
import com.magistr.app.repository.*;
|
||||
import com.magistr.app.service.ScheduleGeneratorService;
|
||||
import com.magistr.app.utils.CourseAndSemesterCalculator;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -13,7 +19,6 @@ import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.time.Year;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
@@ -26,11 +31,29 @@ public class GroupController {
|
||||
|
||||
private final GroupRepository groupRepository;
|
||||
private final EducationFormRepository educationFormRepository;
|
||||
private final SpecialtiesRepository specialtiesRepository;
|
||||
private final SpecialtyProfileRepository specialtyProfileRepository;
|
||||
private final AcademicYearRepository academicYearRepository;
|
||||
private final AcademicCalendarRepository academicCalendarRepository;
|
||||
private final StudentGroupCalendarAssignmentRepository assignmentRepository;
|
||||
private final ScheduleGeneratorService scheduleGeneratorService;
|
||||
|
||||
public GroupController(GroupRepository groupRepository,
|
||||
EducationFormRepository educationFormRepository) {
|
||||
EducationFormRepository educationFormRepository,
|
||||
SpecialtiesRepository specialtiesRepository,
|
||||
SpecialtyProfileRepository specialtyProfileRepository,
|
||||
AcademicYearRepository academicYearRepository,
|
||||
AcademicCalendarRepository academicCalendarRepository,
|
||||
StudentGroupCalendarAssignmentRepository assignmentRepository,
|
||||
ScheduleGeneratorService scheduleGeneratorService) {
|
||||
this.groupRepository = groupRepository;
|
||||
this.educationFormRepository = educationFormRepository;
|
||||
this.specialtiesRepository = specialtiesRepository;
|
||||
this.specialtyProfileRepository = specialtyProfileRepository;
|
||||
this.academicYearRepository = academicYearRepository;
|
||||
this.academicCalendarRepository = academicCalendarRepository;
|
||||
this.assignmentRepository = assignmentRepository;
|
||||
this.scheduleGeneratorService = scheduleGeneratorService;
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
@@ -41,21 +64,7 @@ public class GroupController {
|
||||
List<StudentGroup> groups = groupRepository.findAll();
|
||||
|
||||
List<GroupResponse> response = groups.stream()
|
||||
.map(g -> {
|
||||
int course = CourseAndSemesterCalculator.getActualCourse(g.getYearStartStudy());
|
||||
int semester = CourseAndSemesterCalculator.getActualSemester(g.getYearStartStudy());
|
||||
return new GroupResponse(
|
||||
g.getId(),
|
||||
g.getName(),
|
||||
g.getGroupSize(),
|
||||
g.getEducationForm().getId(),
|
||||
g.getEducationForm().getName(),
|
||||
g.getDepartmentId(),
|
||||
course,
|
||||
semester,
|
||||
g.getSpecialityCode()
|
||||
);
|
||||
})
|
||||
.map(this::mapToResponse)
|
||||
.toList();
|
||||
logger.info("Получено {} групп", response.size());
|
||||
return response;
|
||||
@@ -78,21 +87,7 @@ public class GroupController {
|
||||
}
|
||||
|
||||
List<GroupResponse> response = groups.stream()
|
||||
.map(g -> {
|
||||
int course = CourseAndSemesterCalculator.getActualCourse(g.getYearStartStudy());
|
||||
int semester = CourseAndSemesterCalculator.getActualSemester(g.getYearStartStudy());
|
||||
return new GroupResponse(
|
||||
g.getId(),
|
||||
g.getName(),
|
||||
g.getGroupSize(),
|
||||
g.getEducationForm().getId(),
|
||||
g.getEducationForm().getName(),
|
||||
g.getDepartmentId(),
|
||||
course,
|
||||
semester,
|
||||
g.getSpecialityCode()
|
||||
);
|
||||
})
|
||||
.map(this::mapToResponse)
|
||||
.toList();
|
||||
|
||||
logger.info("Найдено {} групп для кафедры с ID - {}", response.size(), departmentId);
|
||||
@@ -110,51 +105,25 @@ public class GroupController {
|
||||
logger.info("Получен запрос на создание новой группы: name = {}, groupSize = {}, educationFormId = {}, departmentId = {}, yearStartStudy = {}",
|
||||
request.getName(), request.getGroupSize(), request.getEducationFormId(), request.getDepartmentId(), request.getYearStartStudy());
|
||||
try {
|
||||
if (request.getName() == null || request.getName().isBlank()) {
|
||||
String errorMessage = "Название группы обязательно";
|
||||
logger.error("Ошибка валидации: {}", errorMessage);
|
||||
return ResponseEntity.badRequest().body(Map.of("message", errorMessage));
|
||||
}
|
||||
if (groupRepository.findByName(request.getName().trim()).isPresent()) {
|
||||
String errorMessage = "Группа с таким названием уже существует";
|
||||
logger.error("Ошибка валидации: {}", errorMessage);
|
||||
return ResponseEntity.badRequest().body(Map.of("message", errorMessage));
|
||||
}
|
||||
if (request.getGroupSize() == null) {
|
||||
String errorMessage = "Численность группы обязательна";
|
||||
logger.error("Ошибка валидации: {}", errorMessage);
|
||||
return ResponseEntity.badRequest().body(Map.of("message", errorMessage));
|
||||
}
|
||||
if (request.getEducationFormId() == null) {
|
||||
String errorMessage = "Форма обучения обязательна";
|
||||
logger.error("Ошибка валидации: {}", errorMessage);
|
||||
return ResponseEntity.badRequest().body(Map.of("message", errorMessage));
|
||||
}
|
||||
if (request.getDepartmentId() == null || request.getDepartmentId() == 0) {
|
||||
String errorMessage = "ID кафедры обязателен";
|
||||
logger.error("Ошибка валидации: {}", errorMessage);
|
||||
return ResponseEntity.badRequest().body(Map.of("message", errorMessage));
|
||||
}
|
||||
// if (request.getCourse() == null || request.getCourse() == 0) {
|
||||
// String errorMessage = "Курс обязателен";
|
||||
// logger.error("Ошибка валидации: {}", errorMessage);
|
||||
// return ResponseEntity.badRequest().body(Map.of("message", errorMessage));
|
||||
// }
|
||||
if (request.getYearStartStudy() == null || request.getYearStartStudy() == 0) {
|
||||
String errorMessage = "Год начала обучения обязателен";
|
||||
logger.error("Ошибка валидации: {}", errorMessage);
|
||||
return ResponseEntity.badRequest().body(Map.of("message", errorMessage));
|
||||
}
|
||||
if (request.getSpecialityCode() == null || request.getSpecialityCode() == 0) {
|
||||
String errorMessage = "Код специальности обязателен";
|
||||
logger.error("Ошибка валидации: {}", errorMessage);
|
||||
return ResponseEntity.badRequest().body(Map.of("message", errorMessage));
|
||||
ResponseEntity<?> validationError = validateGroupRequest(request);
|
||||
if (validationError != null) {
|
||||
return validationError;
|
||||
}
|
||||
|
||||
Optional<EducationForm> efOpt = educationFormRepository.findById(request.getEducationFormId());
|
||||
if (efOpt.isEmpty()) {
|
||||
return ResponseEntity.badRequest().body(Map.of("message", "Форма обучения не найдена"));
|
||||
}
|
||||
Speciality speciality = specialtiesRepository.findById(request.getEffectiveSpecialtyId())
|
||||
.orElse(null);
|
||||
if (speciality == null) {
|
||||
return ResponseEntity.badRequest().body(Map.of("message", "Специальность не найдена"));
|
||||
}
|
||||
SpecialtyProfile profile = specialtyProfileRepository.findById(request.getSpecialtyProfileId())
|
||||
.orElse(null);
|
||||
if (profile == null || !profile.getSpeciality().getId().equals(speciality.getId())) {
|
||||
return ResponseEntity.badRequest().body(Map.of("message", "Профиль обучения не найден для выбранной специальности"));
|
||||
}
|
||||
|
||||
StudentGroup group = new StudentGroup();
|
||||
group.setName(request.getName().trim());
|
||||
@@ -162,20 +131,13 @@ public class GroupController {
|
||||
group.setEducationForm(efOpt.get());
|
||||
group.setDepartmentId(request.getDepartmentId());
|
||||
group.setYearStartStudy(request.getYearStartStudy());
|
||||
group.setSpecialityCode(request.getSpecialityCode());
|
||||
group.setSpeciality(speciality);
|
||||
group.setSpecialtyProfile(profile);
|
||||
groupRepository.save(group);
|
||||
|
||||
logger.info("Группа успешно создана с ID - {}", group.getId());
|
||||
|
||||
return ResponseEntity.ok(new GroupResponse(
|
||||
group.getId(),
|
||||
group.getName(),
|
||||
group.getGroupSize(),
|
||||
group.getEducationForm().getId(),
|
||||
group.getEducationForm().getName(),
|
||||
group.getDepartmentId(),
|
||||
group.getYearStartStudy(),
|
||||
group.getSpecialityCode()));
|
||||
return ResponseEntity.ok(mapToResponse(group));
|
||||
} catch (Exception e ) {
|
||||
logger.error("Ошибка при создании группы: {}", e.getMessage(), e);
|
||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
@@ -183,6 +145,55 @@ public class GroupController {
|
||||
}
|
||||
}
|
||||
|
||||
@PutMapping("/{id}")
|
||||
public ResponseEntity<?> updateGroup(@PathVariable Long id, @RequestBody CreateGroupRequest request) {
|
||||
logger.info("Получен запрос на обновление группы с ID - {}", id);
|
||||
try {
|
||||
Optional<StudentGroup> groupOpt = groupRepository.findById(id);
|
||||
if (groupOpt.isEmpty()) {
|
||||
logger.info("Группа с ID - {} не найдена", id);
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
|
||||
ResponseEntity<?> validationError = validateGroupRequest(request);
|
||||
if (validationError != null) {
|
||||
return validationError;
|
||||
}
|
||||
|
||||
Optional<EducationForm> efOpt = educationFormRepository.findById(request.getEducationFormId());
|
||||
if (efOpt.isEmpty()) {
|
||||
return ResponseEntity.badRequest().body(Map.of("message", "Форма обучения не найдена"));
|
||||
}
|
||||
Speciality speciality = specialtiesRepository.findById(request.getEffectiveSpecialtyId())
|
||||
.orElse(null);
|
||||
if (speciality == null) {
|
||||
return ResponseEntity.badRequest().body(Map.of("message", "Специальность не найдена"));
|
||||
}
|
||||
SpecialtyProfile profile = specialtyProfileRepository.findById(request.getSpecialtyProfileId())
|
||||
.orElse(null);
|
||||
if (profile == null || !profile.getSpeciality().getId().equals(speciality.getId())) {
|
||||
return ResponseEntity.badRequest().body(Map.of("message", "Профиль обучения не найден для выбранной специальности"));
|
||||
}
|
||||
|
||||
StudentGroup group = groupOpt.get();
|
||||
group.setName(request.getName().trim());
|
||||
group.setGroupSize(request.getGroupSize());
|
||||
group.setEducationForm(efOpt.get());
|
||||
group.setDepartmentId(request.getDepartmentId());
|
||||
group.setYearStartStudy(request.getYearStartStudy());
|
||||
group.setSpeciality(speciality);
|
||||
group.setSpecialtyProfile(profile);
|
||||
groupRepository.save(group);
|
||||
|
||||
logger.info("Группа с ID - {} успешно обновлена", id);
|
||||
return ResponseEntity.ok(mapToResponse(group));
|
||||
} catch (Exception e) {
|
||||
logger.error("Ошибка при обновлении группы с ID - {}: {}", id, e.getMessage(), e);
|
||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
.body(Map.of("message", "Произошла ошибка при обновлении группы: " + e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
public ResponseEntity<?> deleteGroup(@PathVariable Long id) {
|
||||
logger.info("Получен запрос на удаление группы с ID - {}", id);
|
||||
@@ -194,4 +205,126 @@ public class GroupController {
|
||||
logger.info("Группа с ID - {} успешно удалена", id);
|
||||
return ResponseEntity.ok(Map.of("message", "Группа удалена"));
|
||||
}
|
||||
|
||||
private ResponseEntity<?> validateGroupRequest(CreateGroupRequest request) {
|
||||
if (request.getName() == null || request.getName().isBlank()) {
|
||||
return validationError("Название группы обязательно");
|
||||
}
|
||||
if (request.getGroupSize() == null) {
|
||||
return validationError("Численность группы обязательна");
|
||||
}
|
||||
if (request.getEducationFormId() == null) {
|
||||
return validationError("Форма обучения обязательна");
|
||||
}
|
||||
if (request.getDepartmentId() == null || request.getDepartmentId() == 0) {
|
||||
return validationError("ID кафедры обязателен");
|
||||
}
|
||||
if (request.getYearStartStudy() == null || request.getYearStartStudy() == 0) {
|
||||
return validationError("Год начала обучения обязателен");
|
||||
}
|
||||
if (request.getEffectiveSpecialtyId() == null || request.getEffectiveSpecialtyId() == 0) {
|
||||
return validationError("Код специальности обязателен");
|
||||
}
|
||||
if (request.getSpecialtyProfileId() == null || request.getSpecialtyProfileId() == 0) {
|
||||
return validationError("Профиль обучения обязателен");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private ResponseEntity<?> validationError(String errorMessage) {
|
||||
logger.error("Ошибка валидации: {}", errorMessage);
|
||||
return ResponseEntity.badRequest().body(Map.of("message", errorMessage));
|
||||
}
|
||||
|
||||
private GroupResponse mapToResponse(StudentGroup group) {
|
||||
int course = CourseAndSemesterCalculator.getActualCourse(group.getYearStartStudy());
|
||||
int semester = CourseAndSemesterCalculator.getActualSemester(group.getYearStartStudy());
|
||||
Speciality speciality = group.getSpeciality();
|
||||
SpecialtyProfile profile = group.getSpecialtyProfile();
|
||||
return new GroupResponse(
|
||||
group.getId(),
|
||||
group.getName(),
|
||||
group.getGroupSize(),
|
||||
group.getEducationForm().getId(),
|
||||
group.getEducationForm().getName(),
|
||||
group.getDepartmentId(),
|
||||
group.getYearStartStudy(),
|
||||
course,
|
||||
semester,
|
||||
speciality.getId(),
|
||||
speciality.getSpecialityCode(),
|
||||
speciality.getSpecialityName(),
|
||||
profile.getId(),
|
||||
profile.getName()
|
||||
);
|
||||
}
|
||||
|
||||
@GetMapping("/{id}/calendar-assignments")
|
||||
public ResponseEntity<?> getCalendarAssignments(@PathVariable Long id) {
|
||||
if (!groupRepository.existsById(id)) {
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
return ResponseEntity.ok(assignmentRepository.findByGroupIdWithDetails(id).stream()
|
||||
.map(this::toAssignmentDto)
|
||||
.toList());
|
||||
}
|
||||
|
||||
@PutMapping("/{id}/calendar-assignments")
|
||||
public ResponseEntity<?> saveCalendarAssignment(@PathVariable Long id,
|
||||
@RequestBody GroupCalendarAssignmentDto request) {
|
||||
if (request == null || request.academicYearId() == null || request.calendarId() == null) {
|
||||
return ResponseEntity.badRequest().body(Map.of("message", "Учебный год и календарный график обязательны"));
|
||||
}
|
||||
StudentGroup group = groupRepository.findById(id).orElse(null);
|
||||
if (group == null) {
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
AcademicYear academicYear = academicYearRepository.findById(request.academicYearId()).orElse(null);
|
||||
if (academicYear == null) {
|
||||
return ResponseEntity.badRequest().body(Map.of("message", "Учебный год не найден"));
|
||||
}
|
||||
AcademicCalendar calendar = academicCalendarRepository.findByIdWithDetails(request.calendarId()).orElse(null);
|
||||
if (calendar == null) {
|
||||
return ResponseEntity.badRequest().body(Map.of("message", "Календарный график не найден"));
|
||||
}
|
||||
if (!calendar.getAcademicYear().getId().equals(academicYear.getId())) {
|
||||
return ResponseEntity.badRequest().body(Map.of("message", "График относится к другому учебному году"));
|
||||
}
|
||||
if (!calendar.getSpeciality().getId().equals(group.getSpeciality().getId())
|
||||
|| !calendar.getSpecialtyProfile().getId().equals(group.getSpecialtyProfile().getId())) {
|
||||
return ResponseEntity.badRequest().body(Map.of("message", "График не соответствует специальности и профилю группы"));
|
||||
}
|
||||
|
||||
StudentGroupCalendarAssignment assignment = assignmentRepository
|
||||
.findByGroupIdAndAcademicYearIdWithDetails(group.getId(), academicYear.getId())
|
||||
.orElseGet(StudentGroupCalendarAssignment::new);
|
||||
assignment.setStudentGroup(group);
|
||||
assignment.setAcademicYear(academicYear);
|
||||
assignment.setAcademicCalendar(calendar);
|
||||
scheduleGeneratorService.clearCache();
|
||||
return ResponseEntity.ok(toAssignmentDto(assignmentRepository.save(assignment)));
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}/calendar-assignments/{assignmentId}")
|
||||
public ResponseEntity<?> deleteCalendarAssignment(@PathVariable Long id, @PathVariable Long assignmentId) {
|
||||
StudentGroupCalendarAssignment assignment = assignmentRepository.findById(assignmentId).orElse(null);
|
||||
if (assignment == null || !assignment.getStudentGroup().getId().equals(id)) {
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
assignmentRepository.delete(assignment);
|
||||
scheduleGeneratorService.clearCache();
|
||||
return ResponseEntity.ok(Map.of("message", "Назначение календарного графика удалено"));
|
||||
}
|
||||
|
||||
private GroupCalendarAssignmentDto toAssignmentDto(StudentGroupCalendarAssignment assignment) {
|
||||
return new GroupCalendarAssignmentDto(
|
||||
assignment.getId(),
|
||||
assignment.getStudentGroup().getId(),
|
||||
assignment.getStudentGroup().getName(),
|
||||
assignment.getAcademicYear().getId(),
|
||||
assignment.getAcademicYear().getTitle(),
|
||||
assignment.getAcademicCalendar().getId(),
|
||||
assignment.getAcademicCalendar().getTitle()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,11 @@ package com.magistr.app.controller;
|
||||
|
||||
import com.magistr.app.dto.CreateSpecialityRequest;
|
||||
import com.magistr.app.dto.SpecialityResponse;
|
||||
import com.magistr.app.dto.SpecialtyProfileDto;
|
||||
import com.magistr.app.model.Speciality;
|
||||
import com.magistr.app.model.SpecialtyProfile;
|
||||
import com.magistr.app.repository.SpecialtiesRepository;
|
||||
import com.magistr.app.repository.SpecialtyProfileRepository;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.HttpStatus;
|
||||
@@ -20,9 +23,12 @@ public class SpecialityController {
|
||||
private static final Logger logger = LoggerFactory.getLogger(SpecialityController.class);
|
||||
|
||||
private final SpecialtiesRepository specialtiesRepository;
|
||||
private final SpecialtyProfileRepository specialtyProfileRepository;
|
||||
|
||||
public SpecialityController(SpecialtiesRepository specialtiesRepository) {
|
||||
public SpecialityController(SpecialtiesRepository specialtiesRepository,
|
||||
SpecialtyProfileRepository specialtyProfileRepository) {
|
||||
this.specialtiesRepository = specialtiesRepository;
|
||||
this.specialtyProfileRepository = specialtyProfileRepository;
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
@@ -75,6 +81,10 @@ public class SpecialityController {
|
||||
speciality.setSpecialityName(request.getSpecialityName());
|
||||
speciality.setSpecialityCode(request.getSpecialityCode());
|
||||
specialtiesRepository.save(speciality);
|
||||
SpecialtyProfile defaultProfile = new SpecialtyProfile();
|
||||
defaultProfile.setSpeciality(speciality);
|
||||
defaultProfile.setName("Без профиля");
|
||||
specialtyProfileRepository.save(defaultProfile);
|
||||
|
||||
logger.info("Специальность успешно создана с ID: {}", speciality.getId());
|
||||
|
||||
@@ -159,4 +169,98 @@ public class SpecialityController {
|
||||
logger.info("Специальность с ID - {} успешно удалена", id);
|
||||
return ResponseEntity.ok(Map.of("message", "Специальность удалена"));
|
||||
}
|
||||
|
||||
@GetMapping("/{specialtyId}/profiles")
|
||||
public ResponseEntity<?> getProfiles(@PathVariable Long specialtyId) {
|
||||
if (!specialtiesRepository.existsById(specialtyId)) {
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
return ResponseEntity.ok(specialtyProfileRepository.findBySpecialityIdOrderByNameAsc(specialtyId).stream()
|
||||
.map(this::toProfileDto)
|
||||
.toList());
|
||||
}
|
||||
|
||||
@PostMapping("/{specialtyId}/profiles")
|
||||
public ResponseEntity<?> createProfile(@PathVariable Long specialtyId, @RequestBody SpecialtyProfileDto request) {
|
||||
Speciality speciality = specialtiesRepository.findById(specialtyId).orElse(null);
|
||||
if (speciality == null) {
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
String validationError = validateProfile(specialtyId, null, request);
|
||||
if (validationError != null) {
|
||||
return ResponseEntity.badRequest().body(Map.of("message", validationError));
|
||||
}
|
||||
|
||||
SpecialtyProfile profile = new SpecialtyProfile();
|
||||
profile.setSpeciality(speciality);
|
||||
profile.setName(request.name().trim());
|
||||
profile.setDescription(trimToNull(request.description()));
|
||||
return ResponseEntity.ok(toProfileDto(specialtyProfileRepository.save(profile)));
|
||||
}
|
||||
|
||||
@PutMapping("/{specialtyId}/profiles/{profileId}")
|
||||
public ResponseEntity<?> updateProfile(@PathVariable Long specialtyId,
|
||||
@PathVariable Long profileId,
|
||||
@RequestBody SpecialtyProfileDto request) {
|
||||
SpecialtyProfile profile = specialtyProfileRepository.findById(profileId).orElse(null);
|
||||
if (profile == null || !profile.getSpeciality().getId().equals(specialtyId)) {
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
String validationError = validateProfile(specialtyId, profileId, request);
|
||||
if (validationError != null) {
|
||||
return ResponseEntity.badRequest().body(Map.of("message", validationError));
|
||||
}
|
||||
|
||||
profile.setName(request.name().trim());
|
||||
profile.setDescription(trimToNull(request.description()));
|
||||
return ResponseEntity.ok(toProfileDto(specialtyProfileRepository.save(profile)));
|
||||
}
|
||||
|
||||
@DeleteMapping("/{specialtyId}/profiles/{profileId}")
|
||||
public ResponseEntity<?> deleteProfile(@PathVariable Long specialtyId, @PathVariable Long profileId) {
|
||||
SpecialtyProfile profile = specialtyProfileRepository.findById(profileId).orElse(null);
|
||||
if (profile == null || !profile.getSpeciality().getId().equals(specialtyId)) {
|
||||
return ResponseEntity.notFound().build();
|
||||
}
|
||||
try {
|
||||
specialtyProfileRepository.delete(profile);
|
||||
return ResponseEntity.ok(Map.of("message", "Профиль обучения удалён"));
|
||||
} catch (Exception e) {
|
||||
logger.error("Ошибка при удалении профиля обучения с ID - {}: {}", profileId, e.getMessage(), e);
|
||||
return ResponseEntity.badRequest()
|
||||
.body(Map.of("message", "Нельзя удалить профиль, который используется группами или календарными графиками"));
|
||||
}
|
||||
}
|
||||
|
||||
private String validateProfile(Long specialtyId, Long profileId, SpecialtyProfileDto request) {
|
||||
if (request == null) {
|
||||
return "Передайте данные профиля";
|
||||
}
|
||||
if (request.name() == null || request.name().isBlank()) {
|
||||
return "Название профиля обязательно";
|
||||
}
|
||||
return specialtyProfileRepository.findBySpecialityIdAndName(specialtyId, request.name().trim())
|
||||
.filter(existing -> !existing.getId().equals(profileId))
|
||||
.map(existing -> "Профиль с таким названием уже существует")
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
private SpecialtyProfileDto toProfileDto(SpecialtyProfile profile) {
|
||||
Speciality speciality = profile.getSpeciality();
|
||||
return new SpecialtyProfileDto(
|
||||
profile.getId(),
|
||||
speciality.getId(),
|
||||
speciality.getSpecialityCode(),
|
||||
speciality.getSpecialityName(),
|
||||
profile.getName(),
|
||||
profile.getDescription()
|
||||
);
|
||||
}
|
||||
|
||||
private String trimToNull(String value) {
|
||||
if (value == null || value.isBlank()) {
|
||||
return null;
|
||||
}
|
||||
return value.trim();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.magistr.app.dto;
|
||||
|
||||
public record AcademicCalendarActivityTypeDto(
|
||||
Long id,
|
||||
String code,
|
||||
String name,
|
||||
Boolean allowSchedule,
|
||||
String colorCode,
|
||||
Integer displayOrder,
|
||||
String description
|
||||
) {
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.magistr.app.dto;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
public record AcademicCalendarDto(
|
||||
Long id,
|
||||
String title,
|
||||
Long academicYearId,
|
||||
String academicYearTitle,
|
||||
LocalDate academicYearStartDate,
|
||||
LocalDate academicYearEndDate,
|
||||
Long specialtyId,
|
||||
String specialtyCode,
|
||||
String specialtyName,
|
||||
Long specialtyProfileId,
|
||||
String specialtyProfileName,
|
||||
Long studyFormId,
|
||||
String studyFormName,
|
||||
Integer courseCount
|
||||
) {
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.magistr.app.dto;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
public record AcademicCalendarGridDayDto(
|
||||
Long id,
|
||||
Long calendarId,
|
||||
Integer courseNumber,
|
||||
LocalDate date,
|
||||
Integer weekNumber,
|
||||
Integer dayOfWeek,
|
||||
Long activityTypeId,
|
||||
String activityCode,
|
||||
String activityName,
|
||||
Boolean allowSchedule
|
||||
) {
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package com.magistr.app.dto;
|
||||
|
||||
import com.magistr.app.model.AcademicActivityType;
|
||||
|
||||
public record AcademicCalendarMatrixDto(
|
||||
Long id,
|
||||
Long semesterId,
|
||||
Integer courseNumber,
|
||||
Long specialtyId,
|
||||
Integer weekNumber,
|
||||
AcademicActivityType activityType
|
||||
) {
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.magistr.app.dto;
|
||||
|
||||
public record CalendarStudyFormDto(
|
||||
Long id,
|
||||
String name,
|
||||
String description
|
||||
) {
|
||||
}
|
||||
@@ -7,6 +7,8 @@ public class CreateGroupRequest {
|
||||
private Long educationFormId;
|
||||
private Long departmentId;
|
||||
private Integer yearStartStudy;
|
||||
private Long specialtyId;
|
||||
private Long specialtyProfileId;
|
||||
private Long specialityCode;
|
||||
|
||||
public String getName() {
|
||||
@@ -56,4 +58,24 @@ public class CreateGroupRequest {
|
||||
public void setSpecialityCode(Long specialityCode) {
|
||||
this.specialityCode = specialityCode;
|
||||
}
|
||||
|
||||
public Long getSpecialtyId() {
|
||||
return specialtyId;
|
||||
}
|
||||
|
||||
public void setSpecialtyId(Long specialtyId) {
|
||||
this.specialtyId = specialtyId;
|
||||
}
|
||||
|
||||
public Long getSpecialtyProfileId() {
|
||||
return specialtyProfileId;
|
||||
}
|
||||
|
||||
public void setSpecialtyProfileId(Long specialtyProfileId) {
|
||||
this.specialtyProfileId = specialtyProfileId;
|
||||
}
|
||||
|
||||
public Long getEffectiveSpecialtyId() {
|
||||
return specialtyId != null ? specialtyId : specialityCode;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.magistr.app.dto;
|
||||
|
||||
public record GroupCalendarAssignmentDto(
|
||||
Long id,
|
||||
Long groupId,
|
||||
String groupName,
|
||||
Long academicYearId,
|
||||
String academicYearTitle,
|
||||
Long calendarId,
|
||||
String calendarTitle
|
||||
) {
|
||||
}
|
||||
@@ -14,21 +14,26 @@ public class GroupResponse {
|
||||
private Integer yearStartStudy;
|
||||
private Integer course;
|
||||
private Integer semester;
|
||||
private Long specialityCode;
|
||||
private Long specialtyId;
|
||||
private String specialtyCode;
|
||||
private String specialtyName;
|
||||
private Long specialtyProfileId;
|
||||
private String specialtyProfileName;
|
||||
|
||||
public GroupResponse(Long id, String name, Long groupSize, Long educationFormId, String educationFormName, Long departmentId, Integer course, Integer semester, Long specialityCode) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.groupSize = groupSize;
|
||||
this.educationFormId = educationFormId;
|
||||
this.educationFormName = educationFormName;
|
||||
this.departmentId = departmentId;
|
||||
this.course = course;
|
||||
this.semester = semester;
|
||||
this.specialityCode = specialityCode;
|
||||
}
|
||||
|
||||
public GroupResponse(Long id, String name, Long groupSize, Long educationFormId, String educationFormName, Long departmentId, Integer yearStartStudy, Long specialityCode) {
|
||||
public GroupResponse(Long id,
|
||||
String name,
|
||||
Long groupSize,
|
||||
Long educationFormId,
|
||||
String educationFormName,
|
||||
Long departmentId,
|
||||
Integer yearStartStudy,
|
||||
Integer course,
|
||||
Integer semester,
|
||||
Long specialtyId,
|
||||
String specialtyCode,
|
||||
String specialtyName,
|
||||
Long specialtyProfileId,
|
||||
String specialtyProfileName) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.groupSize = groupSize;
|
||||
@@ -36,7 +41,13 @@ public class GroupResponse {
|
||||
this.educationFormName = educationFormName;
|
||||
this.departmentId = departmentId;
|
||||
this.yearStartStudy = yearStartStudy;
|
||||
this.specialityCode = specialityCode;
|
||||
this.course = course;
|
||||
this.semester = semester;
|
||||
this.specialtyId = specialtyId;
|
||||
this.specialtyCode = specialtyCode;
|
||||
this.specialtyName = specialtyName;
|
||||
this.specialtyProfileId = specialtyProfileId;
|
||||
this.specialtyProfileName = specialtyProfileName;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
@@ -76,6 +87,26 @@ public class GroupResponse {
|
||||
}
|
||||
|
||||
public Long getSpecialityCode() {
|
||||
return specialityCode;
|
||||
return specialtyId;
|
||||
}
|
||||
|
||||
public Long getSpecialtyId() {
|
||||
return specialtyId;
|
||||
}
|
||||
|
||||
public String getSpecialtyCode() {
|
||||
return specialtyCode;
|
||||
}
|
||||
|
||||
public String getSpecialtyName() {
|
||||
return specialtyName;
|
||||
}
|
||||
|
||||
public Long getSpecialtyProfileId() {
|
||||
return specialtyProfileId;
|
||||
}
|
||||
|
||||
public String getSpecialtyProfileName() {
|
||||
return specialtyProfileName;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
package com.magistr.app.dto;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
public record HolidayDto(
|
||||
Long id,
|
||||
LocalDate date,
|
||||
Long academicYearId,
|
||||
String academicYearTitle,
|
||||
String description
|
||||
) {
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.magistr.app.dto;
|
||||
|
||||
import com.magistr.app.model.AcademicActivityType;
|
||||
import com.magistr.app.model.ScheduleParity;
|
||||
|
||||
import java.time.LocalDate;
|
||||
@@ -31,7 +30,7 @@ public record RenderedLessonDto(
|
||||
Long subgroupId,
|
||||
List<Long> groupIds,
|
||||
List<String> groupNames,
|
||||
AcademicActivityType activityType,
|
||||
String activityType,
|
||||
Integer totalAcademicHours,
|
||||
Integer consumedAcademicHoursBeforeLesson,
|
||||
Integer remainingAcademicHoursAfterLesson
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.magistr.app.dto;
|
||||
|
||||
public record SpecialtyProfileDto(
|
||||
Long id,
|
||||
Long specialtyId,
|
||||
String specialtyCode,
|
||||
String specialtyName,
|
||||
String name,
|
||||
String description
|
||||
) {
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
package com.magistr.app.model;
|
||||
|
||||
public enum AcademicActivityType {
|
||||
THEORY,
|
||||
EXAM,
|
||||
VACATION,
|
||||
PRACTICE
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package com.magistr.app.model;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
|
||||
@Entity
|
||||
@Table(name = "academic_calendars")
|
||||
public class AcademicCalendar {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String title;
|
||||
|
||||
@ManyToOne(optional = false)
|
||||
@JoinColumn(name = "academic_year_id", nullable = false)
|
||||
private AcademicYear academicYear;
|
||||
|
||||
@ManyToOne(optional = false)
|
||||
@JoinColumn(name = "specialty_id", nullable = false)
|
||||
private Speciality speciality;
|
||||
|
||||
@ManyToOne(optional = false)
|
||||
@JoinColumn(name = "specialty_profile_id", nullable = false)
|
||||
private SpecialtyProfile specialtyProfile;
|
||||
|
||||
@ManyToOne(optional = false)
|
||||
@JoinColumn(name = "study_form_id", nullable = false)
|
||||
private CalendarStudyForm studyForm;
|
||||
|
||||
@Column(name = "course_count", nullable = false)
|
||||
private Integer courseCount;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public AcademicYear getAcademicYear() {
|
||||
return academicYear;
|
||||
}
|
||||
|
||||
public void setAcademicYear(AcademicYear academicYear) {
|
||||
this.academicYear = academicYear;
|
||||
}
|
||||
|
||||
public Speciality getSpeciality() {
|
||||
return speciality;
|
||||
}
|
||||
|
||||
public void setSpeciality(Speciality speciality) {
|
||||
this.speciality = speciality;
|
||||
}
|
||||
|
||||
public SpecialtyProfile getSpecialtyProfile() {
|
||||
return specialtyProfile;
|
||||
}
|
||||
|
||||
public void setSpecialtyProfile(SpecialtyProfile specialtyProfile) {
|
||||
this.specialtyProfile = specialtyProfile;
|
||||
}
|
||||
|
||||
public CalendarStudyForm getStudyForm() {
|
||||
return studyForm;
|
||||
}
|
||||
|
||||
public void setStudyForm(CalendarStudyForm studyForm) {
|
||||
this.studyForm = studyForm;
|
||||
}
|
||||
|
||||
public Integer getCourseCount() {
|
||||
return courseCount;
|
||||
}
|
||||
|
||||
public void setCourseCount(Integer courseCount) {
|
||||
this.courseCount = courseCount;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package com.magistr.app.model;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
|
||||
@Entity
|
||||
@Table(name = "academic_calendar_activity_types")
|
||||
public class AcademicCalendarActivityType {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(nullable = false, unique = true, length = 10)
|
||||
private String code;
|
||||
|
||||
@Column(nullable = false)
|
||||
private String name;
|
||||
|
||||
@Column(name = "allow_schedule", nullable = false)
|
||||
private Boolean allowSchedule;
|
||||
|
||||
@Column(name = "color_code", nullable = false, length = 7)
|
||||
private String colorCode;
|
||||
|
||||
@Column(name = "display_order", nullable = false)
|
||||
private Integer displayOrder;
|
||||
|
||||
@Column(columnDefinition = "TEXT")
|
||||
private String description;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public void setCode(String code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Boolean getAllowSchedule() {
|
||||
return allowSchedule;
|
||||
}
|
||||
|
||||
public void setAllowSchedule(Boolean allowSchedule) {
|
||||
this.allowSchedule = allowSchedule;
|
||||
}
|
||||
|
||||
public String getColorCode() {
|
||||
return colorCode;
|
||||
}
|
||||
|
||||
public void setColorCode(String colorCode) {
|
||||
this.colorCode = colorCode;
|
||||
}
|
||||
|
||||
public Integer getDisplayOrder() {
|
||||
return displayOrder;
|
||||
}
|
||||
|
||||
public void setDisplayOrder(Integer displayOrder) {
|
||||
this.displayOrder = displayOrder;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package com.magistr.app.model;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
@Entity
|
||||
@Table(name = "academic_calendar_days")
|
||||
public class AcademicCalendarDay {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@ManyToOne(optional = false)
|
||||
@JoinColumn(name = "calendar_id", nullable = false)
|
||||
private AcademicCalendar academicCalendar;
|
||||
|
||||
@Column(name = "course_number", nullable = false)
|
||||
private Integer courseNumber;
|
||||
|
||||
@Column(nullable = false)
|
||||
private LocalDate date;
|
||||
|
||||
@Column(name = "week_number", nullable = false)
|
||||
private Integer weekNumber;
|
||||
|
||||
@Column(name = "day_of_week", nullable = false)
|
||||
private Integer dayOfWeek;
|
||||
|
||||
@ManyToOne(optional = false)
|
||||
@JoinColumn(name = "activity_type_id", nullable = false)
|
||||
private AcademicCalendarActivityType activityType;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public AcademicCalendar getAcademicCalendar() {
|
||||
return academicCalendar;
|
||||
}
|
||||
|
||||
public void setAcademicCalendar(AcademicCalendar academicCalendar) {
|
||||
this.academicCalendar = academicCalendar;
|
||||
}
|
||||
|
||||
public Integer getCourseNumber() {
|
||||
return courseNumber;
|
||||
}
|
||||
|
||||
public void setCourseNumber(Integer courseNumber) {
|
||||
this.courseNumber = courseNumber;
|
||||
}
|
||||
|
||||
public LocalDate getDate() {
|
||||
return date;
|
||||
}
|
||||
|
||||
public void setDate(LocalDate date) {
|
||||
this.date = date;
|
||||
}
|
||||
|
||||
public Integer getWeekNumber() {
|
||||
return weekNumber;
|
||||
}
|
||||
|
||||
public void setWeekNumber(Integer weekNumber) {
|
||||
this.weekNumber = weekNumber;
|
||||
}
|
||||
|
||||
public Integer getDayOfWeek() {
|
||||
return dayOfWeek;
|
||||
}
|
||||
|
||||
public void setDayOfWeek(Integer dayOfWeek) {
|
||||
this.dayOfWeek = dayOfWeek;
|
||||
}
|
||||
|
||||
public AcademicCalendarActivityType getActivityType() {
|
||||
return activityType;
|
||||
}
|
||||
|
||||
public void setActivityType(AcademicCalendarActivityType activityType) {
|
||||
this.activityType = activityType;
|
||||
}
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
package com.magistr.app.model;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
|
||||
@Entity
|
||||
@Table(name = "academic_calendar_matrix")
|
||||
public class AcademicCalendarMatrix {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@ManyToOne(optional = false)
|
||||
@JoinColumn(name = "semester_id", nullable = false)
|
||||
private Semester semester;
|
||||
|
||||
@Column(name = "course_number", nullable = false)
|
||||
private Integer courseNumber;
|
||||
|
||||
@Column(name = "specialty_id", nullable = false)
|
||||
private Long specialtyId;
|
||||
|
||||
@Column(name = "week_number", nullable = false)
|
||||
private Integer weekNumber;
|
||||
|
||||
@Enumerated(EnumType.STRING)
|
||||
@Column(name = "activity_type", nullable = false, length = 20)
|
||||
private AcademicActivityType activityType;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Semester getSemester() {
|
||||
return semester;
|
||||
}
|
||||
|
||||
public void setSemester(Semester semester) {
|
||||
this.semester = semester;
|
||||
}
|
||||
|
||||
public Integer getCourseNumber() {
|
||||
return courseNumber;
|
||||
}
|
||||
|
||||
public void setCourseNumber(Integer courseNumber) {
|
||||
this.courseNumber = courseNumber;
|
||||
}
|
||||
|
||||
public Long getSpecialtyId() {
|
||||
return specialtyId;
|
||||
}
|
||||
|
||||
public void setSpecialtyId(Long specialtyId) {
|
||||
this.specialtyId = specialtyId;
|
||||
}
|
||||
|
||||
public Integer getWeekNumber() {
|
||||
return weekNumber;
|
||||
}
|
||||
|
||||
public void setWeekNumber(Integer weekNumber) {
|
||||
this.weekNumber = weekNumber;
|
||||
}
|
||||
|
||||
public AcademicActivityType getActivityType() {
|
||||
return activityType;
|
||||
}
|
||||
|
||||
public void setActivityType(AcademicActivityType activityType) {
|
||||
this.activityType = activityType;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.magistr.app.model;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
|
||||
@Entity
|
||||
@Table(name = "calendar_study_forms")
|
||||
public class CalendarStudyForm {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(nullable = false, unique = true, length = 100)
|
||||
private String name;
|
||||
|
||||
@Column(columnDefinition = "TEXT")
|
||||
private String description;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
package com.magistr.app.model;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
@Entity
|
||||
@Table(name = "holidays")
|
||||
public class Holiday {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(nullable = false)
|
||||
private LocalDate date;
|
||||
|
||||
@ManyToOne(optional = false)
|
||||
@JoinColumn(name = "academic_year_id", nullable = false)
|
||||
private AcademicYear academicYear;
|
||||
|
||||
@Column(length = 255)
|
||||
private String description;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public LocalDate getDate() {
|
||||
return date;
|
||||
}
|
||||
|
||||
public void setDate(LocalDate date) {
|
||||
this.date = date;
|
||||
}
|
||||
|
||||
public AcademicYear getAcademicYear() {
|
||||
return academicYear;
|
||||
}
|
||||
|
||||
public void setAcademicYear(AcademicYear academicYear) {
|
||||
this.academicYear = academicYear;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.magistr.app.model;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
|
||||
@Entity
|
||||
@Table(name = "specialty_profiles")
|
||||
public class SpecialtyProfile {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@ManyToOne(optional = false)
|
||||
@JoinColumn(name = "specialty_id", nullable = false)
|
||||
private Speciality speciality;
|
||||
|
||||
@Column(nullable = false, length = 500)
|
||||
private String name;
|
||||
|
||||
@Column(columnDefinition = "TEXT")
|
||||
private String description;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Speciality getSpeciality() {
|
||||
return speciality;
|
||||
}
|
||||
|
||||
public void setSpeciality(Speciality speciality) {
|
||||
this.speciality = speciality;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@ public class StudentGroup {
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@Column(unique = true, nullable = false, length = 100)
|
||||
@Column(nullable = false, length = 100)
|
||||
private String name;
|
||||
|
||||
@Column(name = "group_size", nullable = false)
|
||||
@@ -23,8 +23,13 @@ public class StudentGroup {
|
||||
@Column(name = "department_id", nullable = false)
|
||||
private Long departmentId;
|
||||
|
||||
@Column(name="specialty_code", nullable = false)
|
||||
private Long specialityCode;
|
||||
@ManyToOne(optional = false)
|
||||
@JoinColumn(name = "specialty_id", nullable = false)
|
||||
private Speciality speciality;
|
||||
|
||||
@ManyToOne(optional = false)
|
||||
@JoinColumn(name = "specialty_profile_id", nullable = false)
|
||||
private SpecialtyProfile specialtyProfile;
|
||||
|
||||
@Column(name="year_start_study", nullable = false)
|
||||
private Integer yearStartStudy;
|
||||
@@ -72,12 +77,20 @@ public class StudentGroup {
|
||||
this.departmentId = departmentId;
|
||||
}
|
||||
|
||||
public Long getSpecialityCode() {
|
||||
return specialityCode;
|
||||
public Speciality getSpeciality() {
|
||||
return speciality;
|
||||
}
|
||||
|
||||
public void setSpecialityCode(Long specialityCode) {
|
||||
this.specialityCode = specialityCode;
|
||||
public void setSpeciality(Speciality speciality) {
|
||||
this.speciality = speciality;
|
||||
}
|
||||
|
||||
public SpecialtyProfile getSpecialtyProfile() {
|
||||
return specialtyProfile;
|
||||
}
|
||||
|
||||
public void setSpecialtyProfile(SpecialtyProfile specialtyProfile) {
|
||||
this.specialtyProfile = specialtyProfile;
|
||||
}
|
||||
|
||||
public Integer getYearStartStudy() {
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.magistr.app.model;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
|
||||
@Entity
|
||||
@Table(name = "student_group_calendar_assignments")
|
||||
public class StudentGroupCalendarAssignment {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
@ManyToOne(optional = false)
|
||||
@JoinColumn(name = "group_id", nullable = false)
|
||||
private StudentGroup studentGroup;
|
||||
|
||||
@ManyToOne(optional = false)
|
||||
@JoinColumn(name = "academic_year_id", nullable = false)
|
||||
private AcademicYear academicYear;
|
||||
|
||||
@ManyToOne(optional = false)
|
||||
@JoinColumn(name = "calendar_id", nullable = false)
|
||||
private AcademicCalendar academicCalendar;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public StudentGroup getStudentGroup() {
|
||||
return studentGroup;
|
||||
}
|
||||
|
||||
public void setStudentGroup(StudentGroup studentGroup) {
|
||||
this.studentGroup = studentGroup;
|
||||
}
|
||||
|
||||
public AcademicYear getAcademicYear() {
|
||||
return academicYear;
|
||||
}
|
||||
|
||||
public void setAcademicYear(AcademicYear academicYear) {
|
||||
this.academicYear = academicYear;
|
||||
}
|
||||
|
||||
public AcademicCalendar getAcademicCalendar() {
|
||||
return academicCalendar;
|
||||
}
|
||||
|
||||
public void setAcademicCalendar(AcademicCalendar academicCalendar) {
|
||||
this.academicCalendar = academicCalendar;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.magistr.app.repository;
|
||||
|
||||
import com.magistr.app.model.AcademicCalendarActivityType;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface AcademicCalendarActivityTypeRepository extends JpaRepository<AcademicCalendarActivityType, Long> {
|
||||
|
||||
List<AcademicCalendarActivityType> findAllByOrderByDisplayOrderAscCodeAsc();
|
||||
|
||||
Optional<AcademicCalendarActivityType> findByCode(String code);
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.magistr.app.repository;
|
||||
|
||||
import com.magistr.app.model.AcademicCalendarDay;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Modifying;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface AcademicCalendarDayRepository extends JpaRepository<AcademicCalendarDay, Long> {
|
||||
|
||||
@Query("""
|
||||
select day
|
||||
from AcademicCalendarDay day
|
||||
join fetch day.activityType
|
||||
where day.academicCalendar.id = :calendarId
|
||||
order by day.courseNumber asc, day.date asc
|
||||
""")
|
||||
List<AcademicCalendarDay> findByCalendarIdWithActivity(@Param("calendarId") Long calendarId);
|
||||
|
||||
@Query("""
|
||||
select day
|
||||
from AcademicCalendarDay day
|
||||
join fetch day.activityType
|
||||
where day.academicCalendar.id = :calendarId
|
||||
and day.courseNumber = :courseNumber
|
||||
and day.date = :date
|
||||
""")
|
||||
Optional<AcademicCalendarDay> findByCalendarIdAndCourseNumberAndDate(
|
||||
@Param("calendarId") Long calendarId,
|
||||
@Param("courseNumber") Integer courseNumber,
|
||||
@Param("date") LocalDate date
|
||||
);
|
||||
|
||||
boolean existsByActivityTypeId(Long activityTypeId);
|
||||
|
||||
@Modifying
|
||||
@Query("delete from AcademicCalendarDay day where day.academicCalendar.id = :calendarId")
|
||||
void deleteByCalendarId(@Param("calendarId") Long calendarId);
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package com.magistr.app.repository;
|
||||
|
||||
import com.magistr.app.model.AcademicCalendarMatrix;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface AcademicCalendarMatrixRepository extends JpaRepository<AcademicCalendarMatrix, Long> {
|
||||
|
||||
Optional<AcademicCalendarMatrix> findBySemesterIdAndCourseNumberAndSpecialtyIdAndWeekNumber(
|
||||
Long semesterId,
|
||||
Integer courseNumber,
|
||||
Long specialtyId,
|
||||
Integer weekNumber
|
||||
);
|
||||
|
||||
List<AcademicCalendarMatrix> findBySemesterIdAndCourseNumberAndSpecialtyIdOrderByWeekNumberAsc(
|
||||
Long semesterId,
|
||||
Integer courseNumber,
|
||||
Long specialtyId
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.magistr.app.repository;
|
||||
|
||||
import com.magistr.app.model.AcademicCalendar;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface AcademicCalendarRepository extends JpaRepository<AcademicCalendar, Long> {
|
||||
|
||||
@Query("""
|
||||
select calendar
|
||||
from AcademicCalendar calendar
|
||||
join fetch calendar.academicYear
|
||||
join fetch calendar.speciality
|
||||
join fetch calendar.specialtyProfile
|
||||
join fetch calendar.studyForm
|
||||
where (:academicYearId is null or calendar.academicYear.id = :academicYearId)
|
||||
and (:specialtyId is null or calendar.speciality.id = :specialtyId)
|
||||
and (:profileId is null or calendar.specialtyProfile.id = :profileId)
|
||||
order by calendar.academicYear.startDate desc, calendar.title asc
|
||||
""")
|
||||
List<AcademicCalendar> findAllWithDetails(
|
||||
@Param("academicYearId") Long academicYearId,
|
||||
@Param("specialtyId") Long specialtyId,
|
||||
@Param("profileId") Long profileId
|
||||
);
|
||||
|
||||
@Query("""
|
||||
select calendar
|
||||
from AcademicCalendar calendar
|
||||
join fetch calendar.academicYear
|
||||
join fetch calendar.speciality
|
||||
join fetch calendar.specialtyProfile
|
||||
join fetch calendar.studyForm
|
||||
where calendar.id = :id
|
||||
""")
|
||||
Optional<AcademicCalendar> findByIdWithDetails(@Param("id") Long id);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.magistr.app.repository;
|
||||
|
||||
import com.magistr.app.model.CalendarStudyForm;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface CalendarStudyFormRepository extends JpaRepository<CalendarStudyForm, Long> {
|
||||
|
||||
List<CalendarStudyForm> findAllByOrderByNameAsc();
|
||||
}
|
||||
@@ -4,12 +4,9 @@ import com.magistr.app.model.StudentGroup;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface GroupRepository extends JpaRepository<StudentGroup, Long> {
|
||||
|
||||
Optional<StudentGroup> findByName(String name);
|
||||
|
||||
List<StudentGroup> findByEducationFormId(Long educationFormId);
|
||||
|
||||
List<StudentGroup> findByDepartmentId(Long departmentId);
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
package com.magistr.app.repository;
|
||||
|
||||
import com.magistr.app.model.Holiday;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
|
||||
public interface HolidayRepository extends JpaRepository<Holiday, Long> {
|
||||
|
||||
List<Holiday> findByAcademicYearIdOrderByDateAsc(Long academicYearId);
|
||||
|
||||
List<Holiday> findByAcademicYearIdAndDateBetween(Long academicYearId, LocalDate startDate, LocalDate endDate);
|
||||
|
||||
boolean existsByAcademicYearIdAndDate(Long academicYearId, LocalDate date);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.magistr.app.repository;
|
||||
|
||||
import com.magistr.app.model.SpecialtyProfile;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface SpecialtyProfileRepository extends JpaRepository<SpecialtyProfile, Long> {
|
||||
|
||||
List<SpecialtyProfile> findBySpecialityIdOrderByNameAsc(Long specialityId);
|
||||
|
||||
Optional<SpecialtyProfile> findBySpecialityIdAndName(Long specialityId, String name);
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.magistr.app.repository;
|
||||
|
||||
import com.magistr.app.model.StudentGroupCalendarAssignment;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface StudentGroupCalendarAssignmentRepository extends JpaRepository<StudentGroupCalendarAssignment, Long> {
|
||||
|
||||
@Query("""
|
||||
select assignment
|
||||
from StudentGroupCalendarAssignment assignment
|
||||
join fetch assignment.studentGroup
|
||||
join fetch assignment.academicYear
|
||||
join fetch assignment.academicCalendar calendar
|
||||
join fetch calendar.speciality
|
||||
join fetch calendar.specialtyProfile
|
||||
join fetch calendar.studyForm
|
||||
where assignment.studentGroup.id = :groupId
|
||||
order by assignment.academicYear.startDate desc
|
||||
""")
|
||||
List<StudentGroupCalendarAssignment> findByGroupIdWithDetails(@Param("groupId") Long groupId);
|
||||
|
||||
@Query("""
|
||||
select assignment
|
||||
from StudentGroupCalendarAssignment assignment
|
||||
join fetch assignment.academicYear
|
||||
join fetch assignment.academicCalendar calendar
|
||||
join fetch calendar.speciality
|
||||
join fetch calendar.specialtyProfile
|
||||
join fetch calendar.studyForm
|
||||
where assignment.studentGroup.id = :groupId
|
||||
and assignment.academicYear.id = :academicYearId
|
||||
""")
|
||||
Optional<StudentGroupCalendarAssignment> findByGroupIdAndAcademicYearIdWithDetails(
|
||||
@Param("groupId") Long groupId,
|
||||
@Param("academicYearId") Long academicYearId
|
||||
);
|
||||
|
||||
@Query("""
|
||||
select assignment
|
||||
from StudentGroupCalendarAssignment assignment
|
||||
join fetch assignment.academicCalendar
|
||||
where assignment.studentGroup.id = :groupId
|
||||
and assignment.academicYear.id = :academicYearId
|
||||
""")
|
||||
Optional<StudentGroupCalendarAssignment> findForSchedule(
|
||||
@Param("groupId") Long groupId,
|
||||
@Param("academicYearId") Long academicYearId
|
||||
);
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
package com.magistr.app.service;
|
||||
|
||||
import com.magistr.app.model.*;
|
||||
import com.magistr.app.repository.AcademicCalendarMatrixRepository;
|
||||
import com.magistr.app.repository.HolidayRepository;
|
||||
import com.magistr.app.repository.AcademicCalendarDayRepository;
|
||||
import com.magistr.app.repository.SemesterRepository;
|
||||
import com.magistr.app.repository.StudentGroupCalendarAssignmentRepository;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@@ -15,17 +15,17 @@ import java.util.Optional;
|
||||
public class AcademicDateService {
|
||||
|
||||
private final SemesterRepository semesterRepository;
|
||||
private final HolidayRepository holidayRepository;
|
||||
private final AcademicCalendarMatrixRepository calendarMatrixRepository;
|
||||
private final AcademicCalendarDayRepository calendarDayRepository;
|
||||
private final StudentGroupCalendarAssignmentRepository assignmentRepository;
|
||||
private final boolean evenWeekIsUpper;
|
||||
|
||||
public AcademicDateService(SemesterRepository semesterRepository,
|
||||
HolidayRepository holidayRepository,
|
||||
AcademicCalendarMatrixRepository calendarMatrixRepository,
|
||||
AcademicCalendarDayRepository calendarDayRepository,
|
||||
StudentGroupCalendarAssignmentRepository assignmentRepository,
|
||||
@Value("${app.schedule.even-week-is-upper:false}") boolean evenWeekIsUpper) {
|
||||
this.semesterRepository = semesterRepository;
|
||||
this.holidayRepository = holidayRepository;
|
||||
this.calendarMatrixRepository = calendarMatrixRepository;
|
||||
this.calendarDayRepository = calendarDayRepository;
|
||||
this.assignmentRepository = assignmentRepository;
|
||||
this.evenWeekIsUpper = evenWeekIsUpper;
|
||||
}
|
||||
|
||||
@@ -50,38 +50,40 @@ public class AcademicDateService {
|
||||
return evenWeek ? ScheduleParity.EVEN : ScheduleParity.ODD;
|
||||
}
|
||||
|
||||
public boolean isHoliday(Semester semester, LocalDate date) {
|
||||
if (semester == null || semester.getAcademicYear() == null) {
|
||||
return false;
|
||||
}
|
||||
return holidayRepository.existsByAcademicYearIdAndDate(semester.getAcademicYear().getId(), date);
|
||||
}
|
||||
|
||||
public int getCourseNumber(StudentGroup group, LocalDate date) {
|
||||
int academicYearStart = date.getMonthValue() >= 9 ? date.getYear() : date.getYear() - 1;
|
||||
return academicYearStart - group.getYearStartStudy() + 1;
|
||||
}
|
||||
|
||||
public AcademicActivityType getActivityType(StudentGroup group, Semester semester, LocalDate date) {
|
||||
int weekNumber = getWeekNumber(semester, date);
|
||||
int courseNumber = getCourseNumber(group, date);
|
||||
if (weekNumber < 1 || courseNumber < 1) {
|
||||
return AcademicActivityType.VACATION;
|
||||
public Optional<AcademicCalendarActivityType> getActivityType(StudentGroup group, Semester semester, LocalDate date) {
|
||||
if (group == null || semester == null || semester.getAcademicYear() == null || date == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
return calendarMatrixRepository
|
||||
.findBySemesterIdAndCourseNumberAndSpecialtyIdAndWeekNumber(
|
||||
semester.getId(),
|
||||
int courseNumber = getCourseNumber(group, date);
|
||||
if (courseNumber < 1) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
return assignmentRepository.findForSchedule(group.getId(), semester.getAcademicYear().getId())
|
||||
.flatMap(assignment -> calendarDayRepository.findByCalendarIdAndCourseNumberAndDate(
|
||||
assignment.getAcademicCalendar().getId(),
|
||||
courseNumber,
|
||||
group.getSpecialityCode(),
|
||||
weekNumber
|
||||
)
|
||||
.map(AcademicCalendarMatrix::getActivityType)
|
||||
.orElse(AcademicActivityType.THEORY);
|
||||
date
|
||||
))
|
||||
.map(AcademicCalendarDay::getActivityType);
|
||||
}
|
||||
|
||||
public boolean isTheoryDay(StudentGroup group, Semester semester, LocalDate date) {
|
||||
return getActivityType(group, semester, date) == AcademicActivityType.THEORY
|
||||
&& !isHoliday(semester, date);
|
||||
return getActivityType(group, semester, date)
|
||||
.map(AcademicCalendarActivityType::getAllowSchedule)
|
||||
.orElse(false);
|
||||
}
|
||||
|
||||
public boolean hasCalendarAssignment(StudentGroup group, Semester semester) {
|
||||
if (group == null || semester == null || semester.getAcademicYear() == null) {
|
||||
return false;
|
||||
}
|
||||
return assignmentRepository.findForSchedule(group.getId(), semester.getAcademicYear().getId()).isPresent();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@ import com.magistr.app.model.*;
|
||||
import com.magistr.app.repository.GroupRepository;
|
||||
import com.magistr.app.repository.ScheduleRuleRepository;
|
||||
import com.magistr.app.repository.UserRepository;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.DayOfWeek;
|
||||
@@ -17,6 +19,7 @@ import java.util.stream.Collectors;
|
||||
@Service
|
||||
public class ScheduleGeneratorService {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ScheduleGeneratorService.class);
|
||||
private static final int ACADEMIC_HOURS_PER_SLOT = 2;
|
||||
private static final long MAX_RANGE_DAYS = 120;
|
||||
|
||||
@@ -43,6 +46,7 @@ public class ScheduleGeneratorService {
|
||||
|
||||
Map<Long, List<ScheduleRule>> rulesBySemester = new HashMap<>();
|
||||
List<RenderedLessonDto> result = new ArrayList<>();
|
||||
Set<Long> warnedAcademicYears = new HashSet<>();
|
||||
|
||||
for (LocalDate date = startDate; !date.isAfter(endDate); date = date.plusDays(1)) {
|
||||
Optional<Semester> semesterOpt = academicDateService.findSemester(date);
|
||||
@@ -51,6 +55,11 @@ public class ScheduleGeneratorService {
|
||||
}
|
||||
|
||||
Semester semester = semesterOpt.get();
|
||||
if (!academicDateService.hasCalendarAssignment(group, semester)
|
||||
&& warnedAcademicYears.add(semester.getAcademicYear().getId())) {
|
||||
logger.info("Для группы '{}' не назначен календарный учебный график на учебный год {}",
|
||||
group.getName(), semester.getAcademicYear().getTitle());
|
||||
}
|
||||
if (!academicDateService.isTheoryDay(group, semester, date)) {
|
||||
continue;
|
||||
}
|
||||
@@ -148,10 +157,6 @@ public class ScheduleGeneratorService {
|
||||
}
|
||||
|
||||
Semester semester = semesterOpt.get();
|
||||
if (academicDateService.isHoliday(semester, date)) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<StudentGroup> eligibleGroups = eligibleGroups(rule, targetGroup, semester, date);
|
||||
if (eligibleGroups.isEmpty()) {
|
||||
return;
|
||||
@@ -216,9 +221,6 @@ public class ScheduleGeneratorService {
|
||||
if (date.isBefore(semester.getStartDate()) || date.isAfter(semester.getEndDate())) {
|
||||
continue;
|
||||
}
|
||||
if (academicDateService.isHoliday(semester, date)) {
|
||||
continue;
|
||||
}
|
||||
if (eligibleGroups(rule, targetGroup, semester, date).isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
@@ -274,7 +276,7 @@ public class ScheduleGeneratorService {
|
||||
slot.getSubgroupId(),
|
||||
sortedGroups.stream().map(StudentGroup::getId).toList(),
|
||||
sortedGroups.stream().map(StudentGroup::getName).collect(Collectors.toList()),
|
||||
AcademicActivityType.THEORY,
|
||||
"Т",
|
||||
rule.getTotalAcademicHours(),
|
||||
consumedBeforeLesson,
|
||||
remainingAfterLesson
|
||||
|
||||
Reference in New Issue
Block a user