@@ -7,6 +7,7 @@ import com.magistr.app.repository.*;
|
||||
import com.magistr.app.service.AcademicCalendarGridService;
|
||||
import com.magistr.app.service.AcademicStructureService;
|
||||
import com.magistr.app.service.ScheduleGeneratorService;
|
||||
import com.magistr.app.utils.AcademicCalendarTitleBuilder;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
@@ -152,9 +153,6 @@ public class AcademicCalendarController {
|
||||
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("Количество курсов должно быть больше нуля");
|
||||
}
|
||||
@@ -178,7 +176,7 @@ public class AcademicCalendarController {
|
||||
EducationForm studyForm = educationFormRepository.findById(request.studyFormId())
|
||||
.orElseThrow(() -> new IllegalArgumentException("Форма обучения не найдена"));
|
||||
|
||||
calendar.setTitle(request.title().trim());
|
||||
calendar.setTitle(AcademicCalendarTitleBuilder.build(year, speciality, profile, studyForm));
|
||||
calendar.setAcademicYear(year);
|
||||
calendar.setSpeciality(speciality);
|
||||
calendar.setSpecialtyProfile(profile);
|
||||
|
||||
@@ -20,6 +20,7 @@ import com.magistr.app.repository.SpecialtiesRepository;
|
||||
import com.magistr.app.repository.SpecialtyProfileRepository;
|
||||
import com.magistr.app.repository.StudentGroupCalendarAssignmentRepository;
|
||||
import com.magistr.app.repository.SubgroupRepository;
|
||||
import com.magistr.app.utils.AcademicCalendarTitleBuilder;
|
||||
import com.magistr.app.utils.CourseAndSemesterCalculator;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -126,7 +127,12 @@ public class AcademicStructureService {
|
||||
);
|
||||
}
|
||||
|
||||
calendar.setTitle(request.title().trim());
|
||||
calendar.setTitle(AcademicCalendarTitleBuilder.build(
|
||||
candidate.academicYear(),
|
||||
candidate.speciality(),
|
||||
candidate.profile(),
|
||||
candidate.studyForm()
|
||||
));
|
||||
applyCalendarDimensions(calendar, candidate, request.courseCount());
|
||||
AcademicCalendar saved = saveCalendar(calendar);
|
||||
clearScheduleCacheAfterCommit();
|
||||
@@ -208,9 +214,6 @@ public class AcademicStructureService {
|
||||
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("Количество курсов должно быть больше нуля");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.magistr.app.utils;
|
||||
|
||||
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 java.util.List;
|
||||
|
||||
public final class AcademicCalendarTitleBuilder {
|
||||
|
||||
private static final String SEPARATOR = " — ";
|
||||
|
||||
private AcademicCalendarTitleBuilder() {
|
||||
}
|
||||
|
||||
public static String build(AcademicYear academicYear,
|
||||
Speciality speciality,
|
||||
SpecialtyProfile profile,
|
||||
EducationForm studyForm) {
|
||||
List<String> parts = List.of(
|
||||
normalize(speciality == null ? null : speciality.getSpecialityCode()),
|
||||
normalize(profile == null ? null : profile.getName()),
|
||||
normalize(studyForm == null ? null : studyForm.getName()),
|
||||
normalize(academicYear == null ? null : academicYear.getTitle())
|
||||
);
|
||||
if (parts.stream().anyMatch(String::isBlank)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Невозможно сформировать название календарного графика из выбранных параметров"
|
||||
);
|
||||
}
|
||||
return String.join(SEPARATOR, parts);
|
||||
}
|
||||
|
||||
private static String normalize(String value) {
|
||||
return value == null ? "" : value.trim();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
package com.magistr.app.controller;
|
||||
|
||||
import com.magistr.app.dto.AcademicCalendarDto;
|
||||
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.repository.AcademicCalendarDayRepository;
|
||||
import com.magistr.app.repository.AcademicCalendarRepository;
|
||||
import com.magistr.app.repository.AcademicCalendarSubjectRepository;
|
||||
import com.magistr.app.repository.AcademicYearRepository;
|
||||
import com.magistr.app.repository.EducationFormRepository;
|
||||
import com.magistr.app.repository.SpecialtiesRepository;
|
||||
import com.magistr.app.repository.SpecialtyProfileRepository;
|
||||
import com.magistr.app.repository.SubjectRepository;
|
||||
import com.magistr.app.service.AcademicCalendarGridService;
|
||||
import com.magistr.app.service.AcademicStructureService;
|
||||
import com.magistr.app.service.ScheduleGeneratorService;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
class AcademicCalendarControllerTest {
|
||||
|
||||
@Test
|
||||
void createCalendarBuildsTitleWithoutClientValue() {
|
||||
AcademicCalendarRepository calendarRepository = mock(AcademicCalendarRepository.class);
|
||||
AcademicYearRepository academicYearRepository = mock(AcademicYearRepository.class);
|
||||
SpecialtiesRepository specialtiesRepository = mock(SpecialtiesRepository.class);
|
||||
SpecialtyProfileRepository profileRepository = mock(SpecialtyProfileRepository.class);
|
||||
EducationFormRepository educationFormRepository = mock(EducationFormRepository.class);
|
||||
|
||||
AcademicYear year = new AcademicYear();
|
||||
year.setId(1L);
|
||||
year.setTitle("2026-2027");
|
||||
year.setStartDate(LocalDate.of(2026, 9, 1));
|
||||
year.setEndDate(LocalDate.of(2027, 6, 30));
|
||||
Speciality speciality = new Speciality(2L, "Программная инженерия", "09.03.04");
|
||||
SpecialtyProfile profile = new SpecialtyProfile();
|
||||
profile.setId(3L);
|
||||
profile.setSpeciality(speciality);
|
||||
profile.setName("Разработка ПО");
|
||||
EducationForm studyForm = new EducationForm();
|
||||
studyForm.setId(4L);
|
||||
studyForm.setName("Очная");
|
||||
|
||||
when(academicYearRepository.findById(1L)).thenReturn(Optional.of(year));
|
||||
when(specialtiesRepository.findById(2L)).thenReturn(Optional.of(speciality));
|
||||
when(profileRepository.findById(3L)).thenReturn(Optional.of(profile));
|
||||
when(educationFormRepository.findById(4L)).thenReturn(Optional.of(studyForm));
|
||||
when(calendarRepository.save(any(AcademicCalendar.class)))
|
||||
.thenAnswer(invocation -> invocation.getArgument(0));
|
||||
|
||||
AcademicCalendarController controller = new AcademicCalendarController(
|
||||
calendarRepository,
|
||||
mock(AcademicCalendarDayRepository.class),
|
||||
academicYearRepository,
|
||||
specialtiesRepository,
|
||||
profileRepository,
|
||||
educationFormRepository,
|
||||
mock(SubjectRepository.class),
|
||||
mock(AcademicCalendarSubjectRepository.class),
|
||||
mock(AcademicCalendarGridService.class),
|
||||
mock(ScheduleGeneratorService.class),
|
||||
mock(AcademicStructureService.class)
|
||||
);
|
||||
AcademicCalendarDto request = new AcademicCalendarDto(
|
||||
null,
|
||||
null,
|
||||
1L,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
2L,
|
||||
null,
|
||||
null,
|
||||
3L,
|
||||
null,
|
||||
4L,
|
||||
null,
|
||||
4
|
||||
);
|
||||
|
||||
var response = controller.createCalendar(request);
|
||||
|
||||
assertThat(response.getStatusCode().value()).isEqualTo(200);
|
||||
assertThat(response.getBody()).isInstanceOf(AcademicCalendarDto.class);
|
||||
assertThat(((AcademicCalendarDto) response.getBody()).title())
|
||||
.isEqualTo("09.03.04 — Разработка ПО — Очная — 2026-2027");
|
||||
}
|
||||
}
|
||||
@@ -168,6 +168,18 @@ class AcademicStructureServiceTest {
|
||||
.hasMessage("Нельзя уменьшить количество курсов: есть дисциплины старших семестров");
|
||||
}
|
||||
|
||||
@Test
|
||||
void buildsCalendarTitleFromDimensionsInsteadOfRequestField() {
|
||||
AcademicCalendar saved = service.updateCalendar(
|
||||
CALENDAR_ID,
|
||||
calendarRequest(4, FORM_ID)
|
||||
);
|
||||
|
||||
assertThat(saved.getTitle())
|
||||
.isEqualTo("09.03.01 — Без профиля — Бакалавриат — 2025-2026");
|
||||
verify(calendarRepository).saveAndFlush(calendar);
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsGroupDimensionChangeAndKeepsAssignment() {
|
||||
when(assignmentRepository.findByGroupIdWithDetails(GROUP_ID))
|
||||
@@ -280,7 +292,7 @@ class AcademicStructureServiceTest {
|
||||
private AcademicCalendarDto calendarRequest(int courseCount, long studyFormId) {
|
||||
return new AcademicCalendarDto(
|
||||
CALENDAR_ID,
|
||||
"График 2026",
|
||||
null,
|
||||
YEAR_ID,
|
||||
null,
|
||||
null,
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.magistr.app.utils;
|
||||
|
||||
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 org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
|
||||
class AcademicCalendarTitleBuilderTest {
|
||||
|
||||
@Test
|
||||
void buildsTitleFromCalendarDimensions() {
|
||||
AcademicYear year = new AcademicYear();
|
||||
year.setTitle(" 2026-2027 ");
|
||||
Speciality speciality = new Speciality();
|
||||
speciality.setSpecialityCode(" 09.03.04 ");
|
||||
SpecialtyProfile profile = new SpecialtyProfile();
|
||||
profile.setName(" Программная инженерия ");
|
||||
EducationForm studyForm = new EducationForm();
|
||||
studyForm.setName(" Очная ");
|
||||
|
||||
assertThat(AcademicCalendarTitleBuilder.build(year, speciality, profile, studyForm))
|
||||
.isEqualTo("09.03.04 — Программная инженерия — Очная — 2026-2027");
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsIncompleteDimensions() {
|
||||
assertThatThrownBy(() -> AcademicCalendarTitleBuilder.build(
|
||||
new AcademicYear(),
|
||||
new Speciality(),
|
||||
new SpecialtyProfile(),
|
||||
new EducationForm()
|
||||
))
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessage("Невозможно сформировать название календарного графика из выбранных параметров");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user