219 lines
9.6 KiB
Java
219 lines
9.6 KiB
Java
package com.magistr.app.controller;
|
|
|
|
import com.magistr.app.config.auth.RequireRoles;
|
|
import com.magistr.app.dto.TimeSlotDateAssignmentDto;
|
|
import com.magistr.app.dto.TimeSlotDto;
|
|
import com.magistr.app.dto.TimeSlotScopeDto;
|
|
import com.magistr.app.model.TimeSlot;
|
|
import com.magistr.app.model.TimeSlotDateAssignment;
|
|
import com.magistr.app.model.TimeSlotScope;
|
|
import com.magistr.app.model.Role;
|
|
import com.magistr.app.repository.TimeSlotDateAssignmentRepository;
|
|
import com.magistr.app.repository.TimeSlotRepository;
|
|
import com.magistr.app.repository.TimeSlotScopeRepository;
|
|
import com.magistr.app.service.TimeSlotService;
|
|
import com.magistr.app.service.EffectiveTimeSlotService;
|
|
import org.springframework.http.ResponseEntity;
|
|
import org.springframework.web.bind.annotation.*;
|
|
|
|
import java.time.LocalDate;
|
|
import java.util.ArrayList;
|
|
import java.util.LinkedHashMap;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.UUID;
|
|
|
|
@RestController
|
|
@RequestMapping("/api/admin/time-slots")
|
|
@RequireRoles({Role.ADMIN, Role.EDUCATION_OFFICE})
|
|
public class TimeSlotAdminController {
|
|
|
|
private static final String APPLY_MODE_DEFAULT = "DEFAULT";
|
|
private static final String APPLY_MODE_WEEKDAY = "WEEKDAY";
|
|
private static final String APPLY_MODE_MANUAL = "MANUAL";
|
|
|
|
private final TimeSlotRepository timeSlotRepository;
|
|
private final TimeSlotScopeRepository timeSlotScopeRepository;
|
|
private final TimeSlotDateAssignmentRepository dateAssignmentRepository;
|
|
private final TimeSlotService timeSlotService;
|
|
private final EffectiveTimeSlotService effectiveTimeSlotService;
|
|
|
|
public TimeSlotAdminController(TimeSlotRepository timeSlotRepository,
|
|
TimeSlotScopeRepository timeSlotScopeRepository,
|
|
TimeSlotDateAssignmentRepository dateAssignmentRepository,
|
|
TimeSlotService timeSlotService,
|
|
EffectiveTimeSlotService effectiveTimeSlotService) {
|
|
this.timeSlotRepository = timeSlotRepository;
|
|
this.timeSlotScopeRepository = timeSlotScopeRepository;
|
|
this.dateAssignmentRepository = dateAssignmentRepository;
|
|
this.timeSlotService = timeSlotService;
|
|
this.effectiveTimeSlotService = effectiveTimeSlotService;
|
|
}
|
|
|
|
@GetMapping
|
|
public List<TimeSlotDto> getAll() {
|
|
return timeSlotRepository.findAllByOrderByTimeSlotScopeDisplayOrderAscOrderNumberAscStartTimeAsc().stream()
|
|
.map(this::toDto)
|
|
.toList();
|
|
}
|
|
|
|
@GetMapping("/effective")
|
|
public ResponseEntity<?> getEffective(@RequestParam LocalDate date) {
|
|
return ResponseEntity.ok(effectiveTimeSlotService.findEffective(date).stream().map(this::toDto).toList());
|
|
}
|
|
|
|
@GetMapping("/scopes")
|
|
public List<TimeSlotScopeDto> getScopes() {
|
|
return timeSlotScopeRepository.findAllByOrderByDisplayOrderAscNameAsc().stream()
|
|
.map(this::toScopeDto)
|
|
.toList();
|
|
}
|
|
|
|
@PostMapping("/scopes")
|
|
public ResponseEntity<?> createScope(@RequestBody TimeSlotScopeDto request) {
|
|
if (request.name() == null || request.name().isBlank()) {
|
|
return ResponseEntity.badRequest().body(Map.of("message", "Название сетки обязательно"));
|
|
}
|
|
|
|
TimeSlotScope scope = new TimeSlotScope();
|
|
scope.setCode("manual_" + UUID.randomUUID().toString().replace("-", ""));
|
|
scope.setName(request.name().trim());
|
|
scope.setApplyMode(APPLY_MODE_MANUAL);
|
|
scope.setDayOfWeek(null);
|
|
scope.setSystemScope(false);
|
|
scope.setDisplayOrder(nextManualDisplayOrder());
|
|
return ResponseEntity.ok(toScopeDto(timeSlotScopeRepository.save(scope)));
|
|
}
|
|
|
|
@PutMapping("/scopes/{id}")
|
|
public ResponseEntity<?> updateScope(@PathVariable Long id, @RequestBody TimeSlotScopeDto request) {
|
|
TimeSlotScope scope = timeSlotScopeRepository.findById(id).orElse(null);
|
|
if (scope == null) {
|
|
return ResponseEntity.notFound().build();
|
|
}
|
|
if (Boolean.TRUE.equals(scope.getSystemScope())) {
|
|
return ResponseEntity.badRequest().body(Map.of("message", "Системную сетку нельзя изменять"));
|
|
}
|
|
if (request.name() == null || request.name().isBlank()) {
|
|
return ResponseEntity.badRequest().body(Map.of("message", "Название сетки обязательно"));
|
|
}
|
|
scope.setName(request.name().trim());
|
|
return ResponseEntity.ok(toScopeDto(timeSlotScopeRepository.save(scope)));
|
|
}
|
|
|
|
@DeleteMapping("/scopes/{id}")
|
|
public ResponseEntity<?> deleteScope(@PathVariable Long id) {
|
|
TimeSlotScope scope = timeSlotScopeRepository.findById(id).orElse(null);
|
|
if (scope == null) {
|
|
return ResponseEntity.notFound().build();
|
|
}
|
|
if (Boolean.TRUE.equals(scope.getSystemScope())) {
|
|
return ResponseEntity.badRequest().body(Map.of("message", "Системную сетку нельзя удалить"));
|
|
}
|
|
timeSlotScopeRepository.delete(scope);
|
|
return ResponseEntity.ok(Map.of("message", "Сетка времени удалена"));
|
|
}
|
|
|
|
@GetMapping("/date-assignments")
|
|
public List<TimeSlotDateAssignmentDto> getDateAssignments(@RequestParam(required = false) LocalDate startDate,
|
|
@RequestParam(required = false) LocalDate endDate) {
|
|
List<TimeSlotDateAssignment> assignments = startDate != null && endDate != null
|
|
? dateAssignmentRepository.findByDateBetweenOrderByDateAsc(startDate, endDate)
|
|
: dateAssignmentRepository.findAllByOrderByDateAsc();
|
|
return assignments.stream().map(this::toAssignmentDto).toList();
|
|
}
|
|
|
|
@PostMapping("/date-assignments")
|
|
public ResponseEntity<?> saveDateAssignment(@RequestBody TimeSlotDateAssignmentDto request) {
|
|
if (request.date() == null) {
|
|
return ResponseEntity.badRequest().body(Map.of("message", "Дата обязательна"));
|
|
}
|
|
if (request.scopeId() == null) {
|
|
return ResponseEntity.badRequest().body(Map.of("message", "Сетка времени обязательна"));
|
|
}
|
|
TimeSlotScope scope = timeSlotScopeRepository.findById(request.scopeId()).orElse(null);
|
|
if (scope == null) {
|
|
return ResponseEntity.badRequest().body(Map.of("message", "Сетка времени не найдена"));
|
|
}
|
|
if (!APPLY_MODE_MANUAL.equals(scope.getApplyMode())) {
|
|
return ResponseEntity.badRequest().body(Map.of("message", "Вручную можно применять только пользовательские сетки"));
|
|
}
|
|
|
|
TimeSlotDateAssignment assignment = dateAssignmentRepository.findByDate(request.date())
|
|
.orElseGet(TimeSlotDateAssignment::new);
|
|
assignment.setDate(request.date());
|
|
assignment.setTimeSlotScope(scope);
|
|
return ResponseEntity.ok(toAssignmentDto(dateAssignmentRepository.save(assignment)));
|
|
}
|
|
|
|
@DeleteMapping("/date-assignments/{id}")
|
|
public ResponseEntity<?> deleteDateAssignment(@PathVariable Long id) {
|
|
if (!dateAssignmentRepository.existsById(id)) {
|
|
return ResponseEntity.notFound().build();
|
|
}
|
|
dateAssignmentRepository.deleteById(id);
|
|
return ResponseEntity.ok(Map.of("message", "Ручное назначение удалено"));
|
|
}
|
|
|
|
@PostMapping
|
|
public ResponseEntity<?> create(@RequestBody TimeSlotDto request) {
|
|
return ResponseEntity.ok(toDto(timeSlotService.create(request)));
|
|
}
|
|
|
|
@PutMapping("/{id}")
|
|
public ResponseEntity<?> update(@PathVariable Long id, @RequestBody TimeSlotDto request) {
|
|
return ResponseEntity.ok(toDto(timeSlotService.update(id, request)));
|
|
}
|
|
|
|
@DeleteMapping("/{id}")
|
|
public ResponseEntity<?> delete(@PathVariable Long id) {
|
|
timeSlotService.delete(id);
|
|
return ResponseEntity.ok(Map.of("message", "Временной слот удалён"));
|
|
}
|
|
|
|
private int nextManualDisplayOrder() {
|
|
return timeSlotScopeRepository.findAllByOrderByDisplayOrderAscNameAsc().stream()
|
|
.map(TimeSlotScope::getDisplayOrder)
|
|
.filter(value -> value != null)
|
|
.max(Integer::compareTo)
|
|
.orElse(100) + 10;
|
|
}
|
|
|
|
private TimeSlotDto toDto(TimeSlot timeSlot) {
|
|
TimeSlotScope scope = timeSlot.getTimeSlotScope();
|
|
return new TimeSlotDto(
|
|
timeSlot.getId(),
|
|
timeSlot.getOrderNumber(),
|
|
scope == null ? null : scope.getId(),
|
|
scope == null ? null : scope.getName(),
|
|
scope == null ? null : scope.getApplyMode(),
|
|
scope == null ? null : scope.getDayOfWeek(),
|
|
timeSlot.getStartTime(),
|
|
timeSlot.getEndTime(),
|
|
timeSlot.getDurationMinutes()
|
|
);
|
|
}
|
|
|
|
private TimeSlotScopeDto toScopeDto(TimeSlotScope scope) {
|
|
return new TimeSlotScopeDto(
|
|
scope.getId(),
|
|
scope.getCode(),
|
|
scope.getName(),
|
|
scope.getApplyMode(),
|
|
scope.getDayOfWeek(),
|
|
scope.getSystemScope(),
|
|
scope.getDisplayOrder()
|
|
);
|
|
}
|
|
|
|
private TimeSlotDateAssignmentDto toAssignmentDto(TimeSlotDateAssignment assignment) {
|
|
TimeSlotScope scope = assignment.getTimeSlotScope();
|
|
return new TimeSlotDateAssignmentDto(
|
|
assignment.getId(),
|
|
assignment.getDate(),
|
|
scope.getId(),
|
|
scope.getName()
|
|
);
|
|
}
|
|
}
|