почти робит(400 ошибка)
This commit is contained in:
@@ -1,10 +1,14 @@
|
||||
package com.example.nto.controller;
|
||||
|
||||
import com.example.nto.entity.Booking;
|
||||
import com.example.nto.exception.BookingConflictException;
|
||||
import com.example.nto.exception.EmployeeNotFoundException;
|
||||
import com.example.nto.exception.InvalidBookingException;
|
||||
import com.example.nto.service.BookingService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.ErrorResponse;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.time.LocalDate;
|
||||
@@ -45,24 +49,48 @@ public class BookingController {
|
||||
|
||||
}
|
||||
}
|
||||
public static class CreateBookingRequest {
|
||||
private LocalDate date;
|
||||
private long placeId;
|
||||
@PostMapping("/{code}/book")
|
||||
public ResponseEntity<?> createBooking(
|
||||
@PathVariable String code,
|
||||
@RequestBody Booking.CreateBookingRequest request
|
||||
) {
|
||||
try {
|
||||
Booking booking = bookingService.createBooking(
|
||||
code,
|
||||
request.getDate(),
|
||||
request.getPlaceId()
|
||||
);
|
||||
|
||||
public LocalDate getDate() {
|
||||
return date;
|
||||
// Возвращаем только статус 201 без тела
|
||||
return ResponseEntity.status(HttpStatus.CREATED).build();
|
||||
|
||||
} catch (EmployeeNotFoundException e) {
|
||||
// 401 - кода не существует
|
||||
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
|
||||
|
||||
} catch (BookingConflictException e) {
|
||||
// 409 - конфликт (уже забронировано)
|
||||
return ResponseEntity.status(HttpStatus.CONFLICT).build();
|
||||
|
||||
} catch (InvalidBookingException e) {
|
||||
// 400 - невалидные данные
|
||||
return ResponseEntity.status(HttpStatus.BAD_REQUEST).build();
|
||||
|
||||
} catch (Exception e) {
|
||||
// 500 - внутренняя ошибка сервера
|
||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
|
||||
}
|
||||
}
|
||||
|
||||
public void setDate(LocalDate date) {
|
||||
this.date = date;
|
||||
}
|
||||
|
||||
public long getPlaceId() {
|
||||
return placeId;
|
||||
}
|
||||
|
||||
public void setPlaceId(long placeId) {
|
||||
this.placeId = placeId;
|
||||
}
|
||||
private Booking.BookingResponse convertToResponse(Booking booking) {
|
||||
Booking.BookingResponse response = new Booking.BookingResponse();
|
||||
response.setId(booking.getId());
|
||||
response.setDate(booking.getDate());
|
||||
response.setPlaceId(booking.getPlace().getId());
|
||||
response.setPlaceName(booking.getPlace().getPlace());
|
||||
response.setEmployeeId(booking.getEmployee().getId());
|
||||
response.setEmployeeName(booking.getEmployee().getName());
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.example.nto.entity;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonBackReference;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import jakarta.persistence.*;
|
||||
import lombok.AllArgsConstructor;
|
||||
@@ -45,4 +46,31 @@ public class Booking {
|
||||
private long id;
|
||||
private String place;
|
||||
}
|
||||
@Data
|
||||
public class CreateBookingRequest {
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
private LocalDate date;
|
||||
private long placeId;
|
||||
}
|
||||
@Data
|
||||
public class ErrorResponse {
|
||||
private String error;
|
||||
private String message;
|
||||
|
||||
public ErrorResponse(String error, String message) {
|
||||
this.error = error;
|
||||
this.message = message;
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class BookingResponse {
|
||||
private Long id;
|
||||
@JsonFormat(pattern = "yyyy-MM-dd")
|
||||
private LocalDate date;
|
||||
private Long placeId;
|
||||
private String placeName;
|
||||
private Long employeeId;
|
||||
private String employeeName;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.example.nto.exception;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
@ResponseStatus(HttpStatus.CONFLICT)
|
||||
public class BookingConflictException extends RuntimeException {
|
||||
public BookingConflictException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.example.nto.exception;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
@ResponseStatus(HttpStatus.NOT_FOUND)
|
||||
public class EmployeeNotFoundException extends RuntimeException {
|
||||
public EmployeeNotFoundException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.example.nto.exception;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||
public class InvalidBookingException extends RuntimeException {
|
||||
public InvalidBookingException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -23,9 +23,7 @@ public interface BookingRepository extends JpaRepository<Booking, Long> {
|
||||
|
||||
Optional<Booking> findById(Long id);
|
||||
|
||||
Optional<Booking> findByDateAndPlace_Id(LocalDate date, Long placeId);
|
||||
|
||||
List<Booking> findByDateAndEmployee_Code(LocalDate date, String employeeCode);
|
||||
|
||||
List<Booking> findByDateInAndEmployee_Code(List<LocalDate> dates, String employeeCode);
|
||||
Optional<Booking> findByDateAndPlace_Id(LocalDate date, long placeId);
|
||||
List<Booking> findByDateAndEmployee_Code(LocalDate date, String employeeCode);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
package com.example.nto.service.impl;
|
||||
|
||||
import com.example.nto.entity.Booking;
|
||||
import com.example.nto.entity.Booking.AvailablePlaceDto;
|
||||
import com.example.nto.entity.Employee;
|
||||
import com.example.nto.entity.Place;
|
||||
import com.example.nto.exception.BookingConflictException;
|
||||
import com.example.nto.exception.EmployeeNotFoundException;
|
||||
import com.example.nto.exception.InvalidBookingException;
|
||||
import com.example.nto.repository.BookingRepository;
|
||||
import com.example.nto.repository.EmployeeRepository;
|
||||
import com.example.nto.repository.PlaceRepository;
|
||||
@@ -10,6 +14,7 @@ import com.example.nto.service.BookingService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.util.*;
|
||||
@@ -49,7 +54,7 @@ public class BookingServiceImpl implements BookingService {
|
||||
public boolean isEmployeeExists(String code) {
|
||||
return employeeRepository.findByCode(code).isPresent();
|
||||
}
|
||||
public Map<String, List<Booking.AvailablePlaceDto>> getAvailablePlaces(String employeeCode) {
|
||||
public Map<String, List<AvailablePlaceDto>> getAvailablePlaces(String employeeCode) {
|
||||
// 1. Получаем сотрудника (для контекста)
|
||||
Employee employee = employeeRepository.findByCode(employeeCode)
|
||||
.orElseThrow(() -> new RuntimeException("Employee not found"));
|
||||
@@ -74,7 +79,7 @@ public class BookingServiceImpl implements BookingService {
|
||||
.collect(Collectors.groupingBy(Booking::getDate));
|
||||
|
||||
// 6. Формируем итоговый ответ
|
||||
Map<String, List<Booking.AvailablePlaceDto>> result = new HashMap<>();
|
||||
Map<String, List<AvailablePlaceDto>> result = new HashMap<>();
|
||||
|
||||
for (LocalDate date : targetDates) {
|
||||
String dateKey = date.toString(); // Формат: "yyyy-MM-dd"
|
||||
@@ -88,10 +93,10 @@ public class BookingServiceImpl implements BookingService {
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
// Фильтруем свободные места
|
||||
List<Booking.AvailablePlaceDto> available = allPlaces.stream()
|
||||
List<AvailablePlaceDto> available = allPlaces.stream()
|
||||
.filter(place -> !occupiedPlaceIds.contains(place.getId()))
|
||||
.map(place -> {
|
||||
Booking.AvailablePlaceDto dto = new Booking.AvailablePlaceDto();
|
||||
AvailablePlaceDto dto = new AvailablePlaceDto();
|
||||
dto.setId(place.getId());
|
||||
dto.setPlace(place.getPlace());
|
||||
return dto;
|
||||
@@ -104,49 +109,67 @@ public class BookingServiceImpl implements BookingService {
|
||||
return result;
|
||||
}
|
||||
@Override
|
||||
@Transactional
|
||||
public Booking createBooking(String employeeCode, LocalDate date, long placeId) {
|
||||
// Проверяем сотрудника
|
||||
// 1. Проверяем существование сотрудника (401 если нет)
|
||||
Employee employee = employeeRepository.findByCode(employeeCode)
|
||||
.orElseThrow(() -> new RuntimeException("Employee not found with code: " + employeeCode));
|
||||
.orElseThrow(() -> new EmployeeNotFoundException("Employee with code '" + employeeCode + "' not found"));
|
||||
|
||||
// Проверяем место
|
||||
// 2. Проверяем существование места (400 если нет)
|
||||
Place place = placeRepository.findById(placeId)
|
||||
.orElseThrow(() -> new RuntimeException("Place not found with id: " + placeId));
|
||||
.orElseThrow(() -> new InvalidBookingException("Place with id " + placeId + " not found"));
|
||||
|
||||
// Проверяем, что дата в пределах 3 дней от сегодня
|
||||
LocalDate today = LocalDate.now();
|
||||
LocalDate maxDate = today.plusDays(3);
|
||||
// 3. Валидация даты (400 если невалидно)
|
||||
validateBookingDate(date);
|
||||
|
||||
if (date.isBefore(today)) {
|
||||
throw new RuntimeException("Cannot book in the past. Date: " + date);
|
||||
}
|
||||
// 4. Проверяем, не занято ли место (409 если занято)
|
||||
checkPlaceAvailability(date, placeId);
|
||||
|
||||
if (date.isAfter(maxDate)) {
|
||||
throw new RuntimeException("Can only book up to 3 days in advance. Date: " + date);
|
||||
}
|
||||
// 5. Проверяем, нет ли уже брони у сотрудника на эту дату (409 если есть)
|
||||
checkEmployeeBookingConflict(employeeCode, date);
|
||||
|
||||
// Проверяем, не занято ли уже это место на эту дату
|
||||
Optional<Booking> existingPlaceBooking = bookingRepository.findByDateAndPlace_Id(date, placeId);
|
||||
if (existingPlaceBooking.isPresent()) {
|
||||
throw new RuntimeException("Place " + placeId + " is already booked for " + date);
|
||||
}
|
||||
|
||||
// Проверяем, нет ли у сотрудника уже брони на эту дату
|
||||
List<Booking> employeeBookings = bookingRepository.findByDateAndEmployee_Code(date, employeeCode);
|
||||
if (!employeeBookings.isEmpty()) {
|
||||
throw new RuntimeException("Employee already has a booking on " + date);
|
||||
}
|
||||
|
||||
// Создаем новое бронирование
|
||||
// 6. Создаем и сохраняем бронирование
|
||||
Booking booking = Booking.builder()
|
||||
.date(date)
|
||||
.place(place)
|
||||
.employee(employee)
|
||||
.build();
|
||||
|
||||
// Сохраняем в базу
|
||||
return bookingRepository.save(booking);
|
||||
}
|
||||
|
||||
private void validateBookingDate(LocalDate date) {
|
||||
LocalDate today = LocalDate.now();
|
||||
LocalDate maxDate = today.plusDays(3);
|
||||
|
||||
if (date == null) {
|
||||
throw new InvalidBookingException("Date is required");
|
||||
}
|
||||
|
||||
if (date.isBefore(today)) {
|
||||
throw new InvalidBookingException("Cannot book in the past");
|
||||
}
|
||||
|
||||
if (date.isAfter(maxDate)) {
|
||||
throw new InvalidBookingException("Can only book up to 3 days in advance");
|
||||
}
|
||||
}
|
||||
|
||||
private void checkPlaceAvailability(LocalDate date, long placeId) {
|
||||
Optional<Booking> existingBooking = bookingRepository.findByDateAndPlace_Id(date, placeId);
|
||||
if (existingBooking.isPresent()) {
|
||||
throw new BookingConflictException("Place " + placeId + " is already booked for " + date);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkEmployeeBookingConflict(String employeeCode, LocalDate date) {
|
||||
List<Booking> employeeBookingsOnDate = bookingRepository.findByDateAndEmployee_Code(date, employeeCode);
|
||||
if (!employeeBookingsOnDate.isEmpty()) {
|
||||
throw new BookingConflictException("Employee already has a booking on " + date);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user