feat: улучшить учебные периоды и просмотр расписаний
This commit is contained in:
@@ -7,6 +7,7 @@ import com.magistr.app.model.ScheduleVersion;
|
||||
import com.magistr.app.model.ScheduleVersionHistory;
|
||||
import com.magistr.app.model.ScheduleVersionStatus;
|
||||
import com.magistr.app.model.Semester;
|
||||
import com.magistr.app.model.SemesterType;
|
||||
import com.magistr.app.repository.AcademicYearRepository;
|
||||
import com.magistr.app.repository.ScheduleVersionHistoryRepository;
|
||||
import com.magistr.app.repository.ScheduleVersionRepository;
|
||||
@@ -19,13 +20,20 @@ import org.springframework.transaction.support.TransactionSynchronizationManager
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Set;
|
||||
|
||||
@Service
|
||||
public class AcademicPeriodService {
|
||||
|
||||
private static final String YEAR_CONFLICT_MESSAGE =
|
||||
"Название или период учебного года конфликтует с существующим учебным годом";
|
||||
"Учебный год или его период конфликтует с существующим учебным годом";
|
||||
private static final String SEMESTER_CONFLICT_MESSAGE =
|
||||
"Тип или период семестра конфликтует с существующим семестром учебного года";
|
||||
|
||||
@@ -49,48 +57,53 @@ public class AcademicPeriodService {
|
||||
|
||||
@Transactional
|
||||
public AcademicYear createYear(AcademicYearDto request) {
|
||||
validateYear(request);
|
||||
String title = request.title().trim();
|
||||
YearPeriod period = resolveYearPeriod(request);
|
||||
List<SemesterDto> semesterRequests = validateRequestedSemesters(
|
||||
request.semesters(), period.startDate(), period.endDate(), true
|
||||
);
|
||||
String title = academicYearTitle(period.startDate(), period.endDate());
|
||||
if (academicYearRepository.existsByTitle(title)
|
||||
|| academicYearRepository.existsOverlapping(request.startDate(), request.endDate())) {
|
||||
|| academicYearRepository.existsOverlapping(period.startDate(), period.endDate())) {
|
||||
throw new ScheduleConflictException(YEAR_CONFLICT_MESSAGE);
|
||||
}
|
||||
|
||||
AcademicYear year = new AcademicYear();
|
||||
applyYear(year, title, request.startDate(), request.endDate());
|
||||
applyYear(year, title, period.startDate(), period.endDate());
|
||||
AcademicYear saved = saveYear(year);
|
||||
for (SemesterDto semesterRequest : semesterRequests) {
|
||||
Semester semester = new Semester();
|
||||
semester.setAcademicYear(saved);
|
||||
applySemester(semester, semesterRequest);
|
||||
Semester savedSemester = saveSemester(semester);
|
||||
createInitialPublishedSchedule(savedSemester);
|
||||
}
|
||||
clearScheduleCacheAfterCommit();
|
||||
return saved;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public AcademicYear updateYear(Long id, AcademicYearDto request) {
|
||||
validateYear(request);
|
||||
YearPeriod period = resolveYearPeriod(request);
|
||||
AcademicYear year = lockYear(id);
|
||||
String title = request.title().trim();
|
||||
String title = academicYearTitle(period.startDate(), period.endDate());
|
||||
|
||||
if (academicYearRepository.existsByTitleAndIdNot(title, id)
|
||||
|| academicYearRepository.existsOverlappingExcluding(
|
||||
id, request.startDate(), request.endDate())) {
|
||||
id, period.startDate(), period.endDate())) {
|
||||
throw new ScheduleConflictException(YEAR_CONFLICT_MESSAGE);
|
||||
}
|
||||
boolean semesterOutsideNewRange = semesterRepository
|
||||
.findByAcademicYearIdOrderByStartDateAsc(id)
|
||||
.stream()
|
||||
.anyMatch(semester -> !contains(
|
||||
request.startDate(),
|
||||
request.endDate(),
|
||||
semester.getStartDate(),
|
||||
semester.getEndDate()
|
||||
));
|
||||
if (semesterOutsideNewRange) {
|
||||
throw new IllegalArgumentException(
|
||||
"Новые границы учебного года не включают все его семестры"
|
||||
);
|
||||
}
|
||||
|
||||
applyYear(year, title, request.startDate(), request.endDate());
|
||||
List<Semester> existingSemesters = semesterRepository.findByAcademicYearIdOrderByStartDateAsc(id);
|
||||
List<SemesterDto> requestedSemesters = request.semesters() == null
|
||||
? List.of()
|
||||
: request.semesters();
|
||||
List<SemesterDto> effectiveSemesterRequests = mergeSemesterRequests(
|
||||
existingSemesters, requestedSemesters, period.startDate(), period.endDate()
|
||||
);
|
||||
|
||||
applyYear(year, title, period.startDate(), period.endDate());
|
||||
AcademicYear saved = saveYear(year);
|
||||
synchronizeSemesters(saved, existingSemesters, effectiveSemesterRequests, requestedSemesters);
|
||||
clearScheduleCacheAfterCommit();
|
||||
return saved;
|
||||
}
|
||||
@@ -139,19 +152,15 @@ public class AcademicPeriodService {
|
||||
return saved;
|
||||
}
|
||||
|
||||
private void validateYear(AcademicYearDto request) {
|
||||
private YearPeriod resolveYearPeriod(AcademicYearDto request) {
|
||||
if (request == null) {
|
||||
throw new IllegalArgumentException("Данные учебного года обязательны");
|
||||
}
|
||||
if (request.title() == null || request.title().isBlank()) {
|
||||
throw new IllegalArgumentException("Название учебного года обязательно");
|
||||
if (request.startDate() == null) {
|
||||
throw new IllegalArgumentException("Дата начала учебного года обязательна");
|
||||
}
|
||||
validateDateRange(
|
||||
request.startDate(),
|
||||
request.endDate(),
|
||||
"Даты начала и окончания учебного года обязательны",
|
||||
"Дата окончания учебного года не может быть раньше даты начала"
|
||||
);
|
||||
LocalDate endDate = LocalDate.of(request.startDate().getYear() + 1, 6, 30);
|
||||
return new YearPeriod(request.startDate(), endDate);
|
||||
}
|
||||
|
||||
private void validateSemester(SemesterDto request) {
|
||||
@@ -189,6 +198,110 @@ public class AcademicPeriodService {
|
||||
}
|
||||
}
|
||||
|
||||
private List<SemesterDto> validateRequestedSemesters(List<SemesterDto> requests,
|
||||
LocalDate yearStart,
|
||||
LocalDate yearEnd,
|
||||
boolean required) {
|
||||
List<SemesterDto> semesters = requests == null ? List.of() : new ArrayList<>(requests);
|
||||
if (required && semesters.isEmpty()) {
|
||||
throw new IllegalArgumentException("Учебный год нельзя создать без семестров");
|
||||
}
|
||||
|
||||
Set<SemesterType> types = new HashSet<>();
|
||||
Set<Long> ids = new HashSet<>();
|
||||
for (SemesterDto semester : semesters) {
|
||||
validateSemester(semester);
|
||||
if (!types.add(semester.semesterType())) {
|
||||
throw new ScheduleConflictException("Типы семестров учебного года не должны повторяться");
|
||||
}
|
||||
if (semester.id() != null && !ids.add(semester.id())) {
|
||||
throw new IllegalArgumentException("Один семестр нельзя передать несколько раз");
|
||||
}
|
||||
if (!contains(yearStart, yearEnd, semester.startDate(), semester.endDate())) {
|
||||
throw new IllegalArgumentException("Семестр должен полностью находиться в границах учебного года");
|
||||
}
|
||||
}
|
||||
|
||||
List<SemesterDto> sorted = new ArrayList<>(semesters);
|
||||
sorted.sort(Comparator.comparing(SemesterDto::startDate));
|
||||
for (int index = 1; index < sorted.size(); index++) {
|
||||
SemesterDto previous = sorted.get(index - 1);
|
||||
SemesterDto current = sorted.get(index);
|
||||
if (!previous.endDate().isBefore(current.startDate())) {
|
||||
throw new ScheduleConflictException(SEMESTER_CONFLICT_MESSAGE);
|
||||
}
|
||||
}
|
||||
return sorted;
|
||||
}
|
||||
|
||||
private List<SemesterDto> mergeSemesterRequests(List<Semester> existingSemesters,
|
||||
List<SemesterDto> requestedSemesters,
|
||||
LocalDate yearStart,
|
||||
LocalDate yearEnd) {
|
||||
Map<Long, Semester> existingById = new HashMap<>();
|
||||
existingSemesters.forEach(semester -> existingById.put(semester.getId(), semester));
|
||||
|
||||
Map<Long, SemesterDto> requestedById = new HashMap<>();
|
||||
List<SemesterDto> newRequests = new ArrayList<>();
|
||||
for (SemesterDto request : requestedSemesters) {
|
||||
if (request == null) {
|
||||
throw new IllegalArgumentException("Данные семестра обязательны");
|
||||
}
|
||||
if (request.id() == null) {
|
||||
newRequests.add(request);
|
||||
continue;
|
||||
}
|
||||
if (!existingById.containsKey(request.id())) {
|
||||
throw new IllegalArgumentException("Семестр не относится к редактируемому учебному году");
|
||||
}
|
||||
if (requestedById.put(request.id(), request) != null) {
|
||||
throw new IllegalArgumentException("Один семестр нельзя передать несколько раз");
|
||||
}
|
||||
}
|
||||
|
||||
List<SemesterDto> effective = new ArrayList<>();
|
||||
for (Semester semester : existingSemesters) {
|
||||
effective.add(requestedById.getOrDefault(semester.getId(), toSemesterRequest(semester)));
|
||||
}
|
||||
effective.addAll(newRequests);
|
||||
return validateRequestedSemesters(effective, yearStart, yearEnd, true);
|
||||
}
|
||||
|
||||
private void synchronizeSemesters(AcademicYear year,
|
||||
List<Semester> existingSemesters,
|
||||
List<SemesterDto> effectiveRequests,
|
||||
List<SemesterDto> requestedSemesters) {
|
||||
if (effectiveRequests.isEmpty() || requestedSemesters.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
Map<Long, Semester> existingById = new HashMap<>();
|
||||
existingSemesters.forEach(semester -> existingById.put(semester.getId(), semester));
|
||||
for (SemesterDto request : requestedSemesters) {
|
||||
Semester semester = request.id() == null ? new Semester() : existingById.get(request.id());
|
||||
if (semester == null) {
|
||||
throw new IllegalArgumentException("Семестр не относится к редактируемому учебному году");
|
||||
}
|
||||
boolean created = semester.getId() == null;
|
||||
semester.setAcademicYear(year);
|
||||
applySemester(semester, request);
|
||||
Semester saved = saveSemester(semester);
|
||||
if (created) {
|
||||
createInitialPublishedSchedule(saved);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private SemesterDto toSemesterRequest(Semester semester) {
|
||||
return new SemesterDto(
|
||||
semester.getId(),
|
||||
semester.getAcademicYear().getId(),
|
||||
semester.getAcademicYear().getTitle(),
|
||||
semester.getSemesterType(),
|
||||
semester.getStartDate(),
|
||||
semester.getEndDate()
|
||||
);
|
||||
}
|
||||
|
||||
private boolean contains(LocalDate outerStart,
|
||||
LocalDate outerEnd,
|
||||
LocalDate innerStart,
|
||||
@@ -226,6 +339,10 @@ public class AcademicPeriodService {
|
||||
year.setEndDate(endDate);
|
||||
}
|
||||
|
||||
private String academicYearTitle(LocalDate startDate, LocalDate endDate) {
|
||||
return startDate.getYear() + "-" + endDate.getYear();
|
||||
}
|
||||
|
||||
private void applySemester(Semester semester, SemesterDto request) {
|
||||
semester.setSemesterType(request.semesterType());
|
||||
semester.setStartDate(request.startDate());
|
||||
@@ -283,4 +400,7 @@ public class AcademicPeriodService {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private record YearPeriod(LocalDate startDate, LocalDate endDate) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ 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;
|
||||
private static final long MAX_RANGE_DAYS = 200;
|
||||
private static final String APPLY_MODE_WEEKDAY = "WEEKDAY";
|
||||
|
||||
private final ScheduleRuleRepository scheduleRuleRepository;
|
||||
@@ -328,7 +328,7 @@ public class ScheduleGeneratorService {
|
||||
}
|
||||
long inclusiveDays = java.time.temporal.ChronoUnit.DAYS.between(startDate, endDate) + 1;
|
||||
if (inclusiveDays > MAX_RANGE_DAYS) {
|
||||
throw new IllegalArgumentException("Диапазон расписания не может превышать 120 дней");
|
||||
throw new IllegalArgumentException("Диапазон расписания не может превышать 200 дней");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,8 @@ import java.util.stream.Collectors;
|
||||
@Service
|
||||
public class ScheduleOverrideService {
|
||||
|
||||
private static final long MAX_RANGE_DAYS = 200;
|
||||
|
||||
private static final Set<String> ACTIONS = Set.of("MOVE", "CANCEL", "REPLACE");
|
||||
private static final Set<String> LESSON_FORMATS = Set.of("Очно", "Онлайн");
|
||||
|
||||
@@ -706,8 +708,8 @@ public class ScheduleOverrideService {
|
||||
if (endDate.isBefore(startDate)) {
|
||||
throw new IllegalArgumentException("Дата окончания не может быть раньше даты начала");
|
||||
}
|
||||
if (ChronoUnit.DAYS.between(startDate, endDate) + 1 > 120) {
|
||||
throw new IllegalArgumentException("Диапазон точечных изменений не может превышать 120 дней");
|
||||
if (ChronoUnit.DAYS.between(startDate, endDate) + 1 > MAX_RANGE_DAYS) {
|
||||
throw new IllegalArgumentException("Диапазон точечных изменений не может превышать 200 дней");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ import java.util.stream.Collectors;
|
||||
public class ScheduleQueryService {
|
||||
|
||||
private static final int MAX_GROUPS_WITHOUT_SCOPE = 50;
|
||||
private static final long MAX_RANGE_DAYS = 120;
|
||||
private static final long MAX_RANGE_DAYS = 200;
|
||||
|
||||
private final ScheduleGeneratorService scheduleGeneratorService;
|
||||
private final GroupRepository groupRepository;
|
||||
@@ -380,7 +380,7 @@ public class ScheduleQueryService {
|
||||
}
|
||||
long inclusiveDays = ChronoUnit.DAYS.between(startDate, endDate) + 1;
|
||||
if (inclusiveDays > MAX_RANGE_DAYS) {
|
||||
throw new IllegalArgumentException("Диапазон расписания не может превышать 120 дней");
|
||||
throw new IllegalArgumentException("Диапазон расписания не может превышать 200 дней");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -73,18 +73,38 @@ class AcademicPeriodServiceTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void createsNonOverlappingYearWithTrimmedTitle() {
|
||||
void createsYearWithAutomaticTitleEndDateAndSemesters() {
|
||||
AcademicYear saved = service.createYear(yearRequest(
|
||||
" 2026-2027 ",
|
||||
"Произвольное название",
|
||||
YEAR_START,
|
||||
YEAR_END
|
||||
YEAR_END.minusMonths(1)
|
||||
));
|
||||
|
||||
assertThat(saved.getTitle()).isEqualTo("2026-2027");
|
||||
assertThat(saved.getStartDate()).isEqualTo(YEAR_START);
|
||||
assertThat(saved.getEndDate()).isEqualTo(YEAR_END);
|
||||
verify(semesterRepository, org.mockito.Mockito.times(2)).saveAndFlush(any(Semester.class));
|
||||
verify(scheduleVersionRepository, org.mockito.Mockito.times(2)).saveAndFlush(any(ScheduleVersion.class));
|
||||
verify(scheduleGeneratorService).clearCache();
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsYearWithoutSemesters() {
|
||||
AcademicYearDto request = new AcademicYearDto(
|
||||
null,
|
||||
null,
|
||||
YEAR_START,
|
||||
null,
|
||||
List.of()
|
||||
);
|
||||
|
||||
assertThatThrownBy(() -> service.createYear(request))
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessage("Учебный год нельзя создать без семестров");
|
||||
|
||||
verify(academicYearRepository, never()).saveAndFlush(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsDuplicateTitleOrOverlappingYear() {
|
||||
when(academicYearRepository.existsByTitle("2026-2027")).thenReturn(true);
|
||||
@@ -95,7 +115,7 @@ class AcademicPeriodServiceTest {
|
||||
YEAR_END
|
||||
)))
|
||||
.isInstanceOf(ScheduleConflictException.class)
|
||||
.hasMessage("Название или период учебного года конфликтует с существующим учебным годом");
|
||||
.hasMessage("Учебный год или его период конфликтует с существующим учебным годом");
|
||||
|
||||
verify(academicYearRepository, never()).saveAndFlush(any());
|
||||
}
|
||||
@@ -112,17 +132,49 @@ class AcademicPeriodServiceTest {
|
||||
when(semesterRepository.findByAcademicYearIdOrderByStartDateAsc(YEAR_ID))
|
||||
.thenReturn(List.of(autumn));
|
||||
|
||||
assertThatThrownBy(() -> service.updateYear(YEAR_ID, yearRequest(
|
||||
"2026-2027",
|
||||
YEAR_START.plusDays(1),
|
||||
YEAR_END
|
||||
)))
|
||||
assertThatThrownBy(() -> service.updateYear(YEAR_ID, yearRequestWithoutSemesters(YEAR_START.plusDays(1))))
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessage("Новые границы учебного года не включают все его семестры");
|
||||
.hasMessage("Семестр должен полностью находиться в границах учебного года");
|
||||
|
||||
verify(academicYearRepository, never()).saveAndFlush(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void updatesYearAndItsSemestersTogether() {
|
||||
Semester autumn = semester(
|
||||
SEMESTER_ID,
|
||||
SemesterType.autumn,
|
||||
YEAR_START,
|
||||
LocalDate.of(2027, 1, 31)
|
||||
);
|
||||
Semester spring = semester(
|
||||
SEMESTER_ID + 1,
|
||||
SemesterType.spring,
|
||||
LocalDate.of(2027, 2, 1),
|
||||
YEAR_END
|
||||
);
|
||||
when(academicYearRepository.findByIdForUpdate(YEAR_ID)).thenReturn(Optional.of(year));
|
||||
when(semesterRepository.findByAcademicYearIdOrderByStartDateAsc(YEAR_ID))
|
||||
.thenReturn(List.of(autumn, spring));
|
||||
|
||||
AcademicYear saved = service.updateYear(YEAR_ID, new AcademicYearDto(
|
||||
YEAR_ID,
|
||||
null,
|
||||
YEAR_START,
|
||||
null,
|
||||
List.of(
|
||||
semesterRequest(SEMESTER_ID, SemesterType.autumn, YEAR_START, LocalDate.of(2027, 1, 25)),
|
||||
semesterRequest(SEMESTER_ID + 1, SemesterType.spring, LocalDate.of(2027, 1, 26), YEAR_END)
|
||||
)
|
||||
));
|
||||
|
||||
assertThat(saved.getTitle()).isEqualTo("2026-2027");
|
||||
assertThat(autumn.getEndDate()).isEqualTo(LocalDate.of(2027, 1, 25));
|
||||
assertThat(spring.getStartDate()).isEqualTo(LocalDate.of(2027, 1, 26));
|
||||
verify(semesterRepository, org.mockito.Mockito.times(2)).saveAndFlush(any(Semester.class));
|
||||
verify(scheduleVersionRepository, never()).saveAndFlush(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsSemesterOutsideAcademicYear() {
|
||||
when(academicYearRepository.findByIdForUpdate(YEAR_ID)).thenReturn(Optional.of(year));
|
||||
@@ -218,19 +270,33 @@ class AcademicPeriodServiceTest {
|
||||
YEAR_END
|
||||
)))
|
||||
.isInstanceOf(ScheduleConflictException.class)
|
||||
.hasMessage("Название или период учебного года конфликтует с существующим учебным годом")
|
||||
.hasMessage("Учебный год или его период конфликтует с существующим учебным годом")
|
||||
.hasNoCause();
|
||||
}
|
||||
|
||||
private AcademicYearDto yearRequest(String title, LocalDate startDate, LocalDate endDate) {
|
||||
return new AcademicYearDto(null, title, startDate, endDate, List.of());
|
||||
return new AcademicYearDto(null, title, startDate, endDate, List.of(
|
||||
semesterRequest(SemesterType.autumn, startDate, LocalDate.of(2027, 1, 31)),
|
||||
semesterRequest(SemesterType.spring, LocalDate.of(2027, 2, 1), YEAR_END)
|
||||
));
|
||||
}
|
||||
|
||||
private AcademicYearDto yearRequestWithoutSemesters(LocalDate startDate) {
|
||||
return new AcademicYearDto(null, null, startDate, null, List.of());
|
||||
}
|
||||
|
||||
private SemesterDto semesterRequest(SemesterType semesterType,
|
||||
LocalDate startDate,
|
||||
LocalDate endDate) {
|
||||
return semesterRequest(null, semesterType, startDate, endDate);
|
||||
}
|
||||
|
||||
private SemesterDto semesterRequest(Long id,
|
||||
SemesterType semesterType,
|
||||
LocalDate startDate,
|
||||
LocalDate endDate) {
|
||||
return new SemesterDto(
|
||||
null,
|
||||
id,
|
||||
YEAR_ID,
|
||||
"2026-2027",
|
||||
semesterType,
|
||||
|
||||
@@ -145,8 +145,8 @@ class ScheduleGenerationQueryCountTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("Генератор отклоняет 121 включительную дату")
|
||||
void rejects121InclusiveDates() {
|
||||
@DisplayName("Генератор отклоняет 201 включительную дату")
|
||||
void rejects201InclusiveDates() {
|
||||
ScheduleGeneratorService generator = new ScheduleGeneratorService(
|
||||
mock(ScheduleRuleRepository.class),
|
||||
mock(GroupRepository.class),
|
||||
@@ -161,10 +161,10 @@ class ScheduleGenerationQueryCountTest {
|
||||
assertThatThrownBy(() -> generator.buildScheduleForGroups(
|
||||
List.of(),
|
||||
startDate,
|
||||
startDate.plusDays(120)
|
||||
startDate.plusDays(200)
|
||||
))
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessage("Диапазон расписания не может превышать 120 дней");
|
||||
.hasMessage("Диапазон расписания не может превышать 200 дней");
|
||||
}
|
||||
|
||||
private AcademicYear academicYear() {
|
||||
|
||||
@@ -181,6 +181,15 @@ class ScheduleOverrideServiceTest {
|
||||
verify(scheduleOverrideRepository).findForRegistry(TARGET_DATE, TARGET_DATE);
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsRegistryRangeLongerThanTwoHundredDays() {
|
||||
assertThatThrownBy(() -> service.getAll(DATE, DATE.plusDays(200)))
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessage("Диапазон точечных изменений не может превышать 200 дней");
|
||||
|
||||
verify(scheduleOverrideRepository, never()).findForRegistry(any(LocalDate.class), any(LocalDate.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void availabilityContainsOnlyStudyDatesOfSourceSemester() {
|
||||
Semester semester = configureRuleForTarget();
|
||||
|
||||
@@ -86,8 +86,8 @@ class ScheduleQueryServiceTest {
|
||||
groupLifecycleService
|
||||
);
|
||||
LocalDate startDate = LocalDate.of(2026, 1, 1);
|
||||
LocalDate allowedEndDate = startDate.plusDays(119);
|
||||
LocalDate rejectedEndDate = startDate.plusDays(120);
|
||||
LocalDate allowedEndDate = startDate.plusDays(199);
|
||||
LocalDate rejectedEndDate = startDate.plusDays(200);
|
||||
when(generatorService.buildScheduleForTeacher(10L, startDate, allowedEndDate))
|
||||
.thenReturn(List.of());
|
||||
when(overrideRepository.findByLessonDateBetweenWithDetails(startDate, allowedEndDate))
|
||||
@@ -101,7 +101,7 @@ class ScheduleQueryServiceTest {
|
||||
null, null, null, null,
|
||||
startDate, rejectedEndDate))
|
||||
.isInstanceOf(IllegalArgumentException.class)
|
||||
.hasMessage("Диапазон расписания не может превышать 120 дней");
|
||||
.hasMessage("Диапазон расписания не может превышать 200 дней");
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
|
||||
Reference in New Issue
Block a user