Изменен фильтр в "группы обучения", изменена механика создания подгрупп

This commit is contained in:
2026-06-02 11:20:35 +03:00
parent 4e1985c28e
commit 6d9f6b7a42
10 changed files with 465 additions and 58 deletions

View File

@@ -66,6 +66,10 @@ public class SubgroupController {
if (subgroupRepository.existsByStudentGroupIdAndNameIgnoreCase(groupId, request.name().trim())) {
return ResponseEntity.badRequest().body(Map.of("message", "Подгруппа с таким названием уже есть в группе"));
}
String capacityError = validateGroupCapacity(group, null, request.studentCapacity());
if (capacityError != null) {
return ResponseEntity.badRequest().body(Map.of("message", capacityError));
}
Subgroup subgroup = new Subgroup();
subgroup.setStudentGroup(group);
@@ -95,6 +99,10 @@ public class SubgroupController {
if (duplicateName) {
return ResponseEntity.badRequest().body(Map.of("message", "Подгруппа с таким названием уже есть в группе"));
}
String capacityError = validateGroupCapacity(subgroup.getStudentGroup(), id, request.studentCapacity());
if (capacityError != null) {
return ResponseEntity.badRequest().body(Map.of("message", capacityError));
}
subgroup.setName(newName);
subgroup.setStudentCapacity(request.studentCapacity());
@@ -113,6 +121,10 @@ public class SubgroupController {
if (scheduleRuleSlotRepository.existsBySubgroupId(id)) {
return ResponseEntity.badRequest().body(Map.of("message", "Подгруппа используется в расписании"));
}
String deleteValidationError = validateDeleteKeepsCompleteSplit(subgroup);
if (deleteValidationError != null) {
return ResponseEntity.badRequest().body(Map.of("message", deleteValidationError));
}
try {
subgroup.archive("Подгруппа архивирована");
subgroupRepository.save(subgroup);
@@ -127,8 +139,39 @@ public class SubgroupController {
if (request == null || request.name() == null || request.name().isBlank()) {
return "Название подгруппы обязательно";
}
if (request.studentCapacity() != null && request.studentCapacity() < 0) {
return "Численность подгруппы не может быть отрицательной";
if (request.studentCapacity() == null) {
return "Численность подгруппы обязательна";
}
if (request.studentCapacity() <= 0) {
return "Численность подгруппы должна быть больше 0";
}
return null;
}
private String validateGroupCapacity(StudentGroup group, Long excludedSubgroupId, Integer requestedCapacity) {
Long currentCapacity = excludedSubgroupId == null
? subgroupRepository.sumActiveStudentCapacityByGroupId(group.getId())
: subgroupRepository.sumActiveStudentCapacityByGroupIdExcludingId(group.getId(), excludedSubgroupId);
long totalCapacity = currentCapacity + requestedCapacity.longValue();
if (totalCapacity > group.getGroupSize()) {
return "Сумма численностей подгрупп не может превышать численность группы (" + group.getGroupSize() + " чел.)";
}
return null;
}
private String validateDeleteKeepsCompleteSplit(Subgroup subgroup) {
StudentGroup group = subgroup.getStudentGroup();
long remainingCount = subgroupRepository.countActiveByGroupIdExcludingId(group.getId(), subgroup.getId());
if (remainingCount == 0) {
return null;
}
Long remainingCapacity = subgroupRepository.sumActiveStudentCapacityByGroupIdExcludingId(
group.getId(),
subgroup.getId()
);
if (remainingCapacity < group.getGroupSize()) {
return "Нельзя удалить одну подгруппу из деления: измените количество подгрупп в форме настройки или отключите деление";
}
return null;
}

View File

@@ -46,4 +46,32 @@ public interface SubgroupRepository extends JpaRepository<Subgroup, Long> {
and subgroup.status <> 'ARCHIVED'
""")
boolean existsByStudentGroupIdAndNameIgnoreCase(@Param("groupId") Long groupId, @Param("name") String name);
@Query("""
select coalesce(sum(subgroup.studentCapacity), 0)
from Subgroup subgroup
where subgroup.studentGroup.id = :groupId
and subgroup.status <> 'ARCHIVED'
""")
Long sumActiveStudentCapacityByGroupId(@Param("groupId") Long groupId);
@Query("""
select coalesce(sum(subgroup.studentCapacity), 0)
from Subgroup subgroup
where subgroup.studentGroup.id = :groupId
and subgroup.status <> 'ARCHIVED'
and subgroup.id <> :excludedId
""")
Long sumActiveStudentCapacityByGroupIdExcludingId(@Param("groupId") Long groupId,
@Param("excludedId") Long excludedId);
@Query("""
select count(subgroup)
from Subgroup subgroup
where subgroup.studentGroup.id = :groupId
and subgroup.status <> 'ARCHIVED'
and subgroup.id <> :excludedId
""")
long countActiveByGroupIdExcludingId(@Param("groupId") Long groupId,
@Param("excludedId") Long excludedId);
}

View File

@@ -0,0 +1,6 @@
ALTER TABLE subgroups
DROP CONSTRAINT IF EXISTS subgroups_group_id_name_key;
CREATE UNIQUE INDEX IF NOT EXISTS ux_subgroups_active_group_name
ON subgroups (group_id, lower(name))
WHERE status <> 'ARCHIVED';